diff --git a/.bazelrc b/.bazelrc index 3c783e1a62b0..03d5a5f7d48e 100644 --- a/.bazelrc +++ b/.bazelrc @@ -64,7 +64,7 @@ common --experimental_allow_tags_propagation build:linux --copt=-fdebug-types-section build:linux --copt=-fPIC build:linux --copt=-Wno-deprecated-declarations -build:linux --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 +build:linux --cxxopt=-std=c++20 --host_cxxopt=-std=c++20 build:linux --cxxopt=-fsized-deallocation --host_cxxopt=-fsized-deallocation build:linux --conlyopt=-fexceptions build:linux --fission=dbg,opt @@ -133,7 +133,7 @@ build:clang-asan --linkopt --rtlib=compiler-rt build:clang-asan --linkopt --unwindlib=libgcc # macOS -build:macos --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 +build:macos --cxxopt=-std=c++20 --host_cxxopt=-std=c++20 build:macos --action_env=PATH=/opt/homebrew/bin:/opt/local/bin:/usr/local/bin:/usr/bin:/bin build:macos --host_action_env=PATH=/opt/homebrew/bin:/opt/local/bin:/usr/local/bin:/usr/bin:/bin build:macos --define tcmalloc=disabled @@ -194,7 +194,7 @@ build:libc++ --define force_libcpp=enabled build:libc++20 --config=libc++ # gRPC has a lot of deprecated-enum-enum-conversion warning. Remove once it is addressed -build:libc++20 --cxxopt=-std=c++20 --copt=-Wno-error=deprecated-enum-enum-conversion +build:libc++20 --copt=-Wno-error=deprecated-enum-enum-conversion # Optimize build for binary size reduction. build:sizeopt -c opt --copt -Os @@ -510,16 +510,18 @@ build:rbe-engflow --remote_timeout=3600s build:rbe-engflow --bes_timeout=3600s build:rbe-engflow --bes_upload_mode=fully_async -build:rbe-envoy-engflow --google_default_credentials=false -build:rbe-envoy-engflow --remote_cache=grpcs://morganite.cluster.engflow.com +build:cache-envoy-engflow --google_default_credentials=false +build:cache-envoy-engflow --remote_cache=grpcs://morganite.cluster.engflow.com +build:cache-envoy-engflow --remote_timeout=3600s +build:cache-envoy-engflow --credential_helper=*.engflow.com=%workspace%/bazel/engflow-bazel-credential-helper.sh +build:cache-envoy-engflow --grpc_keepalive_time=30s +build:bes-envoy-engflow --bes_backend=grpcs://morganite.cluster.engflow.com/ +build:bes-envoy-engflow --bes_results_url=https://morganite.cluster.engflow.com/invocation/ +build:bes-envoy-engflow --bes_timeout=3600s +build:bes-envoy-engflow --bes_upload_mode=fully_async +build:rbe-envoy-engflow --config=cache-envoy-engflow +build:rbe-envoy-engflow --config=bes-envoy-engflow build:rbe-envoy-engflow --remote_executor=grpcs://morganite.cluster.engflow.com -build:rbe-envoy-engflow --bes_backend=grpcs://morganite.cluster.engflow.com/ -build:rbe-envoy-engflow --bes_results_url=https://morganite.cluster.engflow.com/invocation/ -build:rbe-envoy-engflow --credential_helper=*.engflow.com=%workspace%/bazel/engflow-bazel-credential-helper.sh -build:rbe-envoy-engflow --grpc_keepalive_time=30s -build:rbe-envoy-engflow --remote_timeout=3600s -build:rbe-envoy-engflow --bes_timeout=3600s -build:rbe-envoy-engflow --bes_upload_mode=fully_async build:rbe-envoy-engflow --remote_default_exec_properties=container-image=docker://docker.io/envoyproxy/envoy-build-ubuntu:0ca52447572ee105a4730da5e76fe47c9c5a7c64@sha256:d736c58f06f36848e7966752cc7e01519cc1b5101a178d5c6634807e8ac3deab ############################################################################# diff --git a/.gitattributes b/.gitattributes index 8bd5b8b56f71..0dd1d568f0b3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ +* text=auto eol=lf + /generated_api_shadow/envoy/** linguist-generated=true /generated_api_shadow/bazel/** linguist-generated=true *.svg binary diff --git a/.github/config.yml b/.github/config.yml index ec426e498fcc..b3bdcd3985c7 100644 --- a/.github/config.yml +++ b/.github/config.yml @@ -254,6 +254,7 @@ run: mobile-core: paths: - "**/*" + - "*" mobile-format: paths: - .bazelrc diff --git a/.github/workflows/_cache.yml b/.github/workflows/_cache.yml index 199480da01f2..a7283626bf3e 100644 --- a/.github/workflows/_cache.yml +++ b/.github/workflows/_cache.yml @@ -29,7 +29,7 @@ on: # For a job that does, you can restore with something like: # # steps: -# - uses: envoyproxy/toolshed/gh-actions/docker/cache/restore@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 +# - uses: envoyproxy/toolshed/gh-actions/docker/cache/restore@actions-v0.2.27 # with: # key: "${{ needs.env.outputs.build-image }}" # @@ -39,20 +39,20 @@ jobs: docker: runs-on: ubuntu-22.04 steps: - - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 id: appauth name: Appauth (mutex lock) with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/docker/cache/prime@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/docker/cache/prime@actions-v0.2.27 id: docker name: Prime Docker cache (${{ inputs.image-tag }}) with: image-tag: ${{ inputs.image-tag }} lock-token: ${{ steps.appauth.outputs.token }} lock-repository: ${{ inputs.lock-repository }} - - uses: envoyproxy/toolshed/gh-actions/jq@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 id: data name: Cache data with: @@ -60,7 +60,7 @@ jobs: input: | cached: ${{ steps.docker.outputs.cached }} key: ${{ inputs.image-tag }} - - uses: envoyproxy/toolshed/gh-actions/json/table@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/json/table@actions-v0.2.27 name: Summary with: json: ${{ steps.data.outputs.value }} diff --git a/.github/workflows/_finish.yml b/.github/workflows/_finish.yml index c09f05bc130c..bdf6441467bb 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 name: Incoming data id: needs with: @@ -87,7 +87,7 @@ jobs: summary: "Check has finished", text: $text}}}} - - uses: envoyproxy/toolshed/gh-actions/jq@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 name: Appauth id: appauth with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/github/checks@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.27 name: Update check with: action: update diff --git a/.github/workflows/_load.yml b/.github/workflows/_load.yml index c0eefc1f0363..26912abbdfc6 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/env/load@actions-v0.2.27 name: Load env id: data with: @@ -102,13 +102,13 @@ jobs: GH_TOKEN: ${{ github.token }} # Update the check - - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 name: Appauth id: appauth with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/github/checks@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 id: request-output name: Load request with: diff --git a/.github/workflows/_load_env.yml b/.github/workflows/_load_env.yml index 97733df48af1..a4fbad786893 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 id: started name: Create timestamp with: options: -r filter: | now - - uses: envoyproxy/toolshed/gh-actions/github/checkout@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 id: checkout name: Checkout Envoy repository - name: Generate environment variables - uses: envoyproxy/toolshed/gh-actions/envoy/ci/env@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/envoy/ci/env@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/env/summary@actions-v0.2.27 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/_precheck_deps.yml b/.github/workflows/_precheck_deps.yml index d50d62f0ed12..8864b7beada4 100644 --- a/.github/workflows/_precheck_deps.yml +++ b/.github/workflows/_precheck_deps.yml @@ -55,4 +55,4 @@ jobs: ref: ${{ fromJSON(inputs.request).request.sha }} persist-credentials: false - name: Dependency Review - uses: actions/dependency-review-action@4901385134134e04cec5fbe5ddfe3b2c5bd5d976 # v4.0.0 + uses: actions/dependency-review-action@9129d7d40b8c12c1ed0f60400d00c92d437adcce # v4.1.3 diff --git a/.github/workflows/_request.yml b/.github/workflows/_request.yml index cd21dccc20ee..4ae97b2865eb 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 id: started name: Create timestamp with: options: -r filter: | now - - uses: envoyproxy/toolshed/gh-actions/github/checkout@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/envoy/ci/request@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/env/summary@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 id: data with: input: | diff --git a/.github/workflows/_run.yml b/.github/workflows/_run.yml index 14199b0fcd73..5b1ad16e9f18 100644 --- a/.github/workflows/_run.yml +++ b/.github/workflows/_run.yml @@ -52,6 +52,8 @@ on: ERROR error: Error: + fail-match: + type: string notice-match: type: string default: | @@ -94,7 +96,7 @@ on: summary-post: type: string default: | - - uses: envoyproxy/toolshed/gh-actions/envoy/run/summary@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/run/summary@actions-v0.2.27 with: context: %{{ inputs.context }} steps-pre: @@ -116,6 +118,7 @@ on: type: string timeout-minutes: type: number + default: 60 trusted: type: boolean required: true @@ -155,7 +158,7 @@ jobs: name: ${{ inputs.command }} ${{ inputs.target }} timeout-minutes: ${{ inputs.timeout-minutes }} steps: - - uses: envoyproxy/toolshed/gh-actions/jq@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 id: started name: Create timestamp with: @@ -163,7 +166,7 @@ jobs: filter: | now # This controls which input vars are exposed to the run action (and related steps) - - uses: envoyproxy/toolshed/gh-actions/jq@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 name: Context id: context with: @@ -184,11 +187,11 @@ 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/docker/cache/restore@actions-v0.2.27 with: image_tag: ${{ inputs.cache-build-image }} - - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 id: appauth name: Appauth if: ${{ inputs.trusted }} @@ -199,7 +202,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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 id: checkout name: Checkout Envoy repository with: @@ -216,7 +219,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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 id: checkout-extra name: Checkout extra repository (for publishing) if: ${{ inputs.checkout-extra }} @@ -224,7 +227,7 @@ jobs: config: ${{ inputs.checkout-extra }} ssh-key: ${{ inputs.trusted && inputs.ssh-key-extra || '' }} - - uses: envoyproxy/toolshed/gh-actions/github/run@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.27 name: Run CI ${{ inputs.command }} ${{ inputs.target }} with: args: ${{ inputs.args != '--' && inputs.args || inputs.target }} @@ -238,6 +241,7 @@ jobs: downloads: ${{ inputs.downloads }} entrypoint: ${{ inputs.entrypoint }} error-match: ${{ inputs.error-match }} + fail-match: ${{ inputs.fail-match }} notice-match: ${{ inputs.notice-match }} output-path: ${{ inputs.output-path }} report-pre: ${{ inputs.report-pre }} diff --git a/.github/workflows/_stage_publish.yml b/.github/workflows/_stage_publish.yml index c8925a75c5a4..94e7766df102 100644 --- a/.github/workflows/_stage_publish.yml +++ b/.github/workflows/_stage_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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/fetch@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 id: appauth with: app_id: ${{ secrets.ENVOY_CI_SYNC_APP_ID }} key: ${{ secrets.ENVOY_CI_SYNC_APP_KEY }} - - uses: envoyproxy/toolshed/gh-actions/dispatch@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/dispatch@actions-v0.2.27 with: ref: main repository: ${{ fromJSON(inputs.request).request.version.dev && 'envoyproxy/envoy-website' || 'envoyproxy/archive' }} diff --git a/.github/workflows/_stage_verify.yml b/.github/workflows/_stage_verify.yml index d9bd340881cc..33d32850dfab 100644 --- a/.github/workflows/_stage_verify.yml +++ b/.github/workflows/_stage_verify.yml @@ -50,7 +50,7 @@ jobs: rbe: false steps-pre: | - id: url - uses: envoyproxy/toolshed/gh-actions/jq@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 with: options: -Rr input: >- @@ -66,15 +66,15 @@ jobs: end | . as $bucket | "https://storage.googleapis.com/\($bucket)/\($sha)" - - uses: envoyproxy/toolshed/gh-actions/docker/fetch@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.27 with: url: %{{ steps.url.outputs.value }}/docker/envoy.tar variant: dev - - uses: envoyproxy/toolshed/gh-actions/docker/fetch@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.27 with: url: %{{ steps.url.outputs.value }}/docker/envoy-contrib.tar variant: contrib-dev - - uses: envoyproxy/toolshed/gh-actions/docker/fetch@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.27 with: url: %{{ steps.url.outputs.value }}/docker/envoy-google-vrp.tar variant: google-vrp-dev diff --git a/.github/workflows/_start.yml b/.github/workflows/_start.yml index 458dac614033..7ed6c1776e9f 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 name: Appauth id: appauth with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/github/checks@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/json/table@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/env/save@actions-v0.2.27 name: Save env id: data with: diff --git a/.github/workflows/codeql-daily.yml b/.github/workflows/codeql-daily.yml index 2f8fe09ad17c..0217ac0c4462 100644 --- a/.github/workflows/codeql-daily.yml +++ b/.github/workflows/codeql-daily.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Free disk space - uses: envoyproxy/toolshed/gh-actions/diskspace@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/diskspace@actions-v0.2.27 with: to_remove: | /usr/local/lib/android diff --git a/.github/workflows/codeql-push.yml b/.github/workflows/codeql-push.yml index 856f6aafdf48..91cfb8b2df1f 100644 --- a/.github/workflows/codeql-push.yml +++ b/.github/workflows/codeql-push.yml @@ -61,7 +61,7 @@ jobs: - name: Free disk space if: ${{ env.BUILD_TARGETS != '' }} - uses: envoyproxy/toolshed/gh-actions/diskspace@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/diskspace@actions-v0.2.27 with: to_remove: | /usr/local/lib/android diff --git a/.github/workflows/command.yml b/.github/workflows/command.yml index 3c25b7c7bb6d..0d31d698ae5f 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/command@actions-v0.2.27 name: Parse command from comment id: command with: @@ -37,14 +37,14 @@ jobs: ^/(retest) # /retest - - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/retest@actions-v0.2.27 if: ${{ steps.command.outputs.command == 'retest' }} name: Retest with: diff --git a/.github/workflows/envoy-dependency.yml b/.github/workflows/envoy-dependency.yml index e78ace0acd15..1aae9d60d58d 100644 --- a/.github/workflows/envoy-dependency.yml +++ b/.github/workflows/envoy-dependency.yml @@ -50,16 +50,16 @@ jobs: steps: - id: appauth name: Appauth - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 with: token: ${{ steps.appauth.outputs.token }} - - uses: envoyproxy/toolshed/gh-actions/bson@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/bson@actions-v0.2.27 id: update name: Update dependency (${{ inputs.dependency }}) with: @@ -94,13 +94,13 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: envoyproxy/toolshed/gh-actions/upload/diff@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/upload/diff@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.27 with: base: main body: | @@ -131,11 +131,11 @@ jobs: steps: - id: appauth name: Appauth - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 with: app_id: ${{ secrets.ENVOY_CI_DEP_APP_ID }} key: ${{ secrets.ENVOY_CI_DEP_APP_KEY }} - - uses: envoyproxy/toolshed/gh-actions/github/checkout@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 id: checkout name: Checkout Envoy repository with: @@ -177,7 +177,7 @@ jobs: - name: Check Docker SHAs id: build-images - uses: envoyproxy/toolshed/gh-actions/docker/shas@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/docker/shas@actions-v0.2.27 with: images: | sha: envoyproxy/envoy-build-ubuntu:${{ steps.build-tools.outputs.tag }} @@ -206,7 +206,7 @@ jobs: name: Update SHAs working-directory: envoy - name: Create a PR - uses: envoyproxy/toolshed/gh-actions/github/pr@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.27 with: base: main body: Created by Envoy dependency bot diff --git a/.github/workflows/envoy-macos.yml b/.github/workflows/envoy-macos.yml index 22d975afd7ce..087aa8a3433d 100644 --- a/.github/workflows/envoy-macos.yml +++ b/.github/workflows/envoy-macos.yml @@ -37,8 +37,6 @@ jobs: permissions: contents: read packages: read - secrets: - rbe-key: ${{ secrets.GCP_SERVICE_ACCOUNT_KEY }} if: ${{ fromJSON(needs.load.outputs.request).run.build-macos }} needs: - load @@ -49,6 +47,7 @@ jobs: container-command: request: ${{ needs.load.outputs.request }} runs-on: macos-14-xlarge + source: ${{ matrix.source }} steps-post: steps-pre: ${{ matrix.steps-pre }} target: ${{ matrix.target }} @@ -59,19 +58,14 @@ jobs: include: - target: ci/mac_ci_steps.sh name: macOS - steps-pre: | - - run: ./ci/mac_ci_setup.sh - shell: bash - name: Setup macos source: | - GCP_SERVICE_ACCOUNT_KEY_PATH=$(mktemp -t gcp_service_account.XXXXXX.json) - bash -c "echo \"${RBE_KEY}\" | base64 --decode > \"${GCP_SERVICE_ACCOUNT_KEY_PATH}\"" + source ./ci/mac_ci_setup.sh _BAZEL_BUILD_EXTRA_OPTIONS=( --remote_download_toplevel --flaky_test_attempts=2 - --config=cache-google - --config=ci - --google_credentials=${GCP_SERVICE_ACCOUNT_KEY_PATH}) + --config=bes-envoy-engflow + --config=cache-envoy-engflow + --config=ci) export BAZEL_BUILD_EXTRA_OPTIONS=${_BAZEL_BUILD_EXTRA_OPTIONS[*]} request: diff --git a/.github/workflows/envoy-release.yml b/.github/workflows/envoy-release.yml index 1466c5d57d31..bc5be1af287d 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/email/validate@actions-v0.2.27 with: email: ${{ inputs.author }} - - uses: envoyproxy/toolshed/gh-actions/github/run@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.27 with: base: ${{ github.ref_name }} commit: false @@ -136,18 +136,18 @@ jobs: steps: - id: appauth name: App auth - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 with: committer-name: ${{ env.COMMITTER_NAME }} committer-email: ${{ env.COMMITTER_EMAIL }} - - uses: envoyproxy/toolshed/gh-actions/github/run@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.27 name: Sync version histories with: command: >- @@ -157,7 +157,7 @@ jobs: -- --signoff="${{ env.COMMITTER_NAME }} <${{ env.COMMITTER_EMAIL }}>" - name: Create a PR - uses: envoyproxy/toolshed/gh-actions/github/pr@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.27 with: append-commit-message: true base: ${{ github.ref_name }} @@ -187,13 +187,13 @@ jobs: steps: - id: appauth name: App auth - uses: envoyproxy/toolshed/gh-actions/appauth@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.27 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 f9d2dc8cdce0..bfa6fbb385fd 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.27 id: appauth with: app_id: ${{ secrets.ENVOY_CI_SYNC_APP_ID }} key: ${{ secrets.ENVOY_CI_SYNC_APP_KEY }} - - uses: envoyproxy/toolshed/gh-actions/dispatch@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/dispatch@actions-v0.2.27 with: repository: "envoyproxy/${{ matrix.downstream }}" ref: main diff --git a/.github/workflows/envoy-windows.yml b/.github/workflows/envoy-windows.yml index 17be3ff309e8..fbd01b992a95 100644 --- a/.github/workflows/envoy-windows.yml +++ b/.github/workflows/envoy-windows.yml @@ -65,6 +65,7 @@ jobs: steps-post: target: ${{ matrix.target }} temp-dir: 'C:\Users\runner\AppData\Local\Temp\bazel-shared' + timeout-minutes: 120 trusted: ${{ fromJSON(needs.load.outputs.trusted) }} upload-name: windows.release upload-path: 'C:\Users\runner\AppData\Local\Temp\envoy' diff --git a/.github/workflows/garbage.yml b/.github/workflows/garbage.yml new file mode 100644 index 000000000000..19110b583254 --- /dev/null +++ b/.github/workflows/garbage.yml @@ -0,0 +1,40 @@ +name: Garbage collection + +permissions: + contents: read + +on: + schedule: + - cron: '0 0 * * *' + +concurrency: + group: ${{ github.head_ref || github.run_id }}-${{ github.workflow }} + cancel-in-progress: true + + +jobs: + azp-agents: + runs-on: ubuntu-22.04 + if: github.repository == 'envoyproxy/envoy' + strategy: + matrix: + include: + - target: envoy-arm-large + pool-id: 21 + - target: envoy-arm-small + pool-id: 24 + - target: envoy-x64-large + pool-id: 20 + - target: envoy-x64-small + pool-id: 23 + - target: salvo-control + pool-id: 22 + - target: x64-nano + pool-id: 17 + steps: + - name: Remove dead AZP agents (${{ matrix.target }}) + uses: envoyproxy/toolshed/gh-actions/azp/agent-cleanup@actions-v0.2.27 + with: + azp-org: cncf + azp-token: ${{ secrets.AZP_TOKEN }} + pool-id: ${{ matrix.pool-id }} diff --git a/.github/workflows/mobile-android_build.yml b/.github/workflows/mobile-android_build.yml index 70f271a11962..24c26d702ec9 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/pre@actions-v0.2.27 steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/pre@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.27 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@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.27 with: apk: bazel-bin/test/kotlin/apps/experimental/hello_envoy_kt.apk app: io.envoyproxy.envoymobile.helloenvoyexperimentaltest/.MainActivity diff --git a/.github/workflows/mobile-compile_time_options.yml b/.github/workflows/mobile-compile_time_options.yml index be3d009d37d9..081acec27cb2 100644 --- a/.github/workflows/mobile-compile_time_options.yml +++ b/.github/workflows/mobile-compile_time_options.yml @@ -103,10 +103,7 @@ jobs: --config=mobile-remote-ci-macos-swift //library/swift:ios_framework source: | - # TODO(fredyw): A workaround since mobile/WORKSPACE requires Android SDK to be available - # and the GitHub Action runner image no longer includes Android SDK 30: - # https://github.com/actions/runner-images/issues/8952 - ./ci/mac_ci_setup.sh --android + source ./ci/mac_ci_setup.sh ./bazelw shutdown request: diff --git a/.github/workflows/mobile-ios_build.yml b/.github/workflows/mobile-ios_build.yml index 327c815f58d8..f64d6a42f5d3 100644 --- a/.github/workflows/mobile-ios_build.yml +++ b/.github/workflows/mobile-ios_build.yml @@ -44,10 +44,7 @@ jobs: request: ${{ needs.load.outputs.request }} runs-on: macos-12 source: | - # TODO(fredyw): A workaround since mobile/WORKSPACE requires Android SDK to be available - # and the GitHub Action runner image no longer includes Android SDK 30: - # https://github.com/actions/runner-images/issues/8952 - ./ci/mac_ci_setup.sh --android + source ./ci/mac_ci_setup.sh ./bazelw shutdown steps-post: ${{ matrix.steps-post }} target: ${{ matrix.target }} @@ -86,17 +83,17 @@ jobs: request: ${{ needs.load.outputs.request }} runs-on: macos-12 source: | - # TODO(fredyw): A workaround since mobile/WORKSPACE requires Android SDK to be available - # and the GitHub Action runner image no longer includes Android SDK 30: - # https://github.com/actions/runner-images/issues/8952 - ./ci/mac_ci_setup.sh --android + source ./ci/mac_ci_setup.sh ./bazelw shutdown steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@actions-v0.2.27 with: app: ${{ matrix.app }} args: ${{ matrix.args || '--config=mobile-remote-ci-macos-ios' }} expected: received headers with status ${{ matrix.expected-status }} + env: + ANDROID_NDK_HOME: + ANDROID_HOME: target: ${{ matrix.target }} timeout-minutes: ${{ matrix.timeout-minutes }} trusted: ${{ fromJSON(needs.load.outputs.trusted) }} @@ -131,18 +128,18 @@ jobs: request: ${{ needs.load.outputs.request }} runs-on: macos-12 source: | - # TODO(fredyw): A workaround since mobile/WORKSPACE requires Android SDK to be available - # and the GitHub Action runner image no longer includes Android SDK 30: - # https://github.com/actions/runner-images/issues/8952 - ./ci/mac_ci_setup.sh --android + source ./ci/mac_ci_setup.sh steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@680d414be3f56cbb161dfdebebece85d81c3f686 # actions-v0.2.24 + - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@actions-v0.2.27 with: app: ${{ matrix.app }} args: ${{ matrix.args || '--config=mobile-remote-ci-macos-ios' }} expected: >- ${{ matrix.expected || format('received headers with status {0}', matrix.expected-status) }} + env: + ANDROID_NDK_HOME: + ANDROID_HOME: target: ${{ matrix.target }} timeout-minutes: 50 trusted: ${{ fromJSON(needs.load.outputs.trusted) }} diff --git a/.github/workflows/mobile-ios_tests.yml b/.github/workflows/mobile-ios_tests.yml index d77c8a2b94b7..b07e6672e2f3 100644 --- a/.github/workflows/mobile-ios_tests.yml +++ b/.github/workflows/mobile-ios_tests.yml @@ -44,10 +44,7 @@ jobs: request: ${{ needs.load.outputs.request }} runs-on: macos-12 source: | - # TODO(fredyw): A workaround since mobile/WORKSPACE requires Android SDK to be available - # and the GitHub Action runner image no longer includes Android SDK 30: - # https://github.com/actions/runner-images/issues/8952 - ./ci/mac_ci_setup.sh --android + source ./ci/mac_ci_setup.sh steps-post: ${{ matrix.steps-post }} target: ${{ matrix.target }} timeout-minutes: ${{ matrix.timeout-minutes }} diff --git a/.github/workflows/mobile-release_validation.yml b/.github/workflows/mobile-release_validation.yml index 6179cf99fd1c..9fa0847f88ca 100644 --- a/.github/workflows/mobile-release_validation.yml +++ b/.github/workflows/mobile-release_validation.yml @@ -51,10 +51,7 @@ jobs: request: ${{ needs.load.outputs.request }} runs-on: macos-12 source: | - # TODO(fredyw): A workaround since mobile/WORKSPACE always requires Android SDK to be available - # and the GitHub Action runner image no longer includes Android SDK 30: - # https://github.com/actions/runner-images/issues/8952 - ./ci/mac_ci_setup.sh --android + source ./ci/mac_ci_setup.sh # Ignore errors: Bad CRC when unzipping large files: https://bbs.archlinux.org/viewtopic.php?id=153011 steps-post: | - run: | diff --git a/CODEOWNERS b/CODEOWNERS index bd937e7a08ad..d08360957e56 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -258,6 +258,7 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123 # proxy protocol /*/extensions/filters/listener/proxy_protocol @ggreenway @soulxu # access loggers +/*/extensions/access_loggers/fluentd @ohadvano @wbpcode /*/extensions/access_loggers/grpc @wbpcode @cpakulski @giantcroc @gyohuangxin # stats /*/extensions/stat_sinks/statsd @mattklein123 @suniltheta diff --git a/OWNERS.md b/OWNERS.md index a8137725f596..12711f3880c0 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -40,7 +40,7 @@ routing PRs, questions, etc. to the right place. * Stats, abseil, scalability, and performance. * Adi Peleg ([adisuissa](https://github.com/adisuissa)) (adip@google.com) * xDS APIs, configuration, control plane, fuzzing. -* Kevin Baichoo ([KBaichoo](https://github.com/KBaichoo)) (kbaichoo@google.com) +* Kevin Baichoo ([KBaichoo](https://github.com/KBaichoo)) (envoy@kevinbaichoo.com) * Data plane, overload management, flow control. * Keith Smiley ([keith](https://github.com/keith)) (keithbsmiley@gmail.com) * Bazel, CI, compilers, linkers, general build issues, etc. @@ -59,6 +59,8 @@ The following Envoy maintainers have final say over any changes only affecting / * Ali Beyad ([abeyad](https://github.com/abeyad)) (abeyad@google.com) * xDS, C++ integration tests. +* Fredy Wijaya ([fredyw](https://github.com/fredyw)) (fredyw@google.com) + * Android, Java, Kotlin, JNI. # Senior extension maintainers @@ -80,7 +82,7 @@ without further review. * Pradeep Rao ([pradeepcrao](https://github.com/pradeepcrao)) (pcrao@google.com) * Kateryna Nezdolii ([nezdolik](https://github.com/nezdolik)) (kateryna.nezdolii@gmail.com) * Boteng Yao ([botengyao](https://github.com/botengyao)) (boteng@google.com) -* Kevin Baichoo ([KBaichoo](https://github.com/KBaichoo)) (kbaichoo@google.com) +* Kevin Baichoo ([KBaichoo](https://github.com/KBaichoo)) (envoy@kevinbaichoo.com) * Tianyu Xia ([tyxia](https://github.com/tyxia)) (tyxia@google.com) # Emeritus maintainers diff --git a/api/BUILD b/api/BUILD index 2eadff1f606f..33de22a6811c 100644 --- a/api/BUILD +++ b/api/BUILD @@ -134,6 +134,7 @@ proto_library( "//envoy/data/tap/v3:pkg", "//envoy/extensions/access_loggers/file/v3:pkg", "//envoy/extensions/access_loggers/filters/cel/v3:pkg", + "//envoy/extensions/access_loggers/fluentd/v3:pkg", "//envoy/extensions/access_loggers/grpc/v3:pkg", "//envoy/extensions/access_loggers/open_telemetry/v3:pkg", "//envoy/extensions/access_loggers/stream/v3:pkg", @@ -292,6 +293,8 @@ proto_library( "//envoy/extensions/network/dns_resolver/cares/v3:pkg", "//envoy/extensions/network/dns_resolver/getaddrinfo/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", + "//envoy/extensions/outlier_detection_monitors/common/v3:pkg", + "//envoy/extensions/outlier_detection_monitors/consecutive_errors/v3:pkg", "//envoy/extensions/path/match/uri_template/v3:pkg", "//envoy/extensions/path/rewrite/uri_template/v3:pkg", "//envoy/extensions/quic/connection_id_generator/v3:pkg", diff --git a/api/bazel/cc_proto_descriptor_library/BUILD b/api/bazel/cc_proto_descriptor_library/BUILD index fcab612aa49c..993d10801d30 100644 --- a/api/bazel/cc_proto_descriptor_library/BUILD +++ b/api/bazel/cc_proto_descriptor_library/BUILD @@ -12,10 +12,12 @@ cc_library( cc_library( name = "text_format_transcoder", srcs = [ - "create_dynamic_message.h", "text_format_transcoder.cc", ], - hdrs = ["text_format_transcoder.h"], + hdrs = [ + "create_dynamic_message.h", + "text_format_transcoder.h", + ], visibility = ["//visibility:public"], deps = [ ":file_descriptor_info", diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index 33aaa220fb6d..acd03fe0adf6 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -29,13 +29,6 @@ def api_dependencies(): name = "com_github_cncf_xds", ) - # Needed until @com_github_grpc_grpc renames @com_github_cncf_udpa - # to @com_github_cncf_xds as well. - external_http_archive( - name = "com_github_cncf_udpa", - location_name = "com_github_cncf_xds", - ) - external_http_archive( name = "prometheus_metrics_model", build_file_content = PROMETHEUSMETRICS_BUILD_CONTENT, @@ -62,6 +55,9 @@ 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 15265b521878..4ba96d3a72f0 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -92,9 +92,9 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "Prometheus client model", project_desc = "Data model artifacts for Prometheus", project_url = "https://github.com/prometheus/client_model", - version = "0.5.0", - sha256 = "170873e0b91cab5da6634af1498b88876842ff3e01212e2dabf6b4e6512c948d", - release_date = "2023-10-03", + version = "0.6.0", + sha256 = "6f8464471e34749753e5d767b22939b98a73b2149bc551c0f017d861f8a0adeb", + release_date = "2024-02-16", strip_prefix = "client_model-{version}", urls = ["https://github.com/prometheus/client_model/archive/v{version}.tar.gz"], use_category = ["api"], @@ -151,6 +151,17 @@ REPOSITORY_LOCATIONS_SPEC = dict( use_category = ["build"], release_date = "2023-05-30", ), + 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.4.0", + sha256 = "928e4205f701b7798ce32f3d2171c1918b363e9a600390a25c876f075f1efc0a", + 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-05-03", + ), 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/outlier_detection.proto b/api/envoy/config/cluster/v3/outlier_detection.proto index 11289e26b4f4..622486e41cfe 100644 --- a/api/envoy/config/cluster/v3/outlier_detection.proto +++ b/api/envoy/config/cluster/v3/outlier_detection.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package envoy.config.cluster.v3; +import "envoy/config/core/v3/extension.proto"; + import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; @@ -19,7 +21,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // See the :ref:`architecture overview ` for // more information on outlier detection. -// [#next-free-field: 24] +// [#next-free-field: 25] message OutlierDetection { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.cluster.OutlierDetection"; @@ -167,4 +169,8 @@ message OutlierDetection { // To change this default behavior set this config to ``false`` where active health checking will not uneject the host. // Defaults to true. google.protobuf.BoolValue successful_active_health_check_uneject_host = 23; + + // Set of host's passive monitors. + // [#not-implemented-hide:] + repeated core.v3.TypedExtensionConfig monitors = 24; } diff --git a/api/envoy/config/core/v3/base.proto b/api/envoy/config/core/v3/base.proto index 97131e4b8c66..38a18ccecec3 100644 --- a/api/envoy/config/core/v3/base.proto +++ b/api/envoy/config/core/v3/base.proto @@ -245,7 +245,8 @@ message Metadata { // :ref:`typed_filter_metadata ` // fields are present in the metadata with same keys, // only ``typed_filter_metadata`` field will be parsed. - map filter_metadata = 1; + map filter_metadata = 1 + [(validate.rules).map = {keys {string {min_len: 1}}}]; // Key is the reverse DNS filter name, e.g. com.acme.widget. The ``envoy.*`` // namespace is reserved for Envoy's built-in filters. @@ -253,7 +254,8 @@ message Metadata { // If both :ref:`filter_metadata ` // and ``typed_filter_metadata`` fields are present in the metadata with same keys, // only ``typed_filter_metadata`` field will be parsed. - map typed_filter_metadata = 2; + map typed_filter_metadata = 2 + [(validate.rules).map = {keys {string {min_len: 1}}}]; } // Runtime derived uint32 with a default when not specified. diff --git a/api/envoy/config/trace/v3/dynamic_ot.proto b/api/envoy/config/trace/v3/dynamic_ot.proto index 35971f30dfbd..d2664ef717e6 100644 --- a/api/envoy/config/trace/v3/dynamic_ot.proto +++ b/api/envoy/config/trace/v3/dynamic_ot.proto @@ -33,11 +33,15 @@ message DynamicOtConfig { string library = 1 [ deprecated = true, (validate.rules).string = {min_len: 1}, - (envoy.annotations.deprecated_at_minor_version) = "3.0" + (envoy.annotations.deprecated_at_minor_version) = "3.0", + (envoy.annotations.disallowed_by_default) = true ]; // The configuration to use when creating a tracer from the given dynamic // library. - google.protobuf.Struct config = 2 - [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; + google.protobuf.Struct config = 2 [ + deprecated = true, + (envoy.annotations.deprecated_at_minor_version) = "3.0", + (envoy.annotations.disallowed_by_default) = true + ]; } diff --git a/api/envoy/extensions/access_loggers/fluentd/v3/BUILD b/api/envoy/extensions/access_loggers/fluentd/v3/BUILD new file mode 100644 index 000000000000..29ebf0741406 --- /dev/null +++ b/api/envoy/extensions/access_loggers/fluentd/v3/BUILD @@ -0,0 +1,9 @@ +# 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 = ["@com_github_cncf_xds//udpa/annotations:pkg"], +) diff --git a/api/envoy/extensions/access_loggers/fluentd/v3/fluentd.proto b/api/envoy/extensions/access_loggers/fluentd/v3/fluentd.proto new file mode 100644 index 000000000000..e6b2adfdc9c0 --- /dev/null +++ b/api/envoy/extensions/access_loggers/fluentd/v3/fluentd.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; + +package envoy.extensions.access_loggers.fluentd.v3; + +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.access_loggers.fluentd.v3"; +option java_outer_classname = "FluentdProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/fluentd/v3;fluentdv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Fluentd access log] + +// Configuration for the *envoy.access_loggers.fluentd* :ref:`AccessLog `. +// This access log extension will send the emitted access logs over a TCP connection to an upstream that is accepting +// the Fluentd Forward Protocol as described in: `Fluentd Forward Protocol Specification +// `_. +// [#extension: envoy.access_loggers.fluentd] +// [#next-free-field: 7] +message FluentdAccessLogConfig { + // The upstream cluster to connect to for streaming the Fluentd messages. + string cluster = 1 [(validate.rules).string = {min_len: 1}]; + + // A tag is a string separated with '.' (e.g. log.type) to categorize events. + // See: https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#message-modes + string tag = 2 [(validate.rules).string = {min_len: 1}]; + + // The prefix to use when emitting :ref:`statistics `. + string stat_prefix = 3 [(validate.rules).string = {min_len: 1}]; + + // Interval for flushing access logs to the TCP stream. Logger will flush requests every time + // this interval is elapsed, or when batch size limit is hit, whichever comes first. Defaults to + // 1 second. + google.protobuf.Duration buffer_flush_interval = 4 [(validate.rules).duration = {gt {}}]; + + // Soft size limit in bytes for access log entries buffer. The logger will buffer requests until + // this limit it hit, or every time flush interval is elapsed, whichever comes first. When the buffer + // limit is hit, the logger will immediately flush the buffer contents. Setting it to zero effectively + // disables the batching. Defaults to 16384. + google.protobuf.UInt32Value buffer_size_bytes = 5; + + // A struct that represents the record that is sent for each log entry. + // https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#entry + // Values are rendered as strings, numbers, or boolean values as appropriate. + // Nested JSON objects may be produced by some command operators (e.g. FILTER_STATE or DYNAMIC_METADATA). + // See :ref:`format string` documentation for a specific command operator details. + // + // .. validated-code-block:: yaml + // :type-name: envoy.extensions.access_loggers.fluentd.v3.FluentdAccessLogConfig + // + // record: + // status: "%RESPONSE_CODE%" + // message: "%LOCAL_REPLY_BODY%" + // + // The following msgpack record would be created: + // + // .. code-block:: json + // + // { + // "status": 500, + // "message": "My error message" + // } + google.protobuf.Struct record = 6 [(validate.rules).message = {required: true}]; +} 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 ebcc53d774d4..5ef01fd8a290 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 @@ -3,6 +3,7 @@ syntax = "proto3"; 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/extensions/filters/http/ext_proc/v3/processing_mode.proto"; import "envoy/type/matcher/v3/string.proto"; @@ -273,7 +274,7 @@ message ExtProcPerRoute { } // Overrides that may be set on a per-route basis -// [#next-free-field: 7] +// [#next-free-field: 8] message ExtProcOverrides { // Set a different processing mode for this route than the default. ProcessingMode processing_mode = 1; @@ -301,4 +302,10 @@ message ExtProcOverrides { // config used. It is the prerogative of the control plane to ensure this // most-specific config contains the correct final overrides. MetadataOptions metadata_options = 6; + + // Additional metadata to include into streams initiated to the ext_proc gRPC + // service. This can be used for scenarios in which additional ad hoc + // authorization headers (e.g. ``x-foo-bar: baz-key``) are to be injected or + // when a route needs to partially override inherited metadata. + repeated config.core.v3.HeaderValue grpc_initial_metadata = 7; } 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 7a92259eb43b..9e7274daa533 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: 57] +// [#next-free-field: 58] message HttpConnectionManager { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager"; @@ -887,6 +887,10 @@ message HttpConnectionManager { // will be ignored if the ``x-forwarded-port`` header has been set by any trusted proxy in front of Envoy. bool append_x_forwarded_port = 51; + // Append the :ref:`config_http_conn_man_headers_x-envoy-local-overloaded` HTTP header in the scenario where + // the Overload Manager has been triggered. + bool append_local_overload = 57; + // Whether the HCM will add ProxyProtocolFilterState to the Connection lifetime filter state. Defaults to ``true``. // This should be set to ``false`` in cases where Envoy's view of the downstream address may not correspond to the // actual client address, for example, if there's another proxy in front of the Envoy. diff --git a/api/envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.proto b/api/envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.proto index d9f0db325373..b0f7602a8e08 100644 --- a/api/envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.proto +++ b/api/envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.proto @@ -184,6 +184,8 @@ message TcpProxy { // is defined as the period in which there are no bytes sent or received on either // the upstream or downstream connection. If not set, the default idle timeout is 1 hour. If set // to 0s, the timeout will be disabled. + // It is possible to dynamically override this configuration by setting a per-connection filter + // state object for the key ``envoy.tcp_proxy.per_connection_idle_timeout_ms``. // // .. warning:: // Disabling this timeout has a highly likelihood of yielding connection leaks due to lost TCP diff --git a/api/envoy/extensions/outlier_detection_monitors/common/v3/BUILD b/api/envoy/extensions/outlier_detection_monitors/common/v3/BUILD new file mode 100644 index 000000000000..ef19132f9180 --- /dev/null +++ b/api/envoy/extensions/outlier_detection_monitors/common/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/v3:pkg", + "@com_github_cncf_xds//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/extensions/outlier_detection_monitors/common/v3/error_types.proto b/api/envoy/extensions/outlier_detection_monitors/common/v3/error_types.proto new file mode 100644 index 000000000000..7ea14dde2839 --- /dev/null +++ b/api/envoy/extensions/outlier_detection_monitors/common/v3/error_types.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package envoy.extensions.outlier_detection_monitors.common.v3; + +import "envoy/type/v3/range.proto"; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.outlier_detection_monitors.common.v3"; +option java_outer_classname = "ErrorTypesProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/outlier_detection_monitors/common/v3;commonv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Outlier detection error buckets] +// Error bucket for HTTP codes. +// [#not-implemented-hide:] +message HttpErrors { + type.v3.Int32Range range = 1; +} + +// Error bucket for locally originated errors. +// [#not-implemented-hide:] +message LocalOriginErrors { +} + +// Error bucket for database errors. +// Sub-parameters may be added later, like malformed response, error on write, etc. +// [#not-implemented-hide:] +message DatabaseErrors { +} + +// Union of possible error buckets. +// [#not-implemented-hide:] +message ErrorBuckets { + // List of buckets "catching" HTTP codes. + repeated HttpErrors http_errors = 1; + + // List of buckets "catching" locally originated errors. + repeated LocalOriginErrors local_origin_errors = 2; + + // List of buckets "catching" database errors. + repeated DatabaseErrors database_errors = 3; +} diff --git a/api/envoy/extensions/outlier_detection_monitors/consecutive_errors/v3/BUILD b/api/envoy/extensions/outlier_detection_monitors/consecutive_errors/v3/BUILD new file mode 100644 index 000000000000..60022c6b3a07 --- /dev/null +++ b/api/envoy/extensions/outlier_detection_monitors/consecutive_errors/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/extensions/outlier_detection_monitors/common/v3:pkg", + "@com_github_cncf_xds//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/extensions/outlier_detection_monitors/consecutive_errors/v3/consecutive_errors.proto b/api/envoy/extensions/outlier_detection_monitors/consecutive_errors/v3/consecutive_errors.proto new file mode 100644 index 000000000000..8c74f6b574c7 --- /dev/null +++ b/api/envoy/extensions/outlier_detection_monitors/consecutive_errors/v3/consecutive_errors.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package envoy.extensions.outlier_detection_monitors.consecutive_errors.v3; + +import "envoy/extensions/outlier_detection_monitors/common/v3/error_types.proto"; + +import "google/protobuf/wrappers.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.outlier_detection_monitors.consecutive_errors.v3"; +option java_outer_classname = "ConsecutiveErrorsProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/outlier_detection_monitors/consecutive_errors/v3;consecutive_errorsv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// Monitor which counts consecutive errors. +// If number of consecutive errors exceeds the threshold, monitor will report that the host +// is unhealthy. +// [#not-implemented-hide:] +message ConsecutiveErrors { + // Monitor name. + string name = 1; + + // The number of consecutive errors before ejection occurs. + google.protobuf.UInt32Value threshold = 2 [(validate.rules).uint32 = {lte: 100}]; + + // The % chance that a host is actually ejected. Defaults to 100. + google.protobuf.UInt32Value enforcing = 3 [(validate.rules).uint32 = {lte: 100}]; + + // Error buckets. + common.v3.ErrorBuckets error_buckets = 4; +} diff --git a/api/envoy/extensions/tracers/opentelemetry/samplers/v3/BUILD b/api/envoy/extensions/tracers/opentelemetry/samplers/v3/BUILD index 29ebf0741406..09a37ad16b83 100644 --- a/api/envoy/extensions/tracers/opentelemetry/samplers/v3/BUILD +++ b/api/envoy/extensions/tracers/opentelemetry/samplers/v3/BUILD @@ -5,5 +5,8 @@ load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") licenses(["notice"]) # Apache 2 api_proto_package( - deps = ["@com_github_cncf_xds//udpa/annotations:pkg"], + deps = [ + "//envoy/config/core/v3:pkg", + "@com_github_cncf_xds//udpa/annotations:pkg", + ], ) diff --git a/api/envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.proto b/api/envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.proto new file mode 100644 index 000000000000..b74e96a6a416 --- /dev/null +++ b/api/envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +package envoy.extensions.tracers.opentelemetry.samplers.v3; + +import "envoy/config/core/v3/http_uri.proto"; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.tracers.opentelemetry.samplers.v3"; +option java_outer_classname = "DynatraceSamplerProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/tracers/opentelemetry/samplers/v3;samplersv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Dynatrace Sampler config] +// Configuration for the Dynatrace Sampler extension. +// [#extension: envoy.tracers.opentelemetry.samplers.dynatrace] + +// [#next-free-field: 6] +message DynatraceSamplerConfig { + // The Dynatrace tenant. + // + // The value can be obtained from the Envoy deployment page in Dynatrace. + string tenant = 1; + + // The id of the Dynatrace cluster id. + // + // The value can be obtained from the Envoy deployment page in Dynatrace. + int32 cluster_id = 2; + + // The HTTP URI to fetch the sampler configuration (root spans per minute). For example: + // + // .. code-block:: yaml + // + // http_uri: + // uri: .dev.dynatracelabs.com/api/v2/otlp/v1/traces + // cluster: dynatrace + // timeout: 10s + // + config.core.v3.HttpUri http_uri = 3; + + // The access token to fetch the sampling configuration from the Dynatrace API + string token = 4; + + // Default number of root spans per minute, used when the value can't be obtained from the Dynatrace API. + // + // A default value of ``1000`` is used when: + // + // - ``root_spans_per_minute`` is unset + // - ``root_spans_per_minute`` is set to 0 + // + uint32 root_spans_per_minute = 5; +} diff --git a/api/envoy/type/http/v3/cookie.proto b/api/envoy/type/http/v3/cookie.proto index 4fe0c2f69df6..0ceda999dfd3 100644 --- a/api/envoy/type/http/v3/cookie.proto +++ b/api/envoy/type/http/v3/cookie.proto @@ -22,7 +22,7 @@ message Cookie { string name = 1 [(validate.rules).string = {min_len: 1}]; // Duration of cookie. This will be used to set the expiry time of a new cookie when it is - // generated. Set this to 0 to use a session cookie. + // generated. Set this to 0s to use a session cookie and disable cookie expiration. google.protobuf.Duration ttl = 2 [(validate.rules).duration = {gte {}}]; // Path of cookie. This will be used to set the path of a new cookie when it is generated. diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 706d7d6f9d96..86061fda4ab7 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -72,6 +72,7 @@ proto_library( "//envoy/data/tap/v3:pkg", "//envoy/extensions/access_loggers/file/v3:pkg", "//envoy/extensions/access_loggers/filters/cel/v3:pkg", + "//envoy/extensions/access_loggers/fluentd/v3:pkg", "//envoy/extensions/access_loggers/grpc/v3:pkg", "//envoy/extensions/access_loggers/open_telemetry/v3:pkg", "//envoy/extensions/access_loggers/stream/v3:pkg", @@ -231,6 +232,8 @@ proto_library( "//envoy/extensions/network/dns_resolver/cares/v3:pkg", "//envoy/extensions/network/dns_resolver/getaddrinfo/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", + "//envoy/extensions/outlier_detection_monitors/common/v3:pkg", + "//envoy/extensions/outlier_detection_monitors/consecutive_errors/v3:pkg", "//envoy/extensions/path/match/uri_template/v3:pkg", "//envoy/extensions/path/rewrite/uri_template/v3:pkg", "//envoy/extensions/quic/connection_id_generator/v3:pkg", diff --git a/bazel/BUILD b/bazel/BUILD index 775add0417bc..19578ec3c59e 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -481,6 +481,14 @@ config_setting( values = {"define": "boringssl=disabled"}, ) +selects.config_setting_group( + name = "boringssl_fips_x86", + match_all = [ + ":boringssl_fips", + "@platforms//cpu:x86_64", + ], +) + config_setting( name = "zlib_ng", constraint_values = [ diff --git a/bazel/cel-cpp.patch b/bazel/cel-cpp.patch index f0d7d3005be7..34dd41033e56 100644 --- a/bazel/cel-cpp.patch +++ b/bazel/cel-cpp.patch @@ -1,3 +1,18 @@ +diff --git a/base/memory.h b/base/memory.h +index 3552e19..0fbe618 100644 +--- a/base/memory.h ++++ b/base/memory.h +@@ -166,8 +166,8 @@ std::enable_if_t, Handle> HandleFactory::Make( + #if defined(__cpp_lib_is_pointer_interconvertible) && \ + __cpp_lib_is_pointer_interconvertible >= 201907L + // Only available in C++20. +- static_assert(std::is_pointer_interconvertible_base_of_v, +- "F must be pointer interconvertible to Data"); ++// static_assert(std::is_pointer_interconvertible_base_of_v, ++// "F must be pointer interconvertible to Data"); + #endif + if (memory_manager.memory_management() == MemoryManagement::kPooling) { + void* addr; diff --git a/eval/internal/interop.cc b/eval/internal/interop.cc index 3acde6c..20f8ea3 100644 --- a/eval/internal/interop.cc diff --git a/bazel/dependency_imports.bzl b/bazel/dependency_imports.bzl index 85843dc44972..62699582017b 100644 --- a/bazel/dependency_imports.bzl +++ b/bazel/dependency_imports.bzl @@ -16,6 +16,7 @@ load("@com_github_aignas_rules_shellcheck//:deps.bzl", "shellcheck_dependencies" load("@aspect_bazel_lib//lib:repositories.bzl", "register_jq_toolchains", "register_yq_toolchains") load("@com_google_cel_cpp//bazel:deps.bzl", "parser_deps") load("@com_github_chrusty_protoc_gen_jsonschema//:deps.bzl", protoc_gen_jsonschema_go_dependencies = "go_dependencies") +load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains") # go version for rules_go GO_VERSION = "1.20" @@ -156,6 +157,7 @@ def envoy_dependency_imports(go_version = GO_VERSION, jq_version = JQ_VERSION, y ) protoc_gen_jsonschema_go_dependencies() + rules_proto_grpc_toolchains() def envoy_download_go_sdks(go_version): go_download_sdk( diff --git a/bazel/envoy_test.bzl b/bazel/envoy_test.bzl index 73908fc6f1b3..fe01c07d90d6 100644 --- a/bazel/envoy_test.bzl +++ b/bazel/envoy_test.bzl @@ -154,6 +154,7 @@ def envoy_cc_test( tags = [], args = [], copts = [], + linkopts = [], condition = None, shard_count = None, coverage = True, @@ -170,7 +171,7 @@ def envoy_cc_test( data = data, copts = envoy_copts(repository, test = True) + copts + envoy_pch_copts(repository, "//test:test_pch"), additional_linker_inputs = envoy_exported_symbols_input(), - linkopts = _envoy_test_linkopts(), + linkopts = _envoy_test_linkopts() + linkopts, linkstatic = envoy_linkstatic(), malloc = tcmalloc_external_dep(repository), deps = envoy_stdlib_deps() + deps + [envoy_external_dep_path(dep) for dep in external_deps + ["googletest"]] + [ diff --git a/bazel/external/msgpack.BUILD b/bazel/external/msgpack.BUILD new file mode 100644 index 000000000000..5f2d42163398 --- /dev/null +++ b/bazel/external/msgpack.BUILD @@ -0,0 +1,16 @@ +licenses(["notice"]) # Apache 2 + +cc_library( + name = "msgpack", + srcs = glob([ + "src/*.c", + "include/**/*.h", + "include/**/*.hpp", + ]), + defines = ["MSGPACK_NO_BOOST"], + includes = [ + "include", + ], + strip_include_prefix = "include", + visibility = ["//visibility:public"], +) diff --git a/bazel/io_opentelemetry_cpp.patch b/bazel/io_opentelemetry_cpp.patch new file mode 100644 index 000000000000..6eb4cfe2a9a5 --- /dev/null +++ b/bazel/io_opentelemetry_cpp.patch @@ -0,0 +1,13 @@ +# TODO: Remove once https://github.com/open-telemetry/opentelemetry-cpp/issues/2556 is merged + +--- a/api/include/opentelemetry/trace/span_context.h ++++ b/api/include/opentelemetry/trace/span_context.h +@@ -30,7 +30,7 @@ class SpanContext final + SpanContext(bool sampled_flag, bool is_remote) noexcept + : trace_id_(), + span_id_(), +- trace_flags_(trace::TraceFlags((uint8_t)sampled_flag)), ++ trace_flags_(trace::TraceFlags(static_cast(sampled_flag))), + is_remote_(is_remote), + trace_state_(TraceState::GetDefault()) + {} diff --git a/bazel/proxy_wasm_cpp_sdk.patch b/bazel/proxy_wasm_cpp_sdk.patch new file mode 100644 index 000000000000..6dc24d20b2ca --- /dev/null +++ b/bazel/proxy_wasm_cpp_sdk.patch @@ -0,0 +1,40 @@ +diff --git a/proxy_wasm_api.h b/proxy_wasm_api.h +index 166b49c..b44637c 100644 +--- a/proxy_wasm_api.h ++++ b/proxy_wasm_api.h +@@ -1207,8 +1207,9 @@ struct SimpleHistogram { + template struct Counter : public MetricBase { + static Counter *New(std::string_view name, MetricTagDescriptor... fieldnames); + +- Counter(std::string_view name, MetricTagDescriptor... descriptors) +- : Counter(std::string(name), std::vector({toMetricTag(descriptors)...})) { ++ template ++ Counter(std::string_view name, MetricTagDescriptor... descriptors) ++ : Counter(std::string(name), std::vector({toMetricTag(descriptors)...})) { + } + + SimpleCounter resolve(Tags... f) { +@@ -1256,8 +1257,9 @@ inline Counter *Counter::New(std::string_view name, + template struct Gauge : public MetricBase { + static Gauge *New(std::string_view name, MetricTagDescriptor... fieldnames); + +- Gauge(std::string_view name, MetricTagDescriptor... descriptors) +- : Gauge(std::string(name), std::vector({toMetricTag(descriptors)...})) {} ++ template ++ Gauge(std::string_view name, MetricTagDescriptor... descriptors) ++ : Gauge(std::string(name), std::vector({toMetricTag(descriptors)...})) {} + + SimpleGauge resolve(Tags... f) { + std::vector fields{toString(f)...}; +@@ -1302,8 +1304,9 @@ inline Gauge *Gauge::New(std::string_view name, + template struct Histogram : public MetricBase { + static Histogram *New(std::string_view name, MetricTagDescriptor... fieldnames); + +- Histogram(std::string_view name, MetricTagDescriptor... descriptors) +- : Histogram(std::string(name), ++ template ++ Histogram(std::string_view name, MetricTagDescriptor... descriptors) ++ : Histogram(std::string(name), + std::vector({toMetricTag(descriptors)...})) {} + + SimpleHistogram resolve(Tags... f) { diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 1bb053efa516..bec5940badf3 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -318,6 +318,7 @@ def envoy_dependencies(skip_targets = []): _com_github_libevent_libevent() _com_github_luajit_luajit() _com_github_nghttp2_nghttp2() + _com_github_msgpack_cpp() _com_github_skyapm_cpp2sky() _com_github_nodejs_http_parser() _com_github_alibaba_hessian2_codec() @@ -337,6 +338,7 @@ def envoy_dependencies(skip_targets = []): _io_hyperscan() _io_vectorscan() _io_opentracing_cpp() + _io_opentelemetry_api_cpp() _net_colm_open_source_colm() _net_colm_open_source_ragel() _net_zlib() @@ -735,6 +737,16 @@ def _com_github_nghttp2_nghttp2(): actual = "@envoy//bazel/foreign_cc:nghttp2", ) +def _com_github_msgpack_cpp(): + external_http_archive( + name = "com_github_msgpack_cpp", + build_file = "@envoy//bazel/external:msgpack.BUILD", + ) + native.bind( + name = "msgpack", + actual = "@com_github_msgpack_cpp//:msgpack", + ) + def _io_hyperscan(): external_http_archive( name = "io_hyperscan", @@ -764,6 +776,17 @@ def _io_opentracing_cpp(): actual = "@io_opentracing_cpp//:opentracing", ) +def _io_opentelemetry_api_cpp(): + external_http_archive( + name = "io_opentelemetry_cpp", + patch_args = ["-p1"], + patches = ["@envoy//bazel:io_opentelemetry_cpp.patch"], + ) + native.bind( + name = "opentelemetry_api", + actual = "@io_opentelemetry_cpp//api:api", + ) + def _com_github_datadog_dd_trace_cpp(): external_http_archive("com_github_datadog_dd_trace_cpp") native.bind( @@ -1150,6 +1173,8 @@ def _com_github_grpc_grpc(): name = "com_github_grpc_grpc", patch_args = ["-p1"], patches = ["@envoy//bazel:grpc.patch"], + # Needed until grpc updates its naming (v1.62.0) + repo_mapping = {"@com_github_cncf_udpa": "@com_github_cncf_xds"}, ) external_http_archive("build_bazel_rules_apple") @@ -1255,7 +1280,13 @@ def _upb(): ) def _proxy_wasm_cpp_sdk(): - external_http_archive(name = "proxy_wasm_cpp_sdk") + external_http_archive( + name = "proxy_wasm_cpp_sdk", + patch_args = ["-p1"], + patches = [ + "@envoy//bazel:proxy_wasm_cpp_sdk.patch", + ], + ) def _proxy_wasm_cpp_host(): external_http_archive( diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index d6b03fdff44b..6e6043e8452b 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -148,12 +148,12 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "Aspect Bazel helpers", project_desc = "Base Starlark libraries and basic Bazel rules which are useful for constructing rulesets and BUILD files", project_url = "https://github.com/aspect-build/bazel-lib", - version = "2.4.1", - sha256 = "38c5bf333ae70d1bb3a18da6053084ce5f475f0ed0a8f04eed415186d5a7b04b", + version = "2.4.2", + sha256 = "f75d03783588e054899eb0729a97fb5b8973c1a26f30373fafd485c90bf207d1", strip_prefix = "bazel-lib-{version}", urls = ["https://github.com/aspect-build/bazel-lib/archive/v{version}.tar.gz"], use_category = ["build"], - release_date = "2024-02-06", + release_date = "2024-02-21", cpe = "N/A", license = "Apache-2.0", license_url = "https://github.com/aspect-build/bazel-lib/blob/v{version}/LICENSE", @@ -176,11 +176,11 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "Shellcheck rules for bazel", project_desc = "Now you do not need to depend on the system shellcheck version in your bazel-managed (mono)repos.", project_url = "https://github.com/aignas/rules_shellcheck", - version = "0.3.2", - sha256 = "798c7ff488a949e51d7d41d853d79164ce5c5335364ba32f972b79df8dd6be62", + version = "0.3.3", + sha256 = "936ece8097b734ac7fab10f833a68f7d646b4bc760eb5cde3ab17beb85779d50", strip_prefix = "rules_shellcheck-{version}", urls = ["https://github.com/aignas/rules_shellcheck/archive/{version}.tar.gz"], - release_date = "2024-01-10", + release_date = "2024-02-15", use_category = ["build"], cpe = "N/A", license = "MIT", @@ -440,12 +440,12 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "qatlib", project_desc = "Intel QuickAssist Technology Library", project_url = "https://github.com/intel/qatlib", - version = "23.11.0", - sha256 = "f649613c243df98c2b005e58af7e0c9bb6d9638e0a12d2757d18d4930bf893cd", + version = "24.02.0", + sha256 = "ffef9a3a2bd6024b188977411944ec6267da34d40a0c6c1d42c4f59165991176", strip_prefix = "qatlib-{version}", urls = ["https://github.com/intel/qatlib/archive/refs/tags/{version}.tar.gz"], use_category = ["dataplane_ext"], - release_date = "2023-11-15", + release_date = "2024-02-20", extensions = ["envoy.tls.key_providers.qat", "envoy.compression.qatzip.compressor"], cpe = "N/A", license = "BSD-3-Clause", @@ -455,16 +455,16 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "qatzip", project_desc = "Intel QuickAssist Technology QATzip Library", project_url = "https://github.com/intel/qatzip", - version = "1.1.2", - sha256 = "31419fa4b42d217b3e55a70a34545582cbf401a4f4d44738d21b4a3944b1e1ef", + version = "1.2.0", + sha256 = "345a37a7e5b70635cadf9b9e581a9affec09e837ac1abac04d38355b672b3304", strip_prefix = "QATzip-{version}", urls = ["https://github.com/intel/QATzip/archive/v{version}.tar.gz"], use_category = ["dataplane_ext"], - release_date = "2023-03-24", + release_date = "2024-02-08", extensions = ["envoy.compression.qatzip.compressor"], cpe = "N/A", license = "BSD-3-Clause", - license_url = "https://github.com/intel/QATzip/blob/{version}/LICENSE", + license_url = "https://github.com/intel/QATzip/blob/v{version}/LICENSE", ), com_github_luajit_luajit = dict( project_name = "LuaJIT", @@ -553,6 +553,25 @@ REPOSITORY_LOCATIONS_SPEC = dict( license = "Apache-2.0", license_url = "https://github.com/opentracing/opentracing-cpp/blob/v{version}/LICENSE", ), + io_opentelemetry_cpp = dict( + project_name = "OpenTelemetry", + project_desc = "Observability framework and toolkit designed to create and manage telemetry data such as traces, metrics, and logs.", + project_url = "https://opentelemetry.io", + version = "1.14.0", + sha256 = "9a67561b8f4dba8cf8bb323b404069cbcc2f59974e1330b1ba192c5c8d68c28e", + strip_prefix = "opentelemetry-cpp-{version}", + urls = ["https://github.com/open-telemetry/opentelemetry-cpp/archive/refs/tags/v{version}.tar.gz"], + use_category = ["observability_ext"], + extensions = [ + "envoy.tracers.opentelemetry", + "envoy.tracers.opentelemetry.samplers.always_on", + "envoy.tracers.opentelemetry.samplers.dynatrace", + ], + release_date = "2024-02-17", + cpe = "N/A", + license = "Apache-2.0", + license_url = "https://github.com/open-telemetry/opentelemetry-cpp/blob/v{version}/LICENSE", + ), skywalking_data_collect_protocol = dict( project_name = "skywalking-data-collect-protocol", project_desc = "Data Collect Protocols of Apache SkyWalking", @@ -778,6 +797,21 @@ REPOSITORY_LOCATIONS_SPEC = dict( license = "MIT", license_url = "https://github.com/jbeder/yaml-cpp/blob/{version}/LICENSE", ), + com_github_msgpack_cpp = dict( + project_name = "msgpack for C/C++", + project_desc = "MessagePack is an efficient binary serialization format", + project_url = "https://github.com/msgpack/msgpack-c", + version = "6.1.0", + sha256 = "23ede7e93c8efee343ad8c6514c28f3708207e5106af3b3e4969b3a9ed7039e7", + strip_prefix = "msgpack-cxx-{version}", + urls = ["https://github.com/msgpack/msgpack-c/releases/download/cpp-{version}/msgpack-cxx-{version}.tar.gz"], + use_category = ["observability_ext"], + extensions = ["envoy.access_loggers.fluentd"], + release_date = "2023-07-08", + cpe = "cpe:2.3:a:messagepack:messagepack:*", + license = "Boost", + license_url = "https://github.com/msgpack/msgpack-c/blob/cpp-{version}/LICENSE_1_0.txt", + ), com_github_google_jwt_verify = dict( project_name = "jwt_verify_lib", project_desc = "JWT verification library for C++", @@ -1175,12 +1209,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 = "60a22a631bdf944e26407d32a767b4aba953bc39", - sha256 = "70213d0e4016ce79db9f3dfc5e94b4e707c54b69e00fae7ea2593a08e9dfd11e", + version = "3373df94b3713d4e3ef69ee54ba6e7b6aaaebcc0", + sha256 = "fab452b368990d31a241f18a96fad613377752ff114b7584d0e7eb8cfe5464fe", urls = ["https://github.com/google/quiche/archive/{version}.tar.gz"], strip_prefix = "quiche-{version}", use_category = ["controlplane", "dataplane_core"], - release_date = "2024-02-05", + release_date = "2024-02-29", cpe = "N/A", license = "BSD-3-Clause", license_url = "https://github.com/google/quiche/blob/{version}/LICENSE", diff --git a/bazel/v8.patch b/bazel/v8.patch index 9805eb749589..2d7101db917e 100644 --- a/bazel/v8.patch +++ b/bazel/v8.patch @@ -1,11 +1,11 @@ # 1. Use already imported python dependencies # 2. Disable pointer compression (limits the maximum number of WasmVMs). -# 3. Add support for --define=no_debug_info=1. +# 3. Add support for --define=no_debug_info=1. # 4. Allow compiling v8 on macOS 10.15 to 13.0. TODO(dio): Will remove this patch when https://bugs.chromium.org/p/v8/issues/detail?id=13428 is fixed. # 5. Don't expose Wasm C API (only Wasm C++ API). diff --git a/BUILD.bazel b/BUILD.bazel -index 4e89f90e7e..ced403d5aa 100644 +index 4e89f90..0df4f67 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -4,7 +4,7 @@ @@ -17,10 +17,6 @@ index 4e89f90e7e..ced403d5aa 100644 load( "@v8//:bazel/defs.bzl", "v8_binary", -diff --git a/BUILD.bazel b/BUILD.bazel -index 4e89f90e7e..3fcb38b3f3 100644 ---- a/BUILD.bazel -+++ b/BUILD.bazel @@ -157,7 +157,7 @@ v8_int( # If no explicit value for v8_enable_pointer_compression, we set it to 'none'. v8_string( @@ -31,7 +27,7 @@ index 4e89f90e7e..3fcb38b3f3 100644 # Default setting for v8_enable_pointer_compression. diff --git a/bazel/defs.bzl b/bazel/defs.bzl -index e957c0fad3..a6de50e6ab 100644 +index e957c0f..0327669 100644 --- a/bazel/defs.bzl +++ b/bazel/defs.bzl @@ -116,6 +116,7 @@ def _default_args(): @@ -42,15 +38,16 @@ index e957c0fad3..a6de50e6ab 100644 "-std=c++17", ], "@v8//bazel/config:is_gcc": [ -@@ -131,6 +132,7 @@ def _default_args(): +@@ -131,6 +132,8 @@ def _default_args(): "-Wno-redundant-move", "-Wno-return-type", "-Wno-stringop-overflow", + "-Wno-nonnull", ++ "-Wno-pessimizing-move", # Use GNU dialect, because GCC doesn't allow using # ##__VA_ARGS__ when in standards-conforming mode. "-std=gnu++17", -@@ -151,6 +153,23 @@ def _default_args(): +@@ -151,6 +154,23 @@ def _default_args(): "-fno-integrated-as", ], "//conditions:default": [], @@ -75,10 +72,10 @@ index e957c0fad3..a6de50e6ab 100644 includes = ["include"], linkopts = select({ diff --git a/src/wasm/c-api.cc b/src/wasm/c-api.cc -index ce3f569fd5..dc8a4c4f6a 100644 +index 4473e20..65a6ec7 100644 --- a/src/wasm/c-api.cc +++ b/src/wasm/c-api.cc -@@ -2238,6 +2238,8 @@ auto Instance::exports() const -> ownvec { +@@ -2247,6 +2247,8 @@ auto Instance::exports() const -> ownvec { } // namespace wasm @@ -87,22 +84,22 @@ index ce3f569fd5..dc8a4c4f6a 100644 // BEGIN FILE wasm-c.cc extern "C" { -@@ -3257,3 +3259,5 @@ wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) { +@@ -3274,3 +3276,5 @@ wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) { #undef WASM_DEFINE_SHARABLE_REF } // extern "C" + +#endif diff --git a/third_party/inspector_protocol/code_generator.py b/third_party/inspector_protocol/code_generator.py -index c3768b8..d4a1dda 100644 +index c3768b8..d4a1dda 100755 --- a/third_party/inspector_protocol/code_generator.py +++ b/third_party/inspector_protocol/code_generator.py @@ -16,6 +16,8 @@ try: except ImportError: import simplejson as json - + +sys.path += [os.path.dirname(__file__)] + import pdl - + try: diff --git a/changelogs/1.26.7.yaml b/changelogs/1.26.7.yaml new file mode 100644 index 000000000000..48e27387880c --- /dev/null +++ b/changelogs/1.26.7.yaml @@ -0,0 +1,28 @@ +date: February 9, 2024 + +bug_fixes: +- area: buffer + change: | + Fixed a bug (https://github.com/envoyproxy/envoy/issues/28760) that the internal listener causes an undefined + behavior due to the unintended release of the buffer memory. +- area: http + change: | + Fixed recursion when HTTP connection is disconnected due to a high number of premature resets. +- area: proxy protocol + change: | + fixed a crash when Envoy is configured for PROXY protocol on both a listener and cluster, and the listener receives + a PROXY protocol header with address type LOCAL (typically used for health checks). +- area: proxy_protocol + change: | + Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is + received in a proxy protocol header. Connections will instead be dropped/reset. +- area: proxy_protocol + change: | + Fixed a bug where TLVs with non utf8 characters were inserted as protobuf values into filter metadata circumventing + ext_authz checks when ``failure_mode_allow`` is set to ``true``. +- area: http + change: | + Fixed crash when HTTP request idle and per try timeouts occurs within backoff interval. +- area: url matching + change: | + Fixed excessive CPU utilization when using regex URL template matcher. diff --git a/changelogs/1.27.3.yaml b/changelogs/1.27.3.yaml new file mode 100644 index 000000000000..a67d0b6cabb2 --- /dev/null +++ b/changelogs/1.27.3.yaml @@ -0,0 +1,52 @@ +date: February 9, 2024 + +minor_behavior_changes: +- area: access_log + change: | + When emitting grpc logs, only downstream filter state was used. Now, both downstream and upstream filter states will be tried + to find the keys configured in filter_state_objects_to_log. + +bug_fixes: +- area: buffer + change: | + Fixed a bug (https://github.com/envoyproxy/envoy/issues/28760) that the internal listener causes an undefined + behavior due to the unintended release of the buffer memory. +- area: http + change: | + Fixed recursion when HTTP connection is disconnected due to a high number of premature resets. +- area: grpc + change: | + Fixed a bug in gRPC async client cache which intermittently causes CPU spikes due to busy loop in timer expiration. +- area: tracing + change: | + Fixed a bug where Datadog spans tagged as errors would not have the appropriate error property set. +- area: tracing + change: | + Fixed a bug where child spans produced by the Datadog tracer would have an incorrect operation name. +- area: tracing + change: | + Fixed a bug that caused the Datadog tracing extension to drop traces that + should be kept on account of an extracted sampling decision. +- area: proxy protocol + change: | + fixed a crash when Envoy is configured for PROXY protocol on both a listener and cluster, and the listener receives + a PROXY protocol header with address type LOCAL (typically used for health checks). +- area: proxy_protocol + change: | + Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is + received in a proxy protocol header. Connections will instead be dropped/reset. +- area: proxy_protocol + change: | + Fixed a bug where TLVs with non utf8 characters were inserted as protobuf values into filter metadata circumventing + ext_authz checks when ``failure_mode_allow`` is set to ``true``. +- area: tls + change: | + Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is + received in an mTLS client cert IP SAN. These SANs will be ignored. This applies only when using formatter + ``%DOWNSTREAM_PEER_IP_SAN%``. +- area: http + change: | + Fixed crash when HTTP request idle and per try timeouts occurs within backoff interval. +- area: url matching + change: | + Fixed excessive CPU utilization when using regex URL template matcher. diff --git a/changelogs/1.28.1.yaml b/changelogs/1.28.1.yaml new file mode 100644 index 000000000000..626bbf687b29 --- /dev/null +++ b/changelogs/1.28.1.yaml @@ -0,0 +1,53 @@ +date: February 9, 2024 + +behavior_changes: +- area: listener + change: | + undeprecated runtime key ``overload.global_downstream_max_connections`` until :ref:`downstream connections monitor + ` extension becomes stable. + +bug_fixes: +- area: buffer + change: | + Fixed a bug (https://github.com/envoyproxy/envoy/issues/28760) that the internal listener causes an undefined + behavior due to the unintended release of the buffer memory. +- area: grpc + change: | + Fixed a bug in gRPC async client cache which intermittently causes CPU spikes due to busy loop in timer expiration. +- area: tracing + change: | + Fixed a bug where Datadog spans tagged as errors would not have the appropriate error property set. +- area: tracing + change: | + Fixed a bug where child spans produced by the Datadog tracer would have an incorrect operation name. +- area: tracing + change: | + Fixed a bug that caused the Datadog tracing extension to drop traces that + should be kept on account of an extracted sampling decision. +- area: quic + change: | + Fixed a bug in QUIC and HCM interaction which could cause use-after-free during asynchronous certificates retrieval. + The fix is guarded by runtime ``envoy.reloadable_features.quic_fix_filter_manager_uaf``. +- area: proxy protocol + change: | + Fixed a crash when Envoy is configured for PROXY protocol on both a listener and cluster, and the listener receives + a PROXY protocol header with address type LOCAL (typically used for health checks). +- area: proxy_protocol + change: | + Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is + received in a proxy protocol header. Connections will instead be dropped/reset. +- area: proxy_protocol + change: | + Fixed a bug where TLVs with non utf8 characters were inserted as protobuf values into filter metadata circumventing + ext_authz checks when ``failure_mode_allow`` is set to ``true``. +- area: tls + change: | + Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is + received in an mTLS client cert IP SAN. These SANs will be ignored. This applies only when using formatter + ``%DOWNSTREAM_PEER_IP_SAN%``. +- area: http + change: | + Fixed crash when HTTP request idle and per try timeouts occurs within backoff interval. +- area: url matching + change: | + Fixed excessive CPU utilization when using regex URL template matcher. diff --git a/changelogs/1.29.1.yaml b/changelogs/1.29.1.yaml new file mode 100644 index 000000000000..31831f89848b --- /dev/null +++ b/changelogs/1.29.1.yaml @@ -0,0 +1,35 @@ +date: February 9, 2024 + +bug_fixes: +- area: tracing + change: | + Added support for configuring resource detectors on the OpenTelemetry tracer. +- area: proxy protocol + change: | + Fixed a crash when Envoy is configured for PROXY protocol on both a listener and cluster, and the listener receives + a PROXY protocol header with address type LOCAL (typically used for health checks). +- area: url matching + change: | + Fixed excessive CPU utilization when using regex URL template matcher. +- area: http + change: | + Fixed crash when HTTP request idle and per try timeouts occurs within backoff interval. +- area: proxy_protocol + change: | + Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is + received in a proxy protocol header. Connections will instead be dropped/reset. +- area: proxy_protocol + change: | + Fixed a bug where TLVs with non utf8 characters were inserted as protobuf values into filter metadata circumventing + ext_authz checks when ``failure_mode_allow`` is set to ``true``. +- area: tls + change: | + Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is + received in an mTLS client cert IP SAN. These SANs will be ignored. This applies only when using formatter + ``%DOWNSTREAM_PEER_IP_SAN%``. + +removed_config_or_runtime: +- area: postgres proxy + change: | + Fix a race condition that may result from upstream servers refusing to switch to TLS/SSL. + This fix first appeared in ``v1.29.0`` release. diff --git a/changelogs/current.yaml b/changelogs/current.yaml index 5fbdda07e1f0..692821ae863e 100644 --- a/changelogs/current.yaml +++ b/changelogs/current.yaml @@ -6,9 +6,27 @@ behavior_changes: change: | Remove the hop by hop TE header from downstream request headers if it's not set to ``trailers``, else keep it. This change can be temporarily reverted by setting ``envoy.reloadable_features.sanitize_te`` to false. +- area: stats + change: | + The runtime flag ``envoy.reloadable_features.enable_include_histograms`` is now enabled by default. + This causes the ``includeHistogram()`` method on ``Stats::SinkPredicates`` to filter histograms to + be flushed to stat sinks. +- 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``. minor_behavior_changes: # *Changes that may cause incompatibilities for some users, but should not for most* +- area: sockets + change: | + Failure to create an upstream socket should now result in clean connection failure rather than failing a release assert. This behavior + can be temporarily reverted by setting runtime feature ``envoy.restart_features_.allow_client_socket_creation_failure`` to false. - area: adaptive concurrency filter stats change: | Multiply the gradient value stat by 1000 to make it more granular (values will range between 500 and 2000). @@ -38,22 +56,46 @@ minor_behavior_changes: AWS region string is now retrieved from environment and profile consistently within aws_request_signer and grpc_credentials/aws_iam extensions. Region field in aws_request_signer is now optional, explicitly configured xDS region will take preference. aws_request_signer documentation now reflects the region chain. +- area: http + change: | + Enable obsolete line folding in BalsaParser (for behavior parity with http-parser, the + previously used HTTP/1 parser). +- area: proxy status + change: | + Add more conversion in the proxy status utility. It can be disabled by the runtime guard + ``envoy.reloadable_features.proxy_status_mapping_more_core_response_flags``. bug_fixes: # *Changes expected to improve the state of the world and are unlikely to have negative effects* +- area: http3_upstream + change: | + Fixing a bug with HTTP/3 upstream using a non-threadsafe cache cross-thread. Bumping HTTP/3 support down + to alpha as the severity of this bug indicates it is both not in use and not GA quality code. - area: tracers change: | use unary RPC calls for OpenTelemetry trace exports, rather than client-side streaming connections. +- area: stateful_session + change: | + Support 0 TTL for proto-encoded cookies, which disables cookie expiration by Envoy. - area: load balancing change: | Added randomization in locality load-balancing initialization. This helps desynchronizing Envoys across a fleet by randomizing the scheduler starting point. This can be temporarily reverted by setting runtime guard ``envoy.reloadable_features.edf_lb_locality_scheduler_init_fix`` to false. +- area: load balancing + change: | + Added randomization in host load-balancing initialization. This helps desynchronizing Envoys across + a fleet by randomizing the scheduler starting point. This can be temporarily reverted by setting runtime guard + ``envoy.reloadable_features.edf_lb_host_scheduler_init_fix`` to false. - area: UDP and TCP tunneling change: | fixed a bug where second HTTP response headers received would cause Envoy to crash in cases where ``propagate_response_headers`` and retry configurations are enabled at the same time, and an upstream request is retried multiple times. +- area: xds + change: | + Reject xDS configurations where the rate-limit's :ref:`fill_rate ` + is set to Infinity or NaN. - area: tracing change: | Prevent Envoy from crashing at start up when the OpenTelemetry environment resource detector cannot detect any attributes. @@ -67,6 +109,9 @@ bug_fixes: - area: http change: | Fixed crash when HTTP request idle and per try timeouts occurs within backoff interval. +- area: quic + change: | + Fixed crash bug with QUIC upstream + X.509v1 certificates. - area: proxy_protocol change: | Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is @@ -80,9 +125,25 @@ bug_fixes: Fix crash due to uncaught exception when the operating system does not support an address type (such as IPv6) that is received in an mTLS client cert IP SAN. These SANs will be ignored. This applies only when using formatter ``%DOWNSTREAM_PEER_IP_SAN%``. +- area: tcp_proxy + change: | + When tunneling TCP over HTTP, closed the downstream connection (for writing only) when upstream trailers are read + to support half close semantics during TCP tunneling. + This behavioral change can be temporarily reverted by setting runtime guard + ``envoy.reloadable_features.tcp_tunneling_send_downstream_fin_on_upstream_trailers`` to false. - area: jwt_authn change: | Fixed JWT extractor, which concatenated headers with a comma, resultig in invalid tokens. +- area: router + change: | + Fix a timing issue when upstream requests are empty when decoding data and send local reply when that happens. This is + controlled by ``envoy_reloadable_features_send_local_reply_when_no_buffer_and_upstream_request``. +- area: deps + change: | + Updated QUICHE dependencies to incorporate fixes for https://github.com/envoyproxy/envoy/issues/32401. +- area: tracing + change: | + Dynatrace resource detector: Only log warning message when no enrichment attributes are found. removed_config_or_runtime: # *Normally occurs at the end of the* :ref:`deprecation period ` @@ -107,8 +168,20 @@ removed_config_or_runtime: - area: aws change: | Removed ``envoy.reloadable_features.enable_aws_credentials_file`` runtime flag and legacy code paths. +- area: upstream + change: | + removed ``envoy_reloadable_features_initialize_upstream_filters`` and legacy code paths. new_features: +- area: ext_proc + change: | + Added + :ref:`grpc_initial_metadata ` + config API to allow extending inherited metadata from + :ref:`ExternalProcessor.grpc_service ` + and + :ref:`ExtProcOverrides.grpc_service ` + with the new or updated values. - area: aws_request_signing change: | Update ``aws_request_signing`` filter to support use as an upstream HTTP filter. This allows successful calculation of @@ -170,9 +243,30 @@ new_features: Envoy will select the host with the fewest active requests from the entire host set rather than :ref:`choice_count ` random choices. +- area: access_loggers + change: | + Added :ref:`Fluentd access logger ` + to support flushing access logs in `Fluentd format `_. - area: redis change: | Added support for the ``ECHO`` command. +- area: tcp_proxy + change: | + added an option to dynamically set a per downstream connection idle timeout period object under the key + ``envoy.tcp_proxy.per_connection_idle_timeout_ms``. If this filter state value exists, it will override the idle timeout + specified in the filter configuration and the default idle timeout. +- area: load shed point + change: | + Added load shed point ``envoy.load_shed_points.hcm_ondata_creating_codec`` that closes connections before creating codec if + Envoy is under pressure, typically memory. +- area: overload + change: | + added a :ref:`configuration option + ` to add + ``x-envoy-local-overloaded`` header when Overload Manager is triggered. +- area: tracing + change: | + Added support to configure a Dynatrace sampler for the OpenTelemetry tracer. - area: jwt_authn change: | Added @@ -180,3 +274,7 @@ new_features: of subjects a ``JwtProvider`` can assert. deprecated: +- area: listener + change: | + deprecated runtime key ``overload.global_downstream_max_connections`` in favor of :ref:`downstream connections monitor + `. diff --git a/ci/Dockerfile-envoy b/ci/Dockerfile-envoy index 2de63d92e29a..07affa3502e3 100644 --- a/ci/Dockerfile-envoy +++ b/ci/Dockerfile-envoy @@ -58,7 +58,7 @@ COPY --chown=0:0 --chmod=755 \ # STAGE: envoy-distroless -FROM gcr.io/distroless/base-nossl-debian12:nonroot@sha256:49edf7003af1015b0841f34a04197e8b1c5f1d0c91e897c97749c78ee38b8ec2 AS envoy-distroless +FROM gcr.io/distroless/base-nossl-debian12:nonroot@sha256:0e777c69ba810353b9f3f2033280bbe7d029d81fa55760f6eec817ef595aa19c AS envoy-distroless EXPOSE 10000 ENTRYPOINT ["/usr/local/bin/envoy"] CMD ["-c", "/etc/envoy/envoy.yaml"] diff --git a/contrib/all_contrib_extensions.bzl b/contrib/all_contrib_extensions.bzl index 19c605b700bb..6b7994a2623b 100644 --- a/contrib/all_contrib_extensions.bzl +++ b/contrib/all_contrib_extensions.bzl @@ -28,7 +28,7 @@ PPC_SKIP_CONTRIB_TARGETS = [ "envoy.compression.qatzip.compressor", ] -FIPS_SKIP_CONTRIB_TARGETS = [ +FIPS_LINUX_X86_SKIP_CONTRIB_TARGETS = [ "envoy.compression.qatzip.compressor", ] diff --git a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc index 313f93099b90..7ed6246805ee 100644 --- a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc +++ b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc @@ -657,7 +657,8 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider( std::chrono::milliseconds poll_delay = std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(conf, poll_delay, 200)); - std::string private_key = Config::DataSource::read(conf.private_key(), false, api_); + std::string private_key = + THROW_OR_RETURN_VALUE(Config::DataSource::read(conf.private_key(), false, api_), std::string); bssl::UniquePtr bio( BIO_new_mem_buf(const_cast(private_key.data()), private_key.size())); diff --git a/contrib/cryptomb/private_key_providers/test/fake_factory.cc b/contrib/cryptomb/private_key_providers/test/fake_factory.cc index b5a1a0cdae0d..eaa64bf4cc8e 100644 --- a/contrib/cryptomb/private_key_providers/test/fake_factory.cc +++ b/contrib/cryptomb/private_key_providers/test/fake_factory.cc @@ -168,8 +168,10 @@ FakeCryptoMbPrivateKeyMethodFactory::createPrivateKeyMethodProviderInstance( std::make_shared(supported_instruction_set_); // We need to get more RSA key params in order to be able to use BoringSSL signing functions. - std::string private_key = Config::DataSource::read( - conf.private_key(), false, private_key_provider_context.serverFactoryContext().api()); + std::string private_key = THROW_OR_RETURN_VALUE( + Config::DataSource::read(conf.private_key(), false, + private_key_provider_context.serverFactoryContext().api()), + std::string); bssl::UniquePtr bio( BIO_new_mem_buf(const_cast(private_key.data()), private_key.size())); diff --git a/contrib/exe/BUILD b/contrib/exe/BUILD index 1210422f895d..6c085c76ba80 100644 --- a/contrib/exe/BUILD +++ b/contrib/exe/BUILD @@ -7,7 +7,7 @@ load( load( "//contrib:all_contrib_extensions.bzl", "ARM64_SKIP_CONTRIB_TARGETS", - "FIPS_SKIP_CONTRIB_TARGETS", + "FIPS_LINUX_X86_SKIP_CONTRIB_TARGETS", "PPC_SKIP_CONTRIB_TARGETS", "envoy_all_contrib_extensions", ) @@ -24,7 +24,7 @@ alias( SELECTED_CONTRIB_EXTENSIONS = select({ "//bazel:linux_aarch64": envoy_all_contrib_extensions(ARM64_SKIP_CONTRIB_TARGETS), "//bazel:linux_ppc": envoy_all_contrib_extensions(PPC_SKIP_CONTRIB_TARGETS), - "//bazel:boringssl_fips": envoy_all_contrib_extensions(FIPS_SKIP_CONTRIB_TARGETS), + "//bazel:boringssl_fips_x86": envoy_all_contrib_extensions(FIPS_LINUX_X86_SKIP_CONTRIB_TARGETS), "//conditions:default": envoy_all_contrib_extensions(), }) diff --git a/contrib/generic_proxy/filters/network/source/BUILD b/contrib/generic_proxy/filters/network/source/BUILD index 4df7bc7b6f28..67129461e1a5 100644 --- a/contrib/generic_proxy/filters/network/source/BUILD +++ b/contrib/generic_proxy/filters/network/source/BUILD @@ -74,6 +74,7 @@ envoy_cc_library( "//source/common/common:matchers_lib", "//source/common/config:metadata_lib", "//source/common/config:utility_lib", + "//source/common/http:header_utility_lib", "//source/common/matcher:matcher_lib", "@envoy_api//contrib/envoy/extensions/filters/network/generic_proxy/action/v3:pkg_cc_proto", "@envoy_api//contrib/envoy/extensions/filters/network/generic_proxy/v3:pkg_cc_proto", diff --git a/contrib/generic_proxy/filters/network/source/upstream.cc b/contrib/generic_proxy/filters/network/source/upstream.cc index d92ef81d1456..3af4c0b712a1 100644 --- a/contrib/generic_proxy/filters/network/source/upstream.cc +++ b/contrib/generic_proxy/filters/network/source/upstream.cc @@ -8,6 +8,8 @@ namespace GenericProxy { UpstreamConnection::~UpstreamConnection() { // Do clean up here again to ensure the cleanUp is called. This is safe to call // multiple times because of the is_cleand_up_ flag. + // TODO(wbpcode): Clarify/resolve bypassing of virtual dispatch + // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall) this->cleanUp(true); } diff --git a/contrib/generic_proxy/filters/network/test/router/router_test.cc b/contrib/generic_proxy/filters/network/test/router/router_test.cc index 8d98a4229f85..aa04214b75d4 100644 --- a/contrib/generic_proxy/filters/network/test/router/router_test.cc +++ b/contrib/generic_proxy/filters/network/test/router/router_test.cc @@ -175,10 +175,10 @@ class RouterFilterTest : public testing::TestWithParam { ASSERT(!filter_->upstreamRequestsForTest().empty()); auto upstream_request = filter_->upstreamRequestsForTest().begin()->get(); + auto stream_frame = std::make_shared(std::move(response)); EXPECT_CALL(*mock_client_codec_, decode(BufferStringEqual("test_1"), _)) - .WillOnce(Invoke([this, resp = std::make_shared(std::move(response))]( - Buffer::Instance& buffer, bool) { + .WillOnce(Invoke([this, resp = std::move(stream_frame)](Buffer::Instance& buffer, bool) { buffer.drain(buffer.length()); const bool end_stream = (*resp)->frameFlags().endStream(); diff --git a/contrib/kafka/filters/network/source/broker/filter.cc b/contrib/kafka/filters/network/source/broker/filter.cc index 616ac6560364..027ab530affe 100644 --- a/contrib/kafka/filters/network/source/broker/filter.cc +++ b/contrib/kafka/filters/network/source/broker/filter.cc @@ -72,7 +72,7 @@ absl::flat_hash_map& KafkaMetricsFacadeImpl::getRequestA KafkaBrokerFilter::KafkaBrokerFilter(Stats::Scope& scope, TimeSource& time_source, const BrokerFilterConfig& filter_config) : KafkaBrokerFilter{filter_config, std::make_shared( - scope, time_source, filter_config.stat_prefix())} {}; + scope, time_source, filter_config.statPrefix())} {}; KafkaBrokerFilter::KafkaBrokerFilter(const BrokerFilterConfig& filter_config, const KafkaMetricsFacadeSharedPtr& metrics) diff --git a/contrib/kafka/filters/network/source/broker/filter_config.cc b/contrib/kafka/filters/network/source/broker/filter_config.cc index 2167aae35c5f..40e72979063e 100644 --- a/contrib/kafka/filters/network/source/broker/filter_config.cc +++ b/contrib/kafka/filters/network/source/broker/filter_config.cc @@ -48,7 +48,7 @@ BrokerFilterConfig::findBrokerAddressOverride(const uint32_t broker_id) const { return absl::nullopt; } -const std::string& BrokerFilterConfig::stat_prefix() const { return stat_prefix_; } +const std::string& BrokerFilterConfig::statPrefix() const { return stat_prefix_; } } // namespace Broker } // namespace Kafka diff --git a/contrib/kafka/filters/network/source/broker/filter_config.h b/contrib/kafka/filters/network/source/broker/filter_config.h index 4d9526ba711c..9cea074205de 100644 --- a/contrib/kafka/filters/network/source/broker/filter_config.h +++ b/contrib/kafka/filters/network/source/broker/filter_config.h @@ -44,7 +44,7 @@ class BrokerFilterConfig { /** * Returns the prefix for stats. */ - virtual const std::string& stat_prefix() const; + virtual const std::string& statPrefix() const; /** * Whether this configuration means that rewrite should be happening. diff --git a/contrib/kafka/filters/network/source/broker/rewriter.h b/contrib/kafka/filters/network/source/broker/rewriter.h index 82f4613c4c0e..f6a98c1045c9 100644 --- a/contrib/kafka/filters/network/source/broker/rewriter.h +++ b/contrib/kafka/filters/network/source/broker/rewriter.h @@ -21,7 +21,7 @@ namespace Broker { */ class ResponseRewriter : public ResponseCallback { public: - virtual ~ResponseRewriter() = default; + ~ResponseRewriter() override = default; /** * Performs any desired payload changes. diff --git a/contrib/kafka/filters/network/test/broker/rewriter_unit_test.cc b/contrib/kafka/filters/network/test/broker/rewriter_unit_test.cc index cf5195bd9e76..48bfb3fab956 100644 --- a/contrib/kafka/filters/network/test/broker/rewriter_unit_test.cc +++ b/contrib/kafka/filters/network/test/broker/rewriter_unit_test.cc @@ -6,9 +6,7 @@ #include "contrib/kafka/filters/network/test/broker/mock_filter_config.h" #include "gtest/gtest.h" -using testing::_; using testing::Return; -using testing::Throw; namespace Envoy { namespace Extensions { @@ -34,7 +32,7 @@ class FakeResponse : public AbstractResponse { uint32_t computeSize() const override { return size_; }; - virtual uint32_t encode(Buffer::Instance& dst) const override { + uint32_t encode(Buffer::Instance& dst) const override { putBytesIntoBuffer(dst, size_); return size_; }; diff --git a/contrib/language/filters/http/test/language_integration_test.cc b/contrib/language/filters/http/test/language_integration_test.cc index 0870392dd41d..6875c0f23d11 100644 --- a/contrib/language/filters/http/test/language_integration_test.cc +++ b/contrib/language/filters/http/test/language_integration_test.cc @@ -21,7 +21,8 @@ name: envoy.filters.http.language default_language: {} supported_languages: {} )EOF"; - config_helper_.prependFilter(fmt::format(yaml, default_language, supported_languages)); + config_helper_.prependFilter( + fmt::format(fmt::runtime(yaml), default_language, supported_languages)); } }; diff --git a/contrib/mysql_proxy/filters/network/test/mysql_integration_test.cc b/contrib/mysql_proxy/filters/network/test/mysql_integration_test.cc index 0b28e75cf952..282dc83bdb0e 100644 --- a/contrib/mysql_proxy/filters/network/test/mysql_integration_test.cc +++ b/contrib/mysql_proxy/filters/network/test/mysql_integration_test.cc @@ -24,12 +24,12 @@ class MySQLIntegrationTest : public testing::TestWithParam(upstream_ssl_config), // upstream SSL transport socket diff --git a/contrib/qat/compression/qatzip/compressor/source/config.cc b/contrib/qat/compression/qatzip/compressor/source/config.cc index 48144e706b10..47904f927b34 100644 --- a/contrib/qat/compression/qatzip/compressor/source/config.cc +++ b/contrib/qat/compression/qatzip/compressor/source/config.cc @@ -82,7 +82,7 @@ Envoy::Compression::Compressor::CompressorPtr QatzipCompressorFactory::createCom } QatzipCompressorFactory::QatzipThreadLocal::QatzipThreadLocal(QzSessionParams_T params) - : params_(params), session_{}, initialized_(false) {} + : params_(params), session_{} {} QatzipCompressorFactory::QatzipThreadLocal::~QatzipThreadLocal() { if (initialized_) { diff --git a/contrib/qat/compression/qatzip/compressor/source/config.h b/contrib/qat/compression/qatzip/compressor/source/config.h index 4df242bd8a1f..5d638e69ee69 100644 --- a/contrib/qat/compression/qatzip/compressor/source/config.h +++ b/contrib/qat/compression/qatzip/compressor/source/config.h @@ -53,7 +53,7 @@ class QatzipCompressorFactory : public Envoy::Compression::Compressor::Compresso QzSessionParams_T params_; QzSession_T session_; - bool initialized_; + bool initialized_{false}; }; const uint32_t chunk_size_; diff --git a/contrib/qat/private_key_providers/source/qat_private_key_provider.cc b/contrib/qat/private_key_providers/source/qat_private_key_provider.cc index b6a4b0b51658..f90615efcf25 100644 --- a/contrib/qat/private_key_providers/source/qat_private_key_provider.cc +++ b/contrib/qat/private_key_providers/source/qat_private_key_provider.cc @@ -363,7 +363,8 @@ QatPrivateKeyMethodProvider::QatPrivateKeyMethodProvider( std::chrono::milliseconds poll_delay = std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(conf, poll_delay, 5)); - std::string private_key = Config::DataSource::read(conf.private_key(), false, api_); + std::string private_key = + THROW_OR_RETURN_VALUE(Config::DataSource::read(conf.private_key(), false, api_), std::string); bssl::UniquePtr bio( BIO_new_mem_buf(const_cast(private_key.data()), private_key.size())); diff --git a/contrib/sip_proxy/filters/network/source/tra/tra_impl.cc b/contrib/sip_proxy/filters/network/source/tra/tra_impl.cc index 86c68a071668..95b77c071d5a 100644 --- a/contrib/sip_proxy/filters/network/source/tra/tra_impl.cc +++ b/contrib/sip_proxy/filters/network/source/tra/tra_impl.cc @@ -200,12 +200,13 @@ ClientPtr traClient(Event::Dispatcher& dispatcher, Server::Configuration::Factor const std::chrono::milliseconds timeout) { // TODO(ramaraochavali): register client to singleton when GrpcClientImpl supports concurrent // requests. + auto client_or_error = context.serverFactoryContext() + .clusterManager() + .grpcAsyncClientManager() + .getOrCreateRawAsyncClient(grpc_service, context.scope(), true); + THROW_IF_STATUS_NOT_OK(client_or_error, throw); return std::make_unique( - context.serverFactoryContext() - .clusterManager() - .grpcAsyncClientManager() - .getOrCreateRawAsyncClient(grpc_service, context.scope(), true), - dispatcher, timeout); + client_or_error.value(), dispatcher, timeout); } } // namespace TrafficRoutingAssistant diff --git a/contrib/sxg/filters/http/source/BUILD b/contrib/sxg/filters/http/source/BUILD index a6bb7cec6708..1d3b5b9231a6 100644 --- a/contrib/sxg/filters/http/source/BUILD +++ b/contrib/sxg/filters/http/source/BUILD @@ -28,6 +28,7 @@ envoy_cc_library( "//source/common/http:codes_lib", "//source/common/stats:symbol_table_lib", "//source/common/stats:utility_lib", + "//source/common/secret:secret_provider_impl_lib", "//source/extensions/filters/http/common:pass_through_filter_lib", "@envoy_api//contrib/envoy/extensions/filters/http/sxg/v3alpha:pkg_cc_proto", # use boringssl alias to select fips vs non-fips version. diff --git a/contrib/sxg/filters/http/source/config.cc b/contrib/sxg/filters/http/source/config.cc index 68b7d2292a72..541216f8454f 100644 --- a/contrib/sxg/filters/http/source/config.cc +++ b/contrib/sxg/filters/http/source/config.cc @@ -57,7 +57,8 @@ Http::FilterFactoryCb FilterFactory::createFilterFactoryFromProtoTyped( } auto secret_reader = std::make_shared( - secret_provider_certificate, secret_provider_private_key, server_context.api()); + std::move(secret_provider_certificate), std::move(secret_provider_private_key), + server_context.threadLocal(), server_context.api()); auto config = std::make_shared(proto_config, server_context.timeSource(), secret_reader, stat_prefix, context.scope()); return [config](Http::FilterChainFactoryCallbacks& callbacks) -> void { diff --git a/contrib/sxg/filters/http/source/filter_config.h b/contrib/sxg/filters/http/source/filter_config.h index 11532d2e2145..a54f51794259 100644 --- a/contrib/sxg/filters/http/source/filter_config.h +++ b/contrib/sxg/filters/http/source/filter_config.h @@ -4,7 +4,7 @@ #include "envoy/stats/scope.h" #include "envoy/stats/stats_macros.h" -#include "source/common/config/datasource.h" +#include "source/common/secret/secret_provider_impl.h" #include "source/extensions/filters/http/common/pass_through_filter.h" #include "contrib/envoy/extensions/filters/http/sxg/v3alpha/sxg.pb.h" @@ -37,37 +37,18 @@ class SecretReader { class SDSSecretReader : public SecretReader { public: - SDSSecretReader(Secret::GenericSecretConfigProviderSharedPtr certificate_provider, - Secret::GenericSecretConfigProviderSharedPtr private_key_provider, Api::Api& api) - : update_callback_client_(readAndWatchSecret(certificate_, certificate_provider, api)), - update_callback_token_(readAndWatchSecret(private_key_, private_key_provider, api)) {} - + SDSSecretReader(Secret::GenericSecretConfigProviderSharedPtr&& certificate_provider, + Secret::GenericSecretConfigProviderSharedPtr&& private_key_provider, + ThreadLocal::SlotAllocator& tls, Api::Api& api) + : certificate_(std::move(certificate_provider), tls, api), + private_key_(std::move(private_key_provider), tls, api) {} // SecretReader - const std::string& certificate() const override { return certificate_; } - const std::string& privateKey() const override { return private_key_; } + const std::string& certificate() const override { return certificate_.secret(); } + const std::string& privateKey() const override { return private_key_.secret(); } private: - Envoy::Common::CallbackHandlePtr - readAndWatchSecret(std::string& value, - Secret::GenericSecretConfigProviderSharedPtr& secret_provider, Api::Api& api) { - const auto* secret = secret_provider->secret(); - if (secret != nullptr) { - value = Config::DataSource::read(secret->secret(), true, api); - } - - return secret_provider->addUpdateCallback([secret_provider, &api, &value]() { - const auto* secret = secret_provider->secret(); - if (secret != nullptr) { - value = Config::DataSource::read(secret->secret(), true, api); - } - }); - } - - std::string certificate_; - std::string private_key_; - - Envoy::Common::CallbackHandlePtr update_callback_client_; - Envoy::Common::CallbackHandlePtr update_callback_token_; + Secret::ThreadLocalGenericSecretProvider certificate_; + Secret::ThreadLocalGenericSecretProvider private_key_; }; class FilterConfig : public Logger::Loggable { diff --git a/contrib/sxg/filters/http/test/filter_test.cc b/contrib/sxg/filters/http/test/filter_test.cc index 933198e6f6c7..a8ba5c027e18 100644 --- a/contrib/sxg/filters/http/test/filter_test.cc +++ b/contrib/sxg/filters/http/test/filter_test.cc @@ -380,7 +380,9 @@ TEST_F(FilterTest, SdsDynamicGenericSecret) { config_source, "private_key", secret_context, init_manager); auto private_key_callback = secret_context.cluster_manager_.subscription_factory_.callbacks_; - SDSSecretReader secret_reader(certificate_secret_provider, private_key_secret_provider, *api); + NiceMock tls; + SDSSecretReader secret_reader(std::move(certificate_secret_provider), + std::move(private_key_secret_provider), tls, *api); EXPECT_TRUE(secret_reader.certificate().empty()); EXPECT_TRUE(secret_reader.privateKey().empty()); diff --git a/docs/inventories/v1.26/objects.inv b/docs/inventories/v1.26/objects.inv index 477894d1f6bc..26b06951df94 100644 Binary files a/docs/inventories/v1.26/objects.inv and b/docs/inventories/v1.26/objects.inv differ diff --git a/docs/inventories/v1.27/objects.inv b/docs/inventories/v1.27/objects.inv index 0b0acf5c7b42..4eee783c0fd4 100644 Binary files a/docs/inventories/v1.27/objects.inv and b/docs/inventories/v1.27/objects.inv differ diff --git a/docs/inventories/v1.28/objects.inv b/docs/inventories/v1.28/objects.inv index c454862b2315..19b5b89f7d8e 100644 Binary files a/docs/inventories/v1.28/objects.inv and b/docs/inventories/v1.28/objects.inv differ diff --git a/docs/inventories/v1.29/objects.inv b/docs/inventories/v1.29/objects.inv new file mode 100644 index 000000000000..70feb4b0ae53 Binary files /dev/null and b/docs/inventories/v1.29/objects.inv differ diff --git a/docs/root/configuration/advanced/well_known_filter_state.rst b/docs/root/configuration/advanced/well_known_filter_state.rst index 50c4f3476077..f238dd207854 100644 --- a/docs/root/configuration/advanced/well_known_filter_state.rst +++ b/docs/root/configuration/advanced/well_known_filter_state.rst @@ -63,6 +63,11 @@ The following lists the filter state object keys used by the Envoy extensions: A special generic string object factory, to be used as a :ref:`factory lookup key `. +``envoy.tcp_proxy.per_connection_idle_timeout_ms`` + :ref:`TCP proxy idle timeout duration + ` override on a per-connection + basis. Accepts a count of milliseconds number string as a constructor. + Filter state object fields -------------------------- diff --git a/docs/root/configuration/http/http_conn_man/headers.rst b/docs/root/configuration/http/http_conn_man/headers.rst index a5e95670c187..4403a74cf0c4 100644 --- a/docs/root/configuration/http/http_conn_man/headers.rst +++ b/docs/root/configuration/http/http_conn_man/headers.rst @@ -435,6 +435,16 @@ The ``x-forwarded-proto`` header will be used by Envoy over ``:scheme`` where th encryption is wanted, for example clearing default ports based on ``x-forwarded-proto``. See :ref:`why_is_envoy_using_xfp_or_scheme` for more details. +.. _config_http_conn_man_headers_x-envoy-local-overloaded: + +x-envoy-local-overloaded +------------------------ + +Envoy will set this header on the downstream response +if a request was dropped due to :ref:`overload manager` and +:ref:`configuration option ` +is set to true. + .. _config_http_conn_man_headers_x-request-id: x-request-id diff --git a/docs/root/configuration/observability/access_log/stats.rst b/docs/root/configuration/observability/access_log/stats.rst index 632ebaf48283..0a61df4e4518 100644 --- a/docs/root/configuration/observability/access_log/stats.rst +++ b/docs/root/configuration/observability/access_log/stats.rst @@ -33,3 +33,17 @@ The file access log has statistics rooted at the *filesystem.* namespace. flushed_by_timer, Counter, Total number of times internal flush buffers are written to a file due to flush timeout reopen_failed, Counter, Total number of times a file was failed to be opened write_total_buffered, Gauge, Current total size of internal flush buffer in bytes + +Fluentd access log statistics +----------------------------- + +The Fluentd access log has statistics rooted at the *access_logs.fluentd..* namespace. + +.. csv-table:: + :header: Name, Type, Description + :widths: 1, 1, 2 + + entries_lost, Counter, Total number of times an access log entry was discarded due to unavailable connection. + entries_buffered, Counter, Total number of entries (access log record) that was buffered/ + events_sent, Counter, Total number of events (Fluentd Forward Mode events) sent to the upstream. + connections_closed, Counter, Total number of times a connection to the upstream cluster was closed. diff --git a/docs/root/configuration/operations/overload_manager/overload_manager.rst b/docs/root/configuration/operations/overload_manager/overload_manager.rst index 7d45a1bbd758..dcc522e31d12 100644 --- a/docs/root/configuration/operations/overload_manager/overload_manager.rst +++ b/docs/root/configuration/operations/overload_manager/overload_manager.rst @@ -165,6 +165,11 @@ The following core load shed points are supported: - Envoy will send a ``GOAWAY`` while processing HTTP2 requests at the codec level which will eventually drain the HTTP/2 connection. + * - envoy.load_shed_points.hcm_ondata_creating_codec + - Envoy will close the connections before creating codec if Envoy is under + pressure, typically memory. This happens once geting data from the + connection. + .. _config_overload_manager_reducing_timeouts: Reducing timeouts diff --git a/docs/root/intro/arch_overview/http/http3.rst b/docs/root/intro/arch_overview/http/http3.rst index e87cd4dc6b7b..5f574d913ca9 100644 --- a/docs/root/intro/arch_overview/http/http3.rst +++ b/docs/root/intro/arch_overview/http/http3.rst @@ -8,8 +8,7 @@ HTTP/3 overview While HTTP/3 **downstream support is deemed ready for production use**, improvements are ongoing, tracked in the `area-quic `_ tag. - HTTP/3 **upstream support is fine for locally controlled networks**, but is alpha for - general internet use - key features are implemented but have not been tested at scale. + HTTP/3 upstream support is alpha - key features are implemented but have not been tested at scale. .. _arch_overview_http3_downstream: diff --git a/docs/root/intro/arch_overview/observability/access_logging.rst b/docs/root/intro/arch_overview/observability/access_logging.rst index 0371c385f52d..130f70642ce9 100644 --- a/docs/root/intro/arch_overview/observability/access_logging.rst +++ b/docs/root/intro/arch_overview/observability/access_logging.rst @@ -138,6 +138,15 @@ Stderr response headers. * Writes to the standard error of the process. It works in all platforms. +Fluentd +******** + +* Flush access logs over a TCP connection to an upstream that is accepting the Fluentd Forward Protocol as described in: + `Fluentd Forward Protocol Specification `_. +* The data sent over the wire is a stream of + `Fluentd Forward Mode events `_ + which may contain one or more access log entries (depending on the flushing interval and other configuration parameters). + Further reading --------------- @@ -148,3 +157,4 @@ Further reading * OpenTelemetry (gRPC) :ref:`LogsService ` * Stdout :ref:`access log sink ` * Stderr :ref:`access log sink ` +* Fluentd :ref:`access log sink ` diff --git a/docs/root/intro/arch_overview/operations/overload_manager.rst b/docs/root/intro/arch_overview/operations/overload_manager.rst index 1639bcd3ade7..d94aadebd50e 100644 --- a/docs/root/intro/arch_overview/operations/overload_manager.rst +++ b/docs/root/intro/arch_overview/operations/overload_manager.rst @@ -53,3 +53,8 @@ Actions When a trigger changes state, the value is sent to registered actions, which can then affect how connections and requests are processed. Each action interprets the input states differently, and some may ignore the *scaling* state altogether, taking effect only when *saturated*. + +Note that, in case :ref:`append_local_overload +` has been set to true, dropping an HTTP request will cause the :ref:`x-envoy-local-overloaded +` header to be set in the local reply +sent by the connection manager. diff --git a/docs/root/start/sandboxes/index.rst b/docs/root/start/sandboxes/index.rst index d23d536c2447..450fd5176fd2 100644 --- a/docs/root/start/sandboxes/index.rst +++ b/docs/root/start/sandboxes/index.rst @@ -59,7 +59,6 @@ The following sandboxes are available: golang-network grpc_bridge gzip - jaeger_native_tracing jaeger_tracing kafka load_reporting_service diff --git a/docs/root/start/sandboxes/jaeger_native_tracing.rst b/docs/root/start/sandboxes/jaeger_native_tracing.rst deleted file mode 100644 index 5b1295ffba6c..000000000000 --- a/docs/root/start/sandboxes/jaeger_native_tracing.rst +++ /dev/null @@ -1,121 +0,0 @@ -.. _install_sandboxes_jaeger_native_tracing: - -Jaeger native tracing -===================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -.. sidebar:: Compatibility - - The jaeger native tracing sandbox uses a binary built for ``x86_64``, and will therefore - only work on that architecture. - -The Jaeger tracing sandbox demonstrates Envoy's :ref:`request tracing ` -capabilities using `Jaeger `_ as the tracing provider and Jaeger's native -`C++ client `_ as a plugin. Using Jaeger with its -native client instead of with Envoy's builtin Zipkin client has the following advantages: - -- Trace propagation will work with the other services using Jaeger without needing to make - configuration `changes `_. -- A variety of different `sampling strategies `_ - can be used, including probabilistic or remote where sampling can be centrally controlled from Jaeger's backend. -- Spans are sent to the collector in a more efficient binary encoding. - -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-native-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-native-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-native-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 3: Build the sandbox -************************* - -To build this sandbox example, and start the example apps run the following commands: - -.. code-block:: console - - $ pwd - envoy/examples/jaeger-native-tracing - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------------------------------------------------------------- - jaeger-native-tracing_front-envoy_1 /start-front.sh Up 10000/tcp, 0.0.0.0:8000->8000/tcp - jaeger-native-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 - jaeger-native-tracing_service1_1 /start-service.sh Up 10000/tcp - jaeger-native-tracing_service2_1 /start-service.sh Up 10000/tcp - -Step 4: 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 5: 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. - - `Jaeger C++ client `_ - The Jaeger C++ cient. - - `Jaeger Go client `_ - The Jaeger Go client. - - `Jaeger sampling strategies `_ - More information about Jaeger sampling strategies. diff --git a/docs/root/start/sandboxes/jaeger_tracing.rst b/docs/root/start/sandboxes/jaeger_tracing.rst index f9ac3bc2a6b5..83c5bbf3a621 100644 --- a/docs/root/start/sandboxes/jaeger_tracing.rst +++ b/docs/root/start/sandboxes/jaeger_tracing.rst @@ -94,8 +94,5 @@ to service2, as well as the latency incurred at each hop. :ref:`Request tracing ` Learn more about using Envoy's request tracing. - :ref:`Jaeger native tracing sandbox ` - An example of using Jaeger natively with Envoy. - `Jaeger `_ Jaeger tracing website. diff --git a/docs/versions.yaml b/docs/versions.yaml index 06b7cca3c7d4..43dfa10ac3cb 100644 --- a/docs/versions.yaml +++ b/docs/versions.yaml @@ -19,6 +19,7 @@ "1.23": 1.23.12 "1.24": 1.24.12 "1.25": 1.25.11 -"1.26": 1.26.6 -"1.27": 1.27.2 -"1.28": 1.28.0 +"1.26": 1.26.7 +"1.27": 1.27.3 +"1.28": 1.28.1 +"1.29": 1.29.1 diff --git a/envoy/common/exception.h b/envoy/common/exception.h index 48240a1d232b..4d5d9fd45bc0 100644 --- a/envoy/common/exception.h +++ b/envoy/common/exception.h @@ -60,4 +60,12 @@ class EnvoyException : public std::runtime_error { if (!variable.ok()) { \ return variable; \ } + +template Type returnOrThrow(absl::StatusOr type_or_error) { + THROW_IF_STATUS_NOT_OK(type_or_error, throw); + return type_or_error.value(); +} + +#define THROW_OR_RETURN_VALUE(expression, type) returnOrThrow(expression) + } // namespace Envoy diff --git a/envoy/grpc/async_client_manager.h b/envoy/grpc/async_client_manager.h index aa99f2c23a6e..91c13d7d57ee 100644 --- a/envoy/grpc/async_client_manager.h +++ b/envoy/grpc/async_client_manager.h @@ -81,10 +81,9 @@ class AsyncClientManager { * @param skip_cluster_check if set to true skips checks for cluster presence and being statically * configured. * @param cache_option always use cache or use cache when runtime is enabled. - * @return RawAsyncClientPtr a grpc async client. - * @throws EnvoyException when grpc_service validation fails. + * @return RawAsyncClientPtr a grpc async client or an invalid status. */ - virtual RawAsyncClientSharedPtr + virtual absl::StatusOr getOrCreateRawAsyncClient(const envoy::config::core::v3::GrpcService& grpc_service, Stats::Scope& scope, bool skip_cluster_check) PURE; @@ -100,7 +99,7 @@ class AsyncClientManager { * @return RawAsyncClientPtr a grpc async client. * @throws EnvoyException when grpc_service validation fails. */ - virtual RawAsyncClientSharedPtr + virtual absl::StatusOr getOrCreateRawAsyncClientWithHashKey(const GrpcServiceConfigWithHashKey& grpc_service, Stats::Scope& scope, bool skip_cluster_check) PURE; @@ -111,10 +110,9 @@ class AsyncClientManager { * @param scope stats scope. * @param skip_cluster_check if set to true skips checks for cluster presence and being statically * configured. - * @return AsyncClientFactoryPtr factory for grpc_service. - * @throws EnvoyException when grpc_service validation fails. + * @return AsyncClientFactoryPtr factory for grpc_service or an error status. */ - virtual AsyncClientFactoryPtr + virtual absl::StatusOr factoryForGrpcService(const envoy::config::core::v3::GrpcService& grpc_service, Stats::Scope& scope, bool skip_cluster_check) PURE; }; diff --git a/envoy/server/overload/load_shed_point.h b/envoy/server/overload/load_shed_point.h index ef19210a34a7..076eff36b708 100644 --- a/envoy/server/overload/load_shed_point.h +++ b/envoy/server/overload/load_shed_point.h @@ -9,6 +9,29 @@ namespace Envoy { namespace Server { +class LoadShedPointNameValues { +public: + // Envoy will reject (close) new TCP connections. + // This occurs before the Listener Filter Chain is created. + const std::string TcpListenerAccept = "envoy.load_shed_points.tcp_listener_accept"; + + // Envoy will reject new HTTP streams by sending a local reply. + const std::string HcmDecodeHeaders = + "envoy.load_shed_points.http_connection_manager_decode_headers"; + + // Envoy will reject processing HTTP1 at the codec level. + const std::string H1ServerAbortDispatch = "envoy.load_shed_points.http1_server_abort_dispatch"; + + // Envoy will send a GOAWAY while processing HTTP2 requests at the codec level + // which will eventually drain the HTTP/2 connection. + const std::string H2ServerGoAwayOnDispatch = + "envoy.load_shed_points.http2_server_go_away_on_dispatch"; + + const std::string HcmCodecCreation = "envoy.load_shed_points.hcm_ondata_creating_codec"; +}; + +using LoadShedPointName = ConstSingleton; + /** * A point within the connection or request lifecycle that provides context on * whether to shed load at that given stage for the current entity at the point. diff --git a/envoy/stats/stats.h b/envoy/stats/stats.h index ea4596f64aa5..10af2c396620 100644 --- a/envoy/stats/stats.h +++ b/envoy/stats/stats.h @@ -38,10 +38,7 @@ class Metric : public RefcountInterface { * Returns the full name of the Metric. This is intended for most uses, such * as streaming out the name to a stats sink or admin request, or comparing * against it in a test. Independent of the evolution of the data - * representation for the name, this method will be available. For storing the - * name as a map key, however, nameCStr() is a better choice, albeit one that - * might change in the future to return a symbolized representation of the - * elaborated string. + * representation for the name, this method will be available. */ virtual std::string name() const PURE; diff --git a/envoy/tcp/async_tcp_client.h b/envoy/tcp/async_tcp_client.h index df80fd0c3866..bd367a55db1b 100644 --- a/envoy/tcp/async_tcp_client.h +++ b/envoy/tcp/async_tcp_client.h @@ -40,8 +40,11 @@ class AsyncTcpClient { /** * Connect to a remote host. Errors or connection events are reported via the - * event callback registered via setAsyncTcpClientCallbacks(). We need to set the - * callbacks again to call connect() after the connection is disconnected. + * event callback registered via setAsyncTcpClientCallbacks(). If the callbacks + * needs to be changed before reconnecting, it is required to set the callbacks + * again, before calling to connect() to attempting to reconnect. + * @returns true if a new client has created and the connection is in progress. + * @returns false if an underlying client exists and is connected or connecting. */ virtual bool connect() PURE; diff --git a/examples/ext_authz/Dockerfile-opa b/examples/ext_authz/Dockerfile-opa index 5afaffa73be2..85fdf75504ca 100644 --- a/examples/ext_authz/Dockerfile-opa +++ b/examples/ext_authz/Dockerfile-opa @@ -1 +1 @@ -FROM openpolicyagent/opa:0.61.0-istio@sha256:5ee86eb43bbe8a80e24d4d218a7fd568e5e5c1a782f20aa03a5643cad307034f +FROM openpolicyagent/opa:0.62.0-istio@sha256:94244de629099cea0a92d2680c982f16756f1e1e9de465db7af46bbc25516f7f diff --git a/examples/ext_authz/auth/grpc-service/go.mod b/examples/ext_authz/auth/grpc-service/go.mod index 02aef65f5966..3e4511aeab2c 100644 --- a/examples/ext_authz/auth/grpc-service/go.mod +++ b/examples/ext_authz/auth/grpc-service/go.mod @@ -5,6 +5,6 @@ go 1.14 require ( github.com/envoyproxy/go-control-plane v0.12.0 github.com/golang/protobuf v1.5.3 - google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 - google.golang.org/grpc v1.61.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 + google.golang.org/grpc v1.62.0 ) diff --git a/examples/ext_authz/auth/grpc-service/go.sum b/examples/ext_authz/auth/grpc-service/go.sum index 52de68a07117..513e0ac97039 100644 --- a/examples/ext_authz/auth/grpc-service/go.sum +++ b/examples/ext_authz/auth/grpc-service/go.sum @@ -43,6 +43,8 @@ cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5x 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/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= @@ -72,6 +74,9 @@ cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP 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/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= @@ -82,6 +87,7 @@ cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N 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/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= @@ -149,6 +155,8 @@ cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+ok 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/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= @@ -185,6 +193,7 @@ cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mu 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/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= @@ -212,6 +221,7 @@ cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6Pm 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/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= @@ -224,6 +234,7 @@ cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlp 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/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= @@ -234,6 +245,7 @@ cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJx 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/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= @@ -250,6 +262,7 @@ cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Ii 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/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= @@ -261,6 +274,7 @@ cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2 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/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= @@ -315,6 +329,8 @@ cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJ 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/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= @@ -326,6 +342,8 @@ cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBS 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/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= @@ -351,6 +369,8 @@ cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/U 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/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= @@ -391,6 +411,9 @@ cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MP 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/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= @@ -399,6 +422,7 @@ cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LV 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/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= @@ -435,6 +459,9 @@ cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCN 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/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= @@ -450,6 +477,9 @@ cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+ 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/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= @@ -470,6 +500,8 @@ cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJx 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/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= @@ -510,6 +542,7 @@ cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp 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/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= @@ -563,6 +596,7 @@ cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZVi 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/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/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= @@ -647,6 +681,7 @@ cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqN 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= @@ -671,6 +706,8 @@ cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9v 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/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= @@ -707,6 +744,7 @@ cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67m 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/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= @@ -769,6 +807,7 @@ cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK 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/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= @@ -789,6 +828,7 @@ cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3 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/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= @@ -824,6 +864,7 @@ cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9 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/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= @@ -841,6 +882,8 @@ cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3X 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/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= @@ -858,6 +901,7 @@ cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlk 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/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= @@ -911,6 +955,7 @@ cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhO 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/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= @@ -940,6 +985,7 @@ cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY 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/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= @@ -978,6 +1024,10 @@ cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSq 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/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= @@ -989,6 +1039,7 @@ cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ 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/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= @@ -1001,6 +1052,7 @@ cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi 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/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= @@ -1051,6 +1103,7 @@ cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNW 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/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= @@ -1148,6 +1201,7 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd 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/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -1176,8 +1230,8 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH 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 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= -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 h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= 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= @@ -1205,8 +1259,10 @@ github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0+ 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 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +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/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= @@ -1220,6 +1276,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 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/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/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -1228,6 +1288,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU 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= @@ -1284,6 +1345,7 @@ 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= @@ -1313,6 +1375,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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= @@ -1345,8 +1409,10 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9K 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/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/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= @@ -1375,6 +1441,8 @@ github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4 github.com/mattn/go-sqlite3 v1.14.15/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/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= @@ -1402,10 +1470,12 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO 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/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= @@ -1433,6 +1503,16 @@ 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/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +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/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/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/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/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= @@ -1447,6 +1527,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm 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= @@ -1456,6 +1537,9 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y 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/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= @@ -1515,6 +1599,7 @@ 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/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= @@ -1578,10 +1663,13 @@ 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 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= 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 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 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= @@ -1615,7 +1703,8 @@ 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/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= @@ -1636,6 +1725,7 @@ 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/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= @@ -1720,8 +1810,10 @@ 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 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= 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 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= @@ -1738,6 +1830,8 @@ 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/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= @@ -1766,6 +1860,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb 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= @@ -1830,6 +1925,7 @@ 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/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= @@ -1838,6 +1934,7 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T 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= @@ -1911,6 +2008,8 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy 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/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= @@ -2069,8 +2168,14 @@ google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqv 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 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= 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 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= 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= @@ -2088,9 +2193,16 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go. 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-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= 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/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= @@ -2107,8 +2219,14 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go. 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 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= 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-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= 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= @@ -2157,8 +2275,10 @@ google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt 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.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +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.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= diff --git a/examples/grpc-bridge/client/requirements.txt b/examples/grpc-bridge/client/requirements.txt index c256b9ee6aef..f7087d393f20 100644 --- a/examples/grpc-bridge/client/requirements.txt +++ b/examples/grpc-bridge/client/requirements.txt @@ -100,136 +100,136 @@ charset-normalizer==3.3.0 \ --hash=sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e \ --hash=sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8 # via requests -grpcio==1.60.1 \ - --hash=sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8 \ - --hash=sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8 \ - --hash=sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104 \ - --hash=sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc \ - --hash=sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092 \ - --hash=sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1 \ - --hash=sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180 \ - --hash=sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05 \ - --hash=sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287 \ - --hash=sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216 \ - --hash=sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c \ - --hash=sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d \ - --hash=sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594 \ - --hash=sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c \ - --hash=sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87 \ - --hash=sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de \ - --hash=sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9 \ - --hash=sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2 \ - --hash=sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff \ - --hash=sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904 \ - --hash=sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73 \ - --hash=sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549 \ - --hash=sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f \ - --hash=sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c \ - --hash=sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0 \ - --hash=sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e \ - --hash=sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367 \ - --hash=sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc \ - --hash=sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303 \ - --hash=sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb \ - --hash=sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c \ - --hash=sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804 \ - --hash=sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03 \ - --hash=sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6 \ - --hash=sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f \ - --hash=sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0 \ - --hash=sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd \ - --hash=sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21 \ - --hash=sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858 \ - --hash=sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce \ - --hash=sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9 \ - --hash=sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23 \ - --hash=sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073 \ - --hash=sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2 \ - --hash=sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872 \ - --hash=sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe \ - --hash=sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7 \ - --hash=sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6 \ - --hash=sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929 \ - --hash=sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962 \ - --hash=sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a \ - --hash=sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a \ - --hash=sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177 \ - --hash=sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525 +grpcio==1.62.0 \ + --hash=sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701 \ + --hash=sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e \ + --hash=sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532 \ + --hash=sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a \ + --hash=sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271 \ + --hash=sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f \ + --hash=sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7 \ + --hash=sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b \ + --hash=sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4 \ + --hash=sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839 \ + --hash=sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6 \ + --hash=sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb \ + --hash=sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e \ + --hash=sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93 \ + --hash=sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f \ + --hash=sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6 \ + --hash=sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1 \ + --hash=sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35 \ + --hash=sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842 \ + --hash=sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6 \ + --hash=sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c \ + --hash=sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873 \ + --hash=sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7 \ + --hash=sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c \ + --hash=sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928 \ + --hash=sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9 \ + --hash=sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c \ + --hash=sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021 \ + --hash=sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa \ + --hash=sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38 \ + --hash=sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc \ + --hash=sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe \ + --hash=sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8 \ + --hash=sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402 \ + --hash=sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388 \ + --hash=sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0 \ + --hash=sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b \ + --hash=sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b \ + --hash=sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2 \ + --hash=sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b \ + --hash=sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5 \ + --hash=sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829 \ + --hash=sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2 \ + --hash=sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6 \ + --hash=sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd \ + --hash=sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0 \ + --hash=sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8 \ + --hash=sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334 \ + --hash=sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee \ + --hash=sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c \ + --hash=sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72 \ + --hash=sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4 \ + --hash=sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270 \ + --hash=sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170 # via # -r requirements.in # grpcio-tools -grpcio-tools==1.60.1 \ - --hash=sha256:075bb67895970f96aabc1761ca674bf4db193f8fcad387f08e50402023b5f953 \ - --hash=sha256:0aa34c7c21cff2177a4096b2b0d51dfbc9f8a41f929847a434e89b352c5a215d \ - --hash=sha256:0b62cb2d43a7f0eacc6a6962dfff7c2564874012e1a72ae4167e762f449e2912 \ - --hash=sha256:15f13e8f3d77b96adcb1e3615acec5b100bd836c6010c58a51465bcb9c06d128 \ - --hash=sha256:184b27333b627a7cc0972fb70d21a8bb7c02ac4a6febc16768d78ea8ff883ddd \ - --hash=sha256:18d7737f29ef5bbe3352547d0eccd080807834f00df223867dfc860bf81e9180 \ - --hash=sha256:1e96a532d38411f0543fe1903ff522f7142a9901afb0ed94de58d79caf1905be \ - --hash=sha256:214281cdafb7acfdcde848eca2de7c888a6e2b5cd25ab579712b965ea09a9cd4 \ - --hash=sha256:22ce3e3d861321d208d8bfd6161ab976623520b179712c90b2c175151463a6b1 \ - --hash=sha256:26f91161a91f1601777751230eaaafdf416fed08a15c3ba2ae391088e4a906c6 \ - --hash=sha256:284749d20fb22418f17d3d351b9eb838caf4a0393a9cb02c36e5c32fa4bbe9db \ - --hash=sha256:28ae665113affebdd109247386786e5ab4dccfcfad1b5f68e9cce2e326b57ee6 \ - --hash=sha256:2973f75e8ba5c551033a1d59cc97654f6f386deaf2559082011d245d7ed87bba \ - --hash=sha256:2a7fa55bc62d4b8ebe6fb26f8cf89df3cf3b504eb6c5f3a2f0174689d35fddb0 \ - --hash=sha256:2c19be2bba5583e30f88bb5d71b430176c396f0d6d0db3785e5845bfa3d28cd2 \ - --hash=sha256:31294b534f25f02ead204e58dcbe0e5437a95a1a6f276bb9378905595b02ff6d \ - --hash=sha256:3aeecd5b8faa2aab67e6c8b8a57e888c00ce70d39f331ede0a21312e92def1a6 \ - --hash=sha256:3fb6f4d2df0388c35c2804ba170f511238a681b679ead013bfe5e39d0ea9cf48 \ - --hash=sha256:3fcabf484720a9fa1690e2825fc940027a05a0c79a1075a730008ef634bd8ad2 \ - --hash=sha256:402efeec36d8b12b792bae8a900085416fc2f57a34b599445ace2e847b6b0d75 \ - --hash=sha256:40cd8268a675269ce59c4fa50877597ec638bb1099c52237bb726c8ac9791868 \ - --hash=sha256:46b495bae31c5d3f6ac0240eb848f0642b5410f80dff2aacdea20cdea3938c1d \ - --hash=sha256:4e66fe204da15e08e599adb3060109a42927c0868fe8933e2d341ea649eceb03 \ - --hash=sha256:5b4a939097005531edec331f22d0b82bff26e71ede009354d2f375b5d41e74f0 \ - --hash=sha256:5c7ed086fef5ff59f46d53a052b1934b73e0f7d12365d656d6af3a88057d5a3e \ - --hash=sha256:5ea6e397d87f458bb2c387a4a6e1b65df74ce5b5194a1f16850c38309012e981 \ - --hash=sha256:652b08c9fef39186ce4f97f05f5440c0ed41f117db0f7d6cb0e0d75dbc6afd3f \ - --hash=sha256:6801cfc5a85f0fb6fd12cade45942aaa1c814422328d594d12d364815fe34123 \ - --hash=sha256:8540f6480428a52614db71dd6394f52cbc0d2565b5ea1136a982f26390a42c7a \ - --hash=sha256:8c4b917aa4fcdc77990773063f0f14540aab8d4a8bf6c862b964a45d891a31d2 \ - --hash=sha256:985ac476da365267a2367ab20060f9096fbfc2e190fb02dd394f9ec05edf03ca \ - --hash=sha256:9aadc9c00baa2064baa4414cff7c269455449f14805a355226674d89c507342c \ - --hash=sha256:9bba347000f57dae8aea79c0d76ef7d72895597524d30d0170c7d1974a3a03f3 \ - --hash=sha256:a2bb8efc2cd64bd8f2779b426dd7e94e60924078ba5150cbbb60a846e62d1ed2 \ - --hash=sha256:a8cfab27ba2bd36a3e3b522aed686133531e8b919703d0247a0885dae8815317 \ - --hash=sha256:aafc94616c5f89c891d859057b194a153c451f9921053454e9d7d4cbf79047eb \ - --hash=sha256:acdba77584981fe799104aa545d9d97910bcf88c69b668b768c1f3e7d7e5afac \ - --hash=sha256:af88a2062b9c35034a80b25f289034b9c3c00c42bb88efaa465503a06fbd6a87 \ - --hash=sha256:b1041377cf32ee2338284ee26e6b9c10f9ea7728092376b19803dcb9b91d510d \ - --hash=sha256:b5ae375207af9aa82f516dcd513d2e0c83690b7788d45844daad846ed87550f8 \ - --hash=sha256:b6ef213cb0aecb2832ee82a2eac32f29f31f50b17ce020604d82205096a6bd0c \ - --hash=sha256:bba7230c60238c7a4ffa29f1aff6d78edb41f2c79cbe4443406472b1c80ccb5d \ - --hash=sha256:bd85f6c368b93ae45edf8568473053cb1cc075ef3489efb18f9832d4ecce062f \ - --hash=sha256:c1047bd831de5d9da761e9dc246988d5f07d722186938dfd5f34807398101010 \ - --hash=sha256:c20e752ff5057758845f4e5c7a298739bfba291f373ed18ea9c7c7acbe69e8ab \ - --hash=sha256:c354505e6a3d170da374f20404ea6a78135502df4f5534e5c532bdf24c4cc2a5 \ - --hash=sha256:cc8ba358d2c658c6ecbc58e779bf0fc5a673fecac015a70db27fc5b4d37b76b6 \ - --hash=sha256:cf945bd22f396c0d0c691e0990db2bfc4e77816b1edc2aea8a69c35ae721aac9 \ - --hash=sha256:d2c26ce5f774c98bd2d3d8d1703048394018b55d297ebdb41ed2ba35b9a34f68 \ - --hash=sha256:da08224ab8675c6d464b988bd8ca02cccd2bf0275bceefe8f6219bfd4a4f5e85 \ - --hash=sha256:dffa326cf901fe08a0e218d9fdf593f12276088a8caa07fcbec7d051149cf9ef \ - --hash=sha256:e529cd3d4109a6f4a3f7bdaca68946eb33734e2d7ffe861785a0586abe99ee67 \ - --hash=sha256:eba5fafd70585fbd4cb6ae45e3c5e11d8598e2426c9f289b78f682c0606e81cb \ - --hash=sha256:f95bdc6c7c50b7fc442e53537bc5b4eb8cab2a671c1da80d40b5a4ab1fd5d416 +grpcio-tools==1.62.0 \ + --hash=sha256:006ea0cc16e8bf8f307326e0556e1384f24abb402cc4e6a720aa1dfe8f268647 \ + --hash=sha256:0d9c9a4832f52c4597d6dc12d9ab3109c3bd0ee1686b8bf6d64f9eab4145e3cb \ + --hash=sha256:0e87f105f1d152934759f8975ed002d5ce057b3cdf1cc6cb63fe6008671a27b9 \ + --hash=sha256:14201950513636f515dd455a06890e3a21d115b943cf6a8f5af67ad1413cfa1f \ + --hash=sha256:17c16e9a89c0b9f4ff2b143f232c5256383453ce7b55fe981598f9517adc8252 \ + --hash=sha256:1927934dfba4658a97c2dab267e53ed239264d40fdd5b295fc317693543db85b \ + --hash=sha256:19b74e141937c885c9e56b6a7dfa190ca7d583bd48bce9171dd65bbf108b9271 \ + --hash=sha256:1faa5006fe9e7b9e65c47bc23f7cd333fdcdd4ba35d44080303848266db5ab05 \ + --hash=sha256:2e1fd7301d762bf5984b7e7fb62fce82cff864d75f0a57e15cfd07ae1bd79133 \ + --hash=sha256:2f5bd22203e64e1732e149bfdd3083716d038abca294e4e2852159b3d893f9ec \ + --hash=sha256:3730b1cd998a0cffc817602cc55e51f268fa97b3e38fa4bee578e3741474547a \ + --hash=sha256:3b526dc5566161a3a17599753838b9cfbdd4cb15b6ad419aae8a5d12053fa8ae \ + --hash=sha256:3bbe79b134dfb7c98cf60e4962e31039bef824834cc7034bdf1886a2ed1097f9 \ + --hash=sha256:3dee3be61d9032f777a9b4e2696ea3d0748a582cb99c672b5d41ca66821e8c87 \ + --hash=sha256:465c51ebaa184ee3bb619cd5bfaf562bbdde166f2822a6935461e6a741f5ac19 \ + --hash=sha256:523adf731fa4c5af0bf7ee2edb65e8c7ef4d9df9951461d6a18fe096688efd2d \ + --hash=sha256:52b216c458458f6c292e12428916e80974c5113abc505a61e7b0b9f8932a785d \ + --hash=sha256:54bb570bd963905de3bda596b35e06026552705edebbb2cb737b57aa5252b9e5 \ + --hash=sha256:563a75924109e75809b2919e68d7e6ae7872e63d20258aae7899b14f6ff9e18b \ + --hash=sha256:5a482d9625209023481e631c29a6df1392bfc49f9accfa880dabbacff642559a \ + --hash=sha256:5dacc691b18d2c294ea971720ff980a1e2d68a3f7ddcd2f0670b3204e81c4b18 \ + --hash=sha256:5eb63d9207b02a0fa30216907e1e7705cc2670f933e77236c6e0eb966ad3b4bf \ + --hash=sha256:5f8934715577c9cc0c792b8a77f7d0dd2bb60e951161b10c5f46b60856673240 \ + --hash=sha256:679cf2507090e010da73e5001665c76de2a5927b2e2110e459222b1c81cb10c2 \ + --hash=sha256:6999a4e705b03aacad46e625feb7610e47ec88dbd51220c2282b6334f90721fc \ + --hash=sha256:6b900ae319b6f9ac1be0ca572dfb41c23a7ff6fcbf36e3be6d3054e1e4c60de6 \ + --hash=sha256:711314cb4c6c8b3d51bafaee380ffa5012bd0567ed68f1b0b1fc07492b27acab \ + --hash=sha256:74196beed18383d53ff3e2412a6c1eefa3ff109e987be240368496bc3dcabc8b \ + --hash=sha256:75aca28cbeb605c59b5689a7e000fbc2bd659d2f322c58461f3912f00069f6da \ + --hash=sha256:77196c7ac8741d4a2aebb023bcc2964ac65ca44180fd791640889ab2afed3e47 \ + --hash=sha256:791aa220f8f1936e65bc079e9eb954fa0202a1f16e28b83956e59d17dface127 \ + --hash=sha256:7fca6ecfbbf0549058bb29dcc6e435d885b878d07701e77ac58e1e1f591736dc \ + --hash=sha256:84e27206bd884be83a7fdcef8be3c90eb1591341c0ba9b0d25ec9db1043ba2f2 \ + --hash=sha256:88aa62303278aec45bbb26bf679269c7890346c37140ae30e39da1070c341e11 \ + --hash=sha256:95e49839d49e79187c43cd63af5c206dc5743a01d7d3d2f039772fa743cbb30c \ + --hash=sha256:98ddf871c614cc0ed331c7159ebbbf5040be562279677d3bb97c2e6083539f72 \ + --hash=sha256:9ae5cd2f89e33a529790bf8aa59a459484edb05e4f58d4cf78836b9dfa1fab43 \ + --hash=sha256:a09db3688efd3499ce3c0b02c0bac0656abdab4cb99716f81ad879c08b92c56e \ + --hash=sha256:b46ba0b6552b4375ede65e0c89491af532635347f78d52a72f8a027529e713ed \ + --hash=sha256:b65288ebe12e38dd3650fea65d82fcce0d35df1ae4a770b525c10119ee71962f \ + --hash=sha256:bb6802d63e42734d2baf02e1343377fe18590ed6a1f5ffbdebbbe0f8331f176b \ + --hash=sha256:bf9f281f528e0220558d57e09b4518dec148dcb250d78bd9cbb27e09edabb3f9 \ + --hash=sha256:c85391e06620d6e16a56341caae5007d0c6219beba065e1e288f2523fba6a335 \ + --hash=sha256:cd1f4caeca614b04db803566473f7db0971e7a88268f95e4a529b0ace699b949 \ + --hash=sha256:d5652d3a52a2e8e1d9bdf28fbd15e21b166e31b968cd7c8c604bf31611c0bb5b \ + --hash=sha256:d5959e3df126931d28cd94dd5f0a708b7dd96019de80ab715fb922fd0c8a838d \ + --hash=sha256:dce5f04676cf94e6e2d13d7f91ac2de79097d86675bc4d404a3c24dcc0332c88 \ + --hash=sha256:e38d5800151e6804d500e329f7ddfb615c50eee0c1607593e3147a4b21037e40 \ + --hash=sha256:ec6f561c86fe13cff3be16f297cc05e1aa1274294524743a4cf91d971866fbb0 \ + --hash=sha256:ed6cf7ff4a10c46f85340f9c68982f9efb29f51ee4b66828310fcdf3c2d7ffd1 \ + --hash=sha256:f0884eaf6a2bbd7b03fea456e808909ee48dd4f7f455519d67defda791116368 \ + --hash=sha256:f3aaf3b20c0f7063856b2432335af8f76cf580f898e04085548cde28332d6833 \ + --hash=sha256:f54b5181784464bd3573ae7dbcf053da18a4b7a75fe19960791f383be3d035ca \ + --hash=sha256:f74e0053360e0eadd75193c0c379b6d7f51d074ebbff856bd41780e1a028b38d # via -r requirements.in idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -protobuf==4.25.2 \ - --hash=sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62 \ - --hash=sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d \ - --hash=sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61 \ - --hash=sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62 \ - --hash=sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3 \ - --hash=sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9 \ - --hash=sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830 \ - --hash=sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6 \ - --hash=sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0 \ - --hash=sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020 \ - --hash=sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e +protobuf==4.25.3 \ + --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ + --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ + --hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \ + --hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \ + --hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \ + --hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \ + --hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \ + --hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \ + --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ + --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ + --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 # via # -r requirements.in # grpcio-tools diff --git a/examples/grpc-bridge/server/go.mod b/examples/grpc-bridge/server/go.mod index 5cfddbe8f873..623db6c0619b 100644 --- a/examples/grpc-bridge/server/go.mod +++ b/examples/grpc-bridge/server/go.mod @@ -5,5 +5,5 @@ go 1.13 require ( github.com/golang/protobuf v1.5.3 golang.org/x/net v0.21.0 - google.golang.org/grpc v1.61.0 + google.golang.org/grpc v1.62.0 ) diff --git a/examples/grpc-bridge/server/go.sum b/examples/grpc-bridge/server/go.sum index 15e85741a9aa..885828afce3c 100644 --- a/examples/grpc-bridge/server/go.sum +++ b/examples/grpc-bridge/server/go.sum @@ -43,6 +43,8 @@ cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5x 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/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= @@ -72,6 +74,9 @@ cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP 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/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= @@ -82,6 +87,7 @@ cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N 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/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= @@ -149,6 +155,8 @@ cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+ok 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/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= @@ -185,6 +193,7 @@ cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mu 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/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= @@ -212,6 +221,7 @@ cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6Pm 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/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= @@ -224,6 +234,7 @@ cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlp 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/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= @@ -234,6 +245,7 @@ cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJx 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/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= @@ -250,6 +262,7 @@ cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Ii 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/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= @@ -261,6 +274,7 @@ cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2 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/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= @@ -315,6 +329,8 @@ cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJ 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/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= @@ -326,6 +342,8 @@ cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBS 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/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= @@ -351,6 +369,8 @@ cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/U 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/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= @@ -391,6 +411,9 @@ cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MP 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/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= @@ -399,6 +422,7 @@ cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LV 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/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= @@ -435,6 +459,9 @@ cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCN 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/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= @@ -450,6 +477,9 @@ cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+ 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/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= @@ -470,6 +500,8 @@ cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJx 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/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= @@ -510,6 +542,7 @@ cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp 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/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= @@ -563,6 +596,7 @@ cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZVi 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/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/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= @@ -647,6 +681,7 @@ cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqN 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= @@ -671,6 +706,8 @@ cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9v 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/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= @@ -707,6 +744,7 @@ cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67m 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/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= @@ -769,6 +807,7 @@ cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK 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/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= @@ -789,6 +828,7 @@ cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3 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/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= @@ -824,6 +864,7 @@ cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9 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/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= @@ -841,6 +882,8 @@ cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3X 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/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= @@ -858,6 +901,7 @@ cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlk 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/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= @@ -911,6 +955,7 @@ cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhO 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/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= @@ -940,6 +985,7 @@ cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY 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/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= @@ -978,6 +1024,10 @@ cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSq 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/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= @@ -989,6 +1039,7 @@ cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ 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/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= @@ -1001,6 +1052,7 @@ cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi 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/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= @@ -1051,6 +1103,7 @@ cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNW 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/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= @@ -1148,6 +1201,7 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd 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/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -1176,7 +1230,7 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH 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/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= @@ -1196,6 +1250,7 @@ github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJ 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= @@ -1203,6 +1258,8 @@ github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6Ni 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/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= @@ -1216,6 +1273,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 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/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/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -1224,6 +1285,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU 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= @@ -1280,6 +1342,7 @@ 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= @@ -1309,6 +1372,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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= @@ -1337,11 +1402,14 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 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/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/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= @@ -1355,6 +1423,7 @@ 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= @@ -1369,6 +1438,8 @@ github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4 github.com/mattn/go-sqlite3 v1.14.15/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/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= @@ -1383,6 +1454,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: 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= @@ -1395,10 +1467,12 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO 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/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= @@ -1408,6 +1482,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO 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/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= @@ -1425,9 +1500,20 @@ 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/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +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/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/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/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/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= @@ -1438,6 +1524,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm 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= @@ -1447,6 +1534,9 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y 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/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= @@ -1507,6 +1597,7 @@ 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/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= @@ -1570,9 +1661,12 @@ 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 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1608,7 +1702,8 @@ 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/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= @@ -1629,6 +1724,7 @@ 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/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= @@ -1714,6 +1810,8 @@ 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 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1732,6 +1830,8 @@ 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/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= @@ -1761,6 +1861,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb 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= @@ -1825,6 +1926,7 @@ 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/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= @@ -1833,6 +1935,7 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T 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= @@ -1906,6 +2009,8 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy 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/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= @@ -2064,8 +2169,14 @@ google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqv 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 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= 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 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= 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= @@ -2083,9 +2194,16 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go. 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-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= 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/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= @@ -2102,8 +2220,14 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go. 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 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= 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-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= 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= @@ -2152,8 +2276,10 @@ google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt 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.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +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.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= @@ -2172,8 +2298,9 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw 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 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.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= diff --git a/examples/jaeger-native-tracing/README.md b/examples/jaeger-native-tracing/README.md deleted file mode 100644 index e21ecf00ca08..000000000000 --- a/examples/jaeger-native-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_native_tracing) diff --git a/examples/jaeger-native-tracing/docker-compose.yaml b/examples/jaeger-native-tracing/docker-compose.yaml deleted file mode 100644 index 4279e0339ed7..000000000000 --- a/examples/jaeger-native-tracing/docker-compose.yaml +++ /dev/null @@ -1,44 +0,0 @@ -services: - - # jaeger - front-envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-jaeger-native - 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-jaeger-service - volumes: - - ./service1-envoy-jaeger.yaml:/etc/service-envoy.yaml - environment: - - SERVICE_NAME=1 - - service2: - build: - context: ../shared/python - target: aiohttp-jaeger-service - 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-native-tracing/envoy.yaml b/examples/jaeger-native-tracing/envoy.yaml deleted file mode 100644 index 3ee3d6944ebe..000000000000 --- a/examples/jaeger-native-tracing/envoy.yaml +++ /dev/null @@ -1,69 +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.dynamic_ot - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.DynamicOtConfig - library: /usr/local/lib/libjaegertracing_plugin.so - config: - service_name: front-proxy - sampler: - type: const - param: 1 - reporter: - localAgentHostPort: jaeger:6831 - headers: - jaegerDebugHeader: jaeger-debug-id - jaegerBaggageHeader: jaeger-baggage - traceBaggageHeaderPrefix: uberctx- - baggage_restrictions: - denyBaggageOnInitializationFailure: false - hostPort: "" - 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 diff --git a/examples/jaeger-native-tracing/install-jaeger-plugin.sh b/examples/jaeger-native-tracing/install-jaeger-plugin.sh deleted file mode 100755 index 74576be5247e..000000000000 --- a/examples/jaeger-native-tracing/install-jaeger-plugin.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -JAEGER_VERSION=v0.4.2 -curl -Lo /usr/local/lib/libjaegertracing_plugin.so https://github.com/jaegertracing/jaeger-client-cpp/releases/download/$JAEGER_VERSION/libjaegertracing_plugin.linux_amd64.so diff --git a/examples/jaeger-native-tracing/service1-envoy-jaeger.yaml b/examples/jaeger-native-tracing/service1-envoy-jaeger.yaml deleted file mode 100644 index 2c619d649849..000000000000 --- a/examples/jaeger-native-tracing/service1-envoy-jaeger.yaml +++ /dev/null @@ -1,105 +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 - 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.dynamic_ot - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.DynamicOtConfig - library: /usr/local/lib/libjaegertracing_plugin.so - config: - service_name: service1 - sampler: - type: const - param: 1 - reporter: - localAgentHostPort: jaeger:6831 - headers: - jaegerDebugHeader: jaeger-debug-id - jaegerBaggageHeader: jaeger-baggage - traceBaggageHeaderPrefix: uberctx- - baggage_restrictions: - denyBaggageOnInitializationFailure: false - hostPort: "" - 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 diff --git a/examples/jaeger-native-tracing/service2-envoy-jaeger.yaml b/examples/jaeger-native-tracing/service2-envoy-jaeger.yaml deleted file mode 100644 index d0640d85e558..000000000000 --- a/examples/jaeger-native-tracing/service2-envoy-jaeger.yaml +++ /dev/null @@ -1,64 +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.dynamic_ot - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.DynamicOtConfig - library: /usr/local/lib/libjaegertracing_plugin.so - config: - service_name: service2 - sampler: - type: const - param: 1 - reporter: - localAgentHostPort: jaeger:6831 - headers: - jaegerDebugHeader: jaeger-debug-id - jaegerBaggageHeader: jaeger-baggage - traceBaggageHeaderPrefix: uberctx- - baggage_restrictions: - denyBaggageOnInitializationFailure: false - hostPort: "" - 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 diff --git a/examples/jaeger-native-tracing/verify.sh b/examples/jaeger-native-tracing/verify.sh deleted file mode 100755 index 85f4e59e6946..000000000000 --- a/examples/jaeger-native-tracing/verify.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -e - -export NAME=jaeger-native -export PORT_PROXY="${JAEGER_NATIVE_PORT_PROXY:-11000}" -export PORT_UI="${JAEGER_NATIVE_PORT_UI:-11001}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -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 index c44ea13f7391..7fbafda86e9b 100644 --- a/examples/kafka/Dockerfile-kafka +++ b/examples/kafka/Dockerfile-kafka @@ -1 +1 @@ -FROM confluentinc/cp-kafka:latest@sha256:7e332fd046a1b3ef292dcd063d6e7bee4f487ac4d235da1692b15a44daf2c080 +FROM confluentinc/cp-kafka:latest@sha256:24cdd3a7fa89d2bed150560ebea81ff1943badfa61e51d66bb541a6b0d7fb047 diff --git a/examples/kafka/Dockerfile-zookeeper b/examples/kafka/Dockerfile-zookeeper index 9fa15d8028ea..924109d54c93 100644 --- a/examples/kafka/Dockerfile-zookeeper +++ b/examples/kafka/Dockerfile-zookeeper @@ -1 +1 @@ -FROM confluentinc/cp-zookeeper:latest@sha256:0140b9767dc900af6c4a1a0d0cf0d16548152e924f2939a038d8ca8793f69b86 +FROM confluentinc/cp-zookeeper:latest@sha256:9babd1c0beaf93189982bdbb9fe4bf194a2730298b640c057817746c19838866 diff --git a/examples/load-reporting-service/go.mod b/examples/load-reporting-service/go.mod index 72b460b37f3d..fbfbccbb74e0 100644 --- a/examples/load-reporting-service/go.mod +++ b/examples/load-reporting-service/go.mod @@ -5,5 +5,5 @@ go 1.13 require ( github.com/envoyproxy/go-control-plane v0.12.0 github.com/golang/protobuf v1.5.3 - google.golang.org/grpc v1.61.0 + google.golang.org/grpc v1.62.0 ) diff --git a/examples/load-reporting-service/go.sum b/examples/load-reporting-service/go.sum index 52de68a07117..513e0ac97039 100644 --- a/examples/load-reporting-service/go.sum +++ b/examples/load-reporting-service/go.sum @@ -43,6 +43,8 @@ cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5x 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/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= @@ -72,6 +74,9 @@ cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP 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/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= @@ -82,6 +87,7 @@ cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N 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/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= @@ -149,6 +155,8 @@ cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+ok 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/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= @@ -185,6 +193,7 @@ cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mu 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/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= @@ -212,6 +221,7 @@ cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6Pm 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/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= @@ -224,6 +234,7 @@ cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlp 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/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= @@ -234,6 +245,7 @@ cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJx 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/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= @@ -250,6 +262,7 @@ cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Ii 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/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= @@ -261,6 +274,7 @@ cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2 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/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= @@ -315,6 +329,8 @@ cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJ 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/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= @@ -326,6 +342,8 @@ cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBS 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/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= @@ -351,6 +369,8 @@ cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/U 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/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= @@ -391,6 +411,9 @@ cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MP 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/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= @@ -399,6 +422,7 @@ cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LV 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/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= @@ -435,6 +459,9 @@ cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCN 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/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= @@ -450,6 +477,9 @@ cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+ 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/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= @@ -470,6 +500,8 @@ cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJx 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/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= @@ -510,6 +542,7 @@ cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp 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/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= @@ -563,6 +596,7 @@ cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZVi 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/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/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= @@ -647,6 +681,7 @@ cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqN 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= @@ -671,6 +706,8 @@ cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9v 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/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= @@ -707,6 +744,7 @@ cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67m 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/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= @@ -769,6 +807,7 @@ cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK 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/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= @@ -789,6 +828,7 @@ cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3 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/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= @@ -824,6 +864,7 @@ cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9 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/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= @@ -841,6 +882,8 @@ cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3X 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/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= @@ -858,6 +901,7 @@ cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlk 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/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= @@ -911,6 +955,7 @@ cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhO 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/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= @@ -940,6 +985,7 @@ cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY 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/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= @@ -978,6 +1024,10 @@ cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSq 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/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= @@ -989,6 +1039,7 @@ cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ 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/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= @@ -1001,6 +1052,7 @@ cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi 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/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= @@ -1051,6 +1103,7 @@ cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNW 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/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= @@ -1148,6 +1201,7 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd 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/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -1176,8 +1230,8 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH 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 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= -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 h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= 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= @@ -1205,8 +1259,10 @@ github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0+ 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 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +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/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= @@ -1220,6 +1276,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 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/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/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -1228,6 +1288,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU 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= @@ -1284,6 +1345,7 @@ 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= @@ -1313,6 +1375,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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= @@ -1345,8 +1409,10 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9K 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/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/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= @@ -1375,6 +1441,8 @@ github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4 github.com/mattn/go-sqlite3 v1.14.15/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/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= @@ -1402,10 +1470,12 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO 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/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= @@ -1433,6 +1503,16 @@ 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/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +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/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/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/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/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= @@ -1447,6 +1527,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm 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= @@ -1456,6 +1537,9 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y 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/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= @@ -1515,6 +1599,7 @@ 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/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= @@ -1578,10 +1663,13 @@ 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 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= 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 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 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= @@ -1615,7 +1703,8 @@ 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/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= @@ -1636,6 +1725,7 @@ 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/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= @@ -1720,8 +1810,10 @@ 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 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= 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 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= @@ -1738,6 +1830,8 @@ 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/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= @@ -1766,6 +1860,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb 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= @@ -1830,6 +1925,7 @@ 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/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= @@ -1838,6 +1934,7 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T 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= @@ -1911,6 +2008,8 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy 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/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= @@ -2069,8 +2168,14 @@ google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqv 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 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= 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 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= 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= @@ -2088,9 +2193,16 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go. 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-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= 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/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= @@ -2107,8 +2219,14 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go. 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 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= 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-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= 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= @@ -2157,8 +2275,10 @@ google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt 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.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +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.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= diff --git a/examples/local_ratelimit/Dockerfile-nginx b/examples/local_ratelimit/Dockerfile-nginx index 7e7488a884ad..eff6acc5fa7d 100644 --- a/examples/local_ratelimit/Dockerfile-nginx +++ b/examples/local_ratelimit/Dockerfile-nginx @@ -1 +1 @@ -FROM nginx@sha256:84c52dfd55c467e12ef85cad6a252c0990564f03c4850799bf41dd738738691f +FROM nginx@sha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107 diff --git a/examples/mysql/Dockerfile-mysql b/examples/mysql/Dockerfile-mysql index 46078228d2a4..d6ad147ea99b 100644 --- a/examples/mysql/Dockerfile-mysql +++ b/examples/mysql/Dockerfile-mysql @@ -1 +1 @@ -FROM mysql:8.3.0@sha256:2a9ef1075ff30c65bbcf4f96b25a03ea3b3f492c284e6c4a612c269ce4c5bb19 +FROM mysql:8.3.0@sha256:ff5ab9cdce0b4c59704b4e2a09deed5ab8467be795e0ea20228b8528f53fcf82 diff --git a/examples/opentelemetry/Dockerfile-opentelemetry b/examples/opentelemetry/Dockerfile-opentelemetry index 63df37f24b0e..e1ae65ffa24b 100644 --- a/examples/opentelemetry/Dockerfile-opentelemetry +++ b/examples/opentelemetry/Dockerfile-opentelemetry @@ -1,7 +1,7 @@ FROM alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b as otelc_curl RUN apk --update add curl -FROM otel/opentelemetry-collector:latest@sha256:4cead03c35116d31cbf46bccb4952fbcd70d0eb8ae4f6fcfa699ebf2e8ed3f54 +FROM otel/opentelemetry-collector:latest@sha256:246dfe93f68e489a81f17b0335ca1c8e6f37bf69eb66aa9ba3375cc1743064b6 COPY --from=otelc_curl / / diff --git a/examples/redis/Dockerfile-redis b/examples/redis/Dockerfile-redis index a132586d6f90..c0098b611cf2 100644 --- a/examples/redis/Dockerfile-redis +++ b/examples/redis/Dockerfile-redis @@ -1 +1 @@ -FROM redis@sha256:11c3e418c29672341be9a8e3015d96f05b88e5ad58829885d36f8342b4da13c2 +FROM redis@sha256:e647cfe134bf5e8e74e620f66346f93418acfc240b71dd85640325cb7cd01402 diff --git a/examples/shared/golang/Dockerfile b/examples/shared/golang/Dockerfile index fb3547febddf..5a940c392906 100644 --- a/examples/shared/golang/Dockerfile +++ b/examples/shared/golang/Dockerfile @@ -3,7 +3,7 @@ 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.0-bookworm@sha256:874c2677e43be36a429823f2742af85844772664f273c1c8c8235f10aba51cd3 as golang-base +FROM golang:1.22.0-bookworm@sha256:925fe3fa28ba428cf67a7947ae838f8a1523117b40e3e6b5106c378e3f97fa29 as golang-base FROM golang-base as golang-control-plane-builder diff --git a/examples/shared/node/Dockerfile b/examples/shared/node/Dockerfile index fbd63382cd9a..80cd4cb18cad 100644 --- a/examples/shared/node/Dockerfile +++ b/examples/shared/node/Dockerfile @@ -1,4 +1,4 @@ -FROM node:21.6-bookworm-slim@sha256:f2eadc7a5287fc42ca6c4e9177b8120ec4321c9f2d75506210b948857a22b825 as node-base +FROM node:21.6-bookworm-slim@sha256:2254c337b6f7a239620b3876f8d941c65b7834fb38cdf137decc6191a73502bf as node-base FROM node-base as node-http-auth diff --git a/examples/shared/postgres/Dockerfile b/examples/shared/postgres/Dockerfile index 0d01aa6f10ba..eb29c21895f4 100644 --- a/examples/shared/postgres/Dockerfile +++ b/examples/shared/postgres/Dockerfile @@ -1,3 +1,3 @@ -FROM postgres:latest@sha256:2881f973a604ea35d149c129fb98a676945d00ea7cb281ef1ee7ab2d9e22b309 +FROM postgres:latest@sha256:f58300ac8d393b2e3b09d36ea12d7d24ee9440440e421472a300e929ddb63460 COPY docker-healthcheck.sh /usr/local/bin/ HEALTHCHECK CMD ["docker-healthcheck.sh"] diff --git a/examples/skywalking/Dockerfile-elasticsearch b/examples/skywalking/Dockerfile-elasticsearch index 302ff21a4a47..ffd138dc89e8 100644 --- a/examples/skywalking/Dockerfile-elasticsearch +++ b/examples/skywalking/Dockerfile-elasticsearch @@ -1 +1 @@ -FROM elasticsearch:8.12.1@sha256:8c18a68f086b0935c56a7d6fb02e602fc0e2265a31668c6679c7d159a302b1c1 +FROM elasticsearch:8.12.2@sha256:b0dfebb1bf16b89b3cbde7f9197f13b5dd3402595a3dccb0163aa33a042a1541 diff --git a/examples/zipkin/Dockerfile-zipkin b/examples/zipkin/Dockerfile-zipkin index a38690c9abd6..08d46c836de9 100644 --- a/examples/zipkin/Dockerfile-zipkin +++ b/examples/zipkin/Dockerfile-zipkin @@ -1 +1 @@ -FROM openzipkin/zipkin:latest@sha256:bb7f0ddd2aeaace94f3d4e4d370fffe5dbf959ce49522eb5458cac295f808139 +FROM openzipkin/zipkin:latest@sha256:8a2d619189caab1b9d4cede5da177fa88fd383c333dff7c56708effe6822fa60 diff --git a/mobile/.bazelrc b/mobile/.bazelrc index 85c2bb3e2b27..0fc992ca2e46 100644 --- a/mobile/.bazelrc +++ b/mobile/.bazelrc @@ -193,6 +193,8 @@ build:mobile-remote-ci-linux --config=mobile-remote-ci-common build:mobile-remote-ci-linux-clang --action_env=CC=/opt/llvm/bin/clang build:mobile-remote-ci-linux-clang --action_env=CXX=/opt/llvm/bin/clang++ build:mobile-remote-ci-linux-clang --config=mobile-remote-ci-linux +# Temporary revert to C++17 for mobile NDK builds. +build:mobile-remote-ci-linux-clang --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 ############################################################################# # mobile-remote-ci-linux-asan: These options are Linux-only using Clang and AddressSanitizer diff --git a/mobile/ci/mac_ci_setup.sh b/mobile/ci/mac_ci_setup.sh index f01a7ba449f1..eb0fb8ad7a69 100755 --- a/mobile/ci/mac_ci_setup.sh +++ b/mobile/ci/mac_ci_setup.sh @@ -56,15 +56,6 @@ sudo xcode-select --switch /Applications/Xcode_14.1.app retry ./bazelw version -if [[ "${1:-}" == "--android" ]]; then - # Download and set up ndk 21 after GitHub update - # https://github.com/actions/virtual-environments/issues/5595 - ANDROID_HOME=$ANDROID_SDK_ROOT - SDKMANAGER="${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager" - "${SDKMANAGER}" --install "platform-tools" "platforms;android-30" - "${SDKMANAGER}" --uninstall "ndk-bundle" - "${SDKMANAGER}" --install "ndk;21.4.7075529" - "${SDKMANAGER}" --install "build-tools;30.0.2" - ANDROID_NDK_HOME="${ANDROID_HOME}/ndk/21.4.7075529" - export ANDROID_NDK_HOME -fi +# Unset default variables so we don't have to install Android SDK/NDK. +unset ANDROID_HOME +unset ANDROID_NDK_HOME diff --git a/mobile/examples/swift/hello_world/ViewController.swift b/mobile/examples/swift/hello_world/ViewController.swift index 40445047ddc4..30c9e447ef5e 100644 --- a/mobile/examples/swift/hello_world/ViewController.swift +++ b/mobile/examples/swift/hello_world/ViewController.swift @@ -22,6 +22,7 @@ final class ViewController: UITableViewController { .addPlatformFilter(DemoFilter.init) .addPlatformFilter(BufferDemoFilter.init) .addPlatformFilter(AsyncDemoFilter.init) + .respectSystemProxySettings(true) .addNativeFilter( name: "envoy.filters.http.buffer", typedConfig: """ diff --git a/mobile/library/cc/BUILD b/mobile/library/cc/BUILD index 96f01b436fcd..516f8c372a5e 100644 --- a/mobile/library/cc/BUILD +++ b/mobile/library/cc/BUILD @@ -47,7 +47,12 @@ envoy_cc_library( "@envoy_mobile//library/common/extensions/filters/http/network_configuration:filter_cc_proto", "@envoy_mobile//library/common/extensions/filters/http/socket_tag:filter_cc_proto", "@envoy_mobile//library/common/types:matcher_data_lib", - ], + ] + select({ + "@envoy//bazel:apple": [ + "@envoy_mobile//library/common/network:apple_proxy_resolution_lib", + ], + "//conditions:default": [], + }), ) envoy_cc_library( diff --git a/mobile/library/cc/engine_builder.cc b/mobile/library/cc/engine_builder.cc index 9406fc2b9cc3..c3437d435584 100644 --- a/mobile/library/cc/engine_builder.cc +++ b/mobile/library/cc/engine_builder.cc @@ -35,6 +35,10 @@ #include "library/common/extensions/filters/http/socket_tag/filter.pb.h" #include "library/common/extensions/key_value/platform/platform.pb.h" +#if defined(__APPLE__) +#include "library/common/network/apple_proxy_resolution.h" +#endif + namespace Envoy { namespace Platform { @@ -374,6 +378,13 @@ EngineBuilder& EngineBuilder::setRuntimeGuard(std::string guard, bool value) { return *this; } +#if defined(__APPLE__) +EngineBuilder& EngineBuilder::respectSystemProxySettings(bool value) { + respect_system_proxy_settings_ = value; + return *this; +} +#endif + std::unique_ptr EngineBuilder::generateBootstrap() const { // The yaml utilities have non-relevant thread asserts. Thread::SkipAsserts skip; @@ -802,6 +813,8 @@ std::unique_ptr EngineBuilder::generate list->add_patterns()->mutable_safe_regex()->set_regex( "^vhost\\.[\\w]+\\.vcluster\\.[\\w]+?\\.upstream_rq_(?:[12345]xx|[3-5][0-9][0-9]|retry|" "total)"); + list->add_patterns()->set_contains("quic_connection_close_error_code"); + list->add_patterns()->set_contains("quic_reset_stream_error_code"); bootstrap->mutable_stats_config()->mutable_use_all_default_tags()->set_value(false); // Set up watchdog @@ -834,12 +847,20 @@ std::unique_ptr EngineBuilder::generate ProtobufWkt::Struct envoy_layer; ProtobufWkt::Struct& runtime_values = *(*envoy_layer.mutable_fields())["envoy"].mutable_struct_value(); - ProtobufWkt::Struct& flags = + ProtobufWkt::Struct& reloadable_features = *(*runtime_values.mutable_fields())["reloadable_features"].mutable_struct_value(); for (auto& guard_and_value : runtime_guards_) { - (*flags.mutable_fields())[guard_and_value.first].set_bool_value(guard_and_value.second); + (*reloadable_features.mutable_fields())[guard_and_value.first].set_bool_value( + guard_and_value.second); } - (*flags.mutable_fields())["always_use_v6"].set_bool_value(always_use_v6_); + (*reloadable_features.mutable_fields())["always_use_v6"].set_bool_value(always_use_v6_); + ProtobufWkt::Struct& restart_features = + *(*runtime_values.mutable_fields())["restart_features"].mutable_struct_value(); + // TODO(abeyad): This runtime flag is set because https://github.com/envoyproxy/envoy/pull/32370 + // needed to be merged with the default off due to unresolved test issues. Once those are fixed, + // and the default for `allow_client_socket_creation_failure` is true, we can remove this. + (*restart_features.mutable_fields())["allow_client_socket_creation_failure"].set_bool_value(true); + (*runtime_values.mutable_fields())["disallow_global_stats"].set_bool_value(true); ProtobufWkt::Struct& overload_values = *(*envoy_layer.mutable_fields())["overload"].mutable_struct_value(); @@ -894,6 +915,12 @@ EngineSharedPtr EngineBuilder::build() { } } +#if defined(__APPLE__) + if (respect_system_proxy_settings_) { + registerAppleProxyResolver(); + } +#endif + Engine* engine = new Engine(envoy_engine); auto options = std::make_unique(); diff --git a/mobile/library/cc/engine_builder.h b/mobile/library/cc/engine_builder.h index 8db9dc45f0f2..8a77b8d9ad5e 100644 --- a/mobile/library/cc/engine_builder.h +++ b/mobile/library/cc/engine_builder.h @@ -190,6 +190,14 @@ class EngineBuilder { EngineBuilder& addKeyValueStore(std::string name, KeyValueStoreSharedPtr key_value_store); EngineBuilder& addStringAccessor(std::string name, StringAccessorSharedPtr accessor); +#if defined(__APPLE__) + // Right now, this API is only used by Apple (iOS) to register the Apple proxy resolver API for + // use in reading and using the system proxy settings. + // If/when we move Android system proxy registration to the C++ Engine Builder, we will make this + // API available on all platforms. + EngineBuilder& respectSystemProxySettings(bool value); +#endif + // This is separated from build() for the sake of testability virtual std::unique_ptr generateBootstrap() const; @@ -242,6 +250,10 @@ class EngineBuilder { std::vector quic_suffixes_; bool enable_port_migration_ = false; bool always_use_v6_ = false; +#if defined(__APPLE__) + // TODO(abeyad): once stable, consider setting the default to true. + bool respect_system_proxy_settings_ = false; +#endif int dns_min_refresh_seconds_ = 60; int max_connections_per_host_ = 7; diff --git a/mobile/library/cc/stream_callbacks.cc b/mobile/library/cc/stream_callbacks.cc index 31caeafa5a57..1de7f20a39c9 100644 --- a/mobile/library/cc/stream_callbacks.cc +++ b/mobile/library/cc/stream_callbacks.cc @@ -10,8 +10,7 @@ namespace Platform { namespace { -void* c_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel intel, - void* context) { +void c_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel intel, void* context) { auto stream_callbacks = *static_cast(context); if (stream_callbacks->on_headers.has_value()) { auto raw_headers = envoyHeadersAsRawHeaderMap(headers); @@ -27,10 +26,9 @@ void* c_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel in } else { release_envoy_headers(headers); } - return context; } -void* c_on_data(envoy_data data, bool end_stream, envoy_stream_intel, void* context) { +void c_on_data(envoy_data data, bool end_stream, envoy_stream_intel, void* context) { auto stream_callbacks = *static_cast(context); if (stream_callbacks->on_data.has_value()) { auto on_data = stream_callbacks->on_data.value(); @@ -38,10 +36,9 @@ void* c_on_data(envoy_data data, bool end_stream, envoy_stream_intel, void* cont } else { release_envoy_data(data); } - return context; } -void* c_on_trailers(envoy_headers metadata, envoy_stream_intel intel, void* context) { +void c_on_trailers(envoy_headers metadata, envoy_stream_intel intel, void* context) { auto stream_callbacks = *static_cast(context); if (stream_callbacks->on_trailers.has_value()) { auto raw_headers = envoyHeadersAsRawHeaderMap(metadata); @@ -54,11 +51,10 @@ void* c_on_trailers(envoy_headers metadata, envoy_stream_intel intel, void* cont } else { release_envoy_headers(metadata); } - return context; } -void* c_on_error(envoy_error raw_error, envoy_stream_intel intel, - envoy_final_stream_intel final_intel, void* context) { +void c_on_error(envoy_error raw_error, envoy_stream_intel intel, + envoy_final_stream_intel final_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_error.has_value()) { @@ -71,10 +67,9 @@ void* c_on_error(envoy_error raw_error, envoy_stream_intel intel, } release_envoy_error(raw_error); delete stream_callbacks_ptr; - return nullptr; } -void* c_on_complete(envoy_stream_intel intel, envoy_final_stream_intel final_intel, void* context) { +void c_on_complete(envoy_stream_intel intel, envoy_final_stream_intel final_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_complete.has_value()) { @@ -82,10 +77,9 @@ void* c_on_complete(envoy_stream_intel intel, envoy_final_stream_intel final_int on_complete(intel, final_intel); } delete stream_callbacks_ptr; - return nullptr; } -void* c_on_cancel(envoy_stream_intel intel, envoy_final_stream_intel final_intel, void* context) { +void c_on_cancel(envoy_stream_intel intel, envoy_final_stream_intel final_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_cancel.has_value()) { @@ -93,17 +87,15 @@ void* c_on_cancel(envoy_stream_intel intel, envoy_final_stream_intel final_intel on_cancel(intel, final_intel); } delete stream_callbacks_ptr; - return nullptr; } -void* c_on_send_window_available(envoy_stream_intel intel, void* context) { +void c_on_send_window_available(envoy_stream_intel intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_send_window_available.has_value()) { auto on_send_window_available = stream_callbacks->on_send_window_available.value(); on_send_window_available(intel); } - return nullptr; } } // namespace @@ -118,6 +110,15 @@ envoy_http_callbacks StreamCallbacks::asEnvoyHttpCallbacks() { &c_on_complete, &c_on_cancel, &c_on_send_window_available, + // Each of the function pointers in the returned `envoy_http_callbacks` struct have a + // `void* context` parameter. The value of the `context` field of this struct is passed in as + // the value of that parameter. Because this context passes through JNI, the context field + // can not be a smart pointer and must instead be a standard C-pointer. However, the + // `StreamCallbacks` object is reference counted and so will be destroyed when the final + // shared_ptr is destroyed. So in order to make sure that it lives long enough, the `context` + // field here stores a pointer to a newly created `shared_ptr` which will not go out of scope + // when this method returns. When the `StreamCallbacks` is no longer need (c_on_complete, + // c_on_cancel, c_on_error), this new `shared_ptr` will need to be deleted. new StreamCallbacksSharedPtr(shared_from_this()), }; } diff --git a/mobile/library/common/apple/BUILD b/mobile/library/common/apple/BUILD new file mode 100644 index 000000000000..6b3cbcd92fa2 --- /dev/null +++ b/mobile/library/common/apple/BUILD @@ -0,0 +1,28 @@ +load("@envoy//bazel:envoy_build_system.bzl", "envoy_cc_library", "envoy_mobile_package") + +licenses(["notice"]) # Apache 2 + +envoy_mobile_package() + +envoy_cc_library( + name = "utility_lib", + srcs = select({ + "@envoy//bazel:apple": [ + "utility.cc", + ], + "//conditions:default": [], + }), + hdrs = select({ + "@envoy//bazel:apple": [ + "utility.h", + ], + "//conditions:default": [], + }), + repository = "@envoy", + deps = select({ + "@envoy//bazel:apple": [ + "@envoy//source/common/common:assert_lib", + ], + "//conditions:default": [], + }), +) diff --git a/mobile/library/common/apple/utility.cc b/mobile/library/common/apple/utility.cc new file mode 100644 index 000000000000..bcbdfc2a3d3a --- /dev/null +++ b/mobile/library/common/apple/utility.cc @@ -0,0 +1,46 @@ +#include "library/common/apple/utility.h" + +#include "source/common/common/assert.h" + +namespace Envoy { +namespace Apple { + +std::string toString(CFStringRef cf_string) { + // A pointer to a C string or NULL if the internal storage of string + // does not allow this to be returned efficiently. + // CFStringGetCStringPtr will return a pointer to the string with no memory allocation and in + // constant time, if it can; otherwise, it will return null. + const char* efficient_c_str = CFStringGetCStringPtr(cf_string, kCFStringEncodingUTF8); + if (efficient_c_str) { + return std::string(efficient_c_str); + } + + CFIndex length = CFStringGetLength(cf_string); + // Adding 1 to accomodate the `\0` null delimiter in a C string. + CFIndex size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; + char* c_str = static_cast(malloc(size)); + // Use less efficient method of getting c string if CFStringGetCStringPtr failed. + const bool ret = CFStringGetCString(cf_string, c_str, size, kCFStringEncodingUTF8); + ENVOY_BUG(ret, "CFStringGetCString failed to convert CFStringRef to C string."); + + std::string ret_str; + ret_str = std::string(c_str); + + free(c_str); + return ret_str; +} + +int toInt(CFNumberRef number) { + if (number == nullptr) { + return 0; + } + + int value = 0; + const bool ret = CFNumberGetValue(number, kCFNumberSInt32Type, &value); + ENVOY_BUG(ret, "CFNumberGetValue failed to convert CFNumberRef to int."); + + return value; +} + +} // namespace Apple +} // namespace Envoy diff --git a/mobile/library/common/apple/utility.h b/mobile/library/common/apple/utility.h new file mode 100644 index 000000000000..a6ef2943f807 --- /dev/null +++ b/mobile/library/common/apple/utility.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include + +namespace Envoy { +namespace Apple { + +// Converts a CStringRef from Objective-C into a C++ std::string in the most effecient way feasible. +std::string toString(CFStringRef); + +// Converts a CFNumberRef (an Objective-C number representation) into a C++ int value. +int toInt(CFNumberRef); + +} // namespace Apple +} // namespace Envoy diff --git a/mobile/library/common/extensions/filters/http/network_configuration/BUILD b/mobile/library/common/extensions/filters/http/network_configuration/BUILD index ad0cce1697a7..2360408a9028 100644 --- a/mobile/library/common/extensions/filters/http/network_configuration/BUILD +++ b/mobile/library/common/extensions/filters/http/network_configuration/BUILD @@ -21,9 +21,13 @@ envoy_cc_extension( repository = "@envoy", deps = [ ":filter_cc_proto", + "//library/common/api:external_api_lib", "//library/common/http:header_utility_lib", "//library/common/http:internal_headers_lib", "//library/common/network:connectivity_manager_lib", + "//library/common/network:proxy_api_lib", + "//library/common/network:proxy_resolver_interface_lib", + "//library/common/network:proxy_settings_lib", "//library/common/stream_info:extra_stream_info_lib", "//library/common/types:c_types_lib", "@envoy//envoy/http:codes_interface", diff --git a/mobile/library/common/extensions/filters/http/network_configuration/filter.cc b/mobile/library/common/extensions/filters/http/network_configuration/filter.cc index 0502df10dca6..4aa7579f931d 100644 --- a/mobile/library/common/extensions/filters/http/network_configuration/filter.cc +++ b/mobile/library/common/extensions/filters/http/network_configuration/filter.cc @@ -2,9 +2,14 @@ #include "envoy/server/filter_config.h" +#include "source/common/http/headers.h" +#include "source/common/http/utility.h" #include "source/common/network/filter_state_proxy_info.h" +#include "library/common/api/external.h" +#include "library/common/data/utility.h" #include "library/common/http/header_utility.h" +#include "library/common/types/c_types.h" namespace Envoy { namespace Extensions { @@ -55,6 +60,17 @@ bool NetworkConfigurationFilter::onAddressResolved( return false; } +void NetworkConfigurationFilter::onProxyResolutionComplete( + Network::ProxySettingsConstSharedPtr proxy_settings) { + if (continueWithProxySettings(proxy_settings) == Http::FilterHeadersStatus::Continue) { + // PAC URL resolution happens via Apple APIs on a separate thread (Apple's run loop thread), so + // we schedule the continuation callback on the engine's dispatcher. + continue_decoding_callback_ = decoder_callbacks_->dispatcher().createSchedulableCallback( + [this]() { decoder_callbacks_->continueDecoding(); }); + continue_decoding_callback_->scheduleCallbackNextIteration(); + } +} + Http::FilterHeadersStatus NetworkConfigurationFilter::decodeHeaders(Http::RequestHeaderMap& request_headers, bool) { ENVOY_LOG(trace, "NetworkConfigurationFilter::decodeHeaders", request_headers); @@ -64,19 +80,76 @@ NetworkConfigurationFilter::decodeHeaders(Http::RequestHeaderMap& request_header return Http::FilterHeadersStatus::Continue; } - // If there is no proxy configured, continue. + // For iOS, we use the `envoy_proxy_resolver` API, which reads proxy settings asynchronously, + // and callbacks are invoked in the filter when proxy settings are updated. + auto* proxy_resolver = static_cast( + Api::External::retrieveApi("envoy_proxy_resolver", /*allow_absent=*/true)); + if (proxy_resolver != nullptr) { + return resolveProxy(request_headers, proxy_resolver); + } + + // For Android, proxy settings are pushed to the ConnectivityManager and synchronously handled + // here. const auto proxy_settings = connectivity_manager_->getProxySettings(); + return continueWithProxySettings(proxy_settings); +} + +Http::FilterHeadersStatus +NetworkConfigurationFilter::resolveProxy(Http::RequestHeaderMap& request_headers, + Network::ProxyResolverApi* proxy_resolver) { + ASSERT(proxy_resolver != nullptr, "proxy_resolver must not be null."); + + const std::string target_url = Http::Utility::buildOriginalUri(request_headers, absl::nullopt); + + std::weak_ptr weak_self = weak_from_this(); + Network::ProxyResolutionResult proxy_resolution_result = proxy_resolver->resolver->resolveProxy( + target_url, proxy_settings_, + [&weak_self](const std::vector& proxies) { + // This is the callback invoked from the Apple APIs resolving the PAC file URL, which + // happens on a separate Apple run loop thread. We keep a weak_ptr to this filter instance + // so that, if the stream is canceled and the filter chain is torn down in the meantime, + // we will fail to aquire the weak_ptr lock and won't execute any callbacks on the resolved + // proxies. + if (auto caller_ptr = weak_self.lock()) { + Network::ProxySettingsConstSharedPtr proxy_settings = + Network::ProxySettings::create(proxies); + // We are currently in the main thread, so post the proxy resolution callback to the + // worker thread's (i.e. the Engine thread) dispatcher. + caller_ptr->decoder_callbacks_->dispatcher().post([&weak_self, proxy_settings]() { + // Again, the stream may have been canceled in the interim, so try aquiring the + // filter through its weak_ptr before proceding with the proxy resolution callback. + if (auto filter_ptr = weak_self.lock()) { + filter_ptr->onProxyResolutionComplete(proxy_settings); + } + }); + } + }); + + switch (proxy_resolution_result) { + case Network::ProxyResolutionResult::NO_PROXY_CONFIGURED: + return Http::FilterHeadersStatus::Continue; + case Network::ProxyResolutionResult::RESULT_COMPLETED: + return continueWithProxySettings(Network::ProxySettings::create(proxy_settings_)); + case Network::ProxyResolutionResult::RESULT_IN_PROGRESS: + // `onProxyResolutionComplete` method will be called once the proxy resolution completes + return Http::FilterHeadersStatus::StopAllIterationAndWatermark; + } +} + +Http::FilterHeadersStatus NetworkConfigurationFilter::continueWithProxySettings( + Network::ProxySettingsConstSharedPtr proxy_settings) { + // If there is no proxy configured, continue. if (proxy_settings == nullptr) { return Http::FilterHeadersStatus::Continue; } - ENVOY_LOG(trace, "netconf_filter_processing_proxy_for_request", proxy_settings->asString()); + ENVOY_LOG(trace, "netconf_filter_processing_proxy_for_request proxy_settings={}", + proxy_settings->asString()); // If there is a proxy with a raw address, set the information, and continue. const auto proxy_address = proxy_settings->address(); if (proxy_address != nullptr) { - const auto authorityHeader = request_headers.get(AuthorityHeaderName); - - setInfo(request_headers.getHostValue(), proxy_address); + const auto host_value = decoder_callbacks_->streamInfo().getRequestHeaders()->getHostValue(); + setInfo(host_value, proxy_address); return Http::FilterHeadersStatus::Continue; } diff --git a/mobile/library/common/extensions/filters/http/network_configuration/filter.h b/mobile/library/common/extensions/filters/http/network_configuration/filter.h index 7fbe37583ffb..f17ccc38ec8c 100644 --- a/mobile/library/common/extensions/filters/http/network_configuration/filter.h +++ b/mobile/library/common/extensions/filters/http/network_configuration/filter.h @@ -7,6 +7,9 @@ #include "library/common/extensions/filters/http/network_configuration/filter.pb.h" #include "library/common/network/connectivity_manager.h" +#include "library/common/network/proxy_api.h" +#include "library/common/network/proxy_resolver_interface.h" +#include "library/common/network/proxy_settings.h" #include "library/common/stream_info/extra_stream_info.h" #include "library/common/types/c_types.h" @@ -21,7 +24,8 @@ namespace NetworkConfiguration { class NetworkConfigurationFilter final : public Http::PassThroughFilter, public Logger::Loggable, - public Extensions::Common::DynamicForwardProxy::DnsCache::LoadDnsCacheEntryCallbacks { + public Extensions::Common::DynamicForwardProxy::DnsCache::LoadDnsCacheEntryCallbacks, + public std::enable_shared_from_this { public: NetworkConfigurationFilter(Network::ConnectivityManagerSharedPtr connectivity_manager, bool enable_drain_post_dns_refresh, bool enable_interface_binding) @@ -43,11 +47,16 @@ class NetworkConfigurationFilter final const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr& host_info) override; void onDestroy() override; + void onProxyResolutionComplete(Network::ProxySettingsConstSharedPtr proxy_settings); private: void setInfo(absl::string_view authority, Network::Address::InstanceConstSharedPtr address); bool onAddressResolved(const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr& host_info); + Http::FilterHeadersStatus resolveProxy(Http::RequestHeaderMap& request_headers, + Network::ProxyResolverApi* resolver); + Http::FilterHeadersStatus + continueWithProxySettings(Network::ProxySettingsConstSharedPtr proxy_settings); // This is only present if there is an active proxy DNS lookup in progress. std::unique_ptr @@ -57,6 +66,8 @@ class NetworkConfigurationFilter final bool enable_drain_post_dns_refresh_; bool enable_interface_binding_; Event::SchedulableCallbackPtr continue_decoding_callback_; + // The lifetime of proxy settings must be attached to the lifetime of the filter. + std::vector proxy_settings_; }; } // namespace NetworkConfiguration diff --git a/mobile/library/common/network/BUILD b/mobile/library/common/network/BUILD index 7a119bf0bd52..d7f3ae1745be 100644 --- a/mobile/library/common/network/BUILD +++ b/mobile/library/common/network/BUILD @@ -11,17 +11,16 @@ envoy_cc_library( ], hdrs = [ "connectivity_manager.h", - "proxy_settings.h", ], repository = "@envoy", deps = [ + ":proxy_settings_lib", "//library/common/network:src_addr_socket_option_lib", "//library/common/types:c_types_lib", "@envoy//envoy/network:socket_interface", "@envoy//envoy/singleton:manager_interface", "@envoy//source/common/common:assert_lib", "@envoy//source/common/common:scalar_to_byte_vector_lib", - "@envoy//source/common/common:utility_lib", "@envoy//source/common/network:addr_family_aware_socket_option_lib", "@envoy//source/common/network:socket_option_lib", "@envoy//source/extensions/common/dynamic_forward_proxy:dns_cache_manager_impl", @@ -87,3 +86,70 @@ envoy_cc_library( "//conditions:default": [], }), ) + +envoy_cc_library( + name = "proxy_settings_lib", + srcs = [ + "proxy_settings.cc", + ], + hdrs = [ + "proxy_settings.h", + ], + repository = "@envoy", + deps = [ + "@envoy//source/common/network:utility_lib", + ], +) + +envoy_cc_library( + name = "proxy_resolver_interface_lib", + hdrs = ["proxy_resolver_interface.h"], + repository = "@envoy", + deps = [ + ":proxy_settings_lib", + ], +) + +envoy_cc_library( + name = "proxy_api_lib", + hdrs = ["proxy_api.h"], + repository = "@envoy", + deps = [ + ":proxy_resolver_interface_lib", + ], +) + +envoy_cc_library( + name = "apple_proxy_resolution_lib", + srcs = select({ + "@envoy//bazel:apple": [ + "apple_pac_proxy_resolver.cc", + "apple_proxy_resolution.cc", + "apple_proxy_resolver.cc", + "apple_system_proxy_settings_monitor.cc", + ], + "//conditions:default": [], + }), + hdrs = select({ + "@envoy//bazel:apple": [ + "apple_pac_proxy_resolver.h", + "apple_proxy_resolution.h", + "apple_proxy_resolver.h", + "apple_system_proxy_settings_monitor.h", + ], + "//conditions:default": [], + }), + repository = "@envoy", + deps = select({ + "@envoy//bazel:apple": [ + ":proxy_api_lib", + ":proxy_resolver_interface_lib", + ":proxy_settings_lib", + "//library/common/api:external_api_lib", + "//library/common/apple:utility_lib", + "//library/common/extensions/cert_validator/platform_bridge:c_types_lib", + "//library/common/types:c_types_lib", + ], + "//conditions:default": [], + }), +) diff --git a/mobile/library/common/network/apple_pac_proxy_resolver.cc b/mobile/library/common/network/apple_pac_proxy_resolver.cc new file mode 100644 index 000000000000..9a07a00ba607 --- /dev/null +++ b/mobile/library/common/network/apple_pac_proxy_resolver.cc @@ -0,0 +1,109 @@ +#include "library/common/network/apple_pac_proxy_resolver.h" + +#include +#include +#include + +#include "source/common/common/assert.h" + +#include "library/common/apple/utility.h" + +namespace Envoy { +namespace Network { + +namespace { + +// Creates a CFURLRef from a C++ string URL. +CFURLRef createCFURL(const std::string& url_string) { + auto cf_url_string = + CFStringCreateWithCString(kCFAllocatorDefault, url_string.c_str(), kCFStringEncodingUTF8); + auto cf_url = CFURLCreateWithString(kCFAllocatorDefault, cf_url_string, /*baseURL=*/nullptr); + CFRelease(cf_url_string); + return cf_url; +} + +} // namespace + +void proxyAutoConfigurationResultCallback(void* ptr, CFArrayRef cf_proxies, CFErrorRef cf_error) { + // `ptr` contains the unowned pointer to the ProxySettingsResolvedCallback. We extract it from the + // void* and wrap it in a unique_ptr so the memory gets reclaimed at the end of the function when + // `completion_callback` goes out of scope. + std::unique_ptr completion_callback( + static_cast(ptr)); + + std::vector proxies; + if (cf_error != nullptr || cf_proxies == nullptr) { + ENVOY_BUG(cf_error != nullptr, Apple::toString(CFErrorCopyDescription(cf_error))); + // Treat the error case as if no proxy was configured. Seems to be consistent with what iOS + // system (URLSession) is doing. + (*completion_callback)(proxies); + return; + } + + for (int i = 0; i < CFArrayGetCount(cf_proxies); i++) { + CFDictionaryRef cf_dictionary = + static_cast(CFArrayGetValueAtIndex(cf_proxies, i)); + CFStringRef cf_proxy_type = + static_cast(CFDictionaryGetValue(cf_dictionary, kCFProxyTypeKey)); + bool is_http_proxy = CFStringCompare(cf_proxy_type, kCFProxyTypeHTTP, 0) == kCFCompareEqualTo; + bool is_https_proxy = CFStringCompare(cf_proxy_type, kCFProxyTypeHTTPS, 0) == kCFCompareEqualTo; + bool is_direct_proxy = CFStringCompare(cf_proxy_type, kCFProxyTypeNone, 0) == kCFCompareEqualTo; + + if (is_http_proxy || is_https_proxy) { + CFStringRef cf_host = + static_cast(CFDictionaryGetValue(cf_dictionary, kCFProxyHostNameKey)); + CFNumberRef cf_port = + static_cast(CFDictionaryGetValue(cf_dictionary, kCFProxyPortNumberKey)); + proxies.emplace_back(ProxySettings(Apple::toString(cf_host), Apple::toInt(cf_port))); + } else if (is_direct_proxy) { + proxies.push_back(ProxySettings::direct()); + } + } + + (*completion_callback)(proxies); +} + +CFRunLoopSourceRef +ApplePacProxyResolver::createPacUrlResolverSource(CFURLRef cf_proxy_autoconfiguration_file_url, + CFURLRef cf_target_url, + CFStreamClientContext* context) { + // Even though neither the name of the method nor Apple's documentation mentions that, manual + // testing shows that `CFNetworkExecuteProxyAutoConfigurationURL` method does caching of fetched + // PAC file and does not fetch it on every proxy resolution request. + return CFNetworkExecuteProxyAutoConfigurationURL(cf_proxy_autoconfiguration_file_url, + cf_target_url, + proxyAutoConfigurationResultCallback, context); +} + +void ApplePacProxyResolver::resolveProxies( + const std::string& target_url, const std::string& proxy_autoconfiguration_file_url, + ProxySettingsResolvedCallback proxy_resolution_completed) { + CFURLRef cf_target_url = createCFURL(target_url); + CFURLRef cf_proxy_autoconfiguration_file_url = createCFURL(proxy_autoconfiguration_file_url); + + std::unique_ptr completion_callback = + std::make_unique(std::move(proxy_resolution_completed)); + // According to https://developer.apple.com/documentation/corefoundation/cfstreamclientcontext, + // the version must be 0. + auto context = std::make_unique( + CFStreamClientContext{/*version=*/0, + /*info=*/completion_callback.release(), + /*retain=*/nullptr, + /*release=*/nullptr, + /*copyDescription=*/nullptr}); + + // Ownership of the context gets released to the CFRunLoopSourceRef. When + // `proxyAutoConfigurationResultCallback` gets invoked, the pointer is passed in and is + // responsible for releasing the memory. + CFRunLoopSourceRef run_loop_source = createPacUrlResolverSource( + cf_proxy_autoconfiguration_file_url, cf_target_url, context.release()); + + CFRunLoopAddSource(CFRunLoopGetMain(), run_loop_source, kCFRunLoopDefaultMode); + + CFRelease(cf_target_url); + CFRelease(cf_proxy_autoconfiguration_file_url); + CFRelease(run_loop_source); +} + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/apple_pac_proxy_resolver.h b/mobile/library/common/network/apple_pac_proxy_resolver.h new file mode 100644 index 000000000000..24d349056506 --- /dev/null +++ b/mobile/library/common/network/apple_pac_proxy_resolver.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include +#include + +#include "library/common/network/proxy_settings.h" + +namespace Envoy { +namespace Network { + +// The callback function for when the PAC file URL has been resolved and the configured proxies +// are available, if any. +// `ptr` contains the unowned pointer to the ProxySettingsResolvedCallback. +// `cf_proxies` is an array of the resolved proxies. +// `cf_error` is the error, if any, when trying to resolve the PAC file URL. +void proxyAutoConfigurationResultCallback(void* ptr, CFArrayRef cf_proxies, CFErrorRef cf_error); + +/** + * Resolves auto configuration (PAC) proxies. + */ +class ApplePacProxyResolver { +public: + virtual ~ApplePacProxyResolver() = default; + /** + * Resolves proxy for a given URL using proxy auto configuration file that's hosted at a given + * URL. + * @param target_url A request URL to resolve the proxy for. + * @param proxy_autoconfiguration_file_url A URL at which a proxy configuration file is hosted. + * @param proxy_resolution_completed A function that's called with result proxies as its + * arguments when proxy resolution completes. + */ + void resolveProxies(const std::string& target_url, + const std::string& proxy_autoconfiguration_file_url, + ProxySettingsResolvedCallback proxy_resolution_completed); + +protected: + // Creates a CFRunLoopSourceRef for resolving the PAC file URL that the main CFRunLoop will run. + // Implemented as a separate function and made virtual so we can overload in tests. + virtual CFRunLoopSourceRef + createPacUrlResolverSource(CFURLRef cf_proxy_autoconfiguration_file_url, CFURLRef cf_target_url, + CFStreamClientContext* context); +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/apple_platform_cert_verifier.h b/mobile/library/common/network/apple_platform_cert_verifier.h index b559d41a4978..4ed6604c4a83 100644 --- a/mobile/library/common/network/apple_platform_cert_verifier.h +++ b/mobile/library/common/network/apple_platform_cert_verifier.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "absl/strings/string_view.h" diff --git a/mobile/library/common/network/apple_proxy_resolution.cc b/mobile/library/common/network/apple_proxy_resolution.cc new file mode 100644 index 000000000000..5af6f62711ca --- /dev/null +++ b/mobile/library/common/network/apple_proxy_resolution.cc @@ -0,0 +1,27 @@ +#include "library/common/network/apple_proxy_resolution.h" + +#include + +#include "library/common/api/external.h" +#include "library/common/network/apple_proxy_resolver.h" +#include "library/common/network/proxy_api.h" + +// NOLINT(namespace-envoy) + +#ifdef __cplusplus +extern "C" { +#endif + +void registerAppleProxyResolver() { + auto resolver = std::make_unique(); + resolver->start(); + + auto api = std::make_unique(); + api->resolver = std::move(resolver); + + Envoy::Api::External::registerApi("envoy_proxy_resolver", api.release()); +} + +#ifdef __cplusplus +} +#endif diff --git a/mobile/library/common/network/apple_proxy_resolution.h b/mobile/library/common/network/apple_proxy_resolution.h new file mode 100644 index 000000000000..068bf8fceda8 --- /dev/null +++ b/mobile/library/common/network/apple_proxy_resolution.h @@ -0,0 +1,16 @@ +#pragma once + +// NOLINT(namespace-envoy) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Registers the Apple proxy resolver. + */ +void registerAppleProxyResolver(); + +#ifdef __cplusplus +} +#endif diff --git a/mobile/library/common/network/apple_proxy_resolver.cc b/mobile/library/common/network/apple_proxy_resolver.cc new file mode 100644 index 000000000000..8329b1d853b2 --- /dev/null +++ b/mobile/library/common/network/apple_proxy_resolver.cc @@ -0,0 +1,67 @@ +#include "library/common/network/apple_proxy_resolver.h" + +#include "source/common/common/assert.h" + +namespace Envoy { +namespace Network { + +AppleProxyResolver::AppleProxyResolver() + : proxy_settings_monitor_( + std::make_unique(proxySettingsUpdater())), + pac_proxy_resolver_(std::make_unique()) {} + +SystemProxySettingsReadCallback AppleProxyResolver::proxySettingsUpdater() { + return SystemProxySettingsReadCallback( + [this](absl::optional proxy_settings) { + absl::MutexLock l(&mutex_); + proxy_settings_ = std::move(proxy_settings); + }); +} + +void AppleProxyResolver::start() { + proxy_settings_monitor_->start(); + started_ = true; +} + +ProxyResolutionResult +AppleProxyResolver::resolveProxy(const std::string& target_url_string, + std::vector& proxies, + ProxySettingsResolvedCallback proxy_resolution_completed) { + ASSERT(started_, "AppleProxyResolver not started."); + + std::string pac_file_url; + { + absl::MutexLock l(&mutex_); + if (!proxy_settings_.has_value()) { + return ProxyResolutionResult::NO_PROXY_CONFIGURED; + } + + const auto proxy_settings = proxy_settings_.value(); + if (!proxy_settings.isPacEnabled()) { + ProxySettings settings(proxy_settings.hostname(), proxy_settings.port()); + if (settings.isDirect()) { + return ProxyResolutionResult::NO_PROXY_CONFIGURED; + } + proxies.emplace_back(std::move(settings)); + return ProxyResolutionResult::RESULT_COMPLETED; + } + + pac_file_url = proxy_settings.pacFileUrl(); + } + + // TODO(abeyad): As stated in ApplePacProxyResolver's comments, + // CFNetworkExecuteProxyAutoConfigurationURL caches PAC file resolution, so it's not fetched on + // every request. However, it would be good to not depend on Apple's undocumented behavior and + // implement a caching layer with TTLs for PAC file URL resolution within AppleProxyResolver + // itself. + ASSERT(!pac_file_url.empty(), "PAC file URL must not be empty if PAC is enabled."); + pac_proxy_resolver_->resolveProxies( + pac_file_url, target_url_string, + [proxy_resolution_completed](const std::vector& proxies) { + proxy_resolution_completed(proxies); + }); + return ProxyResolutionResult::RESULT_IN_PROGRESS; +} + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/apple_proxy_resolver.h b/mobile/library/common/network/apple_proxy_resolver.h new file mode 100644 index 000000000000..7a39eed82fbe --- /dev/null +++ b/mobile/library/common/network/apple_proxy_resolver.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +#include +#include + +#include "library/common/network/apple_pac_proxy_resolver.h" +#include "library/common/network/apple_system_proxy_settings_monitor.h" +#include "library/common/network/proxy_resolver_interface.h" +#include "library/common/network/proxy_settings.h" + +namespace Envoy { +namespace Network { + +/** + * Resolves proxies on Apple platforms. + */ +class AppleProxyResolver : public ProxyResolver { +public: + AppleProxyResolver(); + virtual ~AppleProxyResolver() = default; + + /** + * Starts proxy resolver. It needs to be called prior to any proxy resolution attempt. + */ + void start(); + + /** + * Resolves the proxy settings for the target URL. The result of proxy resolution is returned in + * the ProxyResolutionResult enum. If proxy resolution returns RESULT_COMPLETED, the `proxies` + * vector gets populated with the resolved proxy setting. If proxy resolution returns + * RESULT_IN_PROGRESS, the `proxy_resolution_completed` function gets invoked upon successful + * resolution of the proxy settings. + */ + virtual ProxyResolutionResult + resolveProxy(const std::string& target_url_string, std::vector& proxies, + ProxySettingsResolvedCallback proxy_resolution_completed) override; + + /* + * Supplies a function that updates this instance's proxy settings. + */ + SystemProxySettingsReadCallback proxySettingsUpdater(); + +private: + friend class TestAppleProxyResolver; + + std::unique_ptr proxy_settings_monitor_; + std::unique_ptr pac_proxy_resolver_; + absl::optional proxy_settings_; + absl::Mutex mutex_; + bool started_; +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/apple_system_proxy_settings_monitor.cc b/mobile/library/common/network/apple_system_proxy_settings_monitor.cc new file mode 100644 index 000000000000..b5f5ef4b1b0d --- /dev/null +++ b/mobile/library/common/network/apple_system_proxy_settings_monitor.cc @@ -0,0 +1,99 @@ +#include "library/common/network/apple_system_proxy_settings_monitor.h" + +#include +#include +#include + +#include "library/common/apple/utility.h" + +namespace Envoy { +namespace Network { + +// The interval at which system proxy settings should be polled at. +CFTimeInterval kProxySettingsRefreshRateSeconds = 7; + +AppleSystemProxySettingsMonitor::AppleSystemProxySettingsMonitor( + SystemProxySettingsReadCallback proxy_settings_read_callback) + : proxy_settings_read_callback_(proxy_settings_read_callback) {} + +void AppleSystemProxySettingsMonitor::start() { + if (started_) { + return; + } + + started_ = true; + + dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class( + DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, DISPATCH_QUEUE_PRIORITY_DEFAULT); + queue_ = dispatch_queue_create("io.envoyproxy.envoymobile.AppleSystemProxySettingsMonitor", + attributes); + + __block absl::optional proxy_settings; + dispatch_sync(queue_, ^{ + proxy_settings = readSystemProxySettings(); + proxy_settings_read_callback_(std::move(proxy_settings)); + }); + + source_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue_); + dispatch_source_set_timer(source_, dispatch_time(DISPATCH_TIME_NOW, 0), + kProxySettingsRefreshRateSeconds * NSEC_PER_SEC, 0); + dispatch_source_set_event_handler(source_, ^{ + const auto new_proxy_settings = readSystemProxySettings(); + if (new_proxy_settings != proxy_settings) { + proxy_settings = new_proxy_settings; + proxy_settings_read_callback_(std::move(new_proxy_settings)); + } + }); + dispatch_resume(source_); +} + +AppleSystemProxySettingsMonitor::~AppleSystemProxySettingsMonitor() { + if (source_ != nullptr) { + dispatch_suspend(source_); + } + if (queue_ != nullptr) { + dispatch_release(queue_); + } +} + +CFDictionaryRef AppleSystemProxySettingsMonitor::getSystemProxySettings() const { + return CFNetworkCopySystemProxySettings(); +} + +absl::optional +AppleSystemProxySettingsMonitor::readSystemProxySettings() const { + CFDictionaryRef proxy_settings = getSystemProxySettings(); + if (proxy_settings == nullptr) { + return absl::nullopt; + } + + // iOS system settings allow users to enter an arbitrary big integer number i.e. 88888888 as a + // port number. That being said, testing using iOS 16 shows that Apple's APIs return + // `is_http_proxy_enabled` equal to false unless entered port number is within [0, 65535] range. + CFNumberRef cf_is_http_proxy_enabled = + static_cast(CFDictionaryGetValue(proxy_settings, kCFNetworkProxiesHTTPEnable)); + CFNumberRef cf_is_auto_config_proxy_enabled = static_cast( + CFDictionaryGetValue(proxy_settings, kCFNetworkProxiesProxyAutoConfigEnable)); + const bool is_http_proxy_enabled = Apple::toInt(cf_is_http_proxy_enabled) > 0; + const bool is_auto_config_proxy_enabled = Apple::toInt(cf_is_auto_config_proxy_enabled) > 0; + + absl::optional settings; + if (is_http_proxy_enabled) { + CFStringRef cf_hostname = + static_cast(CFDictionaryGetValue(proxy_settings, kCFNetworkProxiesHTTPProxy)); + CFNumberRef cf_port = + static_cast(CFDictionaryGetValue(proxy_settings, kCFNetworkProxiesHTTPPort)); + settings = absl::make_optional(Apple::toString(cf_hostname), + Apple::toInt(cf_port)); + } else if (is_auto_config_proxy_enabled) { + CFStringRef cf_pac_file_url_string = static_cast( + CFDictionaryGetValue(proxy_settings, kCFNetworkProxiesProxyAutoConfigURLString)); + settings = absl::make_optional(Apple::toString(cf_pac_file_url_string)); + } + + CFRelease(proxy_settings); + return settings; +} + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/apple_system_proxy_settings_monitor.h b/mobile/library/common/network/apple_system_proxy_settings_monitor.h new file mode 100644 index 000000000000..bbf898bb5333 --- /dev/null +++ b/mobile/library/common/network/apple_system_proxy_settings_monitor.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +#include + +#include "absl/types/optional.h" +#include "library/common/network/proxy_settings.h" + +namespace Envoy { +namespace Network { + +/** + * Monitors Apple system proxy settings changes. Optimized for iOS platform. + */ +class AppleSystemProxySettingsMonitor { +public: + /** + * Creates a new instance of the receiver. Calls provided function every time it detects a + * change of system proxy settings. Treats invalid PAC URLs as a lack of proxy configuration. + * + * @param proxy_settings_read_callback The closure to call every time system proxy settings + * change. The closure is called on a non-main queue. + */ + AppleSystemProxySettingsMonitor(SystemProxySettingsReadCallback proxy_settings_read_callback); + virtual ~AppleSystemProxySettingsMonitor(); + + /** + * Starts monitoring system proxy settings. + */ + void start(); + +protected: + // Protected and virtual so they can be overridden by tests to provide mocked system proxy + // settings. + virtual CFDictionaryRef getSystemProxySettings() const; + +private: + absl::optional readSystemProxySettings() const; + + dispatch_source_t source_; + dispatch_queue_t queue_; + bool started_; + SystemProxySettingsReadCallback proxy_settings_read_callback_; +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/proxy_api.h b/mobile/library/common/network/proxy_api.h new file mode 100644 index 000000000000..83f9f8d47fbf --- /dev/null +++ b/mobile/library/common/network/proxy_api.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "library/common/network/proxy_resolver_interface.h" + +namespace Envoy { +namespace Network { + +struct ProxyResolverApi { + std::unique_ptr resolver; +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/proxy_resolver_interface.h b/mobile/library/common/network/proxy_resolver_interface.h new file mode 100644 index 000000000000..dd9213566819 --- /dev/null +++ b/mobile/library/common/network/proxy_resolver_interface.h @@ -0,0 +1,34 @@ +#pragma once + +#include "library/common/network/proxy_settings.h" + +namespace Envoy { +namespace Network { + +enum class ProxyResolutionResult { + NO_PROXY_CONFIGURED = 0, + RESULT_COMPLETED = 1, + RESULT_IN_PROGRESS = 2, +}; + +// An interface for resolving the system's proxy settings. +class ProxyResolver { +public: + virtual ~ProxyResolver() = default; + + /** + * Resolves proxy for a given url. Depending on the type current system proxy settings the method + * may return results in synchronous or asynchronous way. + * @param proxies Result proxies for when the proxy resolution is performed synchronously. + * @param proxy_resolution_completed A function that's called with result proxies as its + * arguments for when the proxy resolution is performed asynchronously. + * @return Whether there is a proxy or no and whether proxy resolution was performed synchronously + * or whether it's still running. + */ + virtual ProxyResolutionResult + resolveProxy(const std::string& target_url_string, std::vector& proxies, + ProxySettingsResolvedCallback proxy_resolution_completed) PURE; +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/proxy_settings.cc b/mobile/library/common/network/proxy_settings.cc new file mode 100644 index 000000000000..6350b67c3e23 --- /dev/null +++ b/mobile/library/common/network/proxy_settings.cc @@ -0,0 +1,91 @@ +#include "library/common/network/proxy_settings.h" + +#include + +namespace Envoy { +namespace Network { + +ProxySettings::ProxySettings(const std::string& host, const uint16_t port) + : address_(Envoy::Network::Utility::parseInternetAddressNoThrow(host, port)), hostname_(host), + port_(port) {} + +/*static*/ +ProxySettingsConstSharedPtr ProxySettings::parseHostAndPort(const std::string& host, + const uint16_t port) { + if (host == "" && port == 0) { + return nullptr; + } + return std::make_shared(host, port); +} + +/*static*/ +ProxySettings ProxySettings::direct() { return ProxySettings("", 0); } + +/*static*/ +ProxySettingsConstSharedPtr ProxySettings::create(const std::vector& settings_list) { + if (settings_list.empty()) { + return nullptr; + } + + for (const auto& proxy_settings : settings_list) { + if (!proxy_settings.isDirect()) { + // We'll use the first non-direct ProxySettings. + return std::make_shared(proxy_settings.hostname(), proxy_settings.port()); + } + } + + // No non-direct ProxySettings was found. + return nullptr; +} + +bool ProxySettings::isDirect() const { return hostname_ == "" && port_ == 0; } + +const Envoy::Network::Address::InstanceConstSharedPtr& ProxySettings::address() const { + return address_; +} + +const std::string& ProxySettings::hostname() const { return hostname_; } + +uint16_t ProxySettings::port() const { return port_; } + +const std::string ProxySettings::asString() const { + if (address_ != nullptr) { + return address_->asString(); + } + if (!hostname_.empty()) { + return absl::StrCat(hostname_, ":", port_); + } + return "no_proxy_configured"; +} + +bool ProxySettings::operator==(ProxySettings const& rhs) const { + // Even if the hostnames are IP addresses, they'll be stored in hostname_ + return hostname() == rhs.hostname() && port() == rhs.port(); +} + +bool ProxySettings::operator!=(ProxySettings const& rhs) const { return !(*this == rhs); } + +SystemProxySettings::SystemProxySettings(std::string&& hostname, int port) + : hostname_(std::move(hostname)), port_(port) {} + +SystemProxySettings::SystemProxySettings(std::string&& pac_file_url) + : port_(-1), pac_file_url_(std::move(pac_file_url)) {} + +const std::string& SystemProxySettings::hostname() const { return hostname_; } + +int SystemProxySettings::port() const { return port_; } + +const std::string& SystemProxySettings::pacFileUrl() const { return pac_file_url_; } + +bool SystemProxySettings::isPacEnabled() const { return !pac_file_url_.empty(); } + +bool SystemProxySettings::operator==(SystemProxySettings const& rhs) const { + return hostname() == rhs.hostname() && port() == rhs.port() && pacFileUrl() == rhs.pacFileUrl(); +} + +bool SystemProxySettings::operator!=(SystemProxySettings const& rhs) const { + return !(*this == rhs); +} + +} // namespace Network +} // namespace Envoy diff --git a/mobile/library/common/network/proxy_settings.h b/mobile/library/common/network/proxy_settings.h index c99aa8bc3066..19a7e4b28ffc 100644 --- a/mobile/library/common/network/proxy_settings.h +++ b/mobile/library/common/network/proxy_settings.h @@ -1,34 +1,47 @@ #pragma once +#include +#include +#include + #include "source/common/network/utility.h" +#include "absl/types/optional.h" + namespace Envoy { namespace Network { -struct ProxySettings; +class ProxySettings; +class SystemProxySettings; using ProxySettingsConstSharedPtr = std::shared_ptr; +using ProxySettingsResolvedCallback = std::function&)>; +using SystemProxySettingsReadCallback = std::function)>; /** * Proxy settings coming from platform specific APIs, i.e. ConnectivityManager in * the case of Android platform. * + * ProxySettings represents already-resolved proxy settings. For example, if the proxy + * settings are obtained from a PAC URL, then this object represents the resolved proxy + * settings after reading and parsing the PAC URL. + * + * TODO(abeyad): rename this class to ProxySetting (the plural in the name is confusing). */ -struct ProxySettings { +class ProxySettings { +public: /** - * @brief Construct a new Proxy Settings object. + * Construct a new Proxy Settings object. * * @param host The proxy host defined as a hostname or an IP address. Some platforms * (i.e., Android) allow users to specify proxy using either one of these. * @param port The proxy port. */ - ProxySettings(const std::string& host, const uint16_t port) - : address_(Envoy::Network::Utility::parseInternetAddressNoThrow(host, port)), hostname_(host), - port_(port) {} + ProxySettings(const std::string& host, const uint16_t port); /** - * @brief Parses given host and domain and creates proxy settings. Returns nullptr - * for an empty host and a port equal to 0 as they are passed to c++ native layer - * as a synonym of the lack of proxy settings configured on a device. + * Parses given host and domain and creates proxy settings. Returns nullptr for an empty host + * and a port equal to 0, as they are passed to the C++ native layer to represent the lack of + * proxy settings configured on a device. * * @param host The proxy host defined as a hostname or an IP address. Some platforms * (i.e., Android) allow users to specify proxy using either one of these. @@ -36,59 +49,76 @@ struct ProxySettings { * @return The created proxy settings, nullptr if the passed host is an empty string and * port is equal to 0. */ - static const ProxySettingsConstSharedPtr parseHostAndPort(const std::string& host, - const uint16_t port) { - if (host == "" && port == 0) { - return nullptr; - } - return std::make_shared(host, port); - } + static ProxySettingsConstSharedPtr parseHostAndPort(const std::string& host, const uint16_t port); + + /** + * Creates a ProxySettings instance to represent a direct connection (i.e. no proxy at all). + * + * @return The ProxySettings object. Calling isDirect() on it returns true. + */ + static ProxySettings direct(); + + /** + * Creates a shared pointer instance of the ProxySettings to use, from the list of resolved + * system proxy settings. + * + * @param settings_list A list of ProxySettings provided by the system. + * + * @return A shared pointer to an instance of the ProxySettings that was chosen from the proxy + * settings list. + */ + static ProxySettingsConstSharedPtr create(const std::vector& settings_list); /** - * @brief Returns an address of a proxy. This method returns nullptr for proxy settings - * that are initialized with anything other than an IP address. + * @return true if the instance represents a direct connection (i.e. no proxy), false otherwise. + */ + bool isDirect() const; + + /** + * Returns an address of a proxy. This method returns nullptr for proxy settings that are + * initialized with anything other than an IP address. * * @return Address of a proxy or nullptr if proxy address is incorrect or host is * defined using a hostname and not an IP address. */ - const Envoy::Network::Address::InstanceConstSharedPtr& address() const { return address_; } + const Envoy::Network::Address::InstanceConstSharedPtr& address() const; /** - * @brief Returns the hostname of a proxy. + * Returns a reference to the hostname of the proxy. * - * @return Hostname of a proxy or the empty string if there is no hostname. + * @return Hostname of the proxy (if the string is empty, there is no hostname). */ - const std::string& hostname() const { return hostname_; } + const std::string& hostname() const; /** - * @brief Returns the port of the proxy. + * Returns the port of the proxy. * * @return Port of the proxy. */ - uint16_t port() const { return port_; } + uint16_t port() const; /** - * @brief Returns a human readable representation of the proxy settings represented - * by the receiver + * Returns a human readable representation of the proxy settings represented by the receiver. * * @return const A human readable representation of the receiver. */ - const std::string asString() const { - if (address_ != nullptr) { - return address_->asString(); - } - if (!hostname_.empty()) { - return absl::StrCat(hostname_, ":", port_); - } - return "no_proxy_configured"; - } + const std::string asString() const; - bool operator==(ProxySettings const& rhs) const { - // Even if the hostnames are IP addresses, they'll be stored in hostname_ - return hostname() == rhs.hostname() && port() == rhs.port(); - } + /** + * Equals operator overload. + * @param rhs another ProxySettings object. + * @return returns true if the two ProxySettings objects are equivalent (represents the + * same configuration); false otherwise. + */ + bool operator==(ProxySettings const& rhs) const; - bool operator!=(ProxySettings const& rhs) const { return !(*this == rhs); } + /** + * Not equals operator overload. + * @param rhs another ProxySettings object. + * @return returns true if the two ProxySettings objects are not equivalent (represents + * different proxy configuration); false otherwise. + */ + bool operator!=(ProxySettings const& rhs) const; private: Envoy::Network::Address::InstanceConstSharedPtr address_; @@ -96,5 +126,67 @@ struct ProxySettings { uint16_t port_; }; +/** + * System proxy settings. There are 2 ways to specify desired proxy settings. Either provide proxy's + * hostname or provide a URL to a Proxy Auto-Configuration (PAC) file. + */ +class SystemProxySettings { +public: + /** + * Creates proxy settings using provided hostname and port. + * @param hostname A domain name or an IP address. + * @param port A valid internet port from within [0-65535] range. + */ + SystemProxySettings(std::string&& hostname, int port); + + /** + * Creates proxy settings using provided URL to a Proxy Auto-Configuration (PAC) file. + * @param pac_file_url A URL to a Proxy Auto-Configuration (PAC) file. + */ + SystemProxySettings(std::string&& pac_file_url); + + /** + * @return a reference to the hostname (which will be an empty string if not configured). + */ + const std::string& hostname() const; + + /* + * @return the port number, or -1 if a PAC file is configured. + */ + int port() const; + + /** + * @return a reference to the PAC file URL (which will be an empty string if not configured). + */ + const std::string& pacFileUrl() const; + + /** + * @return returns true if this object represents a PAC file URL configured proxy, + * returns false if this object represents a host/port configured proxy. + */ + bool isPacEnabled() const; + + /** + * Equals operator overload. + * @param rhs another SystemProxySettings object. + * @return returns true if the two SystemProxySettings objects are equivalent (represents the + * same configuration); false otherwise. + */ + bool operator==(SystemProxySettings const& rhs) const; + + /** + * Not equals operator overload. + * @param rhs another SystemProxySettings object. + * @return returns true if the two SystemProxySettings objects are not equivalent (represents + * different proxy configuration); false otherwise. + */ + bool operator!=(SystemProxySettings const& rhs) const; + +private: + std::string hostname_; + int port_; + std::string pac_file_url_; +}; + } // namespace Network } // namespace Envoy diff --git a/mobile/library/common/types/c_types.h b/mobile/library/common/types/c_types.h index 1fa9ab779509..c942e11d298f 100644 --- a/mobile/library/common/types/c_types.h +++ b/mobile/library/common/types/c_types.h @@ -322,10 +322,9 @@ extern "C" { // function pointers * @param stream_intel, contains internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. - * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_headers_f)(envoy_headers headers, bool end_stream, - envoy_stream_intel stream_intel, void* context); +typedef void (*envoy_on_headers_f)(envoy_headers headers, bool end_stream, + envoy_stream_intel stream_intel, void* context); /** * Callback signature for data on an HTTP stream. @@ -337,10 +336,9 @@ typedef void* (*envoy_on_headers_f)(envoy_headers headers, bool end_stream, * @param stream_intel, contains internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. - * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_data_f)(envoy_data data, bool end_stream, envoy_stream_intel stream_intel, - void* context); +typedef void (*envoy_on_data_f)(envoy_data data, bool end_stream, envoy_stream_intel stream_intel, + void* context); /** * Callback signature for metadata on an HTTP stream. @@ -353,8 +351,8 @@ typedef void* (*envoy_on_data_f)(envoy_data data, bool end_stream, envoy_stream_ * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_metadata_f)(envoy_headers metadata, envoy_stream_intel stream_intel, - void* context); +typedef void (*envoy_on_metadata_f)(envoy_headers metadata, envoy_stream_intel stream_intel, + void* context); /** * Callback signature for trailers on an HTTP stream. @@ -365,10 +363,9 @@ typedef void* (*envoy_on_metadata_f)(envoy_headers metadata, envoy_stream_intel * @param stream_intel, contains internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. - * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_trailers_f)(envoy_headers trailers, envoy_stream_intel stream_intel, - void* context); +typedef void (*envoy_on_trailers_f)(envoy_headers trailers, envoy_stream_intel stream_intel, + void* context); /** * Callback signature for errors with an HTTP stream. @@ -380,10 +377,9 @@ typedef void* (*envoy_on_trailers_f)(envoy_headers trailers, envoy_stream_intel * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. - * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); +typedef void (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context); /** * Callback signature for when an HTTP stream bi-directionally completes without error. @@ -394,10 +390,9 @@ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_i * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. - * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); +typedef void (*envoy_on_complete_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context); /** * Callback signature for when an HTTP stream is cancelled. @@ -408,10 +403,9 @@ typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. - * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); +typedef void (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context); /** * Called when the envoy engine is exiting. @@ -456,9 +450,8 @@ typedef void (*envoy_logger_release_f)(const void* context); * @param stream_intel, contains internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. - * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_send_window_available_f)(envoy_stream_intel stream_intel, void* context); +typedef void (*envoy_on_send_window_available_f)(envoy_stream_intel stream_intel, void* context); /** * Called when envoy's event tracker tracks an event. diff --git a/mobile/library/java/io/envoyproxy/envoymobile/engine/AndroidProxyMonitor.java b/mobile/library/java/io/envoyproxy/envoymobile/engine/AndroidProxyMonitor.java index 6aff90ddd823..96102da6debc 100644 --- a/mobile/library/java/io/envoyproxy/envoymobile/engine/AndroidProxyMonitor.java +++ b/mobile/library/java/io/envoyproxy/envoymobile/engine/AndroidProxyMonitor.java @@ -81,7 +81,7 @@ private ProxyInfo extractProxyInfo(final Intent intent) { // proxy is configured. // // See https://github.com/envoyproxy/envoy-mobile/issues/2531 for more details. - if (info.getPacFileUrl() != null && info.getPacFileUrl() != Uri.EMPTY) { + if (!Uri.EMPTY.equals(info.getPacFileUrl())) { if (intent == null) { // PAC proxies are supported only when Intent is present return null; diff --git a/mobile/library/jni/jni_impl.cc b/mobile/library/jni/jni_impl.cc index 58f2dac10755..0e929f40246c 100644 --- a/mobile/library/jni/jni_impl.cc +++ b/mobile/library/jni/jni_impl.cc @@ -225,8 +225,9 @@ static void passHeaders(const char* method, const Envoy::Types::ManagedEnvoyHead // These methods call jvm methods which means the local references created will not be // released automatically. Manual bookkeeping is required for these methods. -static void* jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoyHeaders& headers, - bool end_stream, envoy_stream_intel stream_intel, void* context) { +static Envoy::JNI::LocalRefUniquePtr +jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoyHeaders& headers, + bool end_stream, envoy_stream_intel stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_headers"); Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); jobject j_context = static_cast(context); @@ -241,7 +242,7 @@ static void* jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoy Envoy::JNI::envoyStreamIntelToJavaLongArray(jni_helper, stream_intel); // Note: be careful of JVM types. Before we casted to jlong we were getting integer problems. // TODO: make this cast safer. - Envoy::JNI::LocalRefUniquePtr result = jni_helper.callObjectMethod( + Envoy::JNI::LocalRefUniquePtr result = jni_helper.callObjectMethod( j_context, jmid_onHeaders, static_cast(headers.get().length), end_stream ? JNI_TRUE : JNI_FALSE, j_stream_intel.get()); // TODO(Augustyniak): Pass the name of the filter in here so that we can instrument the origin of @@ -249,7 +250,7 @@ static void* jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoy bool exception_cleared = Envoy::JNI::Exception::checkAndClear(method); if (!exception_cleared) { - return result.release(); + return result; } // Create a "no operation" result: @@ -273,13 +274,13 @@ static void* jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoy Envoy::JNI::envoyHeadersToJavaArrayOfObjectArray(jni_helper, headers); jni_helper.setObjectArrayElement(noopResult.get(), 1, j_headers.get()); - return noopResult.release(); + return noopResult; } -static void* jvm_on_response_headers(envoy_headers headers, bool end_stream, - envoy_stream_intel stream_intel, void* context) { +static void jvm_on_response_headers(envoy_headers headers, bool end_stream, + envoy_stream_intel stream_intel, void* context) { const auto managed_headers = Envoy::Types::ManagedEnvoyHeaders(headers); - return jvm_on_headers("onResponseHeaders", managed_headers, end_stream, stream_intel, context); + jvm_on_headers("onResponseHeaders", managed_headers, end_stream, stream_intel, context); } static envoy_filter_headers_status @@ -287,25 +288,22 @@ jvm_http_filter_on_request_headers(envoy_headers input_headers, bool end_stream, envoy_stream_intel stream_intel, const void* context) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); const auto headers = Envoy::Types::ManagedEnvoyHeaders(input_headers); - jobjectArray result = static_cast(jvm_on_headers( - "onRequestHeaders", headers, end_stream, stream_intel, const_cast(context))); + Envoy::JNI::LocalRefUniquePtr result = jvm_on_headers( + "onRequestHeaders", headers, end_stream, stream_intel, const_cast(context)); - if (result == NULL || jni_helper.getArrayLength(result) < 2) { - jni_helper.getEnv()->DeleteLocalRef(result); + if (result == nullptr || jni_helper.getArrayLength(result.get()) < 2) { return (envoy_filter_headers_status){/*status*/ kEnvoyFilterHeadersStatusStopIteration, /*headers*/ {}}; } - Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result, 0); + Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result.get(), 0); Envoy::JNI::LocalRefUniquePtr j_headers = - jni_helper.getObjectArrayElement(result, 1); + jni_helper.getObjectArrayElement(result.get(), 1); int unboxed_status = Envoy::JNI::javaIntegerTotInt(jni_helper, status.get()); envoy_headers native_headers = Envoy::JNI::javaArrayOfObjectArrayToEnvoyHeaders(jni_helper, j_headers.get()); - jni_helper.getEnv()->DeleteLocalRef(result); - return (envoy_filter_headers_status){/*status*/ unboxed_status, /*headers*/ native_headers}; } @@ -315,31 +313,30 @@ jvm_http_filter_on_response_headers(envoy_headers input_headers, bool end_stream envoy_stream_intel stream_intel, const void* context) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); const auto headers = Envoy::Types::ManagedEnvoyHeaders(input_headers); - jobjectArray result = static_cast(jvm_on_headers( - "onResponseHeaders", headers, end_stream, stream_intel, const_cast(context))); + Envoy::JNI::LocalRefUniquePtr result = jvm_on_headers( + "onResponseHeaders", headers, end_stream, stream_intel, const_cast(context)); - if (result == NULL || jni_helper.getArrayLength(result) < 2) { - jni_helper.getEnv()->DeleteLocalRef(result); + if (result == nullptr || jni_helper.getArrayLength(result.get()) < 2) { return (envoy_filter_headers_status){/*status*/ kEnvoyFilterHeadersStatusStopIteration, /*headers*/ {}}; } - Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result, 0); + Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result.get(), 0); Envoy::JNI::LocalRefUniquePtr j_headers = - jni_helper.getObjectArrayElement(result, 1); + jni_helper.getObjectArrayElement(result.get(), 1); int unboxed_status = Envoy::JNI::javaIntegerTotInt(jni_helper, status.get()); envoy_headers native_headers = Envoy::JNI::javaArrayOfObjectArrayToEnvoyHeaders(jni_helper, j_headers.get()); - jni_helper.getEnv()->DeleteLocalRef(result); - return (envoy_filter_headers_status){/*status*/ unboxed_status, /*headers*/ native_headers}; } -static void* jvm_on_data(const char* method, envoy_data data, bool end_stream, - envoy_stream_intel stream_intel, void* context) { +static Envoy::JNI::LocalRefUniquePtr jvm_on_data(const char* method, envoy_data data, + bool end_stream, + envoy_stream_intel stream_intel, + void* context) { jni_log("[Envoy]", "jvm_on_data"); Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); jobject j_context = static_cast(context); @@ -353,38 +350,36 @@ static void* jvm_on_data(const char* method, envoy_data data, bool end_stream, Envoy::JNI::envoyDataToJavaByteArray(jni_helper, data); Envoy::JNI::LocalRefUniquePtr j_stream_intel = Envoy::JNI::envoyStreamIntelToJavaLongArray(jni_helper, stream_intel); - jobject result = jni_helper - .callObjectMethod(j_context, jmid_onData, j_data.get(), - end_stream ? JNI_TRUE : JNI_FALSE, j_stream_intel.get()) - .release(); + Envoy::JNI::LocalRefUniquePtr result = jni_helper.callObjectMethod( + j_context, jmid_onData, j_data.get(), end_stream ? JNI_TRUE : JNI_FALSE, + j_stream_intel.get()); release_envoy_data(data); return result; } -static void* jvm_on_response_data(envoy_data data, bool end_stream, envoy_stream_intel stream_intel, - void* context) { - return jvm_on_data("onResponseData", data, end_stream, stream_intel, context); +static void jvm_on_response_data(envoy_data data, bool end_stream, envoy_stream_intel stream_intel, + void* context) { + jvm_on_data("onResponseData", data, end_stream, stream_intel, context); } static envoy_filter_data_status jvm_http_filter_on_request_data(envoy_data data, bool end_stream, envoy_stream_intel stream_intel, const void* context) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); - jobjectArray result = static_cast( - jvm_on_data("onRequestData", data, end_stream, stream_intel, const_cast(context))); + Envoy::JNI::LocalRefUniquePtr result = + jvm_on_data("onRequestData", data, end_stream, stream_intel, const_cast(context)); - if (result == NULL || jni_helper.getArrayLength(result) < 2) { - jni_helper.getEnv()->DeleteLocalRef(result); + if (result == nullptr || jni_helper.getArrayLength(result.get()) < 2) { return (envoy_filter_data_status){/*status*/ kEnvoyFilterHeadersStatusStopIteration, /*data*/ {}, /*pending_headers*/ {}}; } - Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result, 0); + Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result.get(), 0); Envoy::JNI::LocalRefUniquePtr j_data = - jni_helper.getObjectArrayElement(result, 1); + jni_helper.getObjectArrayElement(result.get(), 1); int unboxed_status = Envoy::JNI::javaIntegerTotInt(jni_helper, status.get()); envoy_data native_data = Envoy::JNI::javaByteBufferToEnvoyData(jni_helper, j_data.get()); @@ -393,13 +388,11 @@ static envoy_filter_data_status jvm_http_filter_on_request_data(envoy_data data, // Avoid out-of-bounds access to array when checking for optional pending entities. if (unboxed_status == kEnvoyFilterDataStatusResumeIteration) { Envoy::JNI::LocalRefUniquePtr j_headers = - jni_helper.getObjectArrayElement(result, 2); + jni_helper.getObjectArrayElement(result.get(), 2); pending_headers = Envoy::JNI::javaArrayOfObjectArrayToEnvoyHeadersPtr(jni_helper, j_headers.get()); } - jni_helper.getEnv()->DeleteLocalRef(result); - return (envoy_filter_data_status){/*status*/ unboxed_status, /*data*/ native_data, /*pending_headers*/ pending_headers}; @@ -409,19 +402,18 @@ static envoy_filter_data_status jvm_http_filter_on_response_data(envoy_data data envoy_stream_intel stream_intel, const void* context) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); - jobjectArray result = static_cast( - jvm_on_data("onResponseData", data, end_stream, stream_intel, const_cast(context))); + Envoy::JNI::LocalRefUniquePtr result = + jvm_on_data("onResponseData", data, end_stream, stream_intel, const_cast(context)); - if (result == NULL || jni_helper.getArrayLength(result) < 2) { - jni_helper.getEnv()->DeleteLocalRef(result); + if (result == nullptr || jni_helper.getArrayLength(result.get()) < 2) { return (envoy_filter_data_status){/*status*/ kEnvoyFilterHeadersStatusStopIteration, /*data*/ {}, /*pending_headers*/ {}}; } - Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result, 0); + Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result.get(), 0); Envoy::JNI::LocalRefUniquePtr j_data = - jni_helper.getObjectArrayElement(result, 1); + jni_helper.getObjectArrayElement(result.get(), 1); int unboxed_status = Envoy::JNI::javaIntegerTotInt(jni_helper, status.get()); envoy_data native_data = Envoy::JNI::javaByteBufferToEnvoyData(jni_helper, j_data.get()); @@ -430,27 +422,26 @@ static envoy_filter_data_status jvm_http_filter_on_response_data(envoy_data data // Avoid out-of-bounds access to array when checking for optional pending entities. if (unboxed_status == kEnvoyFilterDataStatusResumeIteration) { Envoy::JNI::LocalRefUniquePtr j_headers = - jni_helper.getObjectArrayElement(result, 2); + jni_helper.getObjectArrayElement(result.get(), 2); pending_headers = Envoy::JNI::javaArrayOfObjectArrayToEnvoyHeadersPtr(jni_helper, j_headers.get()); } - jni_helper.getEnv()->DeleteLocalRef(result); - return (envoy_filter_data_status){/*status*/ unboxed_status, /*data*/ native_data, /*pending_headers*/ pending_headers}; } -static void* jvm_on_metadata(envoy_headers metadata, envoy_stream_intel /*stream_intel*/, - void* /*context*/) { +static void jvm_on_metadata(envoy_headers metadata, envoy_stream_intel /*stream_intel*/, + void* /*context*/) { jni_log("[Envoy]", "jvm_on_metadata"); jni_log("[Envoy]", std::to_string(metadata.length).c_str()); - return nullptr; } -static void* jvm_on_trailers(const char* method, envoy_headers trailers, - envoy_stream_intel stream_intel, void* context) { +static Envoy::JNI::LocalRefUniquePtr jvm_on_trailers(const char* method, + envoy_headers trailers, + envoy_stream_intel stream_intel, + void* context) { jni_log("[Envoy]", "jvm_on_trailers"); Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); @@ -466,37 +457,34 @@ static void* jvm_on_trailers(const char* method, envoy_headers trailers, Envoy::JNI::envoyStreamIntelToJavaLongArray(jni_helper, stream_intel); // Note: be careful of JVM types. Before we casted to jlong we were getting integer problems. // TODO: make this cast safer. - jobject result = jni_helper - .callObjectMethod(j_context, jmid_onTrailers, - static_cast(trailers.length), j_stream_intel.get()) - .release(); + Envoy::JNI::LocalRefUniquePtr result = jni_helper.callObjectMethod( + j_context, jmid_onTrailers, static_cast(trailers.length), j_stream_intel.get()); return result; } -static void* jvm_on_response_trailers(envoy_headers trailers, envoy_stream_intel stream_intel, - void* context) { - return jvm_on_trailers("onResponseTrailers", trailers, stream_intel, context); +static void jvm_on_response_trailers(envoy_headers trailers, envoy_stream_intel stream_intel, + void* context) { + jvm_on_trailers("onResponseTrailers", trailers, stream_intel, context); } static envoy_filter_trailers_status jvm_http_filter_on_request_trailers(envoy_headers trailers, envoy_stream_intel stream_intel, const void* context) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); - jobjectArray result = static_cast( - jvm_on_trailers("onRequestTrailers", trailers, stream_intel, const_cast(context))); + Envoy::JNI::LocalRefUniquePtr result = + jvm_on_trailers("onRequestTrailers", trailers, stream_intel, const_cast(context)); - if (result == NULL || jni_helper.getArrayLength(result) < 2) { - jni_helper.getEnv()->DeleteLocalRef(result); + if (result == nullptr || jni_helper.getArrayLength(result.get()) < 2) { return (envoy_filter_trailers_status){/*status*/ kEnvoyFilterHeadersStatusStopIteration, /*trailers*/ {}, /*pending_headers*/ {}, /*pending_data*/ {}}; } - Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result, 0); + Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result.get(), 0); Envoy::JNI::LocalRefUniquePtr j_trailers = - jni_helper.getObjectArrayElement(result, 1); + jni_helper.getObjectArrayElement(result.get(), 1); int unboxed_status = Envoy::JNI::javaIntegerTotInt(jni_helper, status.get()); envoy_headers native_trailers = @@ -507,16 +495,15 @@ jvm_http_filter_on_request_trailers(envoy_headers trailers, envoy_stream_intel s // Avoid out-of-bounds access to array when checking for optional pending entities. if (unboxed_status == kEnvoyFilterTrailersStatusResumeIteration) { Envoy::JNI::LocalRefUniquePtr j_headers = - jni_helper.getObjectArrayElement(result, 2); + jni_helper.getObjectArrayElement(result.get(), 2); pending_headers = Envoy::JNI::javaArrayOfObjectArrayToEnvoyHeadersPtr(jni_helper, j_headers.get()); - Envoy::JNI::LocalRefUniquePtr j_data = jni_helper.getObjectArrayElement(result, 3); + Envoy::JNI::LocalRefUniquePtr j_data = + jni_helper.getObjectArrayElement(result.get(), 3); pending_data = Envoy::JNI::javaByteBufferToEnvoyDataPtr(jni_helper, j_data.get()); } - jni_helper.getEnv()->DeleteLocalRef(result); - return (envoy_filter_trailers_status){/*status*/ unboxed_status, /*trailers*/ native_trailers, /*pending_headers*/ pending_headers, @@ -527,20 +514,19 @@ static envoy_filter_trailers_status jvm_http_filter_on_response_trailers(envoy_headers trailers, envoy_stream_intel stream_intel, const void* context) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); - jobjectArray result = static_cast( - jvm_on_trailers("onResponseTrailers", trailers, stream_intel, const_cast(context))); + Envoy::JNI::LocalRefUniquePtr result = + jvm_on_trailers("onResponseTrailers", trailers, stream_intel, const_cast(context)); - if (result == NULL || jni_helper.getArrayLength(result) < 2) { - jni_helper.getEnv()->DeleteLocalRef(result); + if (result == nullptr || jni_helper.getArrayLength(result.get()) < 2) { return (envoy_filter_trailers_status){/*status*/ kEnvoyFilterHeadersStatusStopIteration, /*trailers*/ {}, /*pending_headers*/ {}, /*pending_data*/ {}}; } - Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result, 0); + Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result.get(), 0); Envoy::JNI::LocalRefUniquePtr j_trailers = - jni_helper.getObjectArrayElement(result, 1); + jni_helper.getObjectArrayElement(result.get(), 1); int unboxed_status = Envoy::JNI::javaIntegerTotInt(jni_helper, status.get()); envoy_headers native_trailers = @@ -551,16 +537,15 @@ jvm_http_filter_on_response_trailers(envoy_headers trailers, envoy_stream_intel // Avoid out-of-bounds access to array when checking for optional pending entities. if (unboxed_status == kEnvoyFilterTrailersStatusResumeIteration) { Envoy::JNI::LocalRefUniquePtr j_headers = - jni_helper.getObjectArrayElement(result, 2); + jni_helper.getObjectArrayElement(result.get(), 2); pending_headers = Envoy::JNI::javaArrayOfObjectArrayToEnvoyHeadersPtr(jni_helper, j_headers.get()); - Envoy::JNI::LocalRefUniquePtr j_data = jni_helper.getObjectArrayElement(result, 3); + Envoy::JNI::LocalRefUniquePtr j_data = + jni_helper.getObjectArrayElement(result.get(), 3); pending_data = Envoy::JNI::javaByteBufferToEnvoyDataPtr(jni_helper, j_data.get()); } - jni_helper.getEnv()->DeleteLocalRef(result); - return (envoy_filter_trailers_status){/*status*/ unboxed_status, /*trailers*/ native_trailers, /*pending_headers*/ pending_headers, @@ -679,8 +664,8 @@ jvm_http_filter_on_resume_response(envoy_headers* headers, envoy_data* data, stream_intel, context); } -static void* call_jvm_on_complete(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { +static void call_jvm_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_complete"); Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); @@ -695,16 +680,12 @@ static void* call_jvm_on_complete(envoy_stream_intel stream_intel, Envoy::JNI::envoyStreamIntelToJavaLongArray(jni_helper, stream_intel); Envoy::JNI::LocalRefUniquePtr j_final_stream_intel = Envoy::JNI::envoyFinalStreamIntelToJavaLongArray(jni_helper, final_stream_intel); - jobject result = jni_helper - .callObjectMethod(j_context, jmid_onComplete, j_stream_intel.get(), - j_final_stream_intel.get()) - .release(); - - return result; + Envoy::JNI::LocalRefUniquePtr unused = jni_helper.callObjectMethod( + j_context, jmid_onComplete, j_stream_intel.get(), j_final_stream_intel.get()); } -static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { +static void call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_error"); Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); jobject j_context = static_cast(context); @@ -721,25 +702,21 @@ static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_inte Envoy::JNI::LocalRefUniquePtr j_final_stream_intel = Envoy::JNI::envoyFinalStreamIntelToJavaLongArray(jni_helper, final_stream_intel); - jobject result = - jni_helper - .callObjectMethod(j_context, jmid_onError, error.error_code, j_error_message.get(), - error.attempt_count, j_stream_intel.get(), j_final_stream_intel.get()) - .release(); + Envoy::JNI::LocalRefUniquePtr unused = jni_helper.callObjectMethod( + j_context, jmid_onError, error.error_code, j_error_message.get(), error.attempt_count, + j_stream_intel.get(), j_final_stream_intel.get()); release_envoy_error(error); - return result; } -static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_error(error, stream_intel, final_stream_intel, context); +static void jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + call_jvm_on_error(error, stream_intel, final_stream_intel, context); Envoy::JNI::jniDeleteGlobalRef(context); - return result; } -static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { +static void call_jvm_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_cancel"); Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); @@ -755,26 +732,20 @@ static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, Envoy::JNI::LocalRefUniquePtr j_final_stream_intel = Envoy::JNI::envoyFinalStreamIntelToJavaLongArray(jni_helper, final_stream_intel); - jobject result = jni_helper - .callObjectMethod(j_context, jmid_onCancel, j_stream_intel.get(), - j_final_stream_intel.get()) - .release(); - - return result; + Envoy::JNI::LocalRefUniquePtr unused = jni_helper.callObjectMethod( + j_context, jmid_onCancel, j_stream_intel.get(), j_final_stream_intel.get()); } -static void* jvm_on_complete(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_complete(stream_intel, final_stream_intel, context); +static void jvm_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + call_jvm_on_complete(stream_intel, final_stream_intel, context); Envoy::JNI::jniDeleteGlobalRef(context); - return result; } -static void* jvm_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_cancel(stream_intel, final_stream_intel, context); +static void jvm_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + call_jvm_on_cancel(stream_intel, final_stream_intel, context); Envoy::JNI::jniDeleteGlobalRef(context); - return result; } static void jvm_http_filter_on_error(envoy_error error, envoy_stream_intel stream_intel, @@ -789,7 +760,7 @@ static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, call_jvm_on_cancel(stream_intel, final_stream_intel, const_cast(context)); } -static void* jvm_on_send_window_available(envoy_stream_intel stream_intel, void* context) { +static void jvm_on_send_window_available(envoy_stream_intel stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_send_window_available"); Envoy::JNI::JniHelper jni_helper(Envoy::JNI::getEnv()); @@ -803,11 +774,8 @@ static void* jvm_on_send_window_available(envoy_stream_intel stream_intel, void* Envoy::JNI::LocalRefUniquePtr j_stream_intel = Envoy::JNI::envoyStreamIntelToJavaLongArray(jni_helper, stream_intel); - jobject result = - jni_helper.callObjectMethod(j_context, jmid_onSendWindowAvailable, j_stream_intel.get()) - .release(); - - return result; + Envoy::JNI::LocalRefUniquePtr unused = + jni_helper.callObjectMethod(j_context, jmid_onSendWindowAvailable, j_stream_intel.get()); } // JvmKeyValueStoreContext diff --git a/mobile/library/objective-c/BUILD b/mobile/library/objective-c/BUILD index 00d6435a4939..ee5c61619d10 100644 --- a/mobile/library/objective-c/BUILD +++ b/mobile/library/objective-c/BUILD @@ -60,6 +60,7 @@ envoy_objc_library( "//library/common:internal_engine_lib", "//library/common/api:c_types", "//library/common/network:apple_platform_cert_verifier", + "//library/common/network:apple_proxy_resolution_lib", ], ) diff --git a/mobile/library/objective-c/EnvoyConfiguration.h b/mobile/library/objective-c/EnvoyConfiguration.h index d38a25d23a82..d6932bfc89f4 100644 --- a/mobile/library/objective-c/EnvoyConfiguration.h +++ b/mobile/library/objective-c/EnvoyConfiguration.h @@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL enforceTrustChainVerification; @property (nonatomic, assign) BOOL forceIPv6; @property (nonatomic, assign) BOOL enablePlatformCertificateValidation; +@property (nonatomic, assign) BOOL respectSystemProxySettings; @property (nonatomic, assign) UInt32 h2ConnectionKeepaliveIdleIntervalMilliseconds; @property (nonatomic, assign) UInt32 h2ConnectionKeepaliveTimeoutSeconds; @property (nonatomic, assign) UInt32 maxConnectionsPerHost; @@ -81,6 +82,7 @@ NS_ASSUME_NONNULL_BEGIN enforceTrustChainVerification:(BOOL)enforceTrustChainVerification forceIPv6:(BOOL)forceIPv6 enablePlatformCertificateValidation:(BOOL)enablePlatformCertificateValidation + respectSystemProxySettings:(BOOL)respectSystemProxySettings h2ConnectionKeepaliveIdleIntervalMilliseconds: (UInt32)h2ConnectionKeepaliveIdleIntervalMilliseconds h2ConnectionKeepaliveTimeoutSeconds:(UInt32)h2ConnectionKeepaliveTimeoutSeconds diff --git a/mobile/library/objective-c/EnvoyConfiguration.mm b/mobile/library/objective-c/EnvoyConfiguration.mm index 02b8cf8a253b..2a2b481ac5d0 100644 --- a/mobile/library/objective-c/EnvoyConfiguration.mm +++ b/mobile/library/objective-c/EnvoyConfiguration.mm @@ -85,6 +85,7 @@ - (instancetype)initWithConnectTimeoutSeconds:(UInt32)connectTimeoutSeconds enforceTrustChainVerification:(BOOL)enforceTrustChainVerification forceIPv6:(BOOL)forceIPv6 enablePlatformCertificateValidation:(BOOL)enablePlatformCertificateValidation + respectSystemProxySettings:(BOOL)respectSystemProxySettings h2ConnectionKeepaliveIdleIntervalMilliseconds: (UInt32)h2ConnectionKeepaliveIdleIntervalMilliseconds h2ConnectionKeepaliveTimeoutSeconds:(UInt32)h2ConnectionKeepaliveTimeoutSeconds @@ -143,6 +144,7 @@ - (instancetype)initWithConnectTimeoutSeconds:(UInt32)connectTimeoutSeconds self.enforceTrustChainVerification = enforceTrustChainVerification; self.forceIPv6 = forceIPv6; self.enablePlatformCertificateValidation = enablePlatformCertificateValidation; + self.respectSystemProxySettings = respectSystemProxySettings; self.h2ConnectionKeepaliveIdleIntervalMilliseconds = h2ConnectionKeepaliveIdleIntervalMilliseconds; self.h2ConnectionKeepaliveTimeoutSeconds = h2ConnectionKeepaliveTimeoutSeconds; @@ -236,6 +238,7 @@ - (instancetype)initWithConnectTimeoutSeconds:(UInt32)connectTimeoutSeconds builder.setAppId([self.appId toCXXString]); builder.setDeviceOs("iOS"); builder.enablePlatformCertificatesValidation(self.enablePlatformCertificateValidation); + builder.respectSystemProxySettings(self.respectSystemProxySettings); builder.enableDnsCache(self.enableDNSCache, self.dnsCacheSaveIntervalSeconds); if (self.nodeRegion != nil) { diff --git a/mobile/library/objective-c/EnvoyEngineImpl.mm b/mobile/library/objective-c/EnvoyEngineImpl.mm index adac27f8ed0a..57f9f3fb2b9f 100644 --- a/mobile/library/objective-c/EnvoyEngineImpl.mm +++ b/mobile/library/objective-c/EnvoyEngineImpl.mm @@ -10,6 +10,8 @@ #import "library/cc/engine_builder.h" #import "library/common/internal_engine.h" +#include "library/common/network/apple_proxy_resolution.h" + #if TARGET_OS_IPHONE #import #endif @@ -511,6 +513,10 @@ - (void)performRegistrationsForConfig:(EnvoyConfiguration *)config { for (NSString *name in config.keyValueStores) { [self registerKeyValueStore:name keyValueStore:config.keyValueStores[name]]; } + + if (config.respectSystemProxySettings) { + registerAppleProxyResolver(); + } } - (int)runWithConfig:(EnvoyConfiguration *)config logLevel:(NSString *)logLevel { diff --git a/mobile/library/objective-c/EnvoyHTTPStreamImpl.mm b/mobile/library/objective-c/EnvoyHTTPStreamImpl.mm index 732eeac0e4c4..d83137c4af33 100644 --- a/mobile/library/objective-c/EnvoyHTTPStreamImpl.mm +++ b/mobile/library/objective-c/EnvoyHTTPStreamImpl.mm @@ -21,8 +21,8 @@ #pragma mark - C callbacks -static void *ios_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel stream_intel, - void *context) { +static void ios_on_headers(envoy_headers headers, bool end_stream, envoy_stream_intel stream_intel, + void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; dispatch_async(callbacks.dispatchQueue, ^{ @@ -30,11 +30,10 @@ callbacks.onHeaders(to_ios_headers(headers), end_stream, stream_intel); } }); - return NULL; } -static void *ios_on_data(envoy_data data, bool end_stream, envoy_stream_intel stream_intel, - void *context) { +static void ios_on_data(envoy_data data, bool end_stream, envoy_stream_intel stream_intel, + void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; dispatch_async(callbacks.dispatchQueue, ^{ @@ -42,16 +41,13 @@ callbacks.onData(to_ios_data(data), end_stream, stream_intel); } }); - return NULL; } -static void *ios_on_metadata(envoy_headers metadata, envoy_stream_intel stream_intel, - void *context) { - return NULL; -} +static void ios_on_metadata(envoy_headers metadata, envoy_stream_intel stream_intel, + void *context) {} -static void *ios_on_trailers(envoy_headers trailers, envoy_stream_intel stream_intel, - void *context) { +static void ios_on_trailers(envoy_headers trailers, envoy_stream_intel stream_intel, + void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; dispatch_async(callbacks.dispatchQueue, ^{ @@ -59,10 +55,9 @@ callbacks.onTrailers(to_ios_headers(trailers), stream_intel); } }); - return NULL; } -static void *ios_on_send_window_available(envoy_stream_intel stream_intel, void *context) { +static void ios_on_send_window_available(envoy_stream_intel stream_intel, void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; dispatch_async(callbacks.dispatchQueue, ^{ @@ -70,11 +65,10 @@ callbacks.onSendWindowAvailable(stream_intel); } }); - return NULL; } -static void *ios_on_complete(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void *context) { +static void ios_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; EnvoyHTTPStreamImpl *stream = c->stream; @@ -86,11 +80,10 @@ assert(stream); [stream cleanUp]; }); - return NULL; } -static void *ios_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void *context) { +static void ios_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void *context) { // This call is atomically gated at the call-site and will only happen once. It may still fire // after a complete response or error callback, but no other callbacks for the stream will ever // fire AFTER the cancellation callback. @@ -106,11 +99,10 @@ assert(stream); [stream cleanUp]; }); - return NULL; } -static void *ios_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void *context) { +static void ios_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; EnvoyHTTPStreamImpl *stream = c->stream; @@ -128,7 +120,6 @@ assert(stream); [stream cleanUp]; }); - return NULL; } #pragma mark - EnvoyHTTPStreamImpl diff --git a/mobile/library/swift/EngineBuilder.swift b/mobile/library/swift/EngineBuilder.swift index 2969e21bc3ea..a71949aa2986 100644 --- a/mobile/library/swift/EngineBuilder.swift +++ b/mobile/library/swift/EngineBuilder.swift @@ -156,6 +156,7 @@ open class EngineBuilder: NSObject { private var enableInterfaceBinding: Bool = false private var enforceTrustChainVerification: Bool = true private var enablePlatformCertificateValidation: Bool = false + private var respectSystemProxySettings: Bool = false private var enableDrainPostDnsRefresh: Bool = false private var forceIPv6: Bool = false private var h2ConnectionKeepaliveIdleIntervalMilliseconds: UInt32 = 1 @@ -366,6 +367,25 @@ open class EngineBuilder: NSObject { return self } + /// + /// Specify whether system proxy settings should be respected. If yes, Envoy Mobile will + /// use iOS APIs to query iOS Proxy settings configured on a device and will + /// respect these settings when establishing connections with remote services. + /// + /// The method is introduced for experimentation purposes and as a safety guard against + /// critical issues in the implementation of the proxying feature. It's intended to be removed + /// after it's confirmed that proxies on iOS work as expected. + /// + /// - parameter respectSystemProxySettings: whether to use the system's proxy settings for + /// outbound connections. + /// + /// - returns: This builder. + @discardableResult + public func respectSystemProxySettings(_ respectSystemProxySettings: Bool) -> Self { + self.respectSystemProxySettings = respectSystemProxySettings + return self + } + /// Specify whether to drain connections after the resolution of a soft DNS refresh. /// A refresh may be triggered directly via the Engine API, or as a result of a network /// status update provided by the OS. Draining connections does not interrupt existing @@ -773,6 +793,7 @@ open class EngineBuilder: NSObject { enforceTrustChainVerification: self.enforceTrustChainVerification, forceIPv6: self.forceIPv6, enablePlatformCertificateValidation: self.enablePlatformCertificateValidation, + respectSystemProxySettings: self.respectSystemProxySettings, h2ConnectionKeepaliveIdleIntervalMilliseconds: self.h2ConnectionKeepaliveIdleIntervalMilliseconds, h2ConnectionKeepaliveTimeoutSeconds: self.h2ConnectionKeepaliveTimeoutSeconds, @@ -844,6 +865,7 @@ private extension EngineBuilder { cxxBuilder.enforceTrustChainVerification(self.enforceTrustChainVerification) cxxBuilder.setForceAlwaysUsev6(self.forceIPv6) cxxBuilder.enablePlatformCertificatesValidation(self.enablePlatformCertificateValidation) + cxxBuilder.respectSystemProxySettings(self.respectSystemProxySettings) cxxBuilder.addH2ConnectionKeepaliveIdleIntervalMilliseconds( Int32(self.h2ConnectionKeepaliveIdleIntervalMilliseconds) ) diff --git a/mobile/test/cc/unit/BUILD b/mobile/test/cc/unit/BUILD index 6087469f874c..212204bf519c 100644 --- a/mobile/test/cc/unit/BUILD +++ b/mobile/test/cc/unit/BUILD @@ -11,6 +11,14 @@ envoy_cc_test( ["envoy_config_test.cc"], "@envoy", ), + linkopts = select({ + "@envoy//bazel:apple": [ + # For the TestProxyResolutionApi test. + "-Wl,-framework,CoreFoundation", + "-Wl,-framework,CFNetwork", + ], + "//conditions:default": [], + }), repository = "@envoy", deps = [ "//library/cc:engine_builder_lib", diff --git a/mobile/test/cc/unit/envoy_config_test.cc b/mobile/test/cc/unit/envoy_config_test.cc index 020d6e97559a..38eaffc6e108 100644 --- a/mobile/test/cc/unit/envoy_config_test.cc +++ b/mobile/test/cc/unit/envoy_config_test.cc @@ -99,6 +99,7 @@ TEST(TestConfig, ConfigIsApplied) { "key: \"dns_persistent_cache\" save_interval { seconds: 101 }", "key: \"always_use_v6\" value { bool_value: true }", "key: \"test_feature_false\" value { bool_value: true }", + "key: \"allow_client_socket_creation_failure\" value { bool_value: true }", "key: \"device_os\" value { string_value: \"probably-ubuntu-on-CI\" } }", "key: \"app_version\" value { string_value: \"1.2.3\" } }", "key: \"app_id\" value { string_value: \"1234-1234-1234\" } }", diff --git a/mobile/test/common/BUILD b/mobile/test/common/BUILD index cc3f3f7a2009..91686f69ecef 100644 --- a/mobile/test/common/BUILD +++ b/mobile/test/common/BUILD @@ -25,20 +25,6 @@ envoy_cc_test( repository = "@envoy", deps = [ "//library/cc:engine_builder_lib", - "//library/common:internal_engine_lib_no_stamp", - "//library/common/types:c_types_lib", - "@envoy//test/common/http:common_lib", - ], -) - -envoy_cc_test( - name = "main_interface_test", - srcs = envoy_select_enable_yaml( - ["main_interface_test.cc"], - "@envoy", - ), - repository = "@envoy", - deps = [ "//library/common:internal_engine_lib_no_stamp", "//library/common/data:utility_lib", "//library/common/http:header_utility_lib", diff --git a/mobile/test/common/extensions/filters/http/network_configuration/BUILD b/mobile/test/common/extensions/filters/http/network_configuration/BUILD index 9630ee6652bb..bac5601177cb 100644 --- a/mobile/test/common/extensions/filters/http/network_configuration/BUILD +++ b/mobile/test/common/extensions/filters/http/network_configuration/BUILD @@ -18,6 +18,9 @@ envoy_extension_cc_test( "//library/common/data:utility_lib", "//library/common/extensions/filters/http/network_configuration:config", "//library/common/extensions/filters/http/network_configuration:filter_cc_proto", + "//library/common/network:proxy_api_lib", + "//library/common/network:proxy_resolver_interface_lib", + "//library/common/network:proxy_settings_lib", "@envoy//test/extensions/common/dynamic_forward_proxy:mocks", "@envoy//test/mocks/event:event_mocks", "@envoy//test/mocks/http:http_mocks", diff --git a/mobile/test/common/extensions/filters/http/network_configuration/network_configuration_filter_test.cc b/mobile/test/common/extensions/filters/http/network_configuration/network_configuration_filter_test.cc index 813c4b7fdcd4..05a272da5bc0 100644 --- a/mobile/test/common/extensions/filters/http/network_configuration/network_configuration_filter_test.cc +++ b/mobile/test/common/extensions/filters/http/network_configuration/network_configuration_filter_test.cc @@ -11,6 +11,8 @@ #include "library/common/data/utility.h" #include "library/common/extensions/filters/http/network_configuration/filter.h" #include "library/common/extensions/filters/http/network_configuration/filter.pb.h" +#include "library/common/network/proxy_api.h" +#include "library/common/network/proxy_resolver_interface.h" #include "library/common/network/proxy_settings.h" using Envoy::Extensions::Common::DynamicForwardProxy::DnsCache; @@ -60,8 +62,8 @@ class MockConnectivityManager : public Network::ConnectivityManager { class NetworkConfigurationFilterTest : public testing::Test { public: NetworkConfigurationFilterTest() - : connectivity_manager_(new NiceMock), - proxy_settings_(new Network::ProxySettings("127.0.0.1", 82)), + : connectivity_manager_(std::make_shared>()), + proxy_settings_(std::make_shared("127.0.0.1", 82)), filter_(connectivity_manager_, false, false) { filter_.setDecoderFilterCallbacks(decoder_callbacks_); ON_CALL(decoder_callbacks_.stream_info_, getRequestHeaders()) @@ -184,6 +186,104 @@ TEST_F(NetworkConfigurationFilterTest, AsyncDnsLookupSuccess) { filter_.onLoadDnsCacheComplete(host_info_); } +class MockProxyResolver : public Network::ProxyResolver { +public: + MOCK_METHOD(Network::ProxyResolutionResult, resolveProxy, + (const std::string& target_url_string, std::vector& proxies, + Network::ProxySettingsResolvedCallback proxy_resolution_completed)); +}; + +class NetworkConfigurationFilterProxyResolverApiTest : public NetworkConfigurationFilterTest { +public: + NetworkConfigurationFilterProxyResolverApiTest() : NetworkConfigurationFilterTest() {} + + void SetUp() override { + auto proxy_resolver_api = std::make_unique(); + proxy_resolver_api->resolver = std::make_unique>(); + Api::External::registerApi("envoy_proxy_resolver", proxy_resolver_api.release()); + } + + void TearDown() override { + std::unique_ptr wrapped_api(getResolverApi()); + // Safe deletion of the envoy_proxy_resolver API. + wrapped_api.reset(); + } + + Network::ProxyResolverApi* getResolverApi() { + return static_cast( + Api::External::retrieveApi("envoy_proxy_resolver")); + } + + MockProxyResolver& getMockProxyResolver() { + return *static_cast(getResolverApi()->resolver.get()); + } +}; + +TEST_F(NetworkConfigurationFilterProxyResolverApiTest, NoProxyConfigured) { + std::vector proxy_settings; + EXPECT_CALL(getMockProxyResolver(), resolveProxy(_, proxy_settings, _)) + .WillOnce(Return(Network::ProxyResolutionResult::NO_PROXY_CONFIGURED)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, + filter_.decodeHeaders(default_request_headers_, false)); +} + +TEST_F(NetworkConfigurationFilterProxyResolverApiTest, EmptyProxyConfigured) { + std::vector proxy_settings; + EXPECT_CALL(getMockProxyResolver(), resolveProxy(_, proxy_settings, _)) + .WillOnce(Return(Network::ProxyResolutionResult::RESULT_COMPLETED)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, + filter_.decodeHeaders(default_request_headers_, false)); +} + +TEST_F(NetworkConfigurationFilterProxyResolverApiTest, DirectProxyConfigured) { + std::vector proxy_settings; + EXPECT_CALL(getMockProxyResolver(), resolveProxy(_, proxy_settings, _)) + .WillOnce([](const std::string& /*target_url_string*/, + std::vector& proxies, + Network::ProxySettingsResolvedCallback /*proxy_resolution_completed*/) { + proxies.emplace_back(Network::ProxySettings::direct()); + return Network::ProxyResolutionResult::RESULT_COMPLETED; + }); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, + filter_.decodeHeaders(default_request_headers_, false)); +} + +TEST_F(NetworkConfigurationFilterProxyResolverApiTest, ProxyWithIpAddressConfigured) { + std::vector proxy_settings; + EXPECT_CALL(getMockProxyResolver(), resolveProxy(_, proxy_settings, _)) + .WillOnce([](const std::string& /*target_url_string*/, + std::vector& proxies, + Network::ProxySettingsResolvedCallback /*proxy_resolution_completed*/) { + proxies.emplace_back(Network::ProxySettings("127.0.0.1", 8080)); + return Network::ProxyResolutionResult::RESULT_COMPLETED; + }); + EXPECT_CALL(decoder_callbacks_.stream_info_, filterState()); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, + filter_.decodeHeaders(default_request_headers_, false)); +} + +TEST_F(NetworkConfigurationFilterProxyResolverApiTest, ProxyWithHostConfigured) { + createCache(); + + std::vector proxy_settings; + EXPECT_CALL(getMockProxyResolver(), resolveProxy(_, proxy_settings, _)) + .WillOnce([](const std::string& /*target_url_string*/, + std::vector& proxies, + Network::ProxySettingsResolvedCallback /*proxy_resolution_completed*/) { + proxies.emplace_back(Network::ProxySettings("foo.com", 8080)); + return Network::ProxyResolutionResult::RESULT_COMPLETED; + }); + EXPECT_CALL(decoder_callbacks_.stream_info_, filterState()); + EXPECT_CALL(*dns_cache_, loadDnsCacheEntry_(Eq("foo.com"), 8080, false, _)) + .WillOnce( + Invoke([&](absl::string_view, uint16_t, bool, DnsCache::LoadDnsCacheEntryCallbacks&) { + return MockDnsCache::MockLoadDnsCacheEntryResult{ + DnsCache::LoadDnsCacheEntryStatus::InCache, nullptr, host_info_}; + })); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, + filter_.decodeHeaders(default_request_headers_, false)); +} + } // namespace } // namespace NetworkConfiguration } // namespace HttpFilters diff --git a/mobile/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc b/mobile/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc index 63b348c931ce..0fc1c915f3a4 100644 --- a/mobile/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc +++ b/mobile/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc @@ -69,7 +69,7 @@ class PlatformBridgeFilterTest : public testing::Test { )EOF"; std::string expected_state = fmt::format( - expected_state_template, name, error_response, request.iteration_state, + fmt::runtime(expected_state_template), name, error_response, request.iteration_state, request.on_headers_called, request.headers_forwarded, request.on_data_called, request.data_forwarded, request.on_trailers_called, request.trailers_forwarded, request.on_resume_called, request.pending_headers, request.buffer, request.pending_trailers, diff --git a/mobile/test/common/http/client_test.cc b/mobile/test/common/http/client_test.cc index beaf5f3ef936..7ba8ba41bf43 100644 --- a/mobile/test/common/http/client_test.cc +++ b/mobile/test/common/http/client_test.cc @@ -78,52 +78,45 @@ class ClientTest : public testing::TestWithParam { // Set up default bridge callbacks. Indivividual tests can override. bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + void* context) -> void { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; - return nullptr; }; bridge_callbacks_.on_headers = [](envoy_headers c_headers, bool end_stream, envoy_stream_intel, - void* context) -> void* { + void* context) -> void { ResponseHeaderMapPtr response_headers = toResponseHeaders(c_headers); callbacks_called* cc = static_cast(context); EXPECT_EQ(end_stream, cc->end_stream_with_headers_); EXPECT_EQ(response_headers->Status()->value().getStringView(), cc->expected_status_); cc->on_headers_calls++; - return nullptr; }; bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + void* context) -> void { callbacks_called* cc = static_cast(context); cc->on_error_calls++; - return nullptr; }; bridge_callbacks_.on_data = [](envoy_data c_data, bool, envoy_stream_intel, - void* context) -> void* { + void* context) -> void { callbacks_called* cc = static_cast(context); cc->on_data_calls++; cc->body_data_ += Data::Utility::copyToString(c_data); release_envoy_data(c_data); - return nullptr; }; bridge_callbacks_.on_cancel = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + void* context) -> void { callbacks_called* cc = static_cast(context); cc->on_cancel_calls++; - return nullptr; }; - bridge_callbacks_.on_send_window_available = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_send_window_available = [](envoy_stream_intel, void* context) -> void { callbacks_called* cc = static_cast(context); cc->on_send_window_available_calls++; - return nullptr; }; bridge_callbacks_.on_trailers = [](envoy_headers c_trailers, envoy_stream_intel, - void* context) -> void* { + void* context) -> void { ResponseHeaderMapPtr response_trailers = toResponseHeaders(c_trailers); EXPECT_TRUE(response_trailers.get() != nullptr); callbacks_called* cc = static_cast(context); cc->on_trailers_calls++; - return nullptr; }; helper_handle_ = test::SystemHelperPeer::replaceSystemHelper(); EXPECT_CALL(helper_handle_->mock_helper(), isCleartextPermitted(_)) @@ -212,13 +205,12 @@ TEST_P(ClientTest, BasicStreamData) { cc_.end_stream_with_headers_ = false; bridge_callbacks_.on_data = [](envoy_data c_data, bool end_stream, envoy_stream_intel, - void* context) -> void* { + void* context) -> void { EXPECT_TRUE(end_stream); EXPECT_EQ(Data::Utility::copyToString(c_data), "response body"); callbacks_called* cc = static_cast(context); cc->on_data_calls++; release_envoy_data(c_data); - return nullptr; }; // Build body data @@ -249,13 +241,12 @@ TEST_P(ClientTest, BasicStreamData) { TEST_P(ClientTest, BasicStreamTrailers) { bridge_callbacks_.on_trailers = [](envoy_headers c_trailers, envoy_stream_intel, - void* context) -> void* { + void* context) -> void { ResponseHeaderMapPtr response_trailers = toResponseHeaders(c_trailers); EXPECT_EQ(response_trailers->get(LowerCaseString("x-test-trailer"))[0]->value().getStringView(), "test_trailer"); callbacks_called* cc = static_cast(context); cc->on_trailers_calls++; - return nullptr; }; // Build a set of request trailers. @@ -419,19 +410,17 @@ TEST_P(ClientTest, MultipleStreams) { callbacks_called cc2 = {0, 0, 0, 0, 0, 0, 0, "200", true, ""}; bridge_callbacks_2.context = &cc2; bridge_callbacks_2.on_headers = [](envoy_headers c_headers, bool end_stream, envoy_stream_intel, - void* context) -> void* { + void* context) -> void { EXPECT_TRUE(end_stream); ResponseHeaderMapPtr response_headers = toResponseHeaders(c_headers); EXPECT_EQ(response_headers->Status()->value().getStringView(), "200"); bool* on_headers_called2 = static_cast(context); *on_headers_called2 = true; - return nullptr; }; bridge_callbacks_2.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + void* context) -> void { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; - return nullptr; }; envoy_headers c_headers2 = defaultRequestHeaders(); @@ -478,13 +467,12 @@ TEST_P(ClientTest, MultipleStreams) { TEST_P(ClientTest, EnvoyLocalError) { // Override the on_error default with some custom checks. bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + void* context) -> void { EXPECT_EQ(error.error_code, ENVOY_CONNECTION_FAILURE); EXPECT_EQ(error.attempt_count, 123); callbacks_called* cc = static_cast(context); cc->on_error_calls++; release_envoy_error(error); - return nullptr; }; // Create a stream, and set up request_decoder_ and response_encoder_ @@ -552,7 +540,7 @@ TEST_P(ClientTest, RemoteResetAfterStreamStart) { cc_.end_stream_with_headers_ = false; bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + void* context) -> void { EXPECT_EQ(error.error_code, ENVOY_STREAM_RESET); EXPECT_EQ(error.message.length, 0); EXPECT_EQ(error.attempt_count, 0); @@ -560,7 +548,6 @@ TEST_P(ClientTest, RemoteResetAfterStreamStart) { release_envoy_error(error); callbacks_called* cc = static_cast(context); cc->on_error_calls++; - return nullptr; }; // Create a stream, and set up request_decoder_ and response_encoder_ diff --git a/mobile/test/common/integration/BUILD b/mobile/test/common/integration/BUILD index 3b65dd43cbad..eb8f61380637 100644 --- a/mobile/test/common/integration/BUILD +++ b/mobile/test/common/integration/BUILD @@ -18,6 +18,14 @@ envoy_cc_test( # TODO(willengflow): Remove this once the sandboxNetwork=off works for ipv4 localhost addresses. "sandboxNetwork": "standard", }, + linkopts = select({ + "@envoy//bazel:apple": [ + # For the TestProxyResolutionApi test. + "-Wl,-framework,CoreFoundation", + "-Wl,-framework,CFNetwork", + ], + "//conditions:default": [], + }), repository = "@envoy", shard_count = 6, deps = [ diff --git a/mobile/test/common/integration/client_integration_test.cc b/mobile/test/common/integration/client_integration_test.cc index a3934d66eb3b..a9761afeb3c5 100644 --- a/mobile/test/common/integration/client_integration_test.cc +++ b/mobile/test/common/integration/client_integration_test.cc @@ -701,6 +701,17 @@ TEST_P(ClientIntegrationTest, CancelDuringResponse) { if (upstreamProtocol() != Http::CodecType::HTTP1) { ASSERT_TRUE(upstream_request_->waitForReset()); } + + // Close the HTTP3 connection and verify stats are dumped properly. + if (getCodecType() == Http::CodecType::HTTP3) { + ASSERT_TRUE(upstream_connection_->close()); + ASSERT_TRUE(upstream_connection_->waitForDisconnect()); + upstream_connection_.reset(); + ASSERT_TRUE( + waitForCounterGe("http3.upstream.tx.quic_connection_close_error_code_QUIC_NO_ERROR", 1)); + ASSERT_TRUE(waitForCounterGe( + "http3.upstream.tx.quic_reset_stream_error_code_QUIC_STREAM_CANCELLED", 1)); + } } TEST_P(ClientIntegrationTest, BasicCancelWithCompleteStream) { @@ -1020,5 +1031,13 @@ TEST_P(ClientIntegrationTest, TestStats) { } } +#if defined(__APPLE__) +TEST_P(ClientIntegrationTest, TestProxyResolutionApi) { + builder_.respectSystemProxySettings(true); + initialize(); + ASSERT_TRUE(Envoy::Api::External::retrieveApi("envoy_proxy_resolver") != nullptr); +} +#endif + } // namespace } // namespace Envoy diff --git a/mobile/test/common/internal_engine_test.cc b/mobile/test/common/internal_engine_test.cc index 57586f328e15..c31f8ffc72ae 100644 --- a/mobile/test/common/internal_engine_test.cc +++ b/mobile/test/common/internal_engine_test.cc @@ -1,27 +1,129 @@ +#include "source/common/common/assert.h" + +#include "test/common/http/common.h" +#include "test/common/mocks/common/mocks.h" + #include "absl/synchronization/notification.h" #include "gtest/gtest.h" #include "library/cc/engine_builder.h" +#include "library/common/api/external.h" +#include "library/common/bridge/utility.h" +#include "library/common/data/utility.h" +#include "library/common/http/header_utility.h" #include "library/common/internal_engine.h" namespace Envoy { +using testing::_; +using testing::HasSubstr; +using testing::Return; +using testing::ReturnRef; + +// This config is the minimal envoy mobile config that allows for running the engine. +const std::string MINIMAL_TEST_CONFIG = R"( +listener_manager: + name: envoy.listener_manager_impl.api + typed_config: + "@type": type.googleapis.com/envoy.config.listener.v3.ApiListenerManager +static_resources: + listeners: + - name: base_api_listener + address: + socket_address: { protocol: TCP, address: 0.0.0.0, port_value: 10000 } + api_listener: + api_listener: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.EnvoyMobileHttpConnectionManager + config: + stat_prefix: hcm + route_config: + name: api_router + virtual_hosts: + - name: api + include_attempt_count_in_response: true + domains: ["*"] + routes: + - match: { prefix: "/" } + route: + cluster_header: x-envoy-mobile-cluster + retry_policy: + retry_back_off: { base_interval: 0.25s, max_interval: 60s } + http_filters: + - name: envoy.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router +layered_runtime: + layers: + - name: static_layer_0 + static_layer: + overload: { global_downstream_max_connections: 50000 } +)"; + +const std::string BUFFERED_TEST_CONFIG = R"( +listener_manager: + name: envoy.listener_manager_impl.api + typed_config: + "@type": type.googleapis.com/envoy.config.listener.v3.ApiListenerManager +static_resources: + listeners: + - name: base_api_listener + address: + socket_address: { protocol: TCP, address: 0.0.0.0, port_value: 10000 } + api_listener: + api_listener: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.EnvoyMobileHttpConnectionManager + config: + stat_prefix: hcm + route_config: + name: api_router + virtual_hosts: + - name: api + include_attempt_count_in_response: true + domains: ["*"] + routes: + - match: { prefix: "/" } + direct_response: { status: 200 } + http_filters: + - name: buffer + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer + max_request_bytes: 65000 + - name: envoy.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router +layered_runtime: + layers: + - name: static_layer_0 + static_layer: + overload: { global_downstream_max_connections: 50000 } +)"; + +const std::string LEVEL_DEBUG = "debug"; + +struct EngineTestContext { + absl::Notification on_engine_running; + absl::Notification on_exit; + absl::Notification on_log; + absl::Notification on_logger_release; + absl::Notification on_event; +}; + // RAII wrapper for the engine, ensuring that we properly shut down the engine. If the engine // thread is not torn down, we end up with TSAN failures during shutdown due to a data race // between the main thread and the engine thread both writing to the // Envoy::Logger::current_log_context global. struct TestEngine { std::unique_ptr engine_; - envoy_engine_t handle() { return reinterpret_cast(engine_.get()); } + envoy_engine_t handle() const { return reinterpret_cast(engine_.get()); } TestEngine(envoy_engine_callbacks callbacks, const std::string& level) { engine_.reset(new Envoy::InternalEngine(callbacks, {}, {})); Platform::EngineBuilder builder; auto bootstrap = builder.generateBootstrap(); std::string yaml = Envoy::MessageUtil::getYamlStringFromMessage(*bootstrap); - engine_->run(yaml.c_str(), level.c_str()); + engine_->run(yaml, level); } - envoy_status_t terminate() { return engine_->terminate(); } - bool isTerminated() const { return engine_->isTerminated(); } + envoy_status_t terminate() const { return engine_->terminate(); } + [[nodiscard]] bool isTerminated() const { return engine_->isTerminated(); } ~TestEngine() { if (!engine_->isTerminated()) { @@ -30,27 +132,58 @@ struct TestEngine { } }; -class EngineTest : public testing::Test { +// Transform C map to C++ map. +[[maybe_unused]] static inline std::map toMap(envoy_map map) { + std::map new_map; + for (envoy_map_size_t i = 0; i < map.length; i++) { + envoy_map_entry header = map.entries[i]; + const auto key = Data::Utility::copyToString(header.key); + const auto value = Data::Utility::copyToString(header.value); + new_map.emplace(key, value); + } + + release_envoy_map(map); + return new_map; +} + +// Based on Http::Utility::toRequestHeaders() but only used for these tests. +Http::ResponseHeaderMapPtr toResponseHeaders(envoy_headers headers) { + Http::ResponseHeaderMapPtr transformed_headers = Http::ResponseHeaderMapImpl::create(); + for (envoy_map_size_t i = 0; i < headers.length; i++) { + transformed_headers->addCopy( + Http::LowerCaseString(Data::Utility::copyToString(headers.entries[i].key)), + Data::Utility::copyToString(headers.entries[i].value)); + } + // The C envoy_headers struct can be released now because the headers have been copied. + release_envoy_headers(headers); + return transformed_headers; +} + +class InternalEngineTest : public testing::Test { public: + void SetUp() override { + helper_handle_ = test::SystemHelperPeer::replaceSystemHelper(); + EXPECT_CALL(helper_handle_->mock_helper(), isCleartextPermitted(_)) + .WillRepeatedly(Return(true)); + } + std::unique_ptr engine_; -}; -typedef struct { - absl::Notification on_engine_running; - absl::Notification on_exit; -} engine_test_context; +private: + std::unique_ptr helper_handle_; +}; -TEST_F(EngineTest, EarlyExit) { +TEST_F(InternalEngineTest, EarlyExit) { const std::string level = "debug"; - engine_test_context test_context{}; + EngineTestContext test_context{}; envoy_engine_callbacks callbacks{[](void* context) -> void { auto* engine_running = - static_cast(context); + static_cast(context); engine_running->on_engine_running.Notify(); } /*on_engine_running*/, [](void* context) -> void { - auto* exit = static_cast(context); + auto* exit = static_cast(context); exit->on_exit.Notify(); } /*on_exit*/, &test_context /*context*/}; @@ -67,13 +200,13 @@ TEST_F(EngineTest, EarlyExit) { engine_.reset(); } -TEST_F(EngineTest, AccessEngineAfterInitialization) { +TEST_F(InternalEngineTest, AccessEngineAfterInitialization) { const std::string level = "debug"; - engine_test_context test_context{}; + EngineTestContext test_context{}; envoy_engine_callbacks callbacks{[](void* context) -> void { auto* engine_running = - static_cast(context); + static_cast(context); engine_running->on_engine_running.Notify(); } /*on_engine_running*/, [](void*) -> void {} /*on_exit*/, &test_context /*context*/}; @@ -95,4 +228,376 @@ TEST_F(EngineTest, AccessEngineAfterInitialization) { engine_.reset(); } +TEST_F(InternalEngineTest, RecordCounter) { + EngineTestContext test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* engine_running = + static_cast(context); + engine_running->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* exit = static_cast(context); + exit->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); + + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + EXPECT_EQ(ENVOY_SUCCESS, engine->recordCounterInc("counter", envoy_stats_notags, 1)); + + engine->terminate(); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + +TEST_F(InternalEngineTest, Logger) { + EngineTestContext test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + + envoy_logger logger{[](envoy_log_level, envoy_data data, const void* context) -> void { + auto* test_context = + static_cast(const_cast(context)); + release_envoy_data(data); + if (!test_context->on_log.HasBeenNotified()) { + test_context->on_log.Notify(); + } + } /* log */, + [](const void* context) -> void { + auto* test_context = + static_cast(const_cast(context)); + test_context->on_logger_release.Notify(); + } /* release */, + &test_context}; + std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, logger, {})); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + + ASSERT_TRUE(test_context.on_log.WaitForNotificationWithTimeout(absl::Seconds(3))); + + engine->terminate(); + engine.reset(); + ASSERT_TRUE(test_context.on_logger_release.WaitForNotificationWithTimeout(absl::Seconds(3))); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + +TEST_F(InternalEngineTest, EventTrackerRegistersDefaultAPI) { + EngineTestContext test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + + std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + + // A default event tracker is registered in external API registry. + const auto registered_event_tracker = + static_cast(Api::External::retrieveApi(envoy_event_tracker_api_name)); + EXPECT_TRUE(registered_event_tracker != nullptr); + EXPECT_TRUE(registered_event_tracker->track == nullptr); + EXPECT_TRUE(registered_event_tracker->context == nullptr); + + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + // Simulate a failed assertion by invoking a debug assertion failure + // record action. + // Verify that no crash if the assertion fails when no real event + // tracker is passed at engine's initialization time. + Assert::invokeDebugAssertionFailureRecordActionForAssertMacroUseOnly("foo_location"); + + engine->terminate(); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + +TEST_F(InternalEngineTest, EventTrackerRegistersAPI) { + EngineTestContext test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + envoy_event_tracker event_tracker{[](envoy_map map, const void* context) -> void { + const auto new_map = toMap(map); + if (new_map.count("foo") && new_map.at("foo") == "bar") { + auto* test_context = static_cast( + const_cast(context)); + test_context->on_event.Notify(); + } + } /*track*/, + &test_context /*context*/}; + + std::unique_ptr engine( + new Envoy::InternalEngine(engine_cbs, {}, event_tracker)); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + const auto registered_event_tracker = + static_cast(Api::External::retrieveApi(envoy_event_tracker_api_name)); + EXPECT_TRUE(registered_event_tracker != nullptr); + EXPECT_EQ(event_tracker.track, registered_event_tracker->track); + EXPECT_EQ(event_tracker.context, registered_event_tracker->context); + + event_tracker.track(Bridge::Utility::makeEnvoyMap({{"foo", "bar"}}), + registered_event_tracker->context); + + ASSERT_TRUE(test_context.on_event.WaitForNotificationWithTimeout(absl::Seconds(3))); + engine->terminate(); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + +TEST_F(InternalEngineTest, EventTrackerRegistersAssertionFailureRecordAction) { + EngineTestContext test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + + envoy_event_tracker event_tracker{ + [](envoy_map map, const void* context) -> void { + const auto new_map = toMap(map); + if (new_map.count("name") && new_map.at("name") == "assertion") { + EXPECT_EQ(new_map.at("location"), "foo_location"); + auto* test_context = static_cast(const_cast(context)); + test_context->on_event.Notify(); + } + } /*track*/, + &test_context /*context*/}; + + std::unique_ptr engine( + new Envoy::InternalEngine(engine_cbs, {}, event_tracker)); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + // Simulate a failed assertion by invoking a debug assertion failure + // record action. + // Verify that an envoy event is emitted when an event tracker is passed + // at engine's initialization time. + Assert::invokeDebugAssertionFailureRecordActionForAssertMacroUseOnly("foo_location"); + + ASSERT_TRUE(test_context.on_event.WaitForNotificationWithTimeout(absl::Seconds(3))); + engine->terminate(); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + +TEST_F(InternalEngineTest, EventTrackerRegistersEnvoyBugRecordAction) { + EngineTestContext test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* test_context = static_cast(context); + test_context->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + + envoy_event_tracker event_tracker{[](envoy_map map, const void* context) -> void { + const auto new_map = toMap(map); + if (new_map.count("name") && new_map.at("name") == "bug") { + EXPECT_EQ(new_map.at("location"), "foo_location"); + auto* test_context = static_cast( + const_cast(context)); + test_context->on_event.Notify(); + } + } /*track*/, + &test_context /*context*/}; + + std::unique_ptr engine( + new Envoy::InternalEngine(engine_cbs, {}, event_tracker)); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + // Simulate an envoy bug by invoking an Envoy bug failure + // record action. + // Verify that an envoy event is emitted when an event tracker is passed + // at engine's initialization time. + Assert::invokeEnvoyBugFailureRecordActionForEnvoyBugMacroUseOnly("foo_location"); + + ASSERT_TRUE(test_context.on_event.WaitForNotificationWithTimeout(absl::Seconds(3))); + engine->terminate(); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + +TEST_F(InternalEngineTest, BasicStream) { + const std::string level = "debug"; + EngineTestContext engine_cbs_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* engine_running = + static_cast(context); + engine_running->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* exit = static_cast(context); + exit->on_exit.Notify(); + } /*on_exit*/, + &engine_cbs_context /*context*/}; + std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); + engine->run(BUFFERED_TEST_CONFIG, level); + + ASSERT_TRUE( + engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); + + absl::Notification on_complete_notification; + envoy_http_callbacks stream_cbs{ + [](envoy_headers c_headers, bool end_stream, envoy_stream_intel, void*) -> void { + auto response_headers = toResponseHeaders(c_headers); + EXPECT_EQ(response_headers->Status()->value().getStringView(), "200"); + EXPECT_TRUE(end_stream); + } /* on_headers */, + nullptr /* on_data */, + nullptr /* on_metadata */, + nullptr /* on_trailers */, + nullptr /* on_error */, + [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void { + auto* on_complete_notification = static_cast(context); + on_complete_notification->Notify(); + } /* on_complete */, + nullptr /* on_cancel */, + nullptr /* on_send_window_available*/, + &on_complete_notification /* context */}; + Http::TestRequestHeaderMapImpl headers; + HttpTestUtility::addDefaultHeaders(headers); + envoy_headers c_headers = Http::Utility::toBridgeHeaders(headers); + + Buffer::OwnedImpl request_data = Buffer::OwnedImpl("request body"); + envoy_data c_data = Data::Utility::toBridgeData(request_data); + + Http::TestRequestTrailerMapImpl trailers; + envoy_headers c_trailers = Http::Utility::toBridgeHeaders(trailers); + + envoy_stream_t stream = engine->initStream(); + + engine->startStream(stream, stream_cbs, false); + + engine->sendHeaders(stream, c_headers, false); + engine->sendData(stream, c_data, false); + engine->sendTrailers(stream, c_trailers); + + ASSERT_TRUE(on_complete_notification.WaitForNotificationWithTimeout(absl::Seconds(10))); + + engine->terminate(); + + ASSERT_TRUE(engine_cbs_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(10))); +} + +TEST_F(InternalEngineTest, ResetStream) { + EngineTestContext engine_cbs_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* engine_running = + static_cast(context); + engine_running->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* exit = static_cast(context); + exit->on_exit.Notify(); + } /*on_exit*/, + &engine_cbs_context /*context*/}; + + // There is nothing functional about the config used to run the engine, as the created stream is + // immediately reset. + std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + + ASSERT_TRUE( + engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); + + absl::Notification on_cancel_notification; + envoy_http_callbacks stream_cbs{ + nullptr /* on_headers */, + nullptr /* on_data */, + nullptr /* on_metadata */, + nullptr /* on_trailers */, + nullptr /* on_error */, + nullptr /* on_complete */, + [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void { + auto* on_cancel_notification = static_cast(context); + on_cancel_notification->Notify(); + } /* on_cancel */, + nullptr /* on_send_window_available */, + &on_cancel_notification /* context */}; + + envoy_stream_t stream = engine->initStream(); + + engine->startStream(stream, stream_cbs, false); + + engine->cancelStream(stream); + + ASSERT_TRUE(on_cancel_notification.WaitForNotificationWithTimeout(absl::Seconds(10))); + + engine->terminate(); + + ASSERT_TRUE(engine_cbs_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(10))); +} + +TEST_F(InternalEngineTest, RegisterPlatformApi) { + EngineTestContext engine_cbs_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* engine_running = + static_cast(context); + engine_running->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* exit = static_cast(context); + exit->on_exit.Notify(); + } /*on_exit*/, + &engine_cbs_context /*context*/}; + + // Using the minimal envoy mobile config that allows for running the engine. + std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + + ASSERT_TRUE( + engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); + + uint64_t fake_api; + Envoy::Api::External::registerApi("api", &fake_api); + + engine->terminate(); + + ASSERT_TRUE(engine_cbs_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(10))); +} + +TEST_F(InternalEngineTest, ResetConnectivityState) { + EngineTestContext test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* engine_running = + static_cast(context); + engine_running->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* exit = static_cast(context); + exit->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); + engine->run(MINIMAL_TEST_CONFIG, LEVEL_DEBUG); + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + + ASSERT_EQ(ENVOY_SUCCESS, engine->resetConnectivityState()); + + engine->terminate(); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + } // namespace Envoy diff --git a/mobile/test/common/main_interface_test.cc b/mobile/test/common/main_interface_test.cc deleted file mode 100644 index 62d002cd341d..000000000000 --- a/mobile/test/common/main_interface_test.cc +++ /dev/null @@ -1,534 +0,0 @@ -#include "source/common/common/assert.h" - -#include "test/common/http/common.h" -#include "test/common/mocks/common/mocks.h" - -#include "absl/synchronization/notification.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "library/common/api/external.h" -#include "library/common/bridge/utility.h" -#include "library/common/data/utility.h" -#include "library/common/http/header_utility.h" -#include "library/common/internal_engine.h" - -using testing::_; -using testing::HasSubstr; -using testing::Return; -using testing::ReturnRef; - -namespace Envoy { - -typedef struct { - absl::Notification on_engine_running; - absl::Notification on_exit; - absl::Notification on_log; - absl::Notification on_logger_release; - absl::Notification on_event; -} engine_test_context; - -// This config is the minimal envoy mobile config that allows for running the engine. -const std::string MINIMAL_TEST_CONFIG = R"( -listener_manager: - name: envoy.listener_manager_impl.api - typed_config: - "@type": type.googleapis.com/envoy.config.listener.v3.ApiListenerManager -static_resources: - listeners: - - name: base_api_listener - address: - socket_address: { protocol: TCP, address: 0.0.0.0, port_value: 10000 } - api_listener: - api_listener: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.EnvoyMobileHttpConnectionManager - config: - stat_prefix: hcm - route_config: - name: api_router - virtual_hosts: - - name: api - include_attempt_count_in_response: true - domains: ["*"] - routes: - - match: { prefix: "/" } - route: - cluster_header: x-envoy-mobile-cluster - retry_policy: - retry_back_off: { base_interval: 0.25s, max_interval: 60s } - http_filters: - - name: envoy.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router -layered_runtime: - layers: - - name: static_layer_0 - static_layer: - overload: { global_downstream_max_connections: 50000 } -)"; - -const std::string BUFFERED_TEST_CONFIG = R"( -listener_manager: - name: envoy.listener_manager_impl.api - typed_config: - "@type": type.googleapis.com/envoy.config.listener.v3.ApiListenerManager -static_resources: - listeners: - - name: base_api_listener - address: - socket_address: { protocol: TCP, address: 0.0.0.0, port_value: 10000 } - api_listener: - api_listener: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.EnvoyMobileHttpConnectionManager - config: - stat_prefix: hcm - route_config: - name: api_router - virtual_hosts: - - name: api - include_attempt_count_in_response: true - domains: ["*"] - routes: - - match: { prefix: "/" } - direct_response: { status: 200 } - http_filters: - - name: buffer - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer - max_request_bytes: 65000 - - name: envoy.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router -layered_runtime: - layers: - - name: static_layer_0 - static_layer: - overload: { global_downstream_max_connections: 50000 } -)"; - -const std::string LEVEL_DEBUG = "debug"; - -// Transform C map to C++ map. -[[maybe_unused]] static inline std::map toMap(envoy_map map) { - std::map new_map; - for (envoy_map_size_t i = 0; i < map.length; i++) { - envoy_map_entry header = map.entries[i]; - const auto key = Data::Utility::copyToString(header.key); - const auto value = Data::Utility::copyToString(header.value); - new_map.insert({std::move(key), std::move(value)}); - } - - release_envoy_map(map); - return new_map; -} - -// Based on Http::Utility::toRequestHeaders() but only used for these tests. -Http::ResponseHeaderMapPtr toResponseHeaders(envoy_headers headers) { - Http::ResponseHeaderMapPtr transformed_headers = Http::ResponseHeaderMapImpl::create(); - for (envoy_map_size_t i = 0; i < headers.length; i++) { - transformed_headers->addCopy( - Http::LowerCaseString(Data::Utility::copyToString(headers.entries[i].key)), - Data::Utility::copyToString(headers.entries[i].value)); - } - // The C envoy_headers struct can be released now because the headers have been copied. - release_envoy_headers(headers); - return transformed_headers; -} - -class MainInterfaceTest : public testing::Test { -public: - void SetUp() override { - helper_handle_ = test::SystemHelperPeer::replaceSystemHelper(); - EXPECT_CALL(helper_handle_->mock_helper(), isCleartextPermitted(_)) - .WillRepeatedly(Return(true)); - } - -protected: - std::unique_ptr helper_handle_; -}; - -TEST_F(MainInterfaceTest, BasicStream) { - const std::string level = "debug"; - engine_test_context engine_cbs_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* engine_running = - static_cast(context); - engine_running->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* exit = static_cast(context); - exit->on_exit.Notify(); - } /*on_exit*/, - &engine_cbs_context /*context*/}; - std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); - engine->run(BUFFERED_TEST_CONFIG.c_str(), level.c_str()); - - ASSERT_TRUE( - engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); - - absl::Notification on_complete_notification; - envoy_http_callbacks stream_cbs{ - [](envoy_headers c_headers, bool end_stream, envoy_stream_intel, void*) -> void* { - auto response_headers = toResponseHeaders(c_headers); - EXPECT_EQ(response_headers->Status()->value().getStringView(), "200"); - EXPECT_TRUE(end_stream); - return nullptr; - } /* on_headers */, - nullptr /* on_data */, - nullptr /* on_metadata */, - nullptr /* on_trailers */, - nullptr /* on_error */, - [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { - auto* on_complete_notification = static_cast(context); - on_complete_notification->Notify(); - return nullptr; - } /* on_complete */, - nullptr /* on_cancel */, - nullptr /* on_send_window_available*/, - &on_complete_notification /* context */}; - Http::TestRequestHeaderMapImpl headers; - HttpTestUtility::addDefaultHeaders(headers); - envoy_headers c_headers = Http::Utility::toBridgeHeaders(headers); - - Buffer::OwnedImpl request_data = Buffer::OwnedImpl("request body"); - envoy_data c_data = Data::Utility::toBridgeData(request_data); - - Http::TestRequestTrailerMapImpl trailers; - envoy_headers c_trailers = Http::Utility::toBridgeHeaders(trailers); - - envoy_stream_t stream = engine->initStream(); - - engine->startStream(stream, stream_cbs, false); - - engine->sendHeaders(stream, c_headers, false); - engine->sendData(stream, c_data, false); - engine->sendTrailers(stream, c_trailers); - - ASSERT_TRUE(on_complete_notification.WaitForNotificationWithTimeout(absl::Seconds(10))); - - engine->terminate(); - - ASSERT_TRUE(engine_cbs_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(10))); -} - -TEST_F(MainInterfaceTest, ResetStream) { - engine_test_context engine_cbs_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* engine_running = - static_cast(context); - engine_running->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* exit = static_cast(context); - exit->on_exit.Notify(); - } /*on_exit*/, - &engine_cbs_context /*context*/}; - - // There is nothing functional about the config used to run the engine, as the created stream is - // immediately reset. - std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - - ASSERT_TRUE( - engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); - - absl::Notification on_cancel_notification; - envoy_http_callbacks stream_cbs{ - nullptr /* on_headers */, - nullptr /* on_data */, - nullptr /* on_metadata */, - nullptr /* on_trailers */, - nullptr /* on_error */, - nullptr /* on_complete */, - [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { - auto* on_cancel_notification = static_cast(context); - on_cancel_notification->Notify(); - return nullptr; - } /* on_cancel */, - nullptr /* on_send_window_available */, - &on_cancel_notification /* context */}; - - envoy_stream_t stream = engine->initStream(); - - engine->startStream(stream, stream_cbs, false); - - engine->cancelStream(stream); - - ASSERT_TRUE(on_cancel_notification.WaitForNotificationWithTimeout(absl::Seconds(10))); - - engine->terminate(); - - ASSERT_TRUE(engine_cbs_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(10))); -} - -TEST_F(MainInterfaceTest, RegisterPlatformApi) { - engine_test_context engine_cbs_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* engine_running = - static_cast(context); - engine_running->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* exit = static_cast(context); - exit->on_exit.Notify(); - } /*on_exit*/, - &engine_cbs_context /*context*/}; - - // Using the minimal envoy mobile config that allows for running the engine. - std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - - ASSERT_TRUE( - engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); - - uint64_t fake_api; - Envoy::Api::External::registerApi("api", &fake_api); - - engine->terminate(); - - ASSERT_TRUE(engine_cbs_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(10))); -} - -TEST(EngineTest, RecordCounter) { - engine_test_context test_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* engine_running = - static_cast(context); - engine_running->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* exit = static_cast(context); - exit->on_exit.Notify(); - } /*on_exit*/, - &test_context /*context*/}; - std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); - - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); - EXPECT_EQ(ENVOY_SUCCESS, engine->recordCounterInc("counter", envoy_stats_notags, 1)); - - engine->terminate(); - ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); -} - -TEST(EngineTest, Logger) { - engine_test_context test_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_exit.Notify(); - } /*on_exit*/, - &test_context /*context*/}; - - envoy_logger logger{[](envoy_log_level, envoy_data data, const void* context) -> void { - auto* test_context = - static_cast(const_cast(context)); - release_envoy_data(data); - if (!test_context->on_log.HasBeenNotified()) { - test_context->on_log.Notify(); - } - } /* log */, - [](const void* context) -> void { - auto* test_context = - static_cast(const_cast(context)); - test_context->on_logger_release.Notify(); - } /* release */, - &test_context}; - std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, logger, {})); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); - - ASSERT_TRUE(test_context.on_log.WaitForNotificationWithTimeout(absl::Seconds(3))); - - engine->terminate(); - engine.reset(); - ASSERT_TRUE(test_context.on_logger_release.WaitForNotificationWithTimeout(absl::Seconds(3))); - ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); -} - -TEST(EngineTest, EventTrackerRegistersDefaultAPI) { - engine_test_context test_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_exit.Notify(); - } /*on_exit*/, - &test_context /*context*/}; - - std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - - // A default event tracker is registered in external API registry. - const auto registered_event_tracker = - static_cast(Api::External::retrieveApi(envoy_event_tracker_api_name)); - EXPECT_TRUE(registered_event_tracker != nullptr); - EXPECT_TRUE(registered_event_tracker->track == nullptr); - EXPECT_TRUE(registered_event_tracker->context == nullptr); - - ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); - // Simulate a failed assertion by invoking a debug assertion failure - // record action. - // Verify that no crash if the assertion fails when no real event - // tracker is passed at engine's initialization time. - Assert::invokeDebugAssertionFailureRecordActionForAssertMacroUseOnly("foo_location"); - - engine->terminate(); - ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); -} - -TEST(EngineTest, EventTrackerRegistersAPI) { - engine_test_context test_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_exit.Notify(); - } /*on_exit*/, - &test_context /*context*/}; - envoy_event_tracker event_tracker{[](envoy_map map, const void* context) -> void { - const auto new_map = toMap(map); - if (new_map.count("foo") && new_map.at("foo") == "bar") { - auto* test_context = static_cast( - const_cast(context)); - test_context->on_event.Notify(); - } - } /*track*/, - &test_context /*context*/}; - - std::unique_ptr engine( - new Envoy::InternalEngine(engine_cbs, {}, event_tracker)); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - - ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); - const auto registered_event_tracker = - static_cast(Api::External::retrieveApi(envoy_event_tracker_api_name)); - EXPECT_TRUE(registered_event_tracker != nullptr); - EXPECT_EQ(event_tracker.track, registered_event_tracker->track); - EXPECT_EQ(event_tracker.context, registered_event_tracker->context); - - event_tracker.track(Bridge::Utility::makeEnvoyMap({{"foo", "bar"}}), - registered_event_tracker->context); - - ASSERT_TRUE(test_context.on_event.WaitForNotificationWithTimeout(absl::Seconds(3))); - engine->terminate(); - ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); -} - -TEST(EngineTest, EventTrackerRegistersAssertionFailureRecordAction) { - engine_test_context test_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_exit.Notify(); - } /*on_exit*/, - &test_context /*context*/}; - - envoy_event_tracker event_tracker{ - [](envoy_map map, const void* context) -> void { - const auto new_map = toMap(map); - if (new_map.count("name") && new_map.at("name") == "assertion") { - EXPECT_EQ(new_map.at("location"), "foo_location"); - auto* test_context = static_cast(const_cast(context)); - test_context->on_event.Notify(); - } - } /*track*/, - &test_context /*context*/}; - - std::unique_ptr engine( - new Envoy::InternalEngine(engine_cbs, {}, event_tracker)); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - - ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); - // Simulate a failed assertion by invoking a debug assertion failure - // record action. - // Verify that an envoy event is emitted when an event tracker is passed - // at engine's initialization time. - Assert::invokeDebugAssertionFailureRecordActionForAssertMacroUseOnly("foo_location"); - - ASSERT_TRUE(test_context.on_event.WaitForNotificationWithTimeout(absl::Seconds(3))); - engine->terminate(); - ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); -} - -TEST(EngineTest, EventTrackerRegistersEnvoyBugRecordAction) { - engine_test_context test_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* test_context = - static_cast(context); - test_context->on_exit.Notify(); - } /*on_exit*/, - &test_context /*context*/}; - - envoy_event_tracker event_tracker{[](envoy_map map, const void* context) -> void { - const auto new_map = toMap(map); - if (new_map.count("name") && new_map.at("name") == "bug") { - EXPECT_EQ(new_map.at("location"), "foo_location"); - auto* test_context = static_cast( - const_cast(context)); - test_context->on_event.Notify(); - } - } /*track*/, - &test_context /*context*/}; - - std::unique_ptr engine( - new Envoy::InternalEngine(engine_cbs, {}, event_tracker)); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - - ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); - // Simulate an envoy bug by invoking an Envoy bug failure - // record action. - // Verify that an envoy event is emitted when an event tracker is passed - // at engine's initialization time. - Assert::invokeEnvoyBugFailureRecordActionForEnvoyBugMacroUseOnly("foo_location"); - - ASSERT_TRUE(test_context.on_event.WaitForNotificationWithTimeout(absl::Seconds(3))); - engine->terminate(); - ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); -} - -TEST_F(MainInterfaceTest, ResetConnectivityState) { - engine_test_context test_context{}; - envoy_engine_callbacks engine_cbs{[](void* context) -> void { - auto* engine_running = - static_cast(context); - engine_running->on_engine_running.Notify(); - } /*on_engine_running*/, - [](void* context) -> void { - auto* exit = static_cast(context); - exit->on_exit.Notify(); - } /*on_exit*/, - &test_context /*context*/}; - std::unique_ptr engine(new Envoy::InternalEngine(engine_cbs, {}, {})); - engine->run(MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); - ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); - - ASSERT_EQ(ENVOY_SUCCESS, engine->resetConnectivityState()); - - engine->terminate(); - ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); -} - -} // namespace Envoy diff --git a/mobile/test/common/network/proxy_settings_test.cc b/mobile/test/common/network/proxy_settings_test.cc index db815c633551..bf2f538bd2db 100644 --- a/mobile/test/common/network/proxy_settings_test.cc +++ b/mobile/test/common/network/proxy_settings_test.cc @@ -1,3 +1,5 @@ +#include + #include "gtest/gtest.h" #include "library/common/network/proxy_settings.h" @@ -49,5 +51,39 @@ TEST_F(ProxySettingsTest, Hostname) { EXPECT_EQ(ProxySettings("foo.com", 80).asString(), "foo.com:80"); } +TEST_F(ProxySettingsTest, Direct) { + const ProxySettings direct = ProxySettings::direct(); + EXPECT_TRUE(direct.isDirect()); + EXPECT_EQ(direct.hostname(), ""); + EXPECT_EQ(direct.port(), 0); + EXPECT_EQ(direct.address(), nullptr); + EXPECT_EQ(direct.asString(), "no_proxy_configured"); + + const ProxySettings non_direct = ProxySettings("foo.com", 80); + EXPECT_FALSE(non_direct.isDirect()); +} + +TEST_F(ProxySettingsTest, Create) { + std::vector settings_list; + + // Empty list, so nullptr is returned. + EXPECT_EQ(ProxySettings::create(settings_list), nullptr); + + // 2nd setting in the list is non-direct, so it should be chosen to create the shared_ptr from. + settings_list.emplace_back(ProxySettings::direct()); + settings_list.emplace_back(ProxySettings("foo.com", 80)); + settings_list.emplace_back(ProxySettings("bar.com", 8080)); + ProxySettingsConstSharedPtr settings = ProxySettings::create(settings_list); + EXPECT_EQ(settings->hostname(), "foo.com"); + EXPECT_EQ(settings->port(), 80); + EXPECT_FALSE(settings->isDirect()); + + // All ProxySettings in the list are direct, so nullptr is returned. + settings_list.clear(); + settings_list.emplace_back(ProxySettings::direct()); + settings_list.emplace_back(ProxySettings::direct()); + EXPECT_EQ(ProxySettings::create(settings_list), nullptr); +} + } // namespace Network } // namespace Envoy diff --git a/mobile/test/common/proxy/BUILD b/mobile/test/common/proxy/BUILD new file mode 100644 index 000000000000..6c05ec3608b8 --- /dev/null +++ b/mobile/test/common/proxy/BUILD @@ -0,0 +1,38 @@ +load("@envoy//bazel:envoy_build_system.bzl", "envoy_cc_test_library", "envoy_mobile_package") + +licenses(["notice"]) # Apache 2 + +envoy_mobile_package() + +envoy_cc_test_library( + name = "test_apple_proxy_settings_lib", + srcs = select({ + "@envoy//bazel:apple": [ + "test_apple_api_registration.cc", + "test_apple_pac_proxy_resolver.cc", + "test_apple_proxy_resolver.cc", + "test_apple_proxy_settings_monitor.cc", + ], + "//conditions:default": [], + }), + hdrs = select({ + "@envoy//bazel:apple": [ + "test_apple_api_registration.h", + "test_apple_pac_proxy_resolver.h", + "test_apple_proxy_resolver.h", + "test_apple_proxy_settings_monitor.h", + ], + "//conditions:default": [], + }), + repository = "@envoy", + deps = select({ + "@envoy//bazel:apple": [ + "//library/common/api:external_api_lib", + "//library/common/network:apple_proxy_resolution_lib", + "//library/common/network:proxy_api_lib", + "//library/common/network:proxy_settings_lib", + "//library/common/types:c_types_lib", + ], + "//conditions:default": [], + }), +) diff --git a/mobile/test/common/proxy/test_apple_api_registration.cc b/mobile/test/common/proxy/test_apple_api_registration.cc new file mode 100644 index 000000000000..5a8ea1ff6f9c --- /dev/null +++ b/mobile/test/common/proxy/test_apple_api_registration.cc @@ -0,0 +1,46 @@ +#include "test/common/proxy/test_apple_api_registration.h" + +#include "test/common/proxy/test_apple_pac_proxy_resolver.h" +#include "test/common/proxy/test_apple_proxy_resolver.h" +#include "test/common/proxy/test_apple_proxy_settings_monitor.h" + +#include "library/common/api/external.h" +#include "library/common/network/apple_proxy_resolution.h" +#include "library/common/network/apple_proxy_resolver.h" +#include "library/common/network/proxy_api.h" +#include "library/common/network/proxy_resolver_interface.h" +#include "library/common/types/c_types.h" + +// NOLINT(namespace-envoy) + +void registerTestAppleProxyResolver(absl::string_view host, int port, const bool use_pac_resolver) { + // Fetch the existing registered envoy_proxy_resolver API, if it exists. + void* existing_proxy_resolver = + Envoy::Api::External::retrieveApi("envoy_proxy_resolver", /*allow_absent=*/true); + if (existing_proxy_resolver != nullptr) { + std::unique_ptr wrapped( + static_cast(existing_proxy_resolver)); + // Delete the existing ProxyResolverApi. + wrapped.reset(); + } + + // Create a new test proxy resolver. + auto test_resolver = std::make_unique(); + // Create a TestAppleSystemProxySettingsMonitor and set the test resolver to use it. + test_resolver->setSettingsMonitorForTest( + std::make_unique( + std::string(host), port, use_pac_resolver, test_resolver->proxySettingsUpdater())); + if (use_pac_resolver) { + // Create a TestApplePacProxyResolver and set the test resolver to use it. + test_resolver->setPacResolverForTest( + std::make_unique(std::string(host), port)); + } + // Start the resolver, as we do when registering the envoy_proxy_resolver API. + test_resolver->start(); + // Create a new test ProxyResolverApi. + auto proxy_resolver = std::make_unique(); + // Set the API to use the test AppleProxyResolver. + proxy_resolver->resolver = std::move(test_resolver); + // Register the new test ProxyResolverApi. The Api registry takes over the pointer. + Envoy::Api::External::registerApi("envoy_proxy_resolver", proxy_resolver.release()); +} diff --git a/mobile/test/common/proxy/test_apple_api_registration.h b/mobile/test/common/proxy/test_apple_api_registration.h new file mode 100644 index 000000000000..4edc2f2cafa9 --- /dev/null +++ b/mobile/test/common/proxy/test_apple_api_registration.h @@ -0,0 +1,23 @@ +#pragma once + +#include "absl/strings/string_view.h" + +// NOLINT(namespace-envoy) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Registers the test Apple proxy resolver. If the `envoy_proxy_resolver` API already exists, it + * gets removed and deleted first. The test proxy resolver then gets registered as the + * `envoy_proxy_resolver` API. + * + * @param host The hostname of the test proxy. + * @param port The port of the test proxy. + */ +void registerTestAppleProxyResolver(absl::string_view host, int port, bool use_pac_resolver); + +#ifdef __cplusplus +} +#endif diff --git a/mobile/test/common/proxy/test_apple_pac_proxy_resolver.cc b/mobile/test/common/proxy/test_apple_pac_proxy_resolver.cc new file mode 100644 index 000000000000..9c46434ce4c7 --- /dev/null +++ b/mobile/test/common/proxy/test_apple_pac_proxy_resolver.cc @@ -0,0 +1,92 @@ +#include "test/common/proxy/test_apple_pac_proxy_resolver.h" + +#include +#include + +#include + +#include "library/common/network/proxy_settings.h" + +namespace Envoy { +namespace Network { + +namespace { + +// Contains state that is passed into the run loop callback. +struct RunLoopSourceInfo { + RunLoopSourceInfo(CFStreamClientContext* _context, const std::string& _host, const int _port) + : context(_context), host(_host), port(_port) {} + + CFStreamClientContext* context; + const std::string& host; + const int port; +}; + +void runLoopCallback(void* info) { + // Wrap in unique_ptr so we release the memory at the end of the function execution. + std::unique_ptr run_loop_info(static_cast(info)); + + const void* keys[] = {kCFProxyTypeKey, kCFProxyHostNameKey, kCFProxyPortNumberKey}; + const void* values[] = { + kCFProxyTypeHTTPS, + CFStringCreateWithCString(kCFAllocatorDefault, run_loop_info->host.c_str(), + kCFStringEncodingUTF8), + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &run_loop_info->port)}; + const int num_pairs = sizeof(keys) / sizeof(CFStringRef); + + CFDictionaryRef settings_dict = CFDictionaryCreate( + kCFAllocatorDefault, static_cast(keys), static_cast(values), + num_pairs, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + const void* objects[] = {settings_dict}; + CFArrayRef proxies = CFArrayCreate(kCFAllocatorDefault, static_cast(objects), + /*numValues=*/1, &kCFTypeArrayCallBacks); + + // Wrap in unique_ptr so we release the memory at the end of the function execution. + std::unique_ptr client_context(run_loop_info->context); + + // Invoke the proxy resolution callback that the ApplePacProxyResolver invokes. + Network::proxyAutoConfigurationResultCallback(/*ptr=*/client_context->info, proxies, + /*cf_error=*/nullptr); + + // Release the memory allocated above. + CFRelease(proxies); + CFRelease(settings_dict); + // We don't want to release the first value, since it's a global constant. + for (int i = 1; i < num_pairs; ++i) { + CFRelease(values[i]); + } +} + +} // namespace + +TestApplePacProxyResolver::TestApplePacProxyResolver(const std::string& host, const int port) + : host_(host), port_(port) {} + +CFRunLoopSourceRef TestApplePacProxyResolver::createPacUrlResolverSource( + CFURLRef /*cf_proxy_autoconfiguration_file_url*/, CFURLRef /*cf_target_url*/, + CFStreamClientContext* context) { + auto run_loop_info = std::make_unique(context, host_, port_); + run_loop_context_ = std::make_unique( + CFRunLoopSourceContext{/*version=*/0, + /*info=*/run_loop_info.release(), + /*retain=*/nullptr, + /*release=*/nullptr, + /*copyDescription=*/nullptr, + /*equal=*/nullptr, + /*hash=*/nullptr, + /*schedule=*/nullptr, + /*cancel=*/nullptr, + /*perform=*/runLoopCallback}); + + auto run_loop_source = + CFRunLoopSourceCreate(kCFAllocatorDefault, /*order=*/0, run_loop_context_.get()); + // There are no network events that get triggered to notify this test run loop source that + // it should process a result, so we have to signal it manually. + CFRunLoopSourceSignal(run_loop_source); + + return run_loop_source; +} + +} // namespace Network +} // namespace Envoy diff --git a/mobile/test/common/proxy/test_apple_pac_proxy_resolver.h b/mobile/test/common/proxy/test_apple_pac_proxy_resolver.h new file mode 100644 index 000000000000..d1985c967c03 --- /dev/null +++ b/mobile/test/common/proxy/test_apple_pac_proxy_resolver.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "library/common/network/apple_pac_proxy_resolver.h" + +namespace Envoy { +namespace Network { + +class TestApplePacProxyResolver : public Network::ApplePacProxyResolver { +public: + TestApplePacProxyResolver(const std::string& host, const int port); + virtual ~TestApplePacProxyResolver() = default; + +protected: + CFRunLoopSourceRef createPacUrlResolverSource(CFURLRef cf_proxy_autoconfiguration_file_url, + CFURLRef cf_target_url, + CFStreamClientContext* context) override; + + const std::string host_; + const int port_; + std::unique_ptr run_loop_context_; +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/test/common/proxy/test_apple_proxy_resolver.cc b/mobile/test/common/proxy/test_apple_proxy_resolver.cc new file mode 100644 index 000000000000..283518fef8bc --- /dev/null +++ b/mobile/test/common/proxy/test_apple_proxy_resolver.cc @@ -0,0 +1,17 @@ +#include "test/common/proxy/test_apple_proxy_resolver.h" + +namespace Envoy { +namespace Network { + +void TestAppleProxyResolver::setSettingsMonitorForTest( + std::unique_ptr&& monitor) { + proxy_settings_monitor_ = std::move(monitor); +} + +void TestAppleProxyResolver::setPacResolverForTest( + std::unique_ptr&& resolver) { + pac_proxy_resolver_ = std::move(resolver); +} + +} // namespace Network +} // namespace Envoy diff --git a/mobile/test/common/proxy/test_apple_proxy_resolver.h b/mobile/test/common/proxy/test_apple_proxy_resolver.h new file mode 100644 index 000000000000..f5543685cb2a --- /dev/null +++ b/mobile/test/common/proxy/test_apple_proxy_resolver.h @@ -0,0 +1,27 @@ +#pragma once + +#include "library/common/network/apple_pac_proxy_resolver.h" +#include "library/common/network/apple_proxy_resolver.h" +#include "library/common/network/apple_system_proxy_settings_monitor.h" + +namespace Envoy { +namespace Network { + +class TestAppleProxyResolver : public Network::AppleProxyResolver { +public: + /** + * Resets the proxy settings monitor to the supplied monitor instance. + * For tests only. + */ + void + setSettingsMonitorForTest(std::unique_ptr&& monitor); + + /** + * Resets the PAC URL resolver to the supplied instance. + * For tests only. + */ + void setPacResolverForTest(std::unique_ptr&& resolver); +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/test/common/proxy/test_apple_proxy_settings_monitor.cc b/mobile/test/common/proxy/test_apple_proxy_settings_monitor.cc new file mode 100644 index 000000000000..7c6ff214dc9d --- /dev/null +++ b/mobile/test/common/proxy/test_apple_proxy_settings_monitor.cc @@ -0,0 +1,68 @@ +#include "test/common/proxy/test_apple_proxy_settings_monitor.h" + +#include +#include + +namespace Envoy { +namespace Network { + +TestAppleSystemProxySettingsMonitor::TestAppleSystemProxySettingsMonitor( + const std::string& host, const int port, const bool use_pac_resolver, + Network::SystemProxySettingsReadCallback proxy_settings_read_callback) + : AppleSystemProxySettingsMonitor(std::move(proxy_settings_read_callback)), host_(host), + port_(port), use_pac_resolver_(use_pac_resolver) {} + +CFDictionaryRef TestAppleSystemProxySettingsMonitor::getSystemProxySettings() const { + if (use_pac_resolver_) { + return getSystemProxySettingsWithPac(); + } + return getSystemProxySettingsWithoutPac(); +} + +CFDictionaryRef TestAppleSystemProxySettingsMonitor::getSystemProxySettingsWithoutPac() const { + const void* keys[] = {kCFNetworkProxiesHTTPEnable, kCFNetworkProxiesHTTPProxy, + kCFNetworkProxiesHTTPPort}; + + const void* values[] = { + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one_), + CFStringCreateWithCString(kCFAllocatorDefault, host_.c_str(), kCFStringEncodingUTF8), + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &port_)}; + + int num_pairs = sizeof(keys) / sizeof(CFStringRef); + + CFDictionaryRef settings_dict = CFDictionaryCreate( + kCFAllocatorDefault, static_cast(keys), static_cast(values), + num_pairs, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + for (int i = 0; i < num_pairs; ++i) { + CFRelease(values[i]); + } + return settings_dict; +} + +CFDictionaryRef TestAppleSystemProxySettingsMonitor::getSystemProxySettingsWithPac() const { + const void* keys[] = {kCFNetworkProxiesProxyAutoConfigEnable, + kCFNetworkProxiesProxyAutoConfigURLString}; + + const void* values[] = { + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one_), + // The PAC file URL doesn't matter, we don't use it in the tests; we just need it to exist to + // exercise the PAC file URL code path in the tests. + CFStringCreateWithCString(kCFAllocatorDefault, + "http://randomproxysettingsserver.com/random.pac", + kCFStringEncodingUTF8)}; + + int num_pairs = sizeof(keys) / sizeof(CFStringRef); + + CFDictionaryRef settings_dict = CFDictionaryCreate( + kCFAllocatorDefault, static_cast(keys), static_cast(values), + num_pairs, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + for (int i = 0; i < num_pairs; ++i) { + CFRelease(values[i]); + } + return settings_dict; +} + +} // namespace Network +} // namespace Envoy diff --git a/mobile/test/common/proxy/test_apple_proxy_settings_monitor.h b/mobile/test/common/proxy/test_apple_proxy_settings_monitor.h new file mode 100644 index 000000000000..1255b6c609df --- /dev/null +++ b/mobile/test/common/proxy/test_apple_proxy_settings_monitor.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "library/common/network/apple_system_proxy_settings_monitor.h" +#include "library/common/network/proxy_settings.h" + +namespace Envoy { +namespace Network { + +class TestAppleSystemProxySettingsMonitor : public Network::AppleSystemProxySettingsMonitor { +public: + TestAppleSystemProxySettingsMonitor( + const std::string& host, const int port, bool use_pac_resolver, + Network::SystemProxySettingsReadCallback proxy_settings_read_callback); + virtual ~TestAppleSystemProxySettingsMonitor() = default; + +protected: + CFDictionaryRef getSystemProxySettings() const override; + // Gets mock system proxy settings without a PAC file. + CFDictionaryRef getSystemProxySettingsWithoutPac() const; + // Gets mock system proxy settings with a PAC file. + CFDictionaryRef getSystemProxySettingsWithPac() const; + + const std::string host_; + const int port_; + const bool use_pac_resolver_; + // Used to pass into the Apple APIs to represent the number 1. We pass in pointers to the Apple + // APIs, so the value needs to outline the passed-in pointer. + const int one_{1}; +}; + +} // namespace Network +} // namespace Envoy diff --git a/mobile/test/objective-c/BUILD b/mobile/test/objective-c/BUILD index 1d977756c4ca..2460ad8698cd 100644 --- a/mobile/test/objective-c/BUILD +++ b/mobile/test/objective-c/BUILD @@ -11,7 +11,6 @@ envoy_mobile_objc_test( "EnvoyBridgeUtilityTest.m", ], flaky = True, # TODO(jpsim): Fix timeouts when running these tests on CI - tags = ["no-remote-exec"], # TODO(jpsim): Re-enable remote exec visibility = ["//visibility:public"], deps = [ "//library/objective-c:envoy_objc_bridge_lib", @@ -24,7 +23,6 @@ envoy_mobile_objc_test( "EnvoyKeyValueStoreBridgeImplTest.m", ], flaky = True, # TODO(jpsim): Fix timeouts when running these tests on CI - tags = ["no-remote-exec"], # TODO(jpsim): Re-enable remote exec visibility = ["//visibility:public"], deps = [ "//library/objective-c:envoy_key_value_store_bridge_impl_lib", @@ -45,3 +43,17 @@ envoy_objc_library( "//test/common/integration:test_server_interface_lib", ], ) + +envoy_objc_library( + name = "envoy_test_api", + testonly = True, + srcs = [ + "EnvoyTestApi.mm", + ], + hdrs = ["EnvoyTestApi.h"], + module_name = "EnvoyTestApi", + visibility = ["//visibility:public"], + deps = [ + "//test/common/proxy:test_apple_proxy_settings_lib", + ], +) diff --git a/mobile/test/objective-c/EnvoyTestApi.h b/mobile/test/objective-c/EnvoyTestApi.h new file mode 100644 index 000000000000..6f75e418728a --- /dev/null +++ b/mobile/test/objective-c/EnvoyTestApi.h @@ -0,0 +1,13 @@ +#pragma once + +#import + +// Interface for dealing with custom API registration for test classes. +@interface EnvoyTestApi : NSObject + +// Registers a test Proxy Resolver API. ++ (void)registerTestProxyResolver:(NSString *)host + port:(NSInteger)port + usePacResolver:(BOOL)usePacResolver; + +@end diff --git a/mobile/test/objective-c/EnvoyTestApi.mm b/mobile/test/objective-c/EnvoyTestApi.mm new file mode 100644 index 000000000000..3458aa5774c5 --- /dev/null +++ b/mobile/test/objective-c/EnvoyTestApi.mm @@ -0,0 +1,13 @@ +#import "test/objective-c/EnvoyTestApi.h" + +#import "test/common/proxy/test_apple_api_registration.h" + +@implementation EnvoyTestApi + ++ (void)registerTestProxyResolver:(NSString *)host + port:(NSInteger)port + usePacResolver:(BOOL)usePacResolver { + registerTestAppleProxyResolver([host UTF8String], port, usePacResolver); +} + +@end diff --git a/mobile/test/objective-c/EnvoyTestServer.h b/mobile/test/objective-c/EnvoyTestServer.h index df61cc4bf06b..13b0ea1f48bf 100644 --- a/mobile/test/objective-c/EnvoyTestServer.h +++ b/mobile/test/objective-c/EnvoyTestServer.h @@ -3,12 +3,20 @@ #import // Interface for starting and managing a test server. Calls into to test_server.cc +// +// NB: Any test that utilizes this class must have a `no-remote-exec` tag in its BUILD target. +// EnvoyTestServer binds to a listening socket on the machine it runs on, and on CI, this +// operation is not permitted in remote execution environments. @interface EnvoyTestServer : NSObject // Get the port of the upstream server. + (NSInteger)getEnvoyPort; // Starts a server with HTTP1 and no TLS. + (void)startHttp1PlaintextServer; +// Starts a server as a HTTP proxy. ++ (void)startHttpProxyServer; +// Starts a server as a HTTPS proxy. ++ (void)startHttpsProxyServer; // Shut down and clean up server. + (void)shutdownTestServer; // Add response data to the upstream. diff --git a/mobile/test/objective-c/EnvoyTestServer.mm b/mobile/test/objective-c/EnvoyTestServer.mm index 808863fb67cd..e1d64714fd52 100644 --- a/mobile/test/objective-c/EnvoyTestServer.mm +++ b/mobile/test/objective-c/EnvoyTestServer.mm @@ -11,6 +11,14 @@ + (void)startHttp1PlaintextServer { start_server(Envoy::TestServerType::HTTP1_WITHOUT_TLS); } ++ (void)startHttpProxyServer { + start_server(Envoy::TestServerType::HTTP_PROXY); +} + ++ (void)startHttpsProxyServer { + start_server(Envoy::TestServerType::HTTPS_PROXY); +} + + (void)shutdownTestServer { shutdown_server(); } diff --git a/mobile/test/swift/BUILD b/mobile/test/swift/BUILD index 83b7b81a1a75..80b407888809 100644 --- a/mobile/test/swift/BUILD +++ b/mobile/test/swift/BUILD @@ -21,7 +21,7 @@ envoy_mobile_swift_test( "RetryPolicyTests.swift", ], flaky = True, # TODO(jpsim): Fix timeouts when running these tests on CI - tags = ["no-remote-exec"], # TODO(jpsim): Re-enable remote exec + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ "//library/objective-c:envoy_engine_objc_lib", diff --git a/mobile/test/swift/cxx/BUILD b/mobile/test/swift/cxx/BUILD index 3599e37554e6..fc24ff829083 100644 --- a/mobile/test/swift/cxx/BUILD +++ b/mobile/test/swift/cxx/BUILD @@ -10,6 +10,7 @@ envoy_mobile_swift_test( srcs = [ "LogLevelCxxTests.swift", ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ "//library/swift/EnvoyCxxSwiftInterop", diff --git a/mobile/test/swift/integration/BUILD b/mobile/test/swift/integration/BUILD index 4830157ab739..dfcfd42dee9e 100644 --- a/mobile/test/swift/integration/BUILD +++ b/mobile/test/swift/integration/BUILD @@ -5,13 +5,13 @@ licenses(["notice"]) # Apache 2 envoy_mobile_package() -# TODO(jpsim): Fix remote execution for all the tests in this file. - envoy_mobile_swift_test( name = "end_to_end_networking_test", srcs = [ "EndToEndNetworkingTest.swift", ], + # The test starts an Envoy server, which binds to a local socket. Binding to a local socket is + # not permitted on remote execution hosts, so we have to add the `no-remote-exec` tag. tags = [ "no-remote-exec", ], @@ -28,9 +28,7 @@ envoy_mobile_swift_test( srcs = [ "CancelStreamTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -43,9 +41,7 @@ envoy_mobile_swift_test( srcs = [ "EngineApiTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -58,9 +54,7 @@ envoy_mobile_swift_test( srcs = [ "FilterResetIdleTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -73,9 +67,7 @@ envoy_mobile_swift_test( srcs = [ "GRPCReceiveErrorTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -88,6 +80,8 @@ envoy_mobile_swift_test( srcs = [ "IdleTimeoutTest.swift", ], + # The test starts an Envoy server, which binds to a local socket. Binding to a local socket is + # not permitted on remote execution hosts, so we have to add the `no-remote-exec` tag. tags = [ "no-remote-exec", ], @@ -104,9 +98,7 @@ envoy_mobile_swift_test( srcs = [ "KeyValueStoreTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -119,9 +111,7 @@ envoy_mobile_swift_test( srcs = [ "ReceiveDataTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -134,9 +124,7 @@ envoy_mobile_swift_test( srcs = [ "ReceiveErrorTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -149,9 +137,7 @@ envoy_mobile_swift_test( srcs = [ "ResetConnectivityStateTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -164,9 +150,7 @@ envoy_mobile_swift_test( srcs = [ "SendDataTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -179,9 +163,7 @@ envoy_mobile_swift_test( srcs = [ "SendHeadersTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -194,9 +176,7 @@ envoy_mobile_swift_test( srcs = [ "SendTrailersTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -209,9 +189,7 @@ envoy_mobile_swift_test( srcs = [ "SetEventTrackerTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -224,9 +202,7 @@ envoy_mobile_swift_test( srcs = [ "SetEventTrackerTestNoTracker.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -239,9 +215,7 @@ envoy_mobile_swift_test( srcs = [ "SetLoggerTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -254,9 +228,7 @@ envoy_mobile_swift_test( srcs = [ "CancelGRPCStreamTest.swift", ], - tags = [ - "no-remote-exec", - ], + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ ":test_extensions", @@ -270,6 +242,7 @@ objc_library( "TestExtensions.h", ], module_name = "TestExtensions", + visibility = ["//visibility:public"], deps = [ "@envoy_build_config//:test_extensions_no_autoregister", ], diff --git a/mobile/test/swift/integration/proxying/BUILD b/mobile/test/swift/integration/proxying/BUILD new file mode 100644 index 000000000000..d15f5a6f6526 --- /dev/null +++ b/mobile/test/swift/integration/proxying/BUILD @@ -0,0 +1,24 @@ +load("@envoy//bazel:envoy_build_system.bzl", "envoy_mobile_package") +load("@envoy_mobile//bazel:apple.bzl", "envoy_mobile_swift_test") + +licenses(["notice"]) # Apache 2 + +envoy_mobile_package() + +envoy_mobile_swift_test( + name = "http_request_using_proxy_test", + srcs = [ + "HTTPRequestUsingProxyTest.swift", + ], + # The test starts an Envoy test server, which requires the `no-remote-exec` tag. + tags = [ + "no-remote-exec", + ], + visibility = ["//visibility:public"], + deps = [ + "//library/objective-c:envoy_engine_objc_lib", + "//test/objective-c:envoy_test_api", + "//test/objective-c:envoy_test_server", + "//test/swift/integration:test_extensions", + ], +) diff --git a/mobile/test/swift/integration/proxying/HTTPRequestUsingProxyTest.swift b/mobile/test/swift/integration/proxying/HTTPRequestUsingProxyTest.swift new file mode 100644 index 000000000000..424159b9e6e4 --- /dev/null +++ b/mobile/test/swift/integration/proxying/HTTPRequestUsingProxyTest.swift @@ -0,0 +1,220 @@ +import Envoy +import EnvoyEngine +import EnvoyTestApi +import EnvoyTestServer +import Foundation +import TestExtensions +import XCTest + +final class HTTPRequestUsingProxyTest: XCTestCase { + override static func setUp() { + super.setUp() + register_test_extensions() + } + + func testHTTPRequestUsingProxy() throws { + EnvoyTestServer.startHttpProxyServer() + let port = EnvoyTestServer.getEnvoyPort() + + let engineExpectation = self.expectation(description: "Run started engine") + let responseHeadersExpectation = + self.expectation(description: "Successful response headers received") + let responseTrailersExpectation = + self.expectation(description: "Successful response trailers received") + + let engine = EngineBuilder() + .addLogLevel(.trace) + .setOnEngineRunning { + engineExpectation.fulfill() + } + .respectSystemProxySettings(true) + .build() + + EnvoyTestApi.registerTestProxyResolver("127.0.0.1", port: port, usePacResolver: false) + + XCTAssertEqual(XCTWaiter.wait(for: [engineExpectation], timeout: 5), .completed) + + let requestHeaders = RequestHeadersBuilder(method: .get, scheme: "http", + authority: "neverssl.com", path: "/") + .build() + + var responseBuffer = Data() + engine.streamClient() + .newStreamPrototype() + .setOnResponseHeaders { responseHeaders, _, _ in + XCTAssertEqual(200, responseHeaders.httpStatus) + responseHeadersExpectation.fulfill() + } + .setOnResponseData { data, _, _ in + responseBuffer.append(contentsOf: data) + } + .setOnResponseTrailers { _, _ in + responseTrailersExpectation.fulfill() + } + .start() + .sendHeaders(requestHeaders, endStream: true) + + let expectations = [responseHeadersExpectation, responseTrailersExpectation] + XCTAssertEqual(XCTWaiter.wait(for: expectations, timeout: 10), .completed) + + if let responseBody = String(data: responseBuffer, encoding: .utf8) { + XCTAssertGreaterThanOrEqual(responseBody.utf8.count, 3900) + } + + engine.terminate() + EnvoyTestServer.shutdownTestServer() + } + + func testHTTPSRequestUsingProxy() throws { + EnvoyTestServer.startHttpsProxyServer() + let port = EnvoyTestServer.getEnvoyPort() + + let engineExpectation = self.expectation(description: "Run started engine") + let responseHeadersExpectation = + self.expectation(description: "Successful response headers received") + let responseBodyExpectation = + self.expectation(description: "Successful response trailers received") + + let engine = EngineBuilder() + .addLogLevel(.debug) + .setOnEngineRunning { + engineExpectation.fulfill() + } + .respectSystemProxySettings(true) + .build() + + EnvoyTestApi.registerTestProxyResolver("127.0.0.1", port: port, usePacResolver: false) + + XCTAssertEqual(XCTWaiter.wait(for: [engineExpectation], timeout: 5), .completed) + + let requestHeaders = RequestHeadersBuilder(method: .get, scheme: "https", + authority: "cloud.google.com", path: "/") + .build() + + var responseBuffer = Data() + engine.streamClient() + .newStreamPrototype() + .setOnResponseHeaders { responseHeaders, _, _ in + XCTAssertEqual(200, responseHeaders.httpStatus) + responseHeadersExpectation.fulfill() + } + .setOnResponseData { data, endStream, _ in + responseBuffer.append(contentsOf: data) + if endStream { + responseBodyExpectation.fulfill() + } + } + .setOnResponseTrailers { _, _ in + } + .start() + .sendHeaders(requestHeaders, endStream: true) + + let expectations = [responseHeadersExpectation, responseBodyExpectation] + XCTAssertEqual(XCTWaiter.wait(for: expectations, timeout: 10), .completed) + + if let responseBody = String(data: responseBuffer, encoding: .utf8) { + XCTAssertGreaterThanOrEqual(responseBody.utf8.count, 3900) + } + + engine.terminate() + EnvoyTestServer.shutdownTestServer() + } + + func testHTTPSRequestUsingPacFileUrlResolver() throws { + EnvoyTestServer.startHttpsProxyServer() + let port = EnvoyTestServer.getEnvoyPort() + + let engineExpectation = self.expectation(description: "Run started engine") + let responseHeadersExpectation = + self.expectation(description: "Successful response headers received") + let responseBodyExpectation = + self.expectation(description: "Successful response trailers received") + + let engine = EngineBuilder() + .addLogLevel(.debug) + .setOnEngineRunning { + engineExpectation.fulfill() + } + .respectSystemProxySettings(true) + .build() + + EnvoyTestApi.registerTestProxyResolver("127.0.0.1", port: port, usePacResolver: true) + + XCTAssertEqual(XCTWaiter.wait(for: [engineExpectation], timeout: 5), .completed) + + let requestHeaders = RequestHeadersBuilder(method: .get, scheme: "https", + authority: "cloud.google.com", path: "/") + .build() + + var responseBuffer = Data() + engine.streamClient() + .newStreamPrototype() + .setOnResponseHeaders { responseHeaders, _, _ in + XCTAssertEqual(200, responseHeaders.httpStatus) + responseHeadersExpectation.fulfill() + } + .setOnResponseData { data, endStream, _ in + responseBuffer.append(contentsOf: data) + if endStream { + responseBodyExpectation.fulfill() + } + } + .setOnResponseTrailers { _, _ in + } + .start() + .sendHeaders(requestHeaders, endStream: true) + + let expectations = [responseHeadersExpectation, responseBodyExpectation] + XCTAssertEqual(XCTWaiter.wait(for: expectations, timeout: 10), .completed) + + if let responseBody = String(data: responseBuffer, encoding: .utf8) { + XCTAssertGreaterThanOrEqual(responseBody.utf8.count, 3900) + } + + engine.terminate() + EnvoyTestServer.shutdownTestServer() + } + + func testHTTPRequestUsingProxyCancelStream() throws { + EnvoyTestServer.startHttpProxyServer() + let port = EnvoyTestServer.getEnvoyPort() + + let engineExpectation = self.expectation(description: "Run started engine") + + let engine = EngineBuilder() + .addLogLevel(.trace) + .setOnEngineRunning { + engineExpectation.fulfill() + } + .respectSystemProxySettings(true) + .build() + + EnvoyTestApi.registerTestProxyResolver("127.0.0.1", port: port, usePacResolver: false) + + XCTAssertEqual(XCTWaiter.wait(for: [engineExpectation], timeout: 5), .completed) + + let requestHeaders = RequestHeadersBuilder(method: .get, scheme: "http", + authority: "neverssl.com", path: "/") + .build() + + let cancelExpectation = self.expectation(description: "Stream run with expected cancellation") + + engine.streamClient() + .newStreamPrototype() + .setOnCancel { _ in + // Handle stream cancellation, which is expected since we immediately + // cancel the stream after sending headers on it. + cancelExpectation.fulfill() + } + .start() + .sendHeaders(requestHeaders, endStream: true) + .cancel() + + XCTAssertEqual(XCTWaiter.wait(for: [cancelExpectation], timeout: 10), .completed) + + engine.terminate() + EnvoyTestServer.shutdownTestServer() + } + + // TODO(abeyad): Add test for proxy system settings updated. +} diff --git a/mobile/test/swift/stats/BUILD b/mobile/test/swift/stats/BUILD index dbc34bd9c78a..14e1d31bd8d0 100644 --- a/mobile/test/swift/stats/BUILD +++ b/mobile/test/swift/stats/BUILD @@ -13,7 +13,7 @@ envoy_mobile_swift_test( "TagsBuilderTests.swift", ], flaky = True, # TODO(jpsim): Fix timeouts when running these tests on CI - tags = ["no-remote-exec"], # TODO(jpsim): Re-enable remote exec + tags = ["no-remote-exec"], # TODO(32551): Re-enable remote exec visibility = ["//visibility:public"], deps = [ "//library/objective-c:envoy_engine_objc_lib", diff --git a/source/common/access_log/access_log_impl.cc b/source/common/access_log/access_log_impl.cc index fd72e00b1a74..c13213d9cbbe 100644 --- a/source/common/access_log/access_log_impl.cc +++ b/source/common/access_log/access_log_impl.cc @@ -15,6 +15,7 @@ #include "source/common/common/utility.h" #include "source/common/config/metadata.h" #include "source/common/config/utility.h" +#include "source/common/grpc/common.h" #include "source/common/http/header_map_impl.h" #include "source/common/http/header_utility.h" #include "source/common/http/headers.h" diff --git a/source/common/common/BUILD b/source/common/common/BUILD index aa0edac5aa61..6d630ec2a028 100644 --- a/source/common/common/BUILD +++ b/source/common/common/BUILD @@ -319,6 +319,7 @@ envoy_cc_library( "//envoy/common:matchers_interface", "//source/common/common:regex_lib", "//source/common/config:metadata_lib", + "//source/common/config:utility_lib", "//source/common/http:path_utility_lib", "//source/common/protobuf", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", diff --git a/source/common/config/BUILD b/source/common/config/BUILD index dffb0c2b7f3f..2965f617062a 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -226,15 +226,10 @@ envoy_cc_library( "//source/common/common:backoff_lib", "//source/common/common:hash_lib", "//source/common/common:hex_lib", - "//source/common/grpc:common_lib", "//source/common/protobuf", "//source/common/protobuf:utility_lib", "//source/common/runtime:runtime_features_lib", "//source/common/singleton:const_singleton", - "//source/common/stats:histogram_lib", - "//source/common/stats:stats_lib", - "//source/common/stats:stats_matcher_lib", - "//source/common/stats:tag_producer_lib", "//source/common/version:api_version_lib", "@com_github_cncf_xds//udpa/type/v1:pkg_cc_proto", "@com_github_cncf_xds//xds/type/v3:pkg_cc_proto", @@ -245,6 +240,19 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "stats_utility_lib", + srcs = ["stats_utility.cc"], + hdrs = ["stats_utility.h"], + deps = [ + "//source/common/stats:histogram_lib", + "//source/common/stats:stats_lib", + "//source/common/stats:stats_matcher_lib", + "//source/common/stats:tag_producer_lib", + "@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto", + ], +) + envoy_cc_library( name = "subscription_base_interface", hdrs = ["subscription_base.h"], diff --git a/source/common/config/datasource.cc b/source/common/config/datasource.cc index 1935600c8a43..76e50f1911f2 100644 --- a/source/common/config/datasource.cc +++ b/source/common/config/datasource.cc @@ -10,33 +10,28 @@ namespace Envoy { namespace Config { namespace DataSource { -// Default Parameters of the jittered backoff strategy. -static constexpr uint32_t RetryInitialDelayMilliseconds = 1000; -static constexpr uint32_t RetryMaxDelayMilliseconds = 10 * 1000; -static constexpr uint32_t RetryCount = 1; - -std::string read(const envoy::config::core::v3::DataSource& source, bool allow_empty, Api::Api& api, - uint64_t max_size) { +absl::StatusOr read(const envoy::config::core::v3::DataSource& source, + bool allow_empty, Api::Api& api, uint64_t max_size) { std::string data; absl::StatusOr file_or_error; switch (source.specifier_case()) { case envoy::config::core::v3::DataSource::SpecifierCase::kFilename: if (max_size > 0) { if (!api.fileSystem().fileExists(source.filename())) { - throwEnvoyExceptionOrPanic(fmt::format("file {} does not exist", source.filename())); + return absl::InvalidArgumentError(fmt::format("file {} does not exist", source.filename())); } const ssize_t size = api.fileSystem().fileSize(source.filename()); if (size < 0) { - throwEnvoyExceptionOrPanic( + return absl::InvalidArgumentError( absl::StrCat("cannot determine size of file ", source.filename())); } if (static_cast(size) > max_size) { - throwEnvoyExceptionOrPanic(fmt::format("file {} size is {} bytes; maximum is {}", - source.filename(), size, max_size)); + return absl::InvalidArgumentError(fmt::format("file {} size is {} bytes; maximum is {}", + source.filename(), size, max_size)); } } file_or_error = api.fileSystem().fileReadToEnd(source.filename()); - THROW_IF_STATUS_NOT_OK(file_or_error, throw); + RETURN_IF_STATUS_NOT_OK(file_or_error); data = file_or_error.value(); break; case envoy::config::core::v3::DataSource::SpecifierCase::kInlineBytes: @@ -48,7 +43,7 @@ std::string read(const envoy::config::core::v3::DataSource& source, bool allow_e case envoy::config::core::v3::DataSource::SpecifierCase::kEnvironmentVariable: { const char* environment_variable = std::getenv(source.environment_variable().c_str()); if (environment_variable == nullptr) { - throwEnvoyExceptionOrPanic( + return absl::InvalidArgumentError( fmt::format("Environment variable doesn't exist: {}", source.environment_variable())); } data = environment_variable; @@ -56,12 +51,12 @@ std::string read(const envoy::config::core::v3::DataSource& source, bool allow_e } default: if (!allow_empty) { - throwEnvoyExceptionOrPanic( + return absl::InvalidArgumentError( fmt::format("Unexpected DataSource::specifier_case(): {}", source.specifier_case())); } } if (!allow_empty && data.empty()) { - throwEnvoyExceptionOrPanic("DataSource cannot be empty"); + return absl::InvalidArgumentError("DataSource cannot be empty"); } return data; } @@ -72,27 +67,6 @@ absl::optional getPath(const envoy::config::core::v3::DataSource& s : absl::nullopt; } -RemoteAsyncDataProvider::RemoteAsyncDataProvider( - Upstream::ClusterManager& cm, Init::Manager& manager, - const envoy::config::core::v3::RemoteDataSource& source, Event::Dispatcher& dispatcher, - Random::RandomGenerator& random, bool allow_empty, AsyncDataSourceCb&& callback) - : allow_empty_(allow_empty), callback_(std::move(callback)), - fetcher_(std::make_unique(cm, source.http_uri(), - source.sha256(), *this)), - init_target_("RemoteAsyncDataProvider", [this]() { start(); }), - retries_remaining_( - PROTOBUF_GET_WRAPPED_OR_DEFAULT(source.retry_policy(), num_retries, RetryCount)) { - - auto strategy_or_error = Utility::prepareJitteredExponentialBackOffStrategy( - source, random, RetryInitialDelayMilliseconds, RetryMaxDelayMilliseconds); - THROW_IF_STATUS_NOT_OK(strategy_or_error, throw); - backoff_strategy_ = std::move(strategy_or_error.value()); - - retry_timer_ = dispatcher.createTimer([this]() -> void { start(); }); - - manager.add(init_target_); -} - } // namespace DataSource } // namespace Config } // namespace Envoy diff --git a/source/common/config/datasource.h b/source/common/config/datasource.h index 326c45a3d149..4171548e8c3f 100644 --- a/source/common/config/datasource.h +++ b/source/common/config/datasource.h @@ -26,11 +26,11 @@ namespace DataSource { * @param api reference to the Api object * @param max_size max size limit of file to read, default 0 means no limit, and if the file data * would exceed the limit, it will throw a EnvoyException. - * @return std::string with DataSource contents. - * @throw EnvoyException if no DataSource case is specified and !allow_empty. + * @return std::string with DataSource contents. or an error status if no DataSource case is + * specified and !allow_empty. */ -std::string read(const envoy::config::core::v3::DataSource& source, bool allow_empty, Api::Api& api, - uint64_t max_size = 0); +absl::StatusOr read(const envoy::config::core::v3::DataSource& source, + bool allow_empty, Api::Api& api, uint64_t max_size = 0); /** * @param source data source. @@ -38,85 +38,6 @@ std::string read(const envoy::config::core::v3::DataSource& source, bool allow_e */ absl::optional getPath(const envoy::config::core::v3::DataSource& source); -/** - * Callback for async data source. - */ -using AsyncDataSourceCb = std::function; - -class LocalAsyncDataProvider { -public: - LocalAsyncDataProvider(Init::Manager& manager, const envoy::config::core::v3::DataSource& source, - bool allow_empty, Api::Api& api, AsyncDataSourceCb&& callback) - : init_target_("LocalAsyncDataProvider", [this, &source, allow_empty, &api, callback]() { - callback(DataSource::read(source, allow_empty, api)); - init_target_.ready(); - }) { - manager.add(init_target_); - } - - ~LocalAsyncDataProvider() { init_target_.ready(); } - -private: - Init::TargetImpl init_target_; -}; - -using LocalAsyncDataProviderPtr = std::unique_ptr; - -class RemoteAsyncDataProvider : public Event::DeferredDeletable, - public Config::DataFetcher::RemoteDataFetcherCallback, - public Logger::Loggable { -public: - RemoteAsyncDataProvider(Upstream::ClusterManager& cm, Init::Manager& manager, - const envoy::config::core::v3::RemoteDataSource& source, - Event::Dispatcher& dispatcher, Random::RandomGenerator& random, - bool allow_empty, AsyncDataSourceCb&& callback); - - ~RemoteAsyncDataProvider() override { - init_target_.ready(); - if (retry_timer_) { - retry_timer_->disableTimer(); - } - } - - // Config::DataFetcher::RemoteDataFetcherCallback - void onSuccess(const std::string& data) override { - callback_(data); - init_target_.ready(); - } - - // Config::DataFetcher::RemoteDataFetcherCallback - void onFailure(Config::DataFetcher::FailureReason failure) override { - ENVOY_LOG(debug, "Failed to fetch remote data, failure reason: {}", enumToInt(failure)); - if (retries_remaining_-- == 0) { - ENVOY_LOG(warn, "Retry limit exceeded for fetching data from remote data source."); - if (allow_empty_) { - callback_(EMPTY_STRING); - } - // We need to allow server startup to continue. - init_target_.ready(); - return; - } - - const auto retry_ms = std::chrono::milliseconds(backoff_strategy_->nextBackOffMs()); - ENVOY_LOG(debug, "Remote data provider will retry in {} ms.", retry_ms.count()); - retry_timer_->enableTimer(retry_ms); - } - -private: - void start() { fetcher_->fetch(); } - - bool allow_empty_; - AsyncDataSourceCb callback_; - const Config::DataFetcher::RemoteDataFetcherPtr fetcher_; - Init::TargetImpl init_target_; - - Event::TimerPtr retry_timer_; - BackOffStrategyPtr backoff_strategy_; - uint32_t retries_remaining_; -}; - -using RemoteAsyncDataProviderPtr = std::unique_ptr; - } // namespace DataSource } // namespace Config } // namespace Envoy diff --git a/source/common/config/stats_utility.cc b/source/common/config/stats_utility.cc new file mode 100644 index 000000000000..eed7f4c98b40 --- /dev/null +++ b/source/common/config/stats_utility.cc @@ -0,0 +1,17 @@ +#include "source/common/config/stats_utility.h" + +#include "source/common/stats/histogram_impl.h" +#include "source/common/stats/stats_matcher_impl.h" +#include "source/common/stats/tag_producer_impl.h" + +namespace Envoy { +namespace Config { + +Stats::TagProducerPtr +StatsUtility::createTagProducer(const envoy::config::bootstrap::v3::Bootstrap& bootstrap, + const Stats::TagVector& cli_tags) { + return std::make_unique(bootstrap.stats_config(), cli_tags); +} + +} // namespace Config +} // namespace Envoy diff --git a/source/common/config/stats_utility.h b/source/common/config/stats_utility.h new file mode 100644 index 000000000000..409bd1ddc0c8 --- /dev/null +++ b/source/common/config/stats_utility.h @@ -0,0 +1,28 @@ +#pragma once + +#include "envoy/config/bootstrap/v3/bootstrap.pb.h" +#include "envoy/stats/histogram.h" +#include "envoy/stats/scope.h" +#include "envoy/stats/stats_macros.h" +#include "envoy/stats/stats_matcher.h" +#include "envoy/stats/tag_producer.h" + +namespace Envoy { +namespace Config { + +class StatsUtility { +public: + /** + * Create TagProducer instance. Check all tag names for conflicts to avoid + * unexpected tag name overwriting. + * @param bootstrap bootstrap proto. + * @param cli_tags tags that are provided by the cli + * @throws EnvoyException when the conflict of tag names is found. + */ + static Stats::TagProducerPtr + createTagProducer(const envoy::config::bootstrap::v3::Bootstrap& bootstrap, + const Stats::TagVector& cli_tags); +}; + +} // namespace Config +} // namespace Envoy diff --git a/source/common/config/utility.cc b/source/common/config/utility.cc index eff142670f25..83556c148054 100644 --- a/source/common/config/utility.cc +++ b/source/common/config/utility.cc @@ -11,9 +11,6 @@ #include "source/common/common/assert.h" #include "source/common/protobuf/utility.h" -#include "source/common/stats/histogram_impl.h" -#include "source/common/stats/stats_matcher_impl.h" -#include "source/common/stats/tag_producer_impl.h" namespace Envoy { namespace Config { @@ -183,7 +180,7 @@ std::chrono::milliseconds Utility::configSourceInitialFetchTimeout( PROTOBUF_GET_MS_OR_DEFAULT(config_source, initial_fetch_timeout, 15000)); } -RateLimitSettings +absl::StatusOr Utility::parseRateLimitSettings(const envoy::config::core::v3::ApiConfigSource& api_config_source) { RateLimitSettings rate_limit_settings; if (api_config_source.has_rate_limit_settings()) { @@ -194,16 +191,16 @@ Utility::parseRateLimitSettings(const envoy::config::core::v3::ApiConfigSource& rate_limit_settings.fill_rate_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(api_config_source.rate_limit_settings(), fill_rate, Envoy::Config::RateLimitSettings::DefaultFillRate); + // Reject the NaN and Inf values. + if (std::isnan(rate_limit_settings.fill_rate_) || std::isinf(rate_limit_settings.fill_rate_)) { + return absl::InvalidArgumentError( + fmt::format("The value of fill_rate in RateLimitSettings ({}) must not be NaN nor Inf", + rate_limit_settings.fill_rate_)); + } } return rate_limit_settings; } -Stats::TagProducerPtr -Utility::createTagProducer(const envoy::config::bootstrap::v3::Bootstrap& bootstrap, - const Stats::TagVector& cli_tags) { - return std::make_unique(bootstrap.stats_config(), cli_tags); -} - absl::StatusOr Utility::factoryForGrpcApiConfigSource( Grpc::AsyncClientManager& async_client_manager, const envoy::config::core::v3::ApiConfigSource& api_config_source, Stats::Scope& scope, diff --git a/source/common/config/utility.h b/source/common/config/utility.h index 5dfa959b1f5e..ede6515d3a07 100644 --- a/source/common/config/utility.h +++ b/source/common/config/utility.h @@ -12,11 +12,6 @@ #include "envoy/local_info/local_info.h" #include "envoy/registry/registry.h" #include "envoy/server/filter_config.h" -#include "envoy/stats/histogram.h" -#include "envoy/stats/scope.h" -#include "envoy/stats/stats_macros.h" -#include "envoy/stats/stats_matcher.h" -#include "envoy/stats/tag_producer.h" #include "envoy/upstream/cluster_manager.h" #include "source/common/common/assert.h" @@ -24,7 +19,6 @@ #include "source/common/common/hash.h" #include "source/common/common/hex.h" #include "source/common/common/utility.h" -#include "source/common/grpc/common.h" #include "source/common/protobuf/protobuf.h" #include "source/common/protobuf/utility.h" #include "source/common/runtime/runtime_features.h" @@ -178,9 +172,10 @@ class Utility { * Parses RateLimit configuration from envoy::config::core::v3::ApiConfigSource to * RateLimitSettings. * @param api_config_source ApiConfigSource. - * @return RateLimitSettings. + * @return absl::StatusOr - returns an error when an + * invalid RateLimit config settings are provided. */ - static RateLimitSettings + static absl::StatusOr parseRateLimitSettings(const envoy::config::core::v3::ApiConfigSource& api_config_source); /** @@ -391,17 +386,6 @@ class Utility { */ static std::string truncateGrpcStatusMessage(absl::string_view error_message); - /** - * Create TagProducer instance. Check all tag names for conflicts to avoid - * unexpected tag name overwriting. - * @param bootstrap bootstrap proto. - * @param cli_tags tags that are provided by the cli - * @throws EnvoyException when the conflict of tag names is found. - */ - static Stats::TagProducerPtr - createTagProducer(const envoy::config::bootstrap::v3::Bootstrap& bootstrap, - const Stats::TagVector& cli_tags); - /** * Obtain gRPC async client factory from a envoy::config::core::v3::ApiConfigSource. * @param async_client_manager gRPC async client manager. @@ -490,7 +474,6 @@ class Utility { const envoy::config::core::v3::ApiConfigSource& api_config_source, Random::RandomGenerator& random, const uint32_t default_base_interval_ms, absl::optional default_max_interval_ms) { - auto& grpc_services = api_config_source.grpc_services(); if (!grpc_services.empty() && grpc_services[0].has_envoy_grpc()) { return prepareJitteredExponentialBackOffStrategy( diff --git a/source/common/conn_pool/conn_pool_base.cc b/source/common/conn_pool/conn_pool_base.cc index 9ff006726811..1eb4bc77ee1e 100644 --- a/source/common/conn_pool/conn_pool_base.cc +++ b/source/common/conn_pool/conn_pool_base.cc @@ -593,9 +593,8 @@ void ConnPoolImplBase::onConnectionEvent(ActiveClient& client, absl::string_view client.connection_duration_timer_->enableTimer(max_connection_duration.value()); } // Initialize client read filters - if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.initialize_upstream_filters")) { - client.initializeReadFilters(); - } + client.initializeReadFilters(); + // At this point, for the mixed ALPN pool, the client may be deleted. Do not // refer to client after this point. onConnected(client); diff --git a/source/common/filesystem/posix/filesystem_impl.cc b/source/common/filesystem/posix/filesystem_impl.cc index 567eb43e15ff..d9714ce37b9b 100644 --- a/source/common/filesystem/posix/filesystem_impl.cc +++ b/source/common/filesystem/posix/filesystem_impl.cc @@ -158,7 +158,7 @@ static Api::IoCallResult infoFromStat(absl::string_view path, const st } static Api::IoCallResult infoFromStat(absl::string_view path, const struct stat& s) { - return infoFromStat(path, s, typeFromStat(s)); + return infoFromStat(path, s, typeFromStat(s)); // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) } Api::IoCallResult FileImplPosix::info() { @@ -180,6 +180,7 @@ Api::IoCallResult InstanceImplPosix::stat(absl::string_view path) { // but the reference is broken as the target could not be stat()'ed. // After confirming this with an lstat, treat this file entity as // a regular file, which may be unlink()'ed. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) return infoFromStat(path, s, FileType::Regular); } } diff --git a/source/common/formatter/substitution_format_string.h b/source/common/formatter/substitution_format_string.h index b929fef5d7b3..3cdd032a9eee 100644 --- a/source/common/formatter/substitution_format_string.h +++ b/source/common/formatter/substitution_format_string.h @@ -58,8 +58,9 @@ class SubstitutionFormatStringUtils { commands); case envoy::config::core::v3::SubstitutionFormatString::FormatCase::kTextFormatSource: return std::make_unique>( - Config::DataSource::read(config.text_format_source(), true, - context.serverFactoryContext().api()), + THROW_OR_RETURN_VALUE(Config::DataSource::read(config.text_format_source(), true, + context.serverFactoryContext().api()), + std::string), config.omit_empty_values(), commands); case envoy::config::core::v3::SubstitutionFormatString::FormatCase::FORMAT_NOT_SET: PANIC_DUE_TO_PROTO_UNSET; diff --git a/source/common/grpc/BUILD b/source/common/grpc/BUILD index 9ab2790a7c1c..6fa6e2a21c8d 100644 --- a/source/common/grpc/BUILD +++ b/source/common/grpc/BUILD @@ -212,6 +212,7 @@ envoy_cc_library( "//envoy/grpc:google_grpc_creds_interface", "//envoy/registry", "//source/common/config:datasource_lib", + "//source/common/runtime:runtime_lib", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], alwayslink = LEGACY_ALWAYSLINK, diff --git a/source/common/grpc/async_client_manager_impl.cc b/source/common/grpc/async_client_manager_impl.cc index 73595f9ea0c1..f2875e30466e 100644 --- a/source/common/grpc/async_client_manager_impl.cc +++ b/source/common/grpc/async_client_manager_impl.cc @@ -45,12 +45,14 @@ bool validateGrpcCompatibleAsciiHeaderValue(absl::string_view h_value) { AsyncClientFactoryImpl::AsyncClientFactoryImpl(Upstream::ClusterManager& cm, const envoy::config::core::v3::GrpcService& config, - bool skip_cluster_check, TimeSource& time_source) + bool skip_cluster_check, TimeSource& time_source, + absl::Status& creation_status) : cm_(cm), config_(config), time_source_(time_source) { if (skip_cluster_check) { - return; + creation_status = absl::OkStatus(); + } else { + creation_status = cm_.checkActiveStaticCluster(config.envoy_grpc().cluster_name()); } - THROW_IF_NOT_OK(cm_.checkActiveStaticCluster(config.envoy_grpc().cluster_name())); } AsyncClientManagerImpl::AsyncClientManagerImpl( @@ -81,11 +83,11 @@ RawAsyncClientPtr AsyncClientFactoryImpl::createUncachedRawAsyncClient() { GoogleAsyncClientFactoryImpl::GoogleAsyncClientFactoryImpl( ThreadLocal::Instance& tls, ThreadLocal::Slot* google_tls_slot, Stats::Scope& scope, - const envoy::config::core::v3::GrpcService& config, Api::Api& api, const StatNames& stat_names) + const envoy::config::core::v3::GrpcService& config, Api::Api& api, const StatNames& stat_names, + absl::Status& creation_status) : tls_(tls), google_tls_slot_(google_tls_slot), scope_(scope.createScope(fmt::format("grpc.{}.", config.google_grpc().stat_prefix()))), config_(config), api_(api), stat_names_(stat_names) { - #ifndef ENVOY_GOOGLE_GRPC UNREFERENCED_PARAMETER(tls_); UNREFERENCED_PARAMETER(google_tls_slot_); @@ -93,26 +95,30 @@ GoogleAsyncClientFactoryImpl::GoogleAsyncClientFactoryImpl( UNREFERENCED_PARAMETER(config_); UNREFERENCED_PARAMETER(api_); UNREFERENCED_PARAMETER(stat_names_); - throwEnvoyExceptionOrPanic("Google C++ gRPC client is not linked"); + creation_status = absl::InvalidArgumentError("Google C++ gRPC client is not linked"); + return; #else ASSERT(google_tls_slot_ != nullptr); #endif + creation_status = absl::OkStatus(); // Check metadata for gRPC API compliance. Uppercase characters are lowered in the HeaderParser. // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md for (const auto& header : config.initial_metadata()) { // Validate key if (!validateGrpcHeaderChars(header.key())) { - throwEnvoyExceptionOrPanic( + creation_status = absl::InvalidArgumentError( fmt::format("Illegal characters in gRPC initial metadata header key: {}.", header.key())); + return; } // Validate value // Binary base64 encoded - handled by the GRPC library if (!::absl::EndsWith(header.key(), "-bin") && !validateGrpcCompatibleAsciiHeaderValue(header.value())) { - throwEnvoyExceptionOrPanic(fmt::format( + creation_status = absl::InvalidArgumentError(fmt::format( "Illegal ASCII value for gRPC initial metadata header key: {}.", header.key())); + return; } } } @@ -128,22 +134,30 @@ RawAsyncClientPtr GoogleAsyncClientFactoryImpl::createUncachedRawAsyncClient() { #endif } -AsyncClientFactoryPtr +absl::StatusOr AsyncClientManagerImpl::factoryForGrpcService(const envoy::config::core::v3::GrpcService& config, Stats::Scope& scope, bool skip_cluster_check) { + absl::Status creation_status = absl::OkStatus(); + AsyncClientFactoryPtr factory; switch (config.target_specifier_case()) { case envoy::config::core::v3::GrpcService::TargetSpecifierCase::kEnvoyGrpc: - return std::make_unique(cm_, config, skip_cluster_check, time_source_); + factory = std::make_unique(cm_, config, skip_cluster_check, + time_source_, creation_status); + break; case envoy::config::core::v3::GrpcService::TargetSpecifierCase::kGoogleGrpc: - return std::make_unique(tls_, google_tls_slot_.get(), scope, - config, api_, stat_names_); + factory = std::make_unique( + tls_, google_tls_slot_.get(), scope, config, api_, stat_names_, creation_status); + break; case envoy::config::core::v3::GrpcService::TargetSpecifierCase::TARGET_SPECIFIER_NOT_SET: PANIC_DUE_TO_PROTO_UNSET; } - return nullptr; + if (!creation_status.ok()) { + return creation_status; + } + return factory; } -RawAsyncClientSharedPtr AsyncClientManagerImpl::getOrCreateRawAsyncClient( +absl::StatusOr AsyncClientManagerImpl::getOrCreateRawAsyncClient( const envoy::config::core::v3::GrpcService& config, Stats::Scope& scope, bool skip_cluster_check) { const GrpcServiceConfigWithHashKey config_with_hash_key = GrpcServiceConfigWithHashKey(config); @@ -151,21 +165,26 @@ RawAsyncClientSharedPtr AsyncClientManagerImpl::getOrCreateRawAsyncClient( if (client != nullptr) { return client; } - client = factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check) - ->createUncachedRawAsyncClient(); + auto factory_or_error = + factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check); + RETURN_IF_STATUS_NOT_OK(factory_or_error); + client = factory_or_error.value()->createUncachedRawAsyncClient(); raw_async_client_cache_->setCache(config_with_hash_key, client); return client; } -RawAsyncClientSharedPtr AsyncClientManagerImpl::getOrCreateRawAsyncClientWithHashKey( +absl::StatusOr +AsyncClientManagerImpl::getOrCreateRawAsyncClientWithHashKey( const GrpcServiceConfigWithHashKey& config_with_hash_key, Stats::Scope& scope, bool skip_cluster_check) { RawAsyncClientSharedPtr client = raw_async_client_cache_->getCache(config_with_hash_key); if (client != nullptr) { return client; } - client = factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check) - ->createUncachedRawAsyncClient(); + auto factory_or_error = + factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check); + RETURN_IF_STATUS_NOT_OK(factory_or_error); + client = factory_or_error.value()->createUncachedRawAsyncClient(); raw_async_client_cache_->setCache(config_with_hash_key, client); return client; } diff --git a/source/common/grpc/async_client_manager_impl.h b/source/common/grpc/async_client_manager_impl.h index a01f02af41a8..54c3cf6b2b00 100644 --- a/source/common/grpc/async_client_manager_impl.h +++ b/source/common/grpc/async_client_manager_impl.h @@ -19,7 +19,8 @@ class AsyncClientFactoryImpl : public AsyncClientFactory { public: AsyncClientFactoryImpl(Upstream::ClusterManager& cm, const envoy::config::core::v3::GrpcService& config, - bool skip_cluster_check, TimeSource& time_source); + bool skip_cluster_check, TimeSource& time_source, + absl::Status& creation_status); RawAsyncClientPtr createUncachedRawAsyncClient() override; private: @@ -33,7 +34,7 @@ class GoogleAsyncClientFactoryImpl : public AsyncClientFactory { GoogleAsyncClientFactoryImpl(ThreadLocal::Instance& tls, ThreadLocal::Slot* google_tls_slot, Stats::Scope& scope, const envoy::config::core::v3::GrpcService& config, Api::Api& api, - const StatNames& stat_names); + const StatNames& stat_names, absl::Status& creation_status); RawAsyncClientPtr createUncachedRawAsyncClient() override; private: @@ -51,17 +52,17 @@ class AsyncClientManagerImpl : public AsyncClientManager { Upstream::ClusterManager& cm, ThreadLocal::Instance& tls, TimeSource& time_source, Api::Api& api, const StatNames& stat_names, const envoy::config::bootstrap::v3::Bootstrap::GrpcAsyncClientManagerConfig& config); - RawAsyncClientSharedPtr + absl::StatusOr getOrCreateRawAsyncClient(const envoy::config::core::v3::GrpcService& config, Stats::Scope& scope, bool skip_cluster_check) override; - RawAsyncClientSharedPtr + absl::StatusOr getOrCreateRawAsyncClientWithHashKey(const GrpcServiceConfigWithHashKey& config_with_hash_key, Stats::Scope& scope, bool skip_cluster_check) override; - AsyncClientFactoryPtr factoryForGrpcService(const envoy::config::core::v3::GrpcService& config, - Stats::Scope& scope, - bool skip_cluster_check) override; + absl::StatusOr + factoryForGrpcService(const envoy::config::core::v3::GrpcService& config, Stats::Scope& scope, + bool skip_cluster_check) override; class RawAsyncClientCache : public ThreadLocal::ThreadLocalObject { public: explicit RawAsyncClientCache(Event::Dispatcher& dispatcher, diff --git a/source/common/grpc/google_grpc_creds_impl.cc b/source/common/grpc/google_grpc_creds_impl.cc index ae49d3257a7f..e70617355a76 100644 --- a/source/common/grpc/google_grpc_creds_impl.cc +++ b/source/common/grpc/google_grpc_creds_impl.cc @@ -4,6 +4,9 @@ #include "envoy/grpc/google_grpc_creds.h" #include "source/common/config/datasource.h" +#include "source/common/runtime/runtime_features.h" + +#include "grpcpp/security/tls_certificate_provider.h" namespace Envoy { namespace Grpc { @@ -15,12 +18,32 @@ std::shared_ptr CredsUtility::getChannelCredentials( case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelCredentials:: CredentialSpecifierCase::kSslCredentials: { const auto& ssl_credentials = google_grpc.channel_credentials().ssl_credentials(); - const grpc::SslCredentialsOptions ssl_credentials_options = { - Config::DataSource::read(ssl_credentials.root_certs(), true, api), - Config::DataSource::read(ssl_credentials.private_key(), true, api), - Config::DataSource::read(ssl_credentials.cert_chain(), true, api), - }; - return grpc::SslCredentials(ssl_credentials_options); + const auto root_certs = THROW_OR_RETURN_VALUE( + Config::DataSource::read(ssl_credentials.root_certs(), true, api), std::string); + const auto private_key = THROW_OR_RETURN_VALUE( + Config::DataSource::read(ssl_credentials.private_key(), true, api), std::string); + const auto cert_chain = THROW_OR_RETURN_VALUE( + Config::DataSource::read(ssl_credentials.cert_chain(), true, api), std::string); + grpc::experimental::TlsChannelCredentialsOptions options; + if (!private_key.empty() || !cert_chain.empty()) { + options.set_certificate_provider( + std::make_shared( + root_certs, + std::vector{{private_key, cert_chain}})); + } else if (!root_certs.empty()) { + options.set_certificate_provider( + std::make_shared(root_certs)); + } + if (!root_certs.empty()) { + options.watch_root_certs(); + } + if (!private_key.empty() || !cert_chain.empty()) { + options.watch_identity_key_cert_pairs(); + } + if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.google_grpc_disable_tls_13")) { + options.set_max_tls_version(grpc_tls_version::TLS1_2); + } + return grpc::experimental::TlsCredentials(options); } case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelCredentials:: CredentialSpecifierCase::kLocalCredentials: { @@ -43,7 +66,11 @@ std::shared_ptr CredsUtility::defaultSslChannelCredent if (creds != nullptr) { return creds; } - return grpc::SslCredentials({}); + grpc::experimental::TlsChannelCredentialsOptions options; + if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.google_grpc_disable_tls_13")) { + options.set_max_tls_version(grpc_tls_version::TLS1_2); + } + return grpc::experimental::TlsCredentials(options); } std::vector> diff --git a/source/common/http/async_client_impl.cc b/source/common/http/async_client_impl.cc index 19a7e72adaba..467f55b09799 100644 --- a/source/common/http/async_client_impl.cc +++ b/source/common/http/async_client_impl.cc @@ -99,8 +99,8 @@ AsyncStreamImpl::AsyncStreamImpl(AsyncClientImpl& parent, AsyncClient::StreamCal retry_policy_(createRetryPolicy(parent, options)), route_(std::make_shared( parent_.cluster_->name(), - retry_policy_ != nullptr ? *retry_policy_.get() : *options.parsed_retry_policy, - options.timeout, options.hash_policy)), + retry_policy_ != nullptr ? *retry_policy_ : *options.parsed_retry_policy, options.timeout, + options.hash_policy)), account_(options.account_), buffer_limit_(options.buffer_limit_), send_xff_(options.send_xff) { stream_info_.dynamicMetadata().MergeFrom(options.metadata); @@ -314,6 +314,7 @@ void AsyncOngoingRequestImpl::initialize() { } void AsyncRequestSharedImpl::onComplete() { + complete_ = true; callbacks_.onBeforeFinalizeUpstreamSpan(*child_span_, &response_->headers()); Tracing::HttpTracerUtility::finalizeUpstreamSpan(*child_span_, streamInfo(), @@ -335,6 +336,11 @@ void AsyncRequestSharedImpl::onTrailers(ResponseTrailerMapPtr&& trailers) { } void AsyncRequestSharedImpl::onReset() { + if (complete_) { + // This request has already been completed; a reset should be ignored. + return; + } + if (!cancelled_) { // Set "error reason" tag related to reset. The tagging for "error true" is done inside the // Tracing::HttpTracerUtility::finalizeUpstreamSpan. diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index 645633adbdf2..7e6354bd931b 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -151,6 +151,7 @@ class AsyncStreamImpl : public virtual AsyncClient::Stream, absl::optional destructor_callback_; // Callback to listen for low/high/overflow watermark events. absl::optional> watermark_callbacks_; + bool complete_{}; private: void cleanup(); diff --git a/source/common/http/conn_manager_config.h b/source/common/http/conn_manager_config.h index a07eb825f789..6730cfb1d322 100644 --- a/source/common/http/conn_manager_config.h +++ b/source/common/http/conn_manager_config.h @@ -533,6 +533,12 @@ class ConnectionManagerConfig { */ virtual bool appendXForwardedPort() const PURE; + /** + * @return whether to append the overload header to a local reply of a request which + * has been dropped due to Overload Manager. + */ + virtual bool appendLocalOverload() const PURE; + /** * @return whether the HCM will insert ProxyProtocolFilterState into the filter state at the * Connection Lifetime. diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 47e7631c1309..4c1420575eb5 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -114,8 +114,10 @@ ConnectionManagerImpl::ConnectionManagerImpl(ConnectionManagerConfig& config, cluster_manager_(cluster_manager), listener_stats_(config_.listenerStats()), overload_manager_(overload_manager), overload_state_(overload_manager.getThreadLocalOverloadState()), - accept_new_http_stream_(overload_manager.getLoadShedPoint( - "envoy.load_shed_points.http_connection_manager_decode_headers")), + accept_new_http_stream_( + overload_manager.getLoadShedPoint(Server::LoadShedPointName::get().HcmDecodeHeaders)), + hcm_ondata_creating_codec_( + overload_manager.getLoadShedPoint(Server::LoadShedPointName::get().HcmCodecCreation)), overload_stop_accepting_requests_ref_( overload_state_.getState(Server::OverloadActionNames::get().StopAcceptingRequests)), overload_disable_keepalive_ref_( @@ -132,6 +134,9 @@ ConnectionManagerImpl::ConnectionManagerImpl(ConnectionManagerConfig& config, trace, accept_new_http_stream_ == nullptr, "LoadShedPoint envoy.load_shed_points.http_connection_manager_decode_headers is not " "found. Is it configured?"); + ENVOY_LOG_ONCE_IF(trace, hcm_ondata_creating_codec_ == nullptr, + "LoadShedPoint envoy.load_shed_points.hcm_ondata_creating_codec is not found. " + "Is it configured?"); } const ResponseHeaderMap& ConnectionManagerImpl::continueHeader() { @@ -479,6 +484,12 @@ void ConnectionManagerImpl::createCodec(Buffer::Instance& data) { Network::FilterStatus ConnectionManagerImpl::onData(Buffer::Instance& data, bool) { requests_during_dispatch_count_ = 0; if (!codec_) { + // Close connections if Envoy is under pressure, typically memory, before creating codec. + if (hcm_ondata_creating_codec_ != nullptr && hcm_ondata_creating_codec_->shouldShedLoad()) { + stats_.named_.downstream_rq_overload_close_.inc(); + handleCodecOverloadError("onData codec creation overload"); + return Network::FilterStatus::StopIteration; + } // Http3 codec should have been instantiated by now. createCodec(data); } @@ -1257,8 +1268,15 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapSharedPt // overload it is more important to avoid unnecessary allocation than to create the filters. filter_manager_.skipFilterChainCreation(); connection_manager_.stats_.named_.downstream_rq_overload_close_.inc(); - sendLocalReply(Http::Code::ServiceUnavailable, "envoy overloaded", nullptr, absl::nullopt, - StreamInfo::ResponseCodeDetails::get().Overload); + sendLocalReply( + Http::Code::ServiceUnavailable, "envoy overloaded", + [this](Http::ResponseHeaderMap& headers) { + if (connection_manager_.config_.appendLocalOverload()) { + headers.addReference(Http::Headers::get().EnvoyLocalOverloaded, + Http::Headers::get().EnvoyOverloadedValues.True); + } + }, + absl::nullopt, StreamInfo::ResponseCodeDetails::get().Overload); return; } @@ -1735,7 +1753,7 @@ void ConnectionManagerImpl::ActiveStream::encode1xxHeaders(ResponseHeaderMap& re // Count both the 1xx and follow-up response code in stats. chargeStats(response_headers); - ENVOY_STREAM_LOG(debug, "encoding 100 continue headers via codec:\n{}", *this, response_headers); + ENVOY_STREAM_LOG(debug, "encoding 1xx continue headers via codec:\n{}", *this, response_headers); // Now actually encode via the codec. response_encoder_->encode1xxHeaders(response_headers); diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index aac42af4b34a..11151b157bf5 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -642,6 +642,7 @@ class ConnectionManagerImpl : Logger::Loggable, Server::OverloadManager& overload_manager_; Server::ThreadLocalOverloadState& overload_state_; Server::LoadShedPoint* accept_new_http_stream_{nullptr}; + Server::LoadShedPoint* hcm_ondata_creating_codec_{nullptr}; // References into the overload manager thread local state map. Using these lets us avoid a // map lookup in the hot path of processing each request. const Server::OverloadActionState& overload_stop_accepting_requests_ref_; diff --git a/source/common/http/conn_pool_grid.cc b/source/common/http/conn_pool_grid.cc index ba51e7eee7e1..1ae84bc56da5 100644 --- a/source/common/http/conn_pool_grid.cc +++ b/source/common/http/conn_pool_grid.cc @@ -96,12 +96,17 @@ void ConnectivityGrid::WrapperCallbacks::onConnectionAttemptFailed( // If this point is reached, all pools have been tried. Pass the pool failure up to the // original caller, if the caller hasn't already been notified. + signalFailureAndDeleteSelf(reason, transport_failure_reason, host); +} + +void ConnectivityGrid::WrapperCallbacks::signalFailureAndDeleteSelf( + ConnectionPool::PoolFailureReason reason, absl::string_view transport_failure_reason, + Upstream::HostDescriptionConstSharedPtr host) { ConnectionPool::Callbacks* callbacks = inner_callbacks_; inner_callbacks_ = nullptr; deleteThis(); if (callbacks != nullptr) { - ENVOY_LOG(trace, "Passing pool failure up to caller.", describePool(attempt->pool()), - host->hostname()); + ENVOY_LOG(trace, "Passing pool failure up to caller."); callbacks->onPoolFailure(reason, transport_failure_reason, host); } } @@ -191,6 +196,9 @@ void ConnectivityGrid::WrapperCallbacks::cancelAllPendingAttempts( absl::optional ConnectivityGrid::WrapperCallbacks::tryAnotherConnection() { + if (grid_.destroying_) { + return {}; + } absl::optional next_pool = grid_.nextPool(current_); if (!next_pool.has_value()) { // If there are no other pools to try, return an empty optional. @@ -236,9 +244,13 @@ ConnectivityGrid::ConnectivityGrid( ConnectivityGrid::~ConnectivityGrid() { // Ignore idle callbacks while the pools are destroyed below. destroying_ = true; - // Callbacks might have pending streams registered with the pools, so cancel and delete - // the callback before deleting the pools. - wrapped_callbacks_.clear(); + while (!wrapped_callbacks_.empty()) { + // Before tearing down the callbacks, make sure they pass up pool failure to + // the caller. We do not call onPoolFailure because it does up-calls to the + // (delete-in-process) grid. + wrapped_callbacks_.front()->signalFailureAndDeleteSelf( + ConnectionPool::PoolFailureReason::LocalConnectionFailure, "grid teardown", host_); + } pools_.clear(); } @@ -344,11 +356,6 @@ void ConnectivityGrid::addIdleCallback(IdleCb cb) { } void ConnectivityGrid::drainConnections(Envoy::ConnectionPool::DrainBehavior drain_behavior) { - if (draining_) { - // A drain callback has already been set, and only needs to happen once. - return; - } - if (drain_behavior == Envoy::ConnectionPool::DrainBehavior::DrainAndDelete) { // Note that no new pools can be created from this point on // as createNextPool fast-fails if `draining_` is true. diff --git a/source/common/http/conn_pool_grid.h b/source/common/http/conn_pool_grid.h index b5b9bb059662..cfc15dc6af72 100644 --- a/source/common/http/conn_pool_grid.h +++ b/source/common/http/conn_pool_grid.h @@ -96,6 +96,12 @@ class ConnectivityGrid : public ConnectionPool::Instance, StreamInfo::StreamInfo& info, absl::optional protocol); + // Called by onConnectionAttemptFailed and on grid deletion destruction to let wrapper + // callback subscribers know the connect attempt failed. + void signalFailureAndDeleteSelf(ConnectionPool::PoolFailureReason reason, + absl::string_view transport_failure_reason, + Upstream::HostDescriptionConstSharedPtr host); + private: // Removes this from the owning list, deleting it. void deleteThis(); diff --git a/source/common/http/filter_manager.cc b/source/common/http/filter_manager.cc index 15c854b14daf..187bb7b58561 100644 --- a/source/common/http/filter_manager.cc +++ b/source/common/http/filter_manager.cc @@ -604,7 +604,9 @@ void FilterManager::decodeHeaders(ActiveStreamDecoderFilter* filter, RequestHead const auto continue_iteration = (*entry)->commonHandleAfterHeadersCallback(status, end_stream); ENVOY_BUG(!continue_iteration || !state_.local_complete_, - "Filter did not return StopAll or StopIteration after sending a local reply."); + fmt::format( + "filter={} did not return StopAll or StopIteration after sending a local reply.", + (*entry)->filter_context_.config_name)); // If this filter ended the stream, decodeComplete() should be called for it. if ((*entry)->end_stream_) { diff --git a/source/common/http/headers.h b/source/common/http/headers.h index 24ee070ae6fb..450894af1f71 100644 --- a/source/common/http/headers.h +++ b/source/common/http/headers.h @@ -170,6 +170,7 @@ class HeaderValues { // filter. We need to figure out if we can remove this header from the set of headers that // participate in prefix overrides. const LowerCaseString EnvoyIpTags{absl::StrCat(prefix(), "-ip-tags")}; + const LowerCaseString EnvoyLocalOverloaded{absl::StrCat(prefix(), "-local-overloaded")}; const LowerCaseString EnvoyMaxRetries{absl::StrCat(prefix(), "-max-retries")}; const LowerCaseString EnvoyNotForwarded{absl::StrCat(prefix(), "-not-forwarded")}; const LowerCaseString EnvoyOriginalDstHost{absl::StrCat(prefix(), "-original-dst-host")}; diff --git a/source/common/http/http1/codec_impl.cc b/source/common/http/http1/codec_impl.cc index fcd62e115024..be3445209e80 100644 --- a/source/common/http/http1/codec_impl.cc +++ b/source/common/http/http1/codec_impl.cc @@ -1071,8 +1071,8 @@ ServerConnectionImpl::ServerConnectionImpl( [&]() -> void { this->onAboveHighWatermark(); }, []() -> void { /* TODO(adisuissa): handle overflow watermark */ })), headers_with_underscores_action_(headers_with_underscores_action), - abort_dispatch_( - overload_manager.getLoadShedPoint("envoy.load_shed_points.http1_server_abort_dispatch")) { + abort_dispatch_(overload_manager.getLoadShedPoint( + Server::LoadShedPointName::get().H1ServerAbortDispatch)) { ENVOY_LOG_ONCE_IF(trace, abort_dispatch_ == nullptr, "LoadShedPoint envoy.load_shed_points.http1_server_abort_dispatch is not " "found. Is it configured?"); diff --git a/source/common/http/http2/codec_impl.cc b/source/common/http/http2/codec_impl.cc index bfeb546128c9..c0e4f569d1bb 100644 --- a/source/common/http/http2/codec_impl.cc +++ b/source/common/http/http2/codec_impl.cc @@ -532,7 +532,6 @@ void ConnectionImpl::ClientStreamImpl::decodeHeaders() { !CodeUtility::is1xx(status) || status == enumToInt(Http::Code::SwitchingProtocols); if (HeaderUtility::isSpecial1xx(*headers)) { - ASSERT(!remote_end_stream_); response_decoder_.decode1xxHeaders(std::move(headers)); } else { response_decoder_.decodeHeaders(std::move(headers), sendEndStream()); @@ -1107,6 +1106,9 @@ enum GoAwayErrorCode ngHttp2ErrorCodeToErrorCode(uint32_t code) noexcept { } Status ConnectionImpl::onPing(uint64_t opaque_data, bool is_ack) { + ENVOY_CONN_LOG(trace, "recv frame type=PING", connection_); + ASSERT(connection_.state() == Network::Connection::State::Open); + if (is_ack) { ENVOY_CONN_LOG(trace, "recv PING ACK {}", connection_, opaque_data); @@ -1115,9 +1117,10 @@ Status ConnectionImpl::onPing(uint64_t opaque_data, bool is_ack) { return okStatus(); } -Status ConnectionImpl::onBeginData(int32_t stream_id, size_t length, uint8_t type, uint8_t flags, +Status ConnectionImpl::onBeginData(int32_t stream_id, size_t length, uint8_t flags, size_t padding) { - RETURN_IF_ERROR(trackInboundFrames(stream_id, length, type, flags, padding)); + ENVOY_CONN_LOG(trace, "recv frame type=DATA stream_id={}", connection_, stream_id); + RETURN_IF_ERROR(trackInboundFrames(stream_id, length, NGHTTP2_DATA, flags, padding)); StreamImpl* stream = getStreamUnchecked(stream_id); if (!stream) { @@ -1133,6 +1136,7 @@ Status ConnectionImpl::onBeginData(int32_t stream_id, size_t length, uint8_t typ } Status ConnectionImpl::onGoAway(uint32_t error_code) { + ENVOY_CONN_LOG(trace, "recv frame type=GOAWAY", connection_); // Only raise GOAWAY once, since we don't currently expose stream information. Shutdown // notifications are the same as a normal GOAWAY. // TODO: handle multiple GOAWAY frames. @@ -1191,11 +1195,12 @@ Status ConnectionImpl::onHeaders(int32_t stream_id, size_t length, uint8_t flags } Status ConnectionImpl::onRstStream(int32_t stream_id, uint32_t error_code) { - ENVOY_CONN_LOG(trace, "remote reset: {} {}", connection_, stream_id, error_code); + ENVOY_CONN_LOG(trace, "recv frame type=RST_STREAM stream_id={}", connection_, stream_id); StreamImpl* stream = getStreamUnchecked(stream_id); if (!stream) { return okStatus(); } + ENVOY_CONN_LOG(trace, "remote reset: {} {}", connection_, stream_id, error_code); // Track bytes received. stream->bytes_meter_->addWireBytesReceived(/*frame_length=*/4 + H2_FRAME_HEADER_SIZE); stream->remote_rst_ = true; @@ -1221,8 +1226,7 @@ Status ConnectionImpl::onFrameReceived(const nghttp2_frame* frame) { return onPing(data, frame->ping.hd.flags & NGHTTP2_FLAG_ACK); } if (frame->hd.type == NGHTTP2_DATA) { - return onBeginData(frame->hd.stream_id, frame->hd.length, frame->hd.type, frame->hd.flags, - frame->data.padlen); + return onBeginData(frame->hd.stream_id, frame->hd.length, frame->hd.flags, frame->data.padlen); } if (frame->hd.type == NGHTTP2_GOAWAY) { ASSERT(frame->hd.stream_id == 0); @@ -2117,7 +2121,7 @@ ServerConnectionImpl::ServerConnectionImpl( max_request_headers_count), callbacks_(callbacks), headers_with_underscores_action_(headers_with_underscores_action), should_send_go_away_on_dispatch_(overload_manager.getLoadShedPoint( - "envoy.load_shed_points.http2_server_go_away_on_dispatch")) { + Server::LoadShedPointName::get().H2ServerGoAwayOnDispatch)) { ENVOY_LOG_ONCE_IF(trace, should_send_go_away_on_dispatch_ == nullptr, "LoadShedPoint envoy.load_shed_points.http2_server_go_away_on_dispatch is not " "found. Is it configured?"); diff --git a/source/common/http/http2/codec_impl.h b/source/common/http/http2/codec_impl.h index 5e7572970378..50e9411eaad7 100644 --- a/source/common/http/http2/codec_impl.h +++ b/source/common/http/http2/codec_impl.h @@ -708,7 +708,7 @@ class ConnectionImpl : public virtual Connection, int onData(int32_t stream_id, const uint8_t* data, size_t len); Status onBeforeFrameReceived(int32_t stream_id, size_t length, uint8_t type, uint8_t flags); Status onPing(uint64_t opaque_data, bool is_ack); - Status onBeginData(int32_t stream_id, size_t length, uint8_t type, uint8_t flags, size_t padding); + Status onBeginData(int32_t stream_id, size_t length, uint8_t flags, size_t padding); Status onGoAway(uint32_t error_code); Status onHeaders(int32_t stream_id, size_t length, uint8_t flags); Status onRstStream(int32_t stream_id, uint32_t error_code); diff --git a/source/common/json/json_internal.cc b/source/common/json/json_internal.cc index e7de7479247d..f7e624ed7881 100644 --- a/source/common/json/json_internal.cc +++ b/source/common/json/json_internal.cc @@ -788,6 +788,10 @@ std::string Factory::serialize(absl::string_view str) { return j.dump(); } +std::vector Factory::jsonToMsgpack(const std::string& json_string) { + return nlohmann::json::to_msgpack(nlohmann::json::parse(json_string, nullptr, false)); +} + } // namespace Nlohmann } // namespace Json } // namespace Envoy diff --git a/source/common/json/json_internal.h b/source/common/json/json_internal.h index bdb2010d1071..f9e9425ff906 100644 --- a/source/common/json/json_internal.h +++ b/source/common/json/json_internal.h @@ -38,6 +38,13 @@ class Factory { * @return A string suitable for inclusion in a JSON stream, including double-quotes. */ static std::string serialize(absl::string_view str); + + /* + * Serializes a JSON string to a byte vector using the MessagePack serialization format. + * If the provided JSON string is invalid, an empty vector will be returned. + * See: https://github.com/msgpack/msgpack/blob/master/spec.md + */ + static std::vector jsonToMsgpack(const std::string& json); }; } // namespace Nlohmann diff --git a/source/common/json/json_loader.cc b/source/common/json/json_loader.cc index f755480634b9..be0a5f04815a 100644 --- a/source/common/json/json_loader.cc +++ b/source/common/json/json_loader.cc @@ -18,5 +18,9 @@ ObjectSharedPtr Factory::loadFromProtobufStruct(const ProtobufWkt::Struct& proto return Nlohmann::Factory::loadFromProtobufStruct(protobuf_struct); } +std::vector Factory::jsonToMsgpack(const std::string& json) { + return Nlohmann::Factory::jsonToMsgpack(json); +} + } // namespace Json } // namespace Envoy diff --git a/source/common/json/json_loader.h b/source/common/json/json_loader.h index 5a427d5d1b4a..34df5376791a 100644 --- a/source/common/json/json_loader.h +++ b/source/common/json/json_loader.h @@ -27,6 +27,13 @@ class Factory { * Constructs a Json Object from a Protobuf struct. */ static ObjectSharedPtr loadFromProtobufStruct(const ProtobufWkt::Struct& protobuf_struct); + + /* + * Serializes a JSON string to a byte vector using the MessagePack serialization format. + * If the provided JSON string is invalid, an empty vector will be returned. + * See: https://github.com/msgpack/msgpack/blob/master/spec.md + */ + static std::vector jsonToMsgpack(const std::string& json); }; } // namespace Json diff --git a/source/common/listener_manager/BUILD b/source/common/listener_manager/BUILD index 1b8e49427033..e567cb0ac856 100644 --- a/source/common/listener_manager/BUILD +++ b/source/common/listener_manager/BUILD @@ -137,8 +137,10 @@ envoy_cc_library( "//source/common/config:api_version_lib", "//source/common/config:subscription_base_interface", "//source/common/config:utility_lib", + "//source/common/grpc:common_lib", "//source/common/init:target_lib", "//source/common/protobuf:utility_lib", + "@com_google_absl//absl/container:node_hash_set", "@envoy_api//envoy/admin/v3:pkg_cc_proto", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", "@envoy_api//envoy/config/listener/v3:pkg_cc_proto", diff --git a/source/common/listener_manager/lds_api.cc b/source/common/listener_manager/lds_api.cc index ee669d306e5d..052872846da6 100644 --- a/source/common/listener_manager/lds_api.cc +++ b/source/common/listener_manager/lds_api.cc @@ -12,6 +12,7 @@ #include "source/common/common/cleanup.h" #include "source/common/config/api_version.h" #include "source/common/config/utility.h" +#include "source/common/grpc/common.h" #include "source/common/protobuf/utility.h" #include "absl/container/node_hash_set.h" diff --git a/source/common/local_reply/local_reply.cc b/source/common/local_reply/local_reply.cc index 1f745e69a8d1..ae1efcc6385b 100644 --- a/source/common/local_reply/local_reply.cc +++ b/source/common/local_reply/local_reply.cc @@ -61,7 +61,9 @@ class ResponseMapper { status_code_ = static_cast(config.status_code().value()); } if (config.has_body()) { - body_ = Config::DataSource::read(config.body(), true, context.serverFactoryContext().api()); + body_ = THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.body(), true, context.serverFactoryContext().api()), + std::string); } if (config.has_body_format_override()) { diff --git a/source/common/network/address_impl.cc b/source/common/network/address_impl.cc index ca18dc9a34af..40dfb793261c 100644 --- a/source/common/network/address_impl.cc +++ b/source/common/network/address_impl.cc @@ -213,18 +213,18 @@ std::string Ipv4Instance::sockaddrToString(const sockaddr_in& addr) { } namespace { -bool force_ipv4_unsupported_for_test = false; +std::atomic force_ipv4_unsupported_for_test = false; } Cleanup Ipv4Instance::forceProtocolUnsupportedForTest(bool new_val) { - bool old_val = force_ipv4_unsupported_for_test; - force_ipv4_unsupported_for_test = new_val; - return Cleanup([old_val]() { force_ipv4_unsupported_for_test = old_val; }); + bool old_val = force_ipv4_unsupported_for_test.load(); + force_ipv4_unsupported_for_test.store(new_val); + return {[old_val]() { force_ipv4_unsupported_for_test.store(old_val); }}; } absl::Status Ipv4Instance::validateProtocolSupported() { static const bool supported = SocketInterfaceSingleton::get().ipFamilySupported(AF_INET); - if (supported && !force_ipv4_unsupported_for_test) { + if (supported && !force_ipv4_unsupported_for_test.load(std::memory_order_relaxed)) { return absl::OkStatus(); } return absl::FailedPreconditionError("IPv4 addresses are not supported on this machine"); @@ -335,18 +335,18 @@ Ipv6Instance::Ipv6Instance(absl::Status& status, const sockaddr_in6& address, bo } namespace { -bool force_ipv6_unsupported_for_test = false; +std::atomic force_ipv6_unsupported_for_test = false; } Cleanup Ipv6Instance::forceProtocolUnsupportedForTest(bool new_val) { - bool old_val = force_ipv6_unsupported_for_test; - force_ipv6_unsupported_for_test = new_val; - return Cleanup([old_val]() { force_ipv6_unsupported_for_test = old_val; }); + bool old_val = force_ipv6_unsupported_for_test.load(); + force_ipv6_unsupported_for_test.store(new_val); + return {[old_val]() { force_ipv6_unsupported_for_test.store(old_val); }}; } absl::Status Ipv6Instance::validateProtocolSupported() { static const bool supported = SocketInterfaceSingleton::get().ipFamilySupported(AF_INET6); - if (supported && !force_ipv6_unsupported_for_test) { + if (supported && !force_ipv6_unsupported_for_test.load(std::memory_order_relaxed)) { return absl::OkStatus(); } return absl::FailedPreconditionError("IPv6 addresses are not supported on this machine"); diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index 0f23f22da1ca..acce9f66e086 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -88,7 +88,10 @@ ConnectionImpl::ConnectionImpl(Event::Dispatcher& dispatcher, ConnectionSocketPt // Keep it as a bool flag to reduce the times calling runtime method.. enable_rst_detect_send_ = Runtime::runtimeFeatureEnabled( "envoy.reloadable_features.detect_and_raise_rst_tcp_connection"); - + if (!socket_->isOpen()) { + IS_ENVOY_BUG("Client socket failure"); + return; + } if (!connected) { connecting_ = true; } @@ -110,7 +113,7 @@ ConnectionImpl::ConnectionImpl(Event::Dispatcher& dispatcher, ConnectionSocketPt } ConnectionImpl::~ConnectionImpl() { - ASSERT(!ioHandle().isOpen() && delayed_close_timer_ == nullptr, + ASSERT(!socket_->isOpen() && delayed_close_timer_ == nullptr, "ConnectionImpl was unexpectedly torn down without being closed."); // In general we assume that owning code has called close() previously to the destructor being @@ -137,7 +140,7 @@ void ConnectionImpl::removeReadFilter(ReadFilterSharedPtr filter) { bool ConnectionImpl::initializeReadFilters() { return filter_manager_.initializeReadFilters(); } void ConnectionImpl::close(ConnectionCloseType type) { - if (!ioHandle().isOpen()) { + if (!socket_->isOpen()) { return; } @@ -230,7 +233,7 @@ void ConnectionImpl::close(ConnectionCloseType type) { } Connection::State ConnectionImpl::state() const { - if (!ioHandle().isOpen()) { + if (!socket_->isOpen()) { return State::Closed; } else if (inDelayedClose()) { return State::Closing; @@ -265,7 +268,7 @@ void ConnectionImpl::setDetectedCloseType(DetectedCloseType close_type) { } void ConnectionImpl::closeSocket(ConnectionEvent close_type) { - if (!ConnectionImpl::ioHandle().isOpen()) { + if (!socket_->isOpen()) { return; } @@ -322,7 +325,7 @@ void ConnectionImpl::noDelay(bool enable) { // invalid. For this call instead of plumbing through logic that will immediately indicate that a // connect failed, we will just ignore the noDelay() call if the socket is invalid since error is // going to be raised shortly anyway and it makes the calling code simpler. - if (!ioHandle().isOpen()) { + if (!socket_->isOpen()) { return; } @@ -360,7 +363,7 @@ void ConnectionImpl::onRead(uint64_t read_buffer_size) { if (inDelayedClose() || !filterChainWantsData()) { return; } - ASSERT(ioHandle().isOpen()); + ASSERT(socket_->isOpen()); if (read_buffer_size == 0 && !read_end_stream_) { return; @@ -646,7 +649,7 @@ void ConnectionImpl::onFileEvent(uint32_t events) { // It's possible for a write event callback to close the socket (which will cause fd_ to be -1). // In this case ignore read event processing. - if (ioHandle().isOpen() && (events & Event::FileReadyType::Read)) { + if (socket_->isOpen() && (events & Event::FileReadyType::Read)) { onReadReady(); } } @@ -815,7 +818,7 @@ void ConnectionImpl::onWriteReady() { } // If a callback closes the socket, stop iterating. - if (!ioHandle().isOpen()) { + if (!socket_->isOpen()) { return; } } @@ -956,6 +959,13 @@ ClientConnectionImpl::ClientConnectionImpl( : ConnectionImpl(dispatcher, std::move(socket), std::move(transport_socket), stream_info_, false), stream_info_(dispatcher_.timeSource(), socket_->connectionInfoProviderSharedPtr()) { + if (!socket_->isOpen()) { + setFailureReason("socket creation failure"); + // Set up the dispatcher to "close" the connection on the next loop after + // the owner has a chance to add callbacks. + dispatcher_.post([this]() { raiseEvent(ConnectionEvent::LocalClose); }); + return; + } stream_info_.setUpstreamInfo(std::make_shared()); diff --git a/source/common/network/filter_manager_impl.cc b/source/common/network/filter_manager_impl.cc index b26b8a39036b..bc621a36139f 100644 --- a/source/common/network/filter_manager_impl.cc +++ b/source/common/network/filter_manager_impl.cc @@ -42,23 +42,20 @@ bool FilterManagerImpl::initializeReadFilters() { if (upstream_filters_.empty()) { return false; } - if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.initialize_upstream_filters")) { - // Initialize read filters without calling onData() afterwards. - // This is called just after an connection has been established and nothing may have been read - // yet. onData() will be called separately as data is read from the connection. - for (auto& entry : upstream_filters_) { - if (entry->filter_ && !entry->initialized_) { - entry->initialized_ = true; - FilterStatus status = entry->filter_->onNewConnection(); - if (status == FilterStatus::StopIteration || - connection_.state() != Connection::State::Open) { - break; - } + + // Initialize read filters without calling onData() afterwards. + // This is called just after an connection has been established and nothing may have been read + // yet. onData() will be called separately as data is read from the connection. + for (auto& entry : upstream_filters_) { + if (entry->filter_ && !entry->initialized_) { + entry->initialized_ = true; + FilterStatus status = entry->filter_->onNewConnection(); + if (status == FilterStatus::StopIteration || connection_.state() != Connection::State::Open) { + break; } } - } else { - onContinueReading(nullptr, connection_); } + return true; } diff --git a/source/common/network/listen_socket_impl.cc b/source/common/network/listen_socket_impl.cc index 596d2c0846f6..121473fdd492 100644 --- a/source/common/network/listen_socket_impl.cc +++ b/source/common/network/listen_socket_impl.cc @@ -46,7 +46,7 @@ void ListenSocketImpl::setupSocket(const Network::Socket::OptionsSharedPtr& opti UdsListenSocket::UdsListenSocket(const Address::InstanceConstSharedPtr& address) : ListenSocketImpl(ioHandleForAddr(Socket::Type::Stream, address, {}), address) { - RELEASE_ASSERT(io_handle_->isOpen(), ""); + RELEASE_ASSERT(io_handle_ && io_handle_->isOpen(), ""); bind(connection_info_provider_->localAddress()); } diff --git a/source/common/network/listen_socket_impl.h b/source/common/network/listen_socket_impl.h index 1dd9a6f668d7..1a365c65d1a3 100644 --- a/source/common/network/listen_socket_impl.h +++ b/source/common/network/listen_socket_impl.h @@ -53,7 +53,7 @@ template class NetworkListenSocket : public ListenSocketImpl { address) { // Prebind is applied if the socket is bind to port. if (bind_to_port) { - RELEASE_ASSERT(io_handle_->isOpen(), ""); + RELEASE_ASSERT(io_handle_ && io_handle_->isOpen(), ""); setPrebindSocketOptions(); setupSocket(options); } else { diff --git a/source/common/network/socket_impl.cc b/source/common/network/socket_impl.cc index 8b0c40a88ff7..4c1ede5de5e7 100644 --- a/source/common/network/socket_impl.cc +++ b/source/common/network/socket_impl.cc @@ -36,6 +36,12 @@ SocketImpl::SocketImpl(IoHandlePtr&& io_handle, return; } + if (!io_handle_) { + // This can happen iff system socket creation fails. + ENVOY_LOG_MISC(warn, "Created socket with null io handle"); + return; + } + // Should not happen but some tests inject -1 fds if (!io_handle_->isOpen()) { return; diff --git a/source/common/network/socket_impl.h b/source/common/network/socket_impl.h index 2becca95532d..1121cebb1fe2 100644 --- a/source/common/network/socket_impl.h +++ b/source/common/network/socket_impl.h @@ -126,11 +126,11 @@ class SocketImpl : public virtual Socket { IoHandle& ioHandle() override { return *io_handle_; } const IoHandle& ioHandle() const override { return *io_handle_; } void close() override { - if (io_handle_->isOpen()) { + if (io_handle_ && io_handle_->isOpen()) { io_handle_->close(); } } - bool isOpen() const override { return io_handle_->isOpen(); } + bool isOpen() const override { return io_handle_ && io_handle_->isOpen(); } void ensureOptions() { if (!options_) { options_ = std::make_shared>(); diff --git a/source/common/network/socket_interface_impl.cc b/source/common/network/socket_interface_impl.cc index 31440cd2b7df..aead17ecc3ab 100644 --- a/source/common/network/socket_interface_impl.cc +++ b/source/common/network/socket_interface_impl.cc @@ -68,15 +68,31 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, Address::Type const Api::SysCallSocketResult result = Api::OsSysCallsSingleton::get().socket(domain, flags, protocol); - RELEASE_ASSERT(SOCKET_VALID(result.return_value_), - fmt::format("socket(2) failed, got error: {}", errorDetails(result.errno_))); + if (!SOCKET_VALID(result.return_value_)) { + if (Runtime::runtimeFeatureEnabled( + "envoy.restart_features.allow_client_socket_creation_failure")) { + IS_ENVOY_BUG(fmt::format("socket(2) failed, got error: {}", errorDetails(result.errno_))); + return nullptr; + } else { + RELEASE_ASSERT(!SOCKET_VALID(result.return_value_), + fmt::format("socket(2) failed, got error: {}", errorDetails(result.errno_))); + } + } IoHandlePtr io_handle = makeSocket(result.return_value_, socket_v6only, domain); #if defined(__APPLE__) || defined(WIN32) // Cannot set SOCK_NONBLOCK as a ::socket flag. const int rc = io_handle->setBlocking(false).return_value_; - RELEASE_ASSERT(!SOCKET_FAILURE(rc), - fmt::format("Unable to set socket non-blocking: got error: {}", rc)); + if (SOCKET_FAILURE(result.return_value_)) { + if (Runtime::runtimeFeatureEnabled( + "envoy.restart_features.allow_client_socket_creation_failure")) { + IS_ENVOY_BUG(fmt::format("Unable to set socket non-blocking: got error: {}", rc)); + return nullptr; + } else { + RELEASE_ASSERT(SOCKET_FAILURE(rc), + fmt::format("Unable to set socket non-blocking: got error: {}", rc)); + } + } #endif return io_handle; @@ -93,7 +109,7 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, IoHandlePtr io_handle = SocketInterfaceImpl::socket(socket_type, addr->type(), ip_version, v6only, options); - if (addr->type() == Address::Type::Ip && ip_version == Address::IpVersion::v6 && + if (io_handle && addr->type() == Address::Type::Ip && ip_version == Address::IpVersion::v6 && !Address::forceV6()) { // Setting IPV6_V6ONLY restricts the IPv6 socket to IPv6 connections only. const Api::SysCallIntResult result = io_handle->setOption( diff --git a/source/common/network/tcp_listener_impl.cc b/source/common/network/tcp_listener_impl.cc index 29b100928521..513f3a688618 100644 --- a/source/common/network/tcp_listener_impl.cc +++ b/source/common/network/tcp_listener_impl.cc @@ -31,7 +31,7 @@ bool TcpListenerImpl::rejectCxOverGlobalLimit() const { if (runtime_.threadsafeSnapshot()->get(Runtime::Keys::GlobalMaxCxRuntimeKey)) { ENVOY_LOG_ONCE_MISC( warn, - "Global downstream connections limits is configured via runtime key {} and in " + "Global downstream connections limits is configured via deprecated runtime key {} and in " "{}. Using overload manager config.", Runtime::Keys::GlobalMaxCxRuntimeKey, Server::OverloadProactiveResources::get().GlobalDownstreamMaxConnections); @@ -164,7 +164,7 @@ void TcpListenerImpl::setRejectFraction(const UnitFloat reject_fraction) { void TcpListenerImpl::configureLoadShedPoints( Server::LoadShedPointProvider& load_shed_point_provider) { listener_accept_ = - load_shed_point_provider.getLoadShedPoint("envoy.load_shed_points.tcp_listener_accept"); + load_shed_point_provider.getLoadShedPoint(Server::LoadShedPointName::get().TcpListenerAccept); ENVOY_LOG_ONCE_MISC_IF( trace, listener_accept_ == nullptr, "LoadShedPoint envoy.load_shed_points.tcp_listener_accept is not found. Is it configured?"); diff --git a/source/common/quic/BUILD b/source/common/quic/BUILD index 9f9043650ac0..6f0315c59fea 100644 --- a/source/common/quic/BUILD +++ b/source/common/quic/BUILD @@ -145,19 +145,25 @@ envoy_cc_library( envoy_cc_library( name = "envoy_quic_stream_lib", + srcs = ["envoy_quic_stream.cc"], hdrs = ["envoy_quic_stream.h"], tags = ["nofips"], deps = [ ":envoy_quic_simulated_watermark_buffer_lib", ":envoy_quic_utils_lib", ":quic_filter_manager_connection_lib", + ":quic_stats_gatherer", ":send_buffer_monitor_lib", "//envoy/event:dispatcher_interface", "//envoy/http:codec_interface", "//source/common/http:codec_helper_lib", "@com_github_google_quiche//:http2_adapter", + "@com_github_google_quiche//:quic_core_http_client_lib", + "@com_github_google_quiche//:quic_core_http_http_encoder_lib", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", - ], + ] + envoy_select_enable_http_datagrams([ + ":http_datagram_handler", + ]), ) envoy_cc_library( @@ -645,7 +651,9 @@ envoy_cc_library( tags = ["nofips"], deps = [ "//envoy/access_log:access_log_interface", + "//envoy/formatter:http_formatter_context_interface", "//envoy/http:codec_interface", + "//source/common/formatter:substitution_formatter_lib", "//source/common/http:header_map_lib", "@com_github_google_quiche//:quic_core_ack_listener_interface_lib", ], diff --git a/source/common/quic/envoy_quic_client_connection.cc b/source/common/quic/envoy_quic_client_connection.cc index 0616b93808a4..9890990091ca 100644 --- a/source/common/quic/envoy_quic_client_connection.cc +++ b/source/common/quic/envoy_quic_client_connection.cc @@ -87,7 +87,7 @@ uint64_t EnvoyQuicClientConnection::maxDatagramSize() const { void EnvoyQuicClientConnection::setUpConnectionSocket(Network::ConnectionSocket& connection_socket, OptRef delegate) { delegate_ = delegate; - if (connection_socket.ioHandle().isOpen()) { + if (connection_socket.isOpen()) { connection_socket.ioHandle().initializeFileEvent( dispatcher_, [this, &connection_socket](uint32_t events) -> void { @@ -102,7 +102,7 @@ void EnvoyQuicClientConnection::setUpConnectionSocket(Network::ConnectionSocket& connection_socket.close(); } } - if (!connection_socket.ioHandle().isOpen()) { + if (!connection_socket.isOpen()) { CloseConnection(quic::QUIC_CONNECTION_CANCELLED, "Fail to set up connection socket.", quic::ConnectionCloseBehavior::SILENT_CLOSE); } diff --git a/source/common/quic/envoy_quic_client_session.cc b/source/common/quic/envoy_quic_client_session.cc index 46bc95d74ebf..51aa33aaf5ad 100644 --- a/source/common/quic/envoy_quic_client_session.cc +++ b/source/common/quic/envoy_quic_client_session.cc @@ -91,7 +91,7 @@ EnvoyQuicClientSession::EnvoyQuicClientSession( quic_stat_names_(quic_stat_names), rtt_cache_(rtt_cache), scope_(scope), transport_socket_options_(transport_socket_options), transport_socket_factory_(makeOptRefFromPtr( - dynamic_cast(transport_socket_factory.ptr()))) { + dynamic_cast(transport_socket_factory.ptr()))) { streamInfo().setUpstreamInfo(std::make_shared()); if (transport_socket_options_ != nullptr && !transport_socket_options_->applicationProtocolListOverride().empty()) { diff --git a/source/common/quic/envoy_quic_client_session.h b/source/common/quic/envoy_quic_client_session.h index 7128c43d8171..1414a5a5f94d 100644 --- a/source/common/quic/envoy_quic_client_session.h +++ b/source/common/quic/envoy_quic_client_session.h @@ -5,9 +5,9 @@ #include "source/common/quic/envoy_quic_client_connection.h" #include "source/common/quic/envoy_quic_client_crypto_stream_factory.h" #include "source/common/quic/envoy_quic_client_stream.h" -#include "source/common/quic/quic_client_transport_socket_factory.h" #include "source/common/quic/quic_filter_manager_connection_impl.h" #include "source/common/quic/quic_stat_names.h" +#include "source/common/quic/quic_transport_socket_factory.h" #include "quiche/quic/core/http/quic_spdy_client_session.h" @@ -130,7 +130,7 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl, Stats::Scope& scope_; bool disable_keepalive_{false}; Network::TransportSocketOptionsConstSharedPtr transport_socket_options_; - OptRef transport_socket_factory_; + OptRef transport_socket_factory_; std::vector configured_alpns_; }; diff --git a/source/common/quic/envoy_quic_client_stream.cc b/source/common/quic/envoy_quic_client_stream.cc index b082eaec01f3..18e02bb0bdc3 100644 --- a/source/common/quic/envoy_quic_client_stream.cc +++ b/source/common/quic/envoy_quic_client_stream.cc @@ -23,6 +23,7 @@ EnvoyQuicClientStream::EnvoyQuicClientStream( const envoy::config::core::v3::Http3ProtocolOptions& http3_options) : quic::QuicSpdyClientStream(id, client_session, type), EnvoyQuicStream( + *this, // Flow control receive window should be larger than 8k so that the send buffer can fully // utilize congestion control window before it reaches the high watermark. static_cast(GetReceiveWindow().value()), *filterManagerConnection(), @@ -115,103 +116,9 @@ Http::Status EnvoyQuicClientStream::encodeHeaders(const Http::RequestHeaderMap& return Http::okStatus(); } -void EnvoyQuicClientStream::encodeData(Buffer::Instance& data, bool end_stream) { - ENVOY_STREAM_LOG(debug, "encodeData (end_stream={}) of {} bytes.", *this, end_stream, - data.length()); - const bool has_data = data.length() > 0; - if (!has_data && !end_stream) { - return; - } - if (write_side_closed()) { - IS_ENVOY_BUG("encodeData is called on write-closed stream."); - return; - } - ASSERT(!local_end_stream_); - local_end_stream_ = end_stream; - SendBufferMonitor::ScopedWatermarkBufferUpdater updater(this, this); -#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS - if (http_datagram_handler_) { - IncrementalBytesSentTracker tracker(*this, *mutableBytesMeter(), false); - if (!http_datagram_handler_->encodeCapsuleFragment(data.toString(), end_stream)) { - Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD); - return; - } - } else { -#endif - Buffer::RawSliceVector raw_slices = data.getRawSlices(); - absl::InlinedVector quic_slices; - quic_slices.reserve(raw_slices.size()); - for (auto& slice : raw_slices) { - ASSERT(slice.len_ != 0); - // Move each slice into a stand-alone buffer. - // TODO(danzh): investigate the cost of allocating one buffer per slice. - // If it turns out to be expensive, add a new function to free data in the middle in buffer - // interface and re-design QuicheMemSliceImpl. - if (!Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.quiche_use_mem_slice_releasor_api")) { - quic_slices.emplace_back(quiche::QuicheMemSlice::InPlace(), data, slice.len_); - } else { - auto single_slice_buffer = std::make_unique(); - single_slice_buffer->move(data, slice.len_); - quic_slices.emplace_back( - reinterpret_cast(slice.mem_), slice.len_, - [single_slice_buffer = std::move(single_slice_buffer)](const char*) mutable { - // Free this memory explicitly when the callback is invoked. - single_slice_buffer = nullptr; - }); - } - } - quic::QuicConsumedData result{0, false}; - absl::Span span(quic_slices); - { - IncrementalBytesSentTracker tracker(*this, *mutableBytesMeter(), false); - result = WriteBodySlices(span, end_stream); - } - // QUIC stream must take all. - if (result.bytes_consumed == 0 && has_data) { - IS_ENVOY_BUG(fmt::format("Send buffer didn't take all the data. Stream is write {} with {} " - "bytes in send buffer. Current write was rejected.", - write_side_closed() ? "closed" : "open", BufferedDataBytes())); - Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD); - return; - } -#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS - } -#endif - if (local_end_stream_) { - if (codec_callbacks_) { - codec_callbacks_->onCodecEncodeComplete(); - } - onLocalEndStream(); - } -} - void EnvoyQuicClientStream::encodeTrailers(const Http::RequestTrailerMap& trailers) { ENVOY_STREAM_LOG(debug, "encodeTrailers: {}.", *this, trailers); - if (write_side_closed()) { - IS_ENVOY_BUG("encodeTrailers is called on write-closed stream."); - return; - } - ASSERT(!local_end_stream_); - local_end_stream_ = true; - ScopedWatermarkBufferUpdater updater(this, this); - - { - IncrementalBytesSentTracker tracker(*this, *mutableBytesMeter(), true); - size_t bytes_sent = WriteTrailers(envoyHeadersToHttp2HeaderBlock(trailers), nullptr); - ENVOY_BUG(bytes_sent != 0, "Failed to encode trailers"); - } - - if (codec_callbacks_) { - codec_callbacks_->onCodecEncodeComplete(); - } - onLocalEndStream(); -} - -void EnvoyQuicClientStream::encodeMetadata(const Http::MetadataMapVector& /*metadata_map_vector*/) { - // Metadata Frame is not supported in QUICHE. - ENVOY_STREAM_LOG(debug, "METADATA is not supported in Http3.", *this); - stats_.metadata_not_supported_error_.inc(); + encodeTrailersImpl(envoyHeadersToHttp2HeaderBlock(trailers)); } void EnvoyQuicClientStream::resetStream(Http::StreamResetReason reason) { diff --git a/source/common/quic/envoy_quic_client_stream.h b/source/common/quic/envoy_quic_client_stream.h index edaba1b04ea5..98607867ea5b 100644 --- a/source/common/quic/envoy_quic_client_stream.h +++ b/source/common/quic/envoy_quic_client_stream.h @@ -25,8 +25,6 @@ class EnvoyQuicClientStream : public quic::QuicSpdyClientStream, void setResponseDecoder(Http::ResponseDecoder& decoder) { response_decoder_ = &decoder; } // Http::StreamEncoder - void encodeData(Buffer::Instance& data, bool end_stream) override; - void encodeMetadata(const Http::MetadataMapVector& metadata_map_vector) override; Http::Http1StreamEncoderOptionsOptRef http1StreamEncoderOptions() override { return absl::nullopt; } @@ -89,10 +87,6 @@ class EnvoyQuicClientStream : public quic::QuicSpdyClientStream, Http::ResponseDecoder* response_decoder_{nullptr}; bool decoded_1xx_{false}; -#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS - // Setting |http_datagram_handler_| enables HTTP Datagram support. - std::unique_ptr http_datagram_handler_; -#endif // When an HTTP Upgrade is requested, this contains the protocol upgrade type, e.g. "websocket". // It will be empty, when no such request is active. diff --git a/source/common/quic/envoy_quic_dispatcher.cc b/source/common/quic/envoy_quic_dispatcher.cc index dd4f14183b0a..d15b175d7604 100644 --- a/source/common/quic/envoy_quic_dispatcher.cc +++ b/source/common/quic/envoy_quic_dispatcher.cc @@ -184,7 +184,7 @@ void EnvoyQuicDispatcher::closeConnectionsWithFilterChain( // from the map as well. connection.close(Network::ConnectionCloseType::NoFlush); if (!delete_sessions_immediately && - dynamic_cast(connection).fix_quic_lifetime_issues()) { + 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. diff --git a/source/common/quic/envoy_quic_proof_verifier.cc b/source/common/quic/envoy_quic_proof_verifier.cc index b971b0a5ced1..93c206be91dd 100644 --- a/source/common/quic/envoy_quic_proof_verifier.cc +++ b/source/common/quic/envoy_quic_proof_verifier.cc @@ -90,7 +90,10 @@ quic::QuicAsyncStatus EnvoyQuicProofVerifier::VerifyCertChain( } std::unique_ptr cert_view = quic::CertificateView::ParseSingleCertificate(certs[0]); - ASSERT(cert_view != nullptr); + if (cert_view == nullptr) { + *error_details = "unable to parse certificate"; + return quic::QUIC_FAILURE; + } int sign_alg = deduceSignatureAlgorithmFromPublicKey(cert_view->public_key(), error_details); if (sign_alg == 0) { return quic::QUIC_FAILURE; diff --git a/source/common/quic/envoy_quic_server_stream.cc b/source/common/quic/envoy_quic_server_stream.cc index 662f4f123d8b..1932010257f7 100644 --- a/source/common/quic/envoy_quic_server_stream.cc +++ b/source/common/quic/envoy_quic_server_stream.cc @@ -30,6 +30,7 @@ EnvoyQuicServerStream::EnvoyQuicServerStream( headers_with_underscores_action) : quic::QuicSpdyServerStreamBase(id, session, type), EnvoyQuicStream( + *this, // Flow control receive window should be larger than 8k to fully utilize congestion // control window before it reaches the high watermark. static_cast(GetReceiveWindow().value()), *filterManagerConnection(), @@ -89,105 +90,9 @@ void EnvoyQuicServerStream::encodeHeaders(const Http::ResponseHeaderMap& headers } } -void EnvoyQuicServerStream::encodeData(Buffer::Instance& data, bool end_stream) { - ENVOY_STREAM_LOG(debug, "encodeData (end_stream={}) of {} bytes.", *this, end_stream, - data.length()); - const bool has_data = data.length() > 0; - if (!has_data && !end_stream) { - return; - } - if (write_side_closed()) { - IS_ENVOY_BUG("encodeData is called on write-closed stream."); - return; - } - ASSERT(!local_end_stream_); - local_end_stream_ = end_stream; - SendBufferMonitor::ScopedWatermarkBufferUpdater updater(this, this); -#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS - if (http_datagram_handler_) { - IncrementalBytesSentTracker tracker(*this, *mutableBytesMeter(), false); - if (!http_datagram_handler_->encodeCapsuleFragment(data.toString(), end_stream)) { - Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD); - return; - } - } else { -#endif - Buffer::RawSliceVector raw_slices = data.getRawSlices(); - absl::InlinedVector quic_slices; - quic_slices.reserve(raw_slices.size()); - for (auto& slice : raw_slices) { - ASSERT(slice.len_ != 0); - // Move each slice into a stand-alone buffer. - // TODO(danzh): investigate the cost of allocating one buffer per slice. - // If it turns out to be expensive, add a new function to free data in the middle in buffer - // interface and re-design QuicheMemSliceImpl. - if (!Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.quiche_use_mem_slice_releasor_api")) { - quic_slices.emplace_back(quiche::QuicheMemSlice::InPlace(), data, slice.len_); - } else { - auto single_slice_buffer = std::make_unique(); - single_slice_buffer->move(data, slice.len_); - quic_slices.emplace_back( - reinterpret_cast(slice.mem_), slice.len_, - [single_slice_buffer = std::move(single_slice_buffer)](const char*) mutable { - // Free this memory explicitly when the callback is invoked. - single_slice_buffer = nullptr; - }); - } - } - quic::QuicConsumedData result{0, false}; - absl::Span span(quic_slices); - { - IncrementalBytesSentTracker tracker(*this, *mutableBytesMeter(), false); - result = WriteBodySlices(span, end_stream); - stats_gatherer_->addBytesSent(result.bytes_consumed, end_stream); - } - // QUIC stream must take all. - if (result.bytes_consumed == 0 && has_data) { - IS_ENVOY_BUG(fmt::format("Send buffer didn't take all the data. Stream is write {} with {} " - "bytes in send buffer. Current write was rejected.", - write_side_closed() ? "closed" : "open", BufferedDataBytes())); - Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD); - return; - } -#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS - } -#endif - if (local_end_stream_) { - if (codec_callbacks_) { - codec_callbacks_->onCodecEncodeComplete(); - } - onLocalEndStream(); - } -} - void EnvoyQuicServerStream::encodeTrailers(const Http::ResponseTrailerMap& trailers) { ENVOY_STREAM_LOG(debug, "encodeTrailers: {}.", *this, trailers); - if (write_side_closed()) { - IS_ENVOY_BUG("encodeTrailers is called on write-closed stream."); - return; - } - ASSERT(!local_end_stream_); - local_end_stream_ = true; - - SendBufferMonitor::ScopedWatermarkBufferUpdater updater(this, this); - - { - IncrementalBytesSentTracker tracker(*this, *mutableBytesMeter(), true); - size_t bytes_sent = WriteTrailers(envoyHeadersToHttp2HeaderBlock(trailers), nullptr); - ENVOY_BUG(bytes_sent != 0, "Failed to encode trailers."); - stats_gatherer_->addBytesSent(bytes_sent, true); - } - if (codec_callbacks_) { - codec_callbacks_->onCodecEncodeComplete(); - } - onLocalEndStream(); -} - -void EnvoyQuicServerStream::encodeMetadata(const Http::MetadataMapVector& /*metadata_map_vector*/) { - // Metadata Frame is not supported in QUIC. - ENVOY_STREAM_LOG(debug, "METADATA is not supported in Http3.", *this); - stats_.metadata_not_supported_error_.inc(); + encodeTrailersImpl(envoyHeadersToHttp2HeaderBlock(trailers)); } void EnvoyQuicServerStream::resetStream(Http::StreamResetReason reason) { diff --git a/source/common/quic/envoy_quic_server_stream.h b/source/common/quic/envoy_quic_server_stream.h index 146e4f8b0f04..bb9c32003b07 100644 --- a/source/common/quic/envoy_quic_server_stream.h +++ b/source/common/quic/envoy_quic_server_stream.h @@ -5,7 +5,6 @@ #ifdef ENVOY_ENABLE_HTTP_DATAGRAMS #include "source/common/quic/http_datagram_handler.h" #endif -#include "source/common/quic/quic_stats_gatherer.h" #include "quiche/common/platform/api/quiche_reference_counted.h" #include "quiche/quic/core/http/quic_spdy_server_stream_base.h" @@ -28,14 +27,11 @@ class EnvoyQuicServerStream : public quic::QuicSpdyServerStreamBase, request_decoder_ = &decoder; stats_gatherer_->setAccessLogHandlers(request_decoder_->accessLogHandlers()); } - QuicStatsGatherer* statsGatherer() { return stats_gatherer_.get(); } // Http::StreamEncoder void encode1xxHeaders(const Http::ResponseHeaderMap& headers) override; void encodeHeaders(const Http::ResponseHeaderMap& headers, bool end_stream) override; - void encodeData(Buffer::Instance& data, bool end_stream) override; void encodeTrailers(const Http::ResponseTrailerMap& trailers) override; - void encodeMetadata(const Http::MetadataMapVector& metadata_map_vector) override; Http::Http1StreamEncoderOptionsOptRef http1StreamEncoderOptions() override { return absl::nullopt; } @@ -121,11 +117,6 @@ class EnvoyQuicServerStream : public quic::QuicSpdyServerStreamBase, envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction headers_with_underscores_action_; - quiche::QuicheReferenceCountedPointer stats_gatherer_; -#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS - // Setting |http_datagram_handler_| enables HTTP Datagram support. - std::unique_ptr http_datagram_handler_; -#endif // True if a :path header has been seen before. bool saw_path_{false}; }; diff --git a/source/common/quic/envoy_quic_stream.cc b/source/common/quic/envoy_quic_stream.cc new file mode 100644 index 000000000000..8ca1e7950466 --- /dev/null +++ b/source/common/quic/envoy_quic_stream.cc @@ -0,0 +1,112 @@ +#include "source/common/quic/envoy_quic_stream.h" + +#include "source/common/http/utility.h" + +#include "quiche/quic/core/http/http_encoder.h" +#include "quiche/quic/core/qpack/qpack_encoder.h" +#include "quiche/quic/core/qpack/qpack_instruction_encoder.h" + +namespace Envoy { +namespace Quic { + +void EnvoyQuicStream::encodeData(Buffer::Instance& data, bool end_stream) { + ENVOY_STREAM_LOG(debug, "encodeData (end_stream={}) of {} bytes.", *this, end_stream, + data.length()); + const bool has_data = data.length() > 0; + if (!has_data && !end_stream) { + return; + } + if (quic_stream_.write_side_closed()) { + IS_ENVOY_BUG("encodeData is called on write-closed stream."); + return; + } + ASSERT(!local_end_stream_); + local_end_stream_ = end_stream; + SendBufferMonitor::ScopedWatermarkBufferUpdater updater(&quic_stream_, this); +#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS + if (http_datagram_handler_) { + IncrementalBytesSentTracker tracker(quic_stream_, *mutableBytesMeter(), false); + if (!http_datagram_handler_->encodeCapsuleFragment(data.toString(), end_stream)) { + quic_stream_.Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD); + return; + } + } else { +#endif + Buffer::RawSliceVector raw_slices = data.getRawSlices(); + absl::InlinedVector quic_slices; + quic_slices.reserve(raw_slices.size()); + for (auto& slice : raw_slices) { + ASSERT(slice.len_ != 0); + // Move each slice into a stand-alone buffer. + // TODO(danzh): investigate the cost of allocating one buffer per slice. + // If it turns out to be expensive, add a new function to free data in the middle in buffer + // interface and re-design QuicheMemSliceImpl. + auto single_slice_buffer = std::make_unique(); + single_slice_buffer->move(data, slice.len_); + quic_slices.emplace_back( + reinterpret_cast(slice.mem_), slice.len_, + [single_slice_buffer = std::move(single_slice_buffer)](const char*) mutable { + // Free this memory explicitly when the callback is invoked. + single_slice_buffer = nullptr; + }); + } + quic::QuicConsumedData result{0, false}; + absl::Span span(quic_slices); + { + IncrementalBytesSentTracker tracker(quic_stream_, *mutableBytesMeter(), false); + result = quic_stream_.WriteBodySlices(span, end_stream); + if (stats_gatherer_ != nullptr) { + stats_gatherer_->addBytesSent(result.bytes_consumed, end_stream); + } + } + // QUIC stream must take all. + if (result.bytes_consumed == 0 && has_data) { + IS_ENVOY_BUG(fmt::format("Send buffer didn't take all the data. Stream is write {} with {} " + "bytes in send buffer. Current write was rejected.", + quic_stream_.write_side_closed() ? "closed" : "open", + quic_stream_.BufferedDataBytes())); + quic_stream_.Reset(quic::QUIC_BAD_APPLICATION_PAYLOAD); + return; + } +#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS + } +#endif + if (local_end_stream_) { + if (codec_callbacks_) { + codec_callbacks_->onCodecEncodeComplete(); + } + onLocalEndStream(); + } +} + +void EnvoyQuicStream::encodeTrailersImpl(spdy::Http2HeaderBlock&& trailers) { + if (quic_stream_.write_side_closed()) { + IS_ENVOY_BUG("encodeTrailers is called on write-closed stream."); + return; + } + ASSERT(!local_end_stream_); + local_end_stream_ = true; + + SendBufferMonitor::ScopedWatermarkBufferUpdater updater(&quic_stream_, this); + { + IncrementalBytesSentTracker tracker(quic_stream_, *mutableBytesMeter(), true); + size_t bytes_sent = quic_stream_.WriteTrailers(std::move(trailers), nullptr); + ENVOY_BUG(bytes_sent != 0, "Failed to encode trailers."); + if (stats_gatherer_ != nullptr) { + stats_gatherer_->addBytesSent(bytes_sent, true); + } + } + if (codec_callbacks_) { + codec_callbacks_->onCodecEncodeComplete(); + } + onLocalEndStream(); +} + +void EnvoyQuicStream::encodeMetadata(const Http::MetadataMapVector& /*metadata_map_vector*/) { + // Metadata Frame is not supported in QUICHE. + ENVOY_STREAM_LOG(debug, "METADATA is not supported in Http3.", *this); + stats_.metadata_not_supported_error_.inc(); +} + +} // namespace Quic +} // namespace Envoy diff --git a/source/common/quic/envoy_quic_stream.h b/source/common/quic/envoy_quic_stream.h index 7bb5af71f25a..360788d2fdcd 100644 --- a/source/common/quic/envoy_quic_stream.h +++ b/source/common/quic/envoy_quic_stream.h @@ -10,10 +10,16 @@ #include "source/common/http/codec_helper.h" #include "source/common/quic/envoy_quic_simulated_watermark_buffer.h" #include "source/common/quic/envoy_quic_utils.h" + +#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS +#include "source/common/quic/http_datagram_handler.h" +#endif #include "source/common/quic/quic_filter_manager_connection_impl.h" +#include "source/common/quic/quic_stats_gatherer.h" #include "source/common/quic/send_buffer_monitor.h" #include "quiche/http2/adapter/header_validator.h" +#include "quiche/quic/core/http/quic_spdy_stream.h" namespace Envoy { namespace Quic { @@ -27,12 +33,13 @@ class EnvoyQuicStream : public virtual Http::StreamEncoder, public: // |buffer_limit| is the high watermark of the stream send buffer, and the low // watermark will be half of it. - EnvoyQuicStream(uint32_t buffer_limit, QuicFilterManagerConnectionImpl& filter_manager_connection, + EnvoyQuicStream(quic::QuicSpdyStream& quic_stream, uint32_t buffer_limit, + QuicFilterManagerConnectionImpl& filter_manager_connection, std::function below_low_watermark, std::function above_high_watermark, Http::Http3::CodecStats& stats, const envoy::config::core::v3::Http3ProtocolOptions& http3_options) : Http::MultiplexedStreamImplBase(filter_manager_connection.dispatcher()), stats_(stats), - http3_options_(http3_options), + http3_options_(http3_options), quic_stream_(quic_stream), send_buffer_simulation_(buffer_limit / 2, buffer_limit, std::move(below_low_watermark), std::move(above_high_watermark), ENVOY_LOGGER()), filter_manager_connection_(filter_manager_connection), @@ -44,6 +51,8 @@ class EnvoyQuicStream : public virtual Http::StreamEncoder, // Http::StreamEncoder Stream& getStream() override { return *this; } + void encodeData(Buffer::Instance& data, bool end_stream) override; + void encodeMetadata(const Http::MetadataMapVector& metadata_map_vector) override; // Http::Stream void readDisable(bool disable) override { @@ -138,6 +147,8 @@ class EnvoyQuicStream : public virtual Http::StreamEncoder, const StreamInfo::BytesMeterSharedPtr& bytesMeter() override { return bytes_meter_; } + QuicStatsGatherer* statsGatherer() { return stats_gatherer_.get(); } + protected: virtual void switchStreamBlockState() PURE; @@ -167,6 +178,14 @@ class EnvoyQuicStream : public virtual Http::StreamEncoder, StreamInfo::BytesMeterSharedPtr& mutableBytesMeter() { return bytes_meter_; } + void encodeTrailersImpl(spdy::Http2HeaderBlock&& trailers); + +#ifdef ENVOY_ENABLE_HTTP_DATAGRAMS + // Setting |http_datagram_handler_| enables HTTP Datagram support. + std::unique_ptr http_datagram_handler_; +#endif + quiche::QuicheReferenceCountedPointer stats_gatherer_; + // True once end of stream is propagated to Envoy. Envoy doesn't expect to be // notified more than once about end of stream. So once this is true, no need // to set it in the callback to Envoy stream any more. @@ -191,6 +210,9 @@ class EnvoyQuicStream : public virtual Http::StreamEncoder, bool saw_regular_headers_{false}; private: + // QUIC stream that this EnvoyQuicStream wraps. + quic::QuicSpdyStream& quic_stream_; + // Keeps track of bytes buffered in the stream send buffer in QUICHE and reacts // upon crossing high and low watermarks. // Its high watermark is also the buffer limit of stream read/write filters in diff --git a/source/common/quic/envoy_quic_utils.cc b/source/common/quic/envoy_quic_utils.cc index 0a90b562b04a..1d4b0bc68aa6 100644 --- a/source/common/quic/envoy_quic_utils.cc +++ b/source/common/quic/envoy_quic_utils.cc @@ -143,6 +143,10 @@ createConnectionSocket(const Network::Address::InstanceConstSharedPtr& peer_addr } auto connection_socket = std::make_unique( Network::Socket::Type::Datagram, local_addr, peer_addr, Network::SocketCreationOptions{}); + if (!connection_socket->isOpen()) { + ENVOY_LOG_MISC(error, "Failed to create socket"); + return connection_socket; + } connection_socket->addOptions(Network::SocketOptionFactory::buildIpPacketInfoOptions()); connection_socket->addOptions(Network::SocketOptionFactory::buildRxQueueOverFlowOptions()); if (options != nullptr) { diff --git a/source/common/quic/platform/BUILD b/source/common/quic/platform/BUILD index d10213a60dc9..4d6061b2e072 100644 --- a/source/common/quic/platform/BUILD +++ b/source/common/quic/platform/BUILD @@ -1,5 +1,6 @@ load( "//bazel:envoy_build_system.bzl", + "envoy_cc_library", "envoy_package", ) load( @@ -36,6 +37,12 @@ envoy_package() # TODO: add build target for quic_platform_impl_lib +envoy_cc_library( + name = "quiche_flags_constants", + hdrs = ["quiche_flags_constants.h"], + deps = ["//source/common/http:utility_lib"], +) + envoy_quiche_platform_impl_cc_library( name = "quiche_flags_impl_lib", srcs = ["quiche_flags_impl.cc"], @@ -45,6 +52,7 @@ envoy_quiche_platform_impl_cc_library( "abseil_synchronization", ], deps = [ + ":quiche_flags_constants", "//source/common/common:assert_lib", "//source/common/http:utility_lib", "@com_github_google_quiche//:quic_core_flags_list_lib", diff --git a/source/common/quic/platform/quiche_flags_constants.h b/source/common/quic/platform/quiche_flags_constants.h new file mode 100644 index 000000000000..cff579bad68c --- /dev/null +++ b/source/common/quic/platform/quiche_flags_constants.h @@ -0,0 +1,46 @@ +#pragma once + +// NOLINT(namespace-envoy) + +// This file is part of the QUICHE platform implementation, and is not to be +// consumed or referenced directly by other Envoy code. It serves purely as a +// porting layer for QUICHE. +// NOLINT(namespace-envoy) + +// This file is part of the QUICHE platform implementation, and is not to be +// consumed or referenced directly by other Envoy code. It serves purely as a +// porting layer for QUICHE. + +#include "source/common/http/utility.h" + +#define OVERRIDDEN_RELOADABLE_FLAGS(KEY_VALUE_PAIR) \ + /* Envoy only supports RFC-v1 in the long term, so disable IETF draft 29 implementation by \ + * default. */ \ + KEY_VALUE_PAIR(quic_disable_version_draft_29, true) \ + /* This flag enables BBR, otherwise QUIC will use Cubic which is less performant */ \ + KEY_VALUE_PAIR(quic_default_to_bbr, true) + +#define OVERRIDDEN_PROTOCOL_FLAGS(KEY_VALUE_PAIR) \ + /* Do not include 32-byte per-entry overhead while counting header size. */ \ + KEY_VALUE_PAIR(quic_header_size_limit_includes_overhead, false) \ + /* Set send buffer twice of max flow control window to ensure that stream send buffer always \ + * takes all the data. The max amount of data buffered is the per-stream high watermark + the \ + * max flow control window of upstream. The per-stream high watermark should be smaller than max \ + * flow control window to make sure upper stream can be flow control blocked early enough not to \ + * send more than the threshold allows. */ \ + /* TODO(#8826) Ideally we should use the negotiated value from upstream which is not accessible \ + * for now. 512MB is way too large, but the actual bytes buffered should be bound by the \ + * negotiated upstream flow control window. */ \ + KEY_VALUE_PAIR(quic_buffered_data_threshold, \ + 2 * ::Envoy::Http2::Utility::OptionsLimits::DEFAULT_INITIAL_STREAM_WINDOW_SIZE) \ + /* Envoy should send server preferred address without a client option by default. */ \ + KEY_VALUE_PAIR(quic_always_support_server_preferred_address, true) + +namespace quiche { + +inline constexpr absl::string_view EnvoyQuicheReloadableFlagPrefix = + "envoy.reloadable_features.FLAGS_envoy_quic_reloadable_flag_"; + +inline constexpr absl::string_view EnvoyFeaturePrefix = "envoy.reloadable_features."; + +} // namespace quiche diff --git a/source/common/quic/platform/quiche_flags_impl.cc b/source/common/quic/platform/quiche_flags_impl.cc index aeeb9bb0143a..f46ef6303e23 100644 --- a/source/common/quic/platform/quiche_flags_impl.cc +++ b/source/common/quic/platform/quiche_flags_impl.cc @@ -5,9 +5,11 @@ // porting layer for QUICHE. #include +#include +#include +#include #include "source/common/common/assert.h" -#include "source/common/http/utility.h" #include "absl/flags/flag.h" #include "absl/strings/ascii.h" @@ -17,6 +19,17 @@ namespace { +#define QUICHE_RELOADABLE_FLAG_OVERRIDE(flag_name, value) \ + {STRINGIFY(quic_reloadable_flag_##flag_name), value}, +constexpr std::pair quiche_reloadable_flag_overrides[]{ + OVERRIDDEN_RELOADABLE_FLAGS(QUICHE_RELOADABLE_FLAG_OVERRIDE)}; +#undef QUICHE_RELOADABLE_FLAG_OVERRIDE + +#define QUICHE_PROTOCOL_FLAG_OVERRIDE(flag_name, value) {STRINGIFY(flag_name), value}, +constexpr std::pair> + quiche_protocol_flag_overrides[]{OVERRIDDEN_PROTOCOL_FLAGS(QUICHE_PROTOCOL_FLAG_OVERRIDE)}; +#undef QUICHE_PROTOCOL_FLAG_OVERRIDE + // Envoy uses different default values for some QUICHE flags. The following methods // ensure that the absl::Flag objects are created with the correct values for // these flags. This ensures that the absl::FlagSaver finds the correct values @@ -25,39 +38,28 @@ namespace { template constexpr T maybeOverride(absl::string_view /*name*/, T val) { return val; } template <> constexpr bool maybeOverride(absl::string_view name, bool val) { - if (name == "quic_reloadable_flag_quic_disable_version_draft_29") { - // Envoy only supports RFC-v1 in the long term, so disable IETF draft 29 implementation by - // default. - return true; - } - if (name == "quic_reloadable_flag_quic_default_to_bbr") { - // This flag enables BBR, otherwise QUIC will use Cubic which is less performant. - return true; - } - if (name == "quic_header_size_limit_includes_overhead") { - // Do not include 32-byte per-entry overhead while counting header size. - return false; + for (const auto& [flag_name, new_value] : quiche_reloadable_flag_overrides) { + if (flag_name == name) { + return new_value; + } } - if (name == "quic_always_support_server_preferred_address") { - // Envoy should send server preferred address without a client option by default. - return true; + for (const auto& [flag_name, new_value_variant] : quiche_protocol_flag_overrides) { + if (flag_name == name) { + if (absl::holds_alternative(new_value_variant)) { + return absl::get(new_value_variant); + } + } } - return val; } template <> constexpr int32_t maybeOverride(absl::string_view name, int32_t val) { - if (name == "quic_buffered_data_threshold") { - // Set send buffer twice of max flow control window to ensure that stream send - // buffer always takes all the data. - // The max amount of data buffered is the per-stream high watermark + the max - // flow control window of upstream. The per-stream high watermark should be - // smaller than max flow control window to make sure upper stream can be flow - // control blocked early enough not to send more than the threshold allows. - // TODO(#8826) Ideally we should use the negotiated value from upstream which is not accessible - // for now. 512MB is way to large, but the actual bytes buffered should be bound by the - // negotiated upstream flow control window. - return 2 * ::Envoy::Http2::Utility::OptionsLimits::DEFAULT_INITIAL_STREAM_WINDOW_SIZE; // 512MB + for (const auto& [flag_name, new_value_variant] : quiche_protocol_flag_overrides) { + if (flag_name == name) { + if (absl::holds_alternative(new_value_variant)) { + return absl::get(new_value_variant); + } + } } return val; } @@ -122,6 +124,11 @@ FlagRegistry::FlagRegistry() : reloadable_flags_(makeReloadableFlagMap()) {} // static FlagRegistry& FlagRegistry::getInstance() { static auto* instance = new FlagRegistry(); + ASSERT(sizeof(quiche_reloadable_flag_overrides) / sizeof(std::pair) == + 2); + ASSERT(sizeof(quiche_protocol_flag_overrides) / + sizeof(std::pair>) == + 3); return *instance; } diff --git a/source/common/quic/platform/quiche_flags_impl.h b/source/common/quic/platform/quiche_flags_impl.h index e3a8d3f87d7c..77c31aea9432 100644 --- a/source/common/quic/platform/quiche_flags_impl.h +++ b/source/common/quic/platform/quiche_flags_impl.h @@ -9,6 +9,8 @@ #include #include +#include "source/common/quic/platform/quiche_flags_constants.h" + #include "absl/container/flat_hash_map.h" #include "absl/flags/declare.h" #include "absl/flags/flag.h" @@ -20,10 +22,6 @@ namespace quiche { -const std::string EnvoyQuicheReloadableFlagPrefix = - "envoy.reloadable_features.FLAGS_envoy_quic_reloadable_flag_"; -const std::string EnvoyFeaturePrefix = "envoy.reloadable_features."; - using ReloadableFlag = absl::Flag; // Registry of QUICHE flags. Can be used to update reloadable flag values. diff --git a/source/common/quic/quic_client_transport_socket_factory.cc b/source/common/quic/quic_client_transport_socket_factory.cc index 7075c9867db6..3b90ee46143e 100644 --- a/source/common/quic/quic_client_transport_socket_factory.cc +++ b/source/common/quic/quic_client_transport_socket_factory.cc @@ -33,7 +33,10 @@ QuicClientTransportSocketFactory::QuicClientTransportSocketFactory( Server::Configuration::TransportSocketFactoryContext& factory_context) : QuicTransportSocketFactoryBase(factory_context.statsScope(), "client"), fallback_factory_(std::make_unique( - std::move(config), factory_context.sslContextManager(), factory_context.statsScope())) {} + std::move(config), factory_context.sslContextManager(), factory_context.statsScope())), + tls_slot_(factory_context.serverFactoryContext().threadLocal()) { + tls_slot_.set([](Event::Dispatcher&) { return std::make_shared(); }); +} void QuicClientTransportSocketFactory::initialize() { if (!fallback_factory_->clientContextConfig()->alpnProtocols().empty()) { @@ -55,15 +58,18 @@ std::shared_ptr QuicClientTransportSocketFactory:: return nullptr; } - if (client_context_ != context) { + ASSERT(tls_slot_.currentThreadRegistered()); + ThreadLocalQuicConfig& tls_config = *tls_slot_; + + if (tls_config.client_context_ != context) { // If the context has been updated, update the crypto config. - client_context_ = context; - crypto_config_ = std::make_shared( + tls_config.client_context_ = context; + tls_config.crypto_config_ = std::make_shared( std::make_unique(std::move(context)), std::make_unique()); } // Return the latest crypto config. - return crypto_config_; + return tls_config.crypto_config_; } REGISTER_FACTORY(QuicClientTransportSocketConfigFactory, diff --git a/source/common/quic/quic_client_transport_socket_factory.h b/source/common/quic/quic_client_transport_socket_factory.h index a9fa4c8b9c43..c6783bd78580 100644 --- a/source/common/quic/quic_client_transport_socket_factory.h +++ b/source/common/quic/quic_client_transport_socket_factory.h @@ -45,14 +45,22 @@ class QuicClientTransportSocketFactory : public Network::CommonUpstreamTransport // fallback_factory_ will update the context. void onSecretUpdated() override {} + // The cache in the QuicCryptoClientConfig is not thread-safe, so crypto_config_ needs to + // be a thread local object. client_context lets the thread local object determine if the crypto + // config needs to be updated. + struct ThreadLocalQuicConfig : public ThreadLocal::ThreadLocalObject { + // Latch the latest client context, to determine if it has updated since last + // checked. + Envoy::Ssl::ClientContextSharedPtr client_context_; + // If client_context_ changes, client config will be updated as well. + std::shared_ptr crypto_config_; + }; + private: // The QUIC client transport socket can create TLS sockets for fallback to TCP. std::unique_ptr fallback_factory_; - // Latch the latest client context, to determine if it has updated since last - // checked. - Envoy::Ssl::ClientContextSharedPtr client_context_; - // If client_context_ changes, client config will be updated as well. - std::shared_ptr crypto_config_; + // The storage for thread local quic config. + ThreadLocal::TypedSlot tls_slot_; }; class QuicClientTransportSocketConfigFactory diff --git a/source/common/quic/quic_filter_manager_connection_impl.h b/source/common/quic/quic_filter_manager_connection_impl.h index 4a1a57a093d3..432f2779673b 100644 --- a/source/common/quic/quic_filter_manager_connection_impl.h +++ b/source/common/quic/quic_filter_manager_connection_impl.h @@ -171,7 +171,7 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase, max_headers_count_ = max_headers_count; } - bool fix_quic_lifetime_issues() const { return fix_quic_lifetime_issues_; } + bool fixQuicLifetimeIssues() const { return fix_quic_lifetime_issues_; } protected: // Propagate connection close to network_connection_callbacks_. diff --git a/source/common/quic/quic_stats_gatherer.cc b/source/common/quic/quic_stats_gatherer.cc index cd663aa3cb15..c1a0da083082 100644 --- a/source/common/quic/quic_stats_gatherer.cc +++ b/source/common/quic/quic_stats_gatherer.cc @@ -2,6 +2,8 @@ #include +#include "envoy/formatter/http_formatter_context.h" + namespace Envoy { namespace Quic { diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index ecf2c3639d90..19f1d7367f3f 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -32,6 +32,7 @@ #include "source/common/config/metadata.h" #include "source/common/config/utility.h" #include "source/common/config/well_known_names.h" +#include "source/common/grpc/common.h" #include "source/common/http/header_utility.h" #include "source/common/http/headers.h" #include "source/common/http/matching/data_impl.h" diff --git a/source/common/router/config_utility.cc b/source/common/router/config_utility.cc index f70bcc217a8f..b261f4a353a0 100644 --- a/source/common/router/config_utility.cc +++ b/source/common/router/config_utility.cc @@ -114,8 +114,9 @@ ConfigUtility::parseDirectResponseBody(const envoy::config::route::v3::Route& ro } const auto& body = route.direct_response().body(); - const std::string string_body = - Envoy::Config::DataSource::read(body, true, api, max_body_size_bytes); + auto body_or_error = Envoy::Config::DataSource::read(body, true, api, max_body_size_bytes); + RETURN_IF_STATUS_NOT_OK(body_or_error); + const std::string& string_body = body_or_error.value(); if (string_body.length() > max_body_size_bytes) { return absl::InvalidArgumentError(fmt::format("response body size is {} bytes; maximum is {}", string_body.length(), max_body_size_bytes)); diff --git a/source/common/router/router.cc b/source/common/router/router.cc index c4172d2d0906..a41e1c3374dc 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -873,10 +873,6 @@ Http::FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_strea } } - // If we aren't buffering and there is no active request, an abort should have occurred - // already. - ASSERT(buffering || !upstream_requests_.empty()); - for (auto* shadow_stream : shadow_streams_) { if (end_stream) { shadow_stream->removeDestructorCallback(); @@ -902,7 +898,23 @@ Http::FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_strea // this stack for whether `data` is the same buffer as already buffered data. callbacks_->addDecodedData(data, true); } else { - upstream_requests_.front()->acceptDataFromRouter(data, end_stream); + if (!Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.send_local_reply_when_no_buffer_and_upstream_request")) { + upstream_requests_.front()->acceptDataFromRouter(data, end_stream); + } else { + if (!upstream_requests_.empty()) { + upstream_requests_.front()->acceptDataFromRouter(data, end_stream); + } else { + // not buffering any data for retry, shadow, and internal redirect, and there will be + // no more upstream request, abort the request and clean up. + cleanup(); + callbacks_->sendLocalReply( + Http::Code::ServiceUnavailable, + "upstream is closed prematurely during decoding data from downstream", modify_headers_, + absl::nullopt, StreamInfo::ResponseCodeDetails::get().EarlyUpstreamReset); + return Http::FilterDataStatus::StopIterationNoBuffer; + } + } } if (end_stream) { diff --git a/source/common/router/upstream_request.cc b/source/common/router/upstream_request.cc index 8496745a80cc..7c9079e58a44 100644 --- a/source/common/router/upstream_request.cc +++ b/source/common/router/upstream_request.cc @@ -134,7 +134,7 @@ UpstreamRequest::UpstreamRequest(RouterFilterInterface& parent, // Set up the upstream HTTP filter manager. filter_manager_callbacks_ = std::make_unique(*this); filter_manager_ = std::make_unique( - *filter_manager_callbacks_, parent_.callbacks()->dispatcher(), connection(), + *filter_manager_callbacks_, parent_.callbacks()->dispatcher(), UpstreamRequest::connection(), parent_.callbacks()->streamId(), parent_.callbacks()->account(), true, parent_.callbacks()->decoderBufferLimit(), *parent_.cluster(), *this); // Attempt to create custom cluster-specified filter chain diff --git a/source/common/router/upstream_request.h b/source/common/router/upstream_request.h index b2369c8cb125..9e88bfefda31 100644 --- a/source/common/router/upstream_request.h +++ b/source/common/router/upstream_request.h @@ -61,12 +61,15 @@ class UpstreamCodecFilter; * There is some required communication between the UpstreamRequest and * UpstreamCodecFilter. This is accomplished via the UpstreamStreamFilterCallbacks * interface, with the UpstreamFilterManager acting as intermediary. + * + * UpstreamRequest is marked as final because no subclasses are expected. + * This class is intended to be used as-is without any specialized inheritance. */ -class UpstreamRequest : public Logger::Loggable, - public UpstreamToDownstream, - public LinkedObject, - public GenericConnectionPoolCallbacks, - public Event::DeferredDeletable { +class UpstreamRequest final : public Logger::Loggable, + public UpstreamToDownstream, + public LinkedObject, + public GenericConnectionPoolCallbacks, + public Event::DeferredDeletable { public: UpstreamRequest(RouterFilterInterface& parent, std::unique_ptr&& conn_pool, bool can_send_early_data, bool can_use_http3); diff --git a/source/common/router/vhds.cc b/source/common/router/vhds.cc index a805597b0870..823ee0b0f86d 100644 --- a/source/common/router/vhds.cc +++ b/source/common/router/vhds.cc @@ -13,6 +13,7 @@ #include "source/common/common/fmt.h" #include "source/common/config/api_version.h" #include "source/common/config/utility.h" +#include "source/common/grpc/common.h" #include "source/common/protobuf/utility.h" #include "source/common/router/config_impl.h" diff --git a/source/common/runtime/BUILD b/source/common/runtime/BUILD index b5b1dc888386..1240f73bd005 100644 --- a/source/common/runtime/BUILD +++ b/source/common/runtime/BUILD @@ -94,6 +94,7 @@ envoy_cc_library( "//source/common/config:subscription_base_interface", "//source/common/filesystem:directory_lib", "//source/common/grpc:common_lib", + "//source/common/http:utility_lib", "//source/common/init:manager_lib", "//source/common/init:target_lib", "//source/common/init:watcher_lib", @@ -106,5 +107,6 @@ envoy_cc_library( "@envoy_api//envoy/type/v3:pkg_cc_proto", ] + envoy_select_enable_http3([ "//source/common/quic/platform:quiche_flags_impl_lib", + "@com_github_google_quiche//:quic_platform_base", ]), ) diff --git a/source/common/runtime/runtime_features.cc b/source/common/runtime/runtime_features.cc index 19173d3b2cd5..528b1e993ffa 100644 --- a/source/common/runtime/runtime_features.cc +++ b/source/common/runtime/runtime_features.cc @@ -39,9 +39,11 @@ RUNTIME_GUARD(envoy_reloadable_features_defer_processing_backedup_streams); RUNTIME_GUARD(envoy_reloadable_features_detect_and_raise_rst_tcp_connection); RUNTIME_GUARD(envoy_reloadable_features_dfp_mixed_scheme); RUNTIME_GUARD(envoy_reloadable_features_dns_cache_set_first_resolve_complete); +RUNTIME_GUARD(envoy_reloadable_features_edf_lb_host_scheduler_init_fix); RUNTIME_GUARD(envoy_reloadable_features_edf_lb_locality_scheduler_init_fix); RUNTIME_GUARD(envoy_reloadable_features_enable_compression_bomb_protection); RUNTIME_GUARD(envoy_reloadable_features_enable_connect_udp_support); +RUNTIME_GUARD(envoy_reloadable_features_enable_include_histograms); RUNTIME_GUARD(envoy_reloadable_features_enable_intermediate_ca); RUNTIME_GUARD(envoy_reloadable_features_enable_zone_routing_different_zone_counts); RUNTIME_GUARD(envoy_reloadable_features_exclude_host_in_eds_status_draining); @@ -63,7 +65,6 @@ 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_immediate_response_use_filter_mutation_rule); -RUNTIME_GUARD(envoy_reloadable_features_initialize_upstream_filters); RUNTIME_GUARD(envoy_reloadable_features_locality_routing_use_new_routing_logic); RUNTIME_GUARD(envoy_reloadable_features_lowercase_scheme); RUNTIME_GUARD(envoy_reloadable_features_no_downgrade_to_canonical_name); @@ -74,6 +75,7 @@ RUNTIME_GUARD(envoy_reloadable_features_oauth_make_token_cookie_httponly); RUNTIME_GUARD(envoy_reloadable_features_oauth_use_standard_max_age_value); RUNTIME_GUARD(envoy_reloadable_features_oauth_use_url_encoding); RUNTIME_GUARD(envoy_reloadable_features_original_dst_rely_on_idle_timeout); +RUNTIME_GUARD(envoy_reloadable_features_proxy_status_mapping_more_core_response_flags); RUNTIME_GUARD(envoy_reloadable_features_proxy_status_upstream_request_timeout); RUNTIME_GUARD(envoy_reloadable_features_quic_fix_filter_manager_uaf); // Ignore the automated "remove this flag" issue: we should keep this for 1 year. Confirm with @@ -81,10 +83,12 @@ RUNTIME_GUARD(envoy_reloadable_features_quic_fix_filter_manager_uaf); RUNTIME_GUARD(envoy_reloadable_features_quic_send_server_preferred_address_to_all_clients); RUNTIME_GUARD(envoy_reloadable_features_sanitize_te); RUNTIME_GUARD(envoy_reloadable_features_send_header_raw_value); +RUNTIME_GUARD(envoy_reloadable_features_send_local_reply_when_no_buffer_and_upstream_request); RUNTIME_GUARD(envoy_reloadable_features_skip_dns_lookup_for_proxied_requests); RUNTIME_GUARD(envoy_reloadable_features_ssl_transport_failure_reason_format); RUNTIME_GUARD(envoy_reloadable_features_stateful_session_encode_ttl_in_cookie); RUNTIME_GUARD(envoy_reloadable_features_stop_decode_metadata_on_local_reply); +RUNTIME_GUARD(envoy_reloadable_features_tcp_tunneling_send_downstream_fin_on_upstream_trailers); RUNTIME_GUARD(envoy_reloadable_features_test_feature_true); RUNTIME_GUARD(envoy_reloadable_features_thrift_allow_negative_field_ids); RUNTIME_GUARD(envoy_reloadable_features_thrift_connection_draining); @@ -97,8 +101,10 @@ RUNTIME_GUARD(envoy_reloadable_features_use_http3_header_normalisation); RUNTIME_GUARD(envoy_reloadable_features_validate_connect); RUNTIME_GUARD(envoy_reloadable_features_validate_grpc_header_before_log_grpc_status); RUNTIME_GUARD(envoy_reloadable_features_validate_upstream_headers); +RUNTIME_GUARD(envoy_restart_features_allow_client_socket_creation_failure); RUNTIME_GUARD(envoy_restart_features_send_goaway_for_premature_rst_streams); RUNTIME_GUARD(envoy_restart_features_udp_read_normalize_addresses); +RUNTIME_GUARD(envoy_restart_features_use_eds_cache_for_ads); // Begin false flags. Most of them should come with a TODO to flip true. @@ -117,8 +123,6 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_runtime_initialized); // TODO(mattklein123): Also unit test this if this sticks and this becomes the default for Apple & // Android. FALSE_RUNTIME_GUARD(envoy_reloadable_features_always_use_v6); -// TODO(pradeepcrao) reset this to true after 2 releases (1.27) -FALSE_RUNTIME_GUARD(envoy_reloadable_features_enable_include_histograms); // TODO(wbpcode) complete remove this feature is no one use it. FALSE_RUNTIME_GUARD(envoy_reloadable_features_refresh_rtt_after_request); // TODO(danzh) false deprecate it once QUICHE has its own enable/disable flag. @@ -130,8 +134,6 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_quiche_use_mem_slice_releasor_api) // 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 @@ -143,6 +145,10 @@ FALSE_RUNTIME_GUARD(envoy_restart_features_use_fast_protobuf_hash); // TODO(panting): flip this to true after some test time. FALSE_RUNTIME_GUARD(envoy_reloadable_features_use_config_in_happy_eyeballs); +// A flag to set the maximum TLS version for google_grpc client to TLS1.2, when needed for +// compliance restrictions. +FALSE_RUNTIME_GUARD(envoy_reloadable_features_google_grpc_disable_tls_13); + // Block of non-boolean flags. Use of int flags is deprecated. Do not add more. ABSL_FLAG(uint64_t, re2_max_program_size_error_level, 100, ""); // NOLINT ABSL_FLAG(uint64_t, re2_max_program_size_warn_level, // NOLINT diff --git a/source/common/runtime/runtime_impl.cc b/source/common/runtime/runtime_impl.cc index c40bcd8a463d..17511407813a 100644 --- a/source/common/runtime/runtime_impl.cc +++ b/source/common/runtime/runtime_impl.cc @@ -17,6 +17,7 @@ #include "source/common/config/api_version.h" #include "source/common/filesystem/directory.h" #include "source/common/grpc/common.h" +#include "source/common/http/utility.h" #include "source/common/protobuf/message_validator_impl.h" #include "source/common/protobuf/utility.h" #include "source/common/runtime/runtime_features.h" @@ -45,20 +46,21 @@ void countDeprecatedFeatureUseInternal(const RuntimeStats& stats) { } void refreshReloadableFlags(const Snapshot::EntryMap& flag_map) { - absl::flat_hash_map quiche_flags_override; for (const auto& it : flag_map) { + if (it.second.bool_value_.has_value() && isRuntimeFeature(it.first)) { + maybeSetRuntimeGuard(it.first, it.second.bool_value_.value()); + } + } #ifdef ENVOY_ENABLE_QUIC + absl::flat_hash_map quiche_flags_override; + for (const auto& it : flag_map) { if (absl::StartsWith(it.first, quiche::EnvoyQuicheReloadableFlagPrefix) && it.second.bool_value_.has_value()) { quiche_flags_override[it.first.substr(quiche::EnvoyFeaturePrefix.length())] = it.second.bool_value_.value(); } -#endif - if (it.second.bool_value_.has_value() && isRuntimeFeature(it.first)) { - maybeSetRuntimeGuard(it.first, it.second.bool_value_.value()); - } } -#ifdef ENVOY_ENABLE_QUIC + quiche::FlagRegistry::getInstance().updateReloadableFlags(quiche_flags_override); // Because this is a QUICHE protocol flag, this behavior can't be flipped with the above @@ -662,8 +664,8 @@ absl::Status RtdsSubscription::validateUpdateSize(uint32_t added_resources_num, if (added_resources_num + removed_resources_num != 1) { init_target_.ready(); return absl::InvalidArgumentError( - fmt::format("Unexpected RTDS resource length, number of added recources " - "{}, number of removed recources {}", + fmt::format("Unexpected RTDS resource length, number of added resources " + "{}, number of removed resources {}", added_resources_num, removed_resources_num)); } return absl::OkStatus(); diff --git a/source/common/secret/BUILD b/source/common/secret/BUILD index b7b25aedbe5b..d6e61c39531f 100644 --- a/source/common/secret/BUILD +++ b/source/common/secret/BUILD @@ -32,6 +32,9 @@ envoy_cc_library( hdrs = ["secret_provider_impl.h"], deps = [ "//envoy/secret:secret_provider_interface", + "//envoy/thread_local:thread_local_interface", + "//envoy/thread_local:thread_local_object", + "//source/common/config:datasource_lib", "//source/common/ssl:certificate_validation_context_config_impl_lib", "//source/common/ssl:tls_certificate_config_impl_lib", "@envoy_api//envoy/extensions/transport_sockets/tls/v3:pkg_cc_proto", diff --git a/source/common/secret/sds_api.cc b/source/common/secret/sds_api.cc index 5492fb92de28..344da3ff5833 100644 --- a/source/common/secret/sds_api.cc +++ b/source/common/secret/sds_api.cc @@ -6,6 +6,7 @@ #include "source/common/common/assert.h" #include "source/common/config/api_version.h" +#include "source/common/grpc/common.h" #include "source/common/protobuf/utility.h" namespace Envoy { diff --git a/source/common/secret/secret_provider_impl.cc b/source/common/secret/secret_provider_impl.cc index 6aed80d0107c..ea2ff427ec19 100644 --- a/source/common/secret/secret_provider_impl.cc +++ b/source/common/secret/secret_provider_impl.cc @@ -3,6 +3,7 @@ #include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h" #include "source/common/common/assert.h" +#include "source/common/config/datasource.h" #include "source/common/ssl/certificate_validation_context_config_impl.h" #include "source/common/ssl/tls_certificate_config_impl.h" @@ -36,5 +37,33 @@ GenericSecretConfigProviderImpl::GenericSecretConfigProviderImpl( std::make_unique( generic_secret)) {} +ThreadLocalGenericSecretProvider::ThreadLocalGenericSecretProvider( + GenericSecretConfigProviderSharedPtr&& provider, ThreadLocal::SlotAllocator& tls, Api::Api& api) + : provider_(provider), api_(api), + tls_(std::make_unique>(tls)), + cb_(provider_->addUpdateCallback([this] { update(); })) { + std::string value; + if (const auto* secret = provider_->secret(); secret != nullptr) { + value = + THROW_OR_RETURN_VALUE(Config::DataSource::read(secret->secret(), true, api_), std::string); + } + tls_->set([value = std::move(value)](Event::Dispatcher&) { + return std::make_shared(value); + }); +} + +const std::string& ThreadLocalGenericSecretProvider::secret() const { return (*tls_)->value_; } + +// This function is executed on the main during xDS update and can throw. +void ThreadLocalGenericSecretProvider::update() { + std::string value; + if (const auto* secret = provider_->secret(); secret != nullptr) { + value = + THROW_OR_RETURN_VALUE(Config::DataSource::read(secret->secret(), true, api_), std::string); + } + tls_->runOnAllThreads( + [value = std::move(value)](OptRef tls) { tls->value_ = value; }); +} + } // namespace Secret } // namespace Envoy diff --git a/source/common/secret/secret_provider_impl.h b/source/common/secret/secret_provider_impl.h index 566f53bf2a86..981f1c84cf41 100644 --- a/source/common/secret/secret_provider_impl.h +++ b/source/common/secret/secret_provider_impl.h @@ -6,6 +6,8 @@ #include "envoy/secret/secret_provider.h" #include "envoy/ssl/certificate_validation_context_config.h" #include "envoy/ssl/tls_certificate_config.h" +#include "envoy/thread_local/thread_local.h" +#include "envoy/thread_local/thread_local_object.h" namespace Envoy { namespace Secret { @@ -108,5 +110,28 @@ class GenericSecretConfigProviderImpl : public GenericSecretConfigProvider { Secret::GenericSecretPtr generic_secret_; }; +/** + * A utility secret provider that uses thread local values to share the updates to the secrets from + * the main to the workers. + **/ +class ThreadLocalGenericSecretProvider { +public: + ThreadLocalGenericSecretProvider(GenericSecretConfigProviderSharedPtr&& provider, + ThreadLocal::SlotAllocator& tls, Api::Api& api); + const std::string& secret() const; + +private: + struct ThreadLocalSecret : public ThreadLocal::ThreadLocalObject { + explicit ThreadLocalSecret(const std::string& value) : value_(value) {} + std::string value_; + }; + void update(); + GenericSecretConfigProviderSharedPtr provider_; + Api::Api& api_; + ThreadLocal::TypedSlotPtr tls_; + // Must be last since it has a non-trivial de-registering destructor. + Common::CallbackHandlePtr cb_; +}; + } // namespace Secret } // namespace Envoy diff --git a/source/common/ssl/certificate_validation_context_config_impl.cc b/source/common/ssl/certificate_validation_context_config_impl.cc index b1249969f8cf..4f030296efcd 100644 --- a/source/common/ssl/certificate_validation_context_config_impl.cc +++ b/source/common/ssl/certificate_validation_context_config_impl.cc @@ -20,10 +20,15 @@ static const std::string INLINE_STRING = ""; CertificateValidationContextConfigImpl::CertificateValidationContextConfigImpl( const envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext& config, Api::Api& api) - : ca_cert_(Config::DataSource::read(config.trusted_ca(), true, api)), + : ca_cert_(THROW_OR_RETURN_VALUE( + THROW_OR_RETURN_VALUE(Config::DataSource::read(config.trusted_ca(), true, api), + std::string), + std::string)), ca_cert_path_(Config::DataSource::getPath(config.trusted_ca()) .value_or(ca_cert_.empty() ? EMPTY_STRING : INLINE_STRING)), - certificate_revocation_list_(Config::DataSource::read(config.crl(), true, api)), + certificate_revocation_list_(THROW_OR_RETURN_VALUE( + THROW_OR_RETURN_VALUE(Config::DataSource::read(config.crl(), true, api), std::string), + std::string)), certificate_revocation_list_path_( Config::DataSource::getPath(config.crl()) .value_or(certificate_revocation_list_.empty() ? EMPTY_STRING : INLINE_STRING)), diff --git a/source/common/ssl/tls_certificate_config_impl.cc b/source/common/ssl/tls_certificate_config_impl.cc index 0b131494b5da..bf5855797f75 100644 --- a/source/common/ssl/tls_certificate_config_impl.cc +++ b/source/common/ssl/tls_certificate_config_impl.cc @@ -14,7 +14,8 @@ namespace Ssl { namespace { std::vector readOcspStaple(const envoy::config::core::v3::DataSource& source, Api::Api& api) { - std::string staple = Config::DataSource::read(source, true, api); + std::string staple = + THROW_OR_RETURN_VALUE(Config::DataSource::read(source, true, api), std::string); if (source.specifier_case() == envoy::config::core::v3::DataSource::SpecifierCase::kInlineString) { throwEnvoyExceptionOrPanic("OCSP staple cannot be provided via inline_string"); @@ -29,17 +30,21 @@ static const std::string INLINE_STRING = ""; TlsCertificateConfigImpl::TlsCertificateConfigImpl( const envoy::extensions::transport_sockets::tls::v3::TlsCertificate& config, Server::Configuration::TransportSocketFactoryContext& factory_context, Api::Api& api) - : certificate_chain_(Config::DataSource::read(config.certificate_chain(), true, api)), + : certificate_chain_(THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.certificate_chain(), true, api), std::string)), certificate_chain_path_( Config::DataSource::getPath(config.certificate_chain()) .value_or(certificate_chain_.empty() ? EMPTY_STRING : INLINE_STRING)), - private_key_(Config::DataSource::read(config.private_key(), true, api)), + private_key_(THROW_OR_RETURN_VALUE(Config::DataSource::read(config.private_key(), true, api), + std::string)), private_key_path_(Config::DataSource::getPath(config.private_key()) .value_or(private_key_.empty() ? EMPTY_STRING : INLINE_STRING)), - pkcs12_(Config::DataSource::read(config.pkcs12(), true, api)), + pkcs12_( + THROW_OR_RETURN_VALUE(Config::DataSource::read(config.pkcs12(), true, api), std::string)), pkcs12_path_(Config::DataSource::getPath(config.pkcs12()) .value_or(pkcs12_.empty() ? EMPTY_STRING : INLINE_STRING)), - password_(Config::DataSource::read(config.password(), true, api)), + password_(THROW_OR_RETURN_VALUE(Config::DataSource::read(config.password(), true, api), + std::string)), password_path_(Config::DataSource::getPath(config.password()) .value_or(password_.empty() ? EMPTY_STRING : INLINE_STRING)), ocsp_staple_(readOcspStaple(config.ocsp_staple(), api)), diff --git a/source/common/stats/symbol_table.cc b/source/common/stats/symbol_table.cc index 8dce2c77d7c0..6a3d87f310b7 100644 --- a/source/common/stats/symbol_table.cc +++ b/source/common/stats/symbol_table.cc @@ -620,12 +620,16 @@ StatNameStorage::~StatNameStorage() { } void StatNameStorage::free(SymbolTable& table) { + // nolint: https://github.com/llvm/llvm-project/issues/81597 + // NOLINTNEXTLINE(clang-analyzer-unix.Malloc) table.free(statName()); clear(); } void StatNamePool::clear() { for (StatNameStorage& storage : storage_vector_) { + // nolint: https://github.com/llvm/llvm-project/issues/81597 + // NOLINTNEXTLINE(clang-analyzer-unix.Malloc) storage.free(symbol_table_); } storage_vector_.clear(); @@ -733,6 +737,8 @@ void StatNameList::iterate(const std::function& f) const { void StatNameList::clear(SymbolTable& symbol_table) { iterate([&symbol_table](StatName stat_name) -> bool { + // nolint: https://github.com/llvm/llvm-project/issues/81597 + // NOLINTNEXTLINE(clang-analyzer-unix.Malloc) symbol_table.free(stat_name); return true; }); diff --git a/source/common/stream_info/uint64_accessor_impl.h b/source/common/stream_info/uint64_accessor_impl.h index 5859263135ab..ff14bbe7844c 100644 --- a/source/common/stream_info/uint64_accessor_impl.h +++ b/source/common/stream_info/uint64_accessor_impl.h @@ -19,6 +19,8 @@ class UInt64AccessorImpl : public UInt64Accessor { return message; } + absl::optional serializeAsString() const override { return std::to_string(value_); } + // From UInt64Accessor. void increment() override { value_++; } uint64_t value() const override { return value_; } diff --git a/source/common/stream_info/utility.cc b/source/common/stream_info/utility.cc index 4045a45981b6..6ef029ef1cfe 100644 --- a/source/common/stream_info/utility.cc +++ b/source/common/stream_info/utility.cc @@ -440,15 +440,44 @@ ProxyStatusUtils::fromStreamInfo(const StreamInfo& stream_info) { return ProxyStatusError::ConnectionTimeout; } return ProxyStatusError::HttpResponseTimeout; - } else if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) { - return ProxyStatusError::ConnectionTimeout; - } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) { - return ProxyStatusError::ConnectionTerminated; - } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) { - return ProxyStatusError::ConnectionRefused; - } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) { - return ProxyStatusError::ConnectionTerminated; - } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamOverflow)) { + } + + if (Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.proxy_status_mapping_more_core_response_flags")) { + if (stream_info.hasResponseFlag(CoreResponseFlag::DurationTimeout)) { + return ProxyStatusError::ConnectionTimeout; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) { + return ProxyStatusError::ConnectionTimeout; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) { + return ProxyStatusError::ConnectionTerminated; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) { + return ProxyStatusError::ConnectionRefused; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::UnauthorizedExternalService)) { + return ProxyStatusError::ConnectionRefused; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) { + return ProxyStatusError::ConnectionTerminated; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::OverloadManager)) { + return ProxyStatusError::ConnectionLimitReached; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::DropOverLoad)) { + return ProxyStatusError::ConnectionLimitReached; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::FaultInjected)) { + return ProxyStatusError::HttpRequestError; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::DownstreamConnectionTermination)) { + return ProxyStatusError::ConnectionTerminated; + } + } else { + if (stream_info.hasResponseFlag(CoreResponseFlag::LocalReset)) { + return ProxyStatusError::ConnectionTimeout; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamRemoteReset)) { + return ProxyStatusError::ConnectionTerminated; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionFailure)) { + return ProxyStatusError::ConnectionRefused; + } else if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamConnectionTermination)) { + return ProxyStatusError::ConnectionTerminated; + } + } + + if (stream_info.hasResponseFlag(CoreResponseFlag::UpstreamOverflow)) { return ProxyStatusError::ConnectionLimitReached; } else if (stream_info.hasResponseFlag(CoreResponseFlag::NoRouteFound)) { return ProxyStatusError::DestinationNotFound; diff --git a/source/common/tcp/async_tcp_client_impl.cc b/source/common/tcp/async_tcp_client_impl.cc index 6bcfa9a21500..4d6482cb5dc6 100644 --- a/source/common/tcp/async_tcp_client_impl.cc +++ b/source/common/tcp/async_tcp_client_impl.cc @@ -22,20 +22,20 @@ AsyncTcpClientImpl::AsyncTcpClientImpl(Event::Dispatcher& dispatcher, : dispatcher_(dispatcher), thread_local_cluster_(thread_local_cluster), cluster_info_(thread_local_cluster_.info()), context_(context), connect_timer_(dispatcher.createTimer([this]() { onConnectTimeout(); })), - enable_half_close_(enable_half_close) { - cluster_info_->trafficStats()->upstream_cx_active_.inc(); - cluster_info_->trafficStats()->upstream_cx_total_.inc(); -} - -AsyncTcpClientImpl::~AsyncTcpClientImpl() { - cluster_info_->trafficStats()->upstream_cx_active_.dec(); -} + enable_half_close_(enable_half_close) {} bool AsyncTcpClientImpl::connect() { + if (connection_) { + return false; + } + connection_ = std::move(thread_local_cluster_.tcpConn(context_).connection_); if (!connection_) { return false; } + + cluster_info_->trafficStats()->upstream_cx_total_.inc(); + cluster_info_->trafficStats()->upstream_cx_active_.inc(); connection_->enableHalfClose(enable_half_close_); connection_->addConnectionCallbacks(*this); connection_->addReadFilter(std::make_shared(*this)); @@ -109,17 +109,20 @@ void AsyncTcpClientImpl::reportConnectionDestroy(Network::ConnectionEvent event) void AsyncTcpClientImpl::onEvent(Network::ConnectionEvent event) { if (event == Network::ConnectionEvent::RemoteClose || event == Network::ConnectionEvent::LocalClose) { - if (disconnected_) { + cluster_info_->trafficStats()->upstream_cx_active_.dec(); + if (!connected_) { cluster_info_->trafficStats()->upstream_cx_connect_fail_.inc(); } - if (!disconnected_ && conn_length_ms_ != nullptr) { + if (connected_ && conn_length_ms_ != nullptr) { conn_length_ms_->complete(); conn_length_ms_.reset(); } + disableConnectTimeout(); reportConnectionDestroy(event); - disconnected_ = true; + + connected_ = false; if (connection_) { detected_close_ = connection_->detectedCloseType(); } @@ -127,10 +130,9 @@ void AsyncTcpClientImpl::onEvent(Network::ConnectionEvent event) { dispatcher_.deferredDelete(std::move(connection_)); if (callbacks_) { callbacks_->onEvent(event); - callbacks_ = nullptr; } } else { - disconnected_ = false; + connected_ = true; conn_connect_ms_->complete(); conn_connect_ms_.reset(); disableConnectTimeout(); diff --git a/source/common/tcp/async_tcp_client_impl.h b/source/common/tcp/async_tcp_client_impl.h index 6250fb574d6d..ef965ca68cc5 100644 --- a/source/common/tcp/async_tcp_client_impl.h +++ b/source/common/tcp/async_tcp_client_impl.h @@ -29,8 +29,6 @@ class AsyncTcpClientImpl : public AsyncTcpClient, Upstream::ThreadLocalCluster& thread_local_cluster, Upstream::LoadBalancerContext* context, bool enable_half_close); - ~AsyncTcpClientImpl() override; - void close(Network::ConnectionCloseType type) override; Network::DetectedCloseType detectedCloseType() const override { return detected_close_; } @@ -56,7 +54,7 @@ class AsyncTcpClientImpl : public AsyncTcpClient, /** * @return if the client connects to a peer host. */ - bool connected() override { return !disconnected_; } + bool connected() override { return connected_; } Event::Dispatcher& dispatcher() override { return dispatcher_; } @@ -108,7 +106,7 @@ class AsyncTcpClientImpl : public AsyncTcpClient, Event::TimerPtr connect_timer_; AsyncTcpClientCallbacks* callbacks_{}; Network::DetectedCloseType detected_close_{Network::DetectedCloseType::Normal}; - bool disconnected_{true}; + bool connected_{false}; bool enable_half_close_{false}; }; diff --git a/source/common/tcp_proxy/BUILD b/source/common/tcp_proxy/BUILD index 07d5c5995d29..3e1f10dba933 100644 --- a/source/common/tcp_proxy/BUILD +++ b/source/common/tcp_proxy/BUILD @@ -62,6 +62,7 @@ envoy_cc_library( "//source/common/common:enum_to_int", "//source/common/common:macros", "//source/common/common:minimal_logger_lib", + "//source/common/config:well_known_names", "//source/common/formatter:substitution_format_string_lib", "//source/common/http:codec_client_lib", "//source/common/network:application_protocol_lib", @@ -78,6 +79,7 @@ envoy_cc_library( "//source/common/router:metadatamatchcriteria_lib", "//source/common/stream_info:stream_id_provider_lib", "//source/common/stream_info:stream_info_lib", + "//source/common/stream_info:uint64_accessor_lib", "//source/common/upstream:load_balancer_lib", "//source/extensions/upstreams/tcp/generic:config", "@envoy_api//envoy/config/accesslog/v3:pkg_cc_proto", diff --git a/source/common/tcp_proxy/tcp_proxy.cc b/source/common/tcp_proxy/tcp_proxy.cc index 4f87dd6ae37a..4e49e16597a8 100644 --- a/source/common/tcp_proxy/tcp_proxy.cc +++ b/source/common/tcp_proxy/tcp_proxy.cc @@ -34,6 +34,7 @@ #include "source/common/network/upstream_socket_options_filter_state.h" #include "source/common/router/metadatamatchcriteria_impl.h" #include "source/common/stream_info/stream_id_provider_impl.h" +#include "source/common/stream_info/uint64_accessor_impl.h" namespace Envoy { namespace TcpProxy { @@ -53,6 +54,22 @@ class PerConnectionClusterFactory : public StreamInfo::FilterState::ObjectFactor REGISTER_FACTORY(PerConnectionClusterFactory, StreamInfo::FilterState::ObjectFactory); +class PerConnectionIdleTimeoutMsObjectFactory : public StreamInfo::FilterState::ObjectFactory { +public: + std::string name() const override { return std::string(PerConnectionIdleTimeoutMs); } + std::unique_ptr + createFromBytes(absl::string_view data) const override { + uint64_t duration_in_milliseconds = 0; + if (absl::SimpleAtoi(data, &duration_in_milliseconds)) { + return std::make_unique(duration_in_milliseconds); + } + + return nullptr; + } +}; + +REGISTER_FACTORY(PerConnectionIdleTimeoutMsObjectFactory, StreamInfo::FilterState::ObjectFactory); + Config::SimpleRouteImpl::SimpleRouteImpl(const Config& parent, absl::string_view cluster_name) : parent_(parent), cluster_name_(cluster_name) {} @@ -755,7 +772,7 @@ void Filter::onDownstreamEvent(Network::ConnectionEvent event) { conn_data->connection().state() != Network::Connection::State::Closed) { config_->drainManager().add(config_->sharedConfig(), std::move(conn_data), std::move(upstream_callbacks_), std::move(idle_timer_), - read_callbacks_->upstreamHost()); + idle_timeout_, read_callbacks_->upstreamHost()); } if (event == Network::ConnectionEvent::LocalClose || event == Network::ConnectionEvent::RemoteClose) { @@ -829,7 +846,15 @@ void Filter::onUpstreamConnection() { read_callbacks_->connection(), getStreamInfo().downstreamAddressProvider().requestedServerName()); - if (config_->idleTimeout()) { + idle_timeout_ = config_->idleTimeout(); + if (const auto* per_connection_idle_timeout = + getStreamInfo().filterState()->getDataReadOnly( + PerConnectionIdleTimeoutMs); + per_connection_idle_timeout != nullptr) { + idle_timeout_ = std::chrono::milliseconds(per_connection_idle_timeout->value()); + } + + if (idle_timeout_) { // The idle_timer_ can be moved to a Drainer, so related callbacks call into // the UpstreamCallbacks, which has the same lifetime as the timer, and can dispatch // the call to either TcpProxy or to Drainer, depending on the current state. @@ -905,8 +930,8 @@ void Filter::disableAccessLogFlushTimer() { void Filter::resetIdleTimer() { if (idle_timer_ != nullptr) { - ASSERT(config_->idleTimeout()); - idle_timer_->enableTimer(config_->idleTimeout().value()); + ASSERT(idle_timeout_); + idle_timer_->enableTimer(idle_timeout_.value()); } } @@ -943,9 +968,10 @@ void UpstreamDrainManager::add(const Config::SharedConfigSharedPtr& config, Tcp::ConnectionPool::ConnectionDataPtr&& upstream_conn_data, const std::shared_ptr& callbacks, Event::TimerPtr&& idle_timer, + absl::optional idle_timeout, const Upstream::HostDescriptionConstSharedPtr& upstream_host) { DrainerPtr drainer(new Drainer(*this, config, callbacks, std::move(upstream_conn_data), - std::move(idle_timer), upstream_host)); + std::move(idle_timer), idle_timeout, upstream_host)); callbacks->drain(*drainer); // Use temporary to ensure we get the pointer before we move it out of drainer @@ -963,9 +989,11 @@ void UpstreamDrainManager::remove(Drainer& drainer, Event::Dispatcher& dispatche Drainer::Drainer(UpstreamDrainManager& parent, const Config::SharedConfigSharedPtr& config, const std::shared_ptr& callbacks, Tcp::ConnectionPool::ConnectionDataPtr&& conn_data, Event::TimerPtr&& idle_timer, + absl::optional idle_timeout, const Upstream::HostDescriptionConstSharedPtr& upstream_host) : parent_(parent), callbacks_(callbacks), upstream_conn_data_(std::move(conn_data)), - timer_(std::move(idle_timer)), upstream_host_(upstream_host), config_(config) { + idle_timer_(std::move(idle_timer)), idle_timeout_(idle_timeout), + upstream_host_(upstream_host), config_(config) { ENVOY_CONN_LOG(trace, "draining the upstream connection", upstream_conn_data_->connection()); config_->stats().upstream_flush_total_.inc(); config_->stats().upstream_flush_active_.inc(); @@ -974,8 +1002,8 @@ Drainer::Drainer(UpstreamDrainManager& parent, const Config::SharedConfigSharedP void Drainer::onEvent(Network::ConnectionEvent event) { if (event == Network::ConnectionEvent::RemoteClose || event == Network::ConnectionEvent::LocalClose) { - if (timer_ != nullptr) { - timer_->disableTimer(); + if (idle_timer_ != nullptr) { + idle_timer_->disableTimer(); } config_->stats().upstream_flush_active_.dec(); parent_.remove(*this, upstream_conn_data_->connection().dispatcher()); @@ -998,8 +1026,8 @@ void Drainer::onIdleTimeout() { } void Drainer::onBytesSent() { - if (timer_ != nullptr) { - timer_->enableTimer(config_->idleTimeout().value()); + if (idle_timer_ != nullptr) { + idle_timer_->enableTimer(idle_timeout_.value()); } } diff --git a/source/common/tcp_proxy/tcp_proxy.h b/source/common/tcp_proxy/tcp_proxy.h index 82ebcb8fb9d9..a7b5e491191d 100644 --- a/source/common/tcp_proxy/tcp_proxy.h +++ b/source/common/tcp_proxy/tcp_proxy.h @@ -38,6 +38,9 @@ namespace Envoy { namespace TcpProxy { +constexpr absl::string_view PerConnectionIdleTimeoutMs = + "envoy.tcp_proxy.per_connection_idle_timeout_ms"; + /** * All tcp proxy stats. @see stats_macros.h */ @@ -547,6 +550,7 @@ class Filter : public Network::ReadFilter, Router::MetadataMatchCriteriaConstPtr metadata_match_criteria_; Network::TransportSocketOptionsConstSharedPtr transport_socket_options_; Network::Socket::OptionsSharedPtr upstream_options_; + absl::optional idle_timeout_; uint32_t connect_attempts_{}; bool connecting_{}; bool downstream_closed_{}; @@ -560,6 +564,7 @@ class Drainer : public Event::DeferredDeletable, protected Logger::Loggable& callbacks, Tcp::ConnectionPool::ConnectionDataPtr&& conn_data, Event::TimerPtr&& idle_timer, + absl::optional idle_timeout, const Upstream::HostDescriptionConstSharedPtr& upstream_host); void onEvent(Network::ConnectionEvent event); @@ -573,7 +578,8 @@ class Drainer : public Event::DeferredDeletable, protected Logger::Loggable callbacks_; Tcp::ConnectionPool::ConnectionDataPtr upstream_conn_data_; - Event::TimerPtr timer_; + Event::TimerPtr idle_timer_; + absl::optional idle_timeout_; Upstream::HostDescriptionConstSharedPtr upstream_host_; Config::SharedConfigSharedPtr config_; }; @@ -586,7 +592,7 @@ class UpstreamDrainManager : public ThreadLocal::ThreadLocalObject { void add(const Config::SharedConfigSharedPtr& config, Tcp::ConnectionPool::ConnectionDataPtr&& upstream_conn_data, const std::shared_ptr& callbacks, - Event::TimerPtr&& idle_timer, + Event::TimerPtr&& idle_timer, absl::optional idle_timeout, const Upstream::HostDescriptionConstSharedPtr& upstream_host); void remove(Drainer& drainer, Event::Dispatcher& dispatcher); diff --git a/source/common/tcp_proxy/upstream.h b/source/common/tcp_proxy/upstream.h index d115bc440cc2..d16126547cc5 100644 --- a/source/common/tcp_proxy/upstream.h +++ b/source/common/tcp_proxy/upstream.h @@ -8,6 +8,7 @@ #include "envoy/upstream/thread_local_cluster.h" #include "envoy/upstream/upstream.h" +#include "source/common/buffer/buffer_impl.h" #include "source/common/common/dump_state_utils.h" #include "source/common/http/codec_client.h" #include "source/common/router/header_parser.h" @@ -196,6 +197,12 @@ class HttpUpstream : public GenericUpstream, protected Http::StreamCallbacks { void decodeTrailers(Http::ResponseTrailerMapPtr&& trailers) override { parent_.config_.propagateResponseTrailers(std::move(trailers), parent_.downstream_info_.filterState()); + if (Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.tcp_tunneling_send_downstream_fin_on_upstream_trailers")) { + Buffer::OwnedImpl data; + parent_.upstream_callbacks_.onUpstreamData(data, /* end_stream = */ true); + } + parent_.doneReading(); } void decodeMetadata(Http::MetadataMapPtr&&) override {} diff --git a/source/common/upstream/edf_scheduler.h b/source/common/upstream/edf_scheduler.h index a625d72a98df..207b8ff744c7 100644 --- a/source/common/upstream/edf_scheduler.h +++ b/source/common/upstream/edf_scheduler.h @@ -27,7 +27,7 @@ namespace Upstream { // weights and an O(log n) pick time. template class EdfScheduler : public Scheduler { public: - EdfScheduler() {} + EdfScheduler() = default; // See scheduler.h for an explanation of each public method. std::shared_ptr peekAgain(std::function calculate_weight) override { @@ -89,7 +89,7 @@ template class EdfScheduler : public Scheduler { })); // Nothing to do if there are no entries. - if (entries.size() == 0) { + if (entries.empty()) { return EdfScheduler(); } diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index 83f22f7adc80..ea76e579b293 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -1084,28 +1084,52 @@ void EdfLoadBalancerBase::refresh(uint32_t priority) { // Skip edf creation. return; } - scheduler.edf_ = std::make_unique>(); - - // Populate scheduler with host list. - // TODO(mattklein123): We must build the EDF schedule even if all of the hosts are currently - // weighted 1. This is because currently we don't refresh host sets if only weights change. - // We should probably change this to refresh at all times. See the comment in - // BaseDynamicClusterImpl::updateDynamicHostList about this. - for (const auto& host : hosts) { - // We use a fixed weight here. While the weight may change without - // notification, this will only be stale until this host is next picked, - // at which point it is reinserted into the EdfScheduler with its new - // weight in chooseHost(). - scheduler.edf_->add(hostWeight(*host), host); - } - // Cycle through hosts to achieve the intended offset behavior. - // TODO(htuch): Consider how we can avoid biasing towards earlier hosts in the schedule across - // refreshes for the weighted case. - if (!hosts.empty()) { - for (uint32_t i = 0; i < seed_ % hosts.size(); ++i) { - auto host = - scheduler.edf_->pickAndAdd([this](const Host& host) { return hostWeight(host); }); + if (Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.edf_lb_host_scheduler_init_fix")) { + // If there are no hosts or a single one, there is no need for an EDF scheduler + // (thus lowering memory and CPU overhead), as the (possibly) single host + // will be the one always selected by the scheduler. + if (hosts.size() <= 1) { + return; + } + + // Populate the scheduler with the host list with a randomized starting point. + // TODO(mattklein123): We must build the EDF schedule even if all of the hosts are currently + // weighted 1. This is because currently we don't refresh host sets if only weights change. + // We should probably change this to refresh at all times. See the comment in + // BaseDynamicClusterImpl::updateDynamicHostList about this. + scheduler.edf_ = std::make_unique>(EdfScheduler::createWithPicks( + hosts, + // We use a fixed weight here. While the weight may change without + // notification, this will only be stale until this host is next picked, + // at which point it is reinserted into the EdfScheduler with its new + // weight in chooseHost(). + [this](const Host& host) { return hostWeight(host); }, seed_)); + } else { + scheduler.edf_ = std::make_unique>(); + + // Populate scheduler with host list. + // TODO(mattklein123): We must build the EDF schedule even if all of the hosts are currently + // weighted 1. This is because currently we don't refresh host sets if only weights change. + // We should probably change this to refresh at all times. See the comment in + // BaseDynamicClusterImpl::updateDynamicHostList about this. + for (const auto& host : hosts) { + // We use a fixed weight here. While the weight may change without + // notification, this will only be stale until this host is next picked, + // at which point it is reinserted into the EdfScheduler with its new + // weight in chooseHost(). + scheduler.edf_->add(hostWeight(*host), host); + } + + // Cycle through hosts to achieve the intended offset behavior. + // TODO(htuch): Consider how we can avoid biasing towards earlier hosts in the schedule across + // refreshes for the weighted case. + if (!hosts.empty()) { + for (uint32_t i = 0; i < seed_ % hosts.size(); ++i) { + auto host = + scheduler.edf_->pickAndAdd([this](const Host& host) { return hostWeight(host); }); + } } } }; diff --git a/source/common/upstream/load_balancer_impl.h b/source/common/upstream/load_balancer_impl.h index 55927ed4a1f0..ef23f188722c 100644 --- a/source/common/upstream/load_balancer_impl.h +++ b/source/common/upstream/load_balancer_impl.h @@ -525,7 +525,7 @@ class EdfLoadBalancerBase : public ZoneAwareLoadBalancerBase { // EdfScheduler for weighted LB. The edf_ is only created when the original // host weights of 2 or more hosts differ. When not present, the // implementation of chooseHostOnce falls back to unweightedHostPick. - std::unique_ptr> edf_; + std::unique_ptr> edf_; }; void initialize(); diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index 66a0d339f83e..43ac5fb9ef2d 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -1167,7 +1167,8 @@ ClusterInfoImpl::ClusterInfoImpl( // Both LoadStatsReporter and per_endpoint_stats need to `latch()` the counters, so if both are // configured they will interfere with each other and both get incorrect values. - if (perEndpointStatsEnabled() && + // TODO(ggreenway): Verify that bypassing virtual dispatch here was intentional + if (ClusterInfoImpl::perEndpointStatsEnabled() && server_context.bootstrap().cluster_manager().has_load_stats_config()) { throwEnvoyExceptionOrPanic("Only one of cluster per_endpoint_stats and cluster manager " "load_stats_config can be specified"); @@ -1728,7 +1729,7 @@ absl::Status ClusterImplBase::parseDropOverloadConfig( return absl::OkStatus(); } const auto& policy = cluster_load_assignment.policy(); - if (policy.drop_overloads().size() == 0) { + if (policy.drop_overloads().empty()) { return absl::OkStatus(); } if (policy.drop_overloads().size() > kDropOverloadSize) { diff --git a/source/docs/histogram.png b/source/docs/histogram.png new file mode 100644 index 000000000000..bd642210da75 Binary files /dev/null and b/source/docs/histogram.png differ diff --git a/source/docs/logging.md b/source/docs/logging.md index 965a50f77048..388b8e09d2cc 100644 --- a/source/docs/logging.md +++ b/source/docs/logging.md @@ -87,3 +87,33 @@ like `ENVOY_LOG` except that they prepend the log message with `[C123]` or `[C123][S456` based on the connection/stream ID of the specified argument. Note that the IDs here are the Envoy IDs *NOT* the on-the-wire IDs from HTTP/2 or HTTP/3. + +#### ENVOY_TAGGED_LOG + +The following logging API allows the call site to pass a key-value object (``std::map``) with additional +context information that would be printed in the final log line. Unless JSON application logging is enabled, +the output log line will prepend the log tags in the following format: '[Tags: "key1":"value1","key2":"value2"]'. +When JSON application logging is enabled, the output JSON log will also include the key-values as additional properties +in the JSON struct. +Example: + +``` +std::map log_tags{{"key1","value1"},{"key2","value2"}}; +ENVOY_TAGGED_LOG(debug, log_tags, "failed to perform the operation"); +// output: [debug] [Tags: "key1":"value1","key2":"value2"] failed to perform the operation +``` + +#### ENVOY_TAGGED_CONN_LOG / ENVOY_TAGGED_STREAM_LOG + +These logging APIs support all the properties as described for ENVOY_TAGGED_LOG, but allow the call site to pass +additional objects to add a connection ID or stream ID (with respect to the relevant macro). +When using these macros, an additional log tag will be added with the key "ConnectionId" or "StreamId" (or both). + +Example: + +``` +std::map log_tags{{"key1","value1"},{"key2","value2"}}; +ENVOY_TAGGED_LOG(debug, log_tags, conn_, "failed to perform the operation"); +ENVOY_TAGGED_LOG(debug, log_tags, stream_, "failed to perform the operation"); +// output: [debug] [Tags: "ConnectionId":"10","StreamId":"11","key1":"value1","key2":"value2"] failed to perform the operation +``` diff --git a/source/docs/stats.md b/source/docs/stats.md index 1616558b9afc..b39b5f252cf8 100644 --- a/source/docs/stats.md +++ b/source/docs/stats.md @@ -77,6 +77,10 @@ followed. accumulates in to *interval* histograms. * Finally the main *interval* histogram is merged to *cumulative* histogram. +Pictorially this looks like: + +![Histogram Stat Flush](histogram.png) + `ParentHistogram`s are held weakly a set in ThreadLocalStore. Like other stats, they keep an embedded reference count and are removed from the set and destroyed when the last strong reference disappears. Consequently, we must hold a lock for diff --git a/source/exe/stripped_main_base.cc b/source/exe/stripped_main_base.cc index 502963e897d1..0e493eeed050 100644 --- a/source/exe/stripped_main_base.cc +++ b/source/exe/stripped_main_base.cc @@ -47,7 +47,7 @@ StrippedMainBase::StrippedMainBase(const Server::Options& options, Event::TimeSy std::unique_ptr platform_impl, std::unique_ptr&& random_generator, std::unique_ptr process_context, - CreateInstanceFunction createInstance) + CreateInstanceFunction create_instance) : platform_impl_(std::move(platform_impl)), options_(options), component_factory_(component_factory), stats_allocator_(symbol_table_) { // Process the option to disable extensions as early as possible, @@ -84,10 +84,10 @@ StrippedMainBase::StrippedMainBase(const Server::Options& options, Event::TimeSy stats_store_ = std::make_unique(stats_allocator_); - server_ = createInstance(*init_manager_, options_, time_system, listener_hooks, *restarter_, - *stats_store_, access_log_lock, component_factory, - std::move(random_generator), *tls_, platform_impl_->threadFactory(), - platform_impl_->fileSystem(), std::move(process_context), nullptr); + server_ = create_instance(*init_manager_, options_, time_system, listener_hooks, *restarter_, + *stats_store_, access_log_lock, component_factory, + std::move(random_generator), *tls_, platform_impl_->threadFactory(), + platform_impl_->fileSystem(), std::move(process_context), nullptr); break; } case Server::Mode::Validate: diff --git a/source/exe/stripped_main_base.h b/source/exe/stripped_main_base.h index 0da36500ff44..81b518e0147e 100644 --- a/source/exe/stripped_main_base.h +++ b/source/exe/stripped_main_base.h @@ -53,7 +53,7 @@ class StrippedMainBase { std::unique_ptr platform_impl, std::unique_ptr&& random_generator, std::unique_ptr process_context, - CreateInstanceFunction createInstance); + CreateInstanceFunction create_instance); void runServer() { ASSERT(options_.mode() == Server::Mode::Serve); diff --git a/source/extensions/access_loggers/fluentd/BUILD b/source/extensions/access_loggers/fluentd/BUILD new file mode 100644 index 000000000000..3a7151731baf --- /dev/null +++ b/source/extensions/access_loggers/fluentd/BUILD @@ -0,0 +1,51 @@ +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 = "substitution_formatter_lib", + srcs = ["substitution_formatter.cc"], + hdrs = ["substitution_formatter.h"], + deps = [ + "//envoy/formatter:substitution_formatter_interface", + "//source/common/json:json_loader_lib", + ], +) + +envoy_cc_library( + name = "fluentd_access_log_lib", + srcs = ["fluentd_access_log_impl.cc"], + hdrs = ["fluentd_access_log_impl.h"], + external_deps = [ + "msgpack", + ], + deps = [ + ":substitution_formatter_lib", + "//envoy/access_log:access_log_interface", + "//source/common/access_log:access_log_lib", + "//source/extensions/access_loggers/common:access_log_base", + "@envoy_api//envoy/extensions/access_loggers/fluentd/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + deps = [ + ":fluentd_access_log_lib", + ":substitution_formatter_lib", + "//envoy/access_log:access_log_config_interface", + "//envoy/registry", + "//source/common/config:config_provider_lib", + "//source/common/formatter:substitution_format_string_lib", + "//source/common/protobuf", + ], +) diff --git a/source/extensions/access_loggers/fluentd/config.cc b/source/extensions/access_loggers/fluentd/config.cc new file mode 100644 index 000000000000..e9929ab0c318 --- /dev/null +++ b/source/extensions/access_loggers/fluentd/config.cc @@ -0,0 +1,81 @@ +#include "source/extensions/access_loggers/fluentd/config.h" + +#include + +#include "envoy/registry/registry.h" +#include "envoy/server/filter_config.h" + +#include "source/common/common/logger.h" +#include "source/common/config/utility.h" +#include "source/common/formatter/substitution_format_string.h" +#include "source/common/formatter/substitution_formatter.h" +#include "source/common/protobuf/protobuf.h" +#include "source/extensions/access_loggers/fluentd/fluentd_access_log_impl.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { + +// Singleton registration via macro defined in envoy/singleton/manager.h +SINGLETON_MANAGER_REGISTRATION(fluentd_access_logger_cache); + +FluentdAccessLoggerCacheSharedPtr +getAccessLoggerCacheSingleton(Server::Configuration::ServerFactoryContext& context) { + return context.singletonManager().getTyped( + SINGLETON_MANAGER_REGISTERED_NAME(fluentd_access_logger_cache), + [&context] { + return std::make_shared( + context.clusterManager(), context.scope(), context.threadLocal()); + }, + /* pin = */ true); +} + +AccessLog::InstanceSharedPtr +FluentdAccessLogFactory::createAccessLogInstance(const Protobuf::Message& config, + AccessLog::FilterPtr&& filter, + Server::Configuration::FactoryContext& context) { + const auto& proto_config = MessageUtil::downcastAndValidate< + const envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig&>( + config, context.messageValidationVisitor()); + + absl::Status status = context.serverFactoryContext().clusterManager().checkActiveStaticCluster( + proto_config.cluster()); + if (!status.ok()) { + throw EnvoyException(fmt::format("cluster '{}' was not found", proto_config.cluster())); + } + + // Supporting nested object serialization is more complex with MessagePack. + // Using an already existing JSON formatter, and later converting the JSON string to a msgpack + // payload. + // TODO(ohadvano): Improve the formatting operation by creating a dedicated formatter that + // will directly serialize the record to msgpack payload. + Formatter::FormatterPtr json_formatter = + Formatter::SubstitutionFormatStringUtils::createJsonFormatter(proto_config.record(), true, + false, false); + FluentdFormatterPtr fluentd_formatter = + std::make_unique(std::move(json_formatter)); + + return std::make_shared( + std::move(filter), std::move(fluentd_formatter), + std::make_shared(proto_config), + context.serverFactoryContext().threadLocal(), + getAccessLoggerCacheSingleton(context.serverFactoryContext())); +} + +ProtobufTypes::MessagePtr FluentdAccessLogFactory::createEmptyConfigProto() { + return std::make_unique(); +} + +std::string FluentdAccessLogFactory::name() const { return "envoy.access_loggers.fluentd"; } + +/** + * Static registration for the fluentd access log. @see RegisterFactory. + */ +REGISTER_FACTORY(FluentdAccessLogFactory, + AccessLog::AccessLogInstanceFactory){"envoy.fluentd_access_log"}; + +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/fluentd/config.h b/source/extensions/access_loggers/fluentd/config.h new file mode 100644 index 000000000000..b7dfff974b1a --- /dev/null +++ b/source/extensions/access_loggers/fluentd/config.h @@ -0,0 +1,27 @@ +#pragma once + +#include "envoy/access_log/access_log_config.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { + +/** + * Config registration for the fluentd access log. @see AccessLogInstanceFactory. + */ +class FluentdAccessLogFactory : public AccessLog::AccessLogInstanceFactory { +public: + AccessLog::InstanceSharedPtr + createAccessLogInstance(const Protobuf::Message& config, AccessLog::FilterPtr&& filter, + Server::Configuration::FactoryContext& context) override; + + ProtobufTypes::MessagePtr createEmptyConfigProto() override; + + std::string name() const override; +}; + +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/fluentd/fluentd_access_log_impl.cc b/source/extensions/access_loggers/fluentd/fluentd_access_log_impl.cc new file mode 100644 index 000000000000..ce1a96694d90 --- /dev/null +++ b/source/extensions/access_loggers/fluentd/fluentd_access_log_impl.cc @@ -0,0 +1,163 @@ +#include "source/extensions/access_loggers/fluentd/fluentd_access_log_impl.h" + +#include "source/common/buffer/buffer_impl.h" + +#include "msgpack.hpp" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { + +using MessagePackBuffer = msgpack::sbuffer; +using MessagePackPacker = msgpack::packer; + +FluentdAccessLoggerImpl::FluentdAccessLoggerImpl(Tcp::AsyncTcpClientPtr client, + Event::Dispatcher& dispatcher, + const FluentdAccessLogConfig& config, + Stats::Scope& parent_scope) + : tag_(config.tag()), id_(dispatcher.name()), + stats_scope_(parent_scope.createScope(config.stat_prefix())), + fluentd_stats_( + {ACCESS_LOG_FLUENTD_STATS(POOL_COUNTER(*stats_scope_), POOL_GAUGE(*stats_scope_))}), + client_(std::move(client)), + buffer_flush_interval_msec_(PROTOBUF_GET_MS_OR_DEFAULT(config, buffer_flush_interval, 1000)), + max_buffer_size_bytes_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, buffer_size_bytes, 16384)), + flush_timer_(dispatcher.createTimer([this]() { + flush(); + flush_timer_->enableTimer(buffer_flush_interval_msec_); + })) { + client_->setAsyncTcpClientCallbacks(*this); + flush_timer_->enableTimer(buffer_flush_interval_msec_); +} + +void FluentdAccessLoggerImpl::onEvent(Network::ConnectionEvent event) { + connecting_ = false; + + if (event == Network::ConnectionEvent::Connected) { + flush(); + } else if (event == Network::ConnectionEvent::LocalClose || + event == Network::ConnectionEvent::RemoteClose) { + ENVOY_LOG(debug, "upstream connection was closed"); + // TODO(ohadvano): add an option to reconnect to the upstream, if configured + + fluentd_stats_.connections_closed_.inc(); + disconnected_ = true; + clearBuffer(); + + ASSERT(flush_timer_ != nullptr); + flush_timer_->disableTimer(); + } +} + +void FluentdAccessLoggerImpl::log(EntryPtr&& entry) { + if (disconnected_) { + fluentd_stats_.entries_lost_.inc(); + // We will lose the data deliberately so the buffer doesn't grow infinitely. + // Since the client is disconnected, there's nothing much we can do with the data anyway. + // TODO(ohadvano): add an option to reconnect to the upstream, if configured + return; + } + + approximate_message_size_bytes_ += sizeof(entry->time_) + entry->record_.size(); + entries_.push_back(std::move(entry)); + fluentd_stats_.entries_buffered_.inc(); + if (approximate_message_size_bytes_ >= max_buffer_size_bytes_) { + flush(); + } +} + +void FluentdAccessLoggerImpl::flush() { + ASSERT(!disconnected_); + + if (entries_.size() == 0 || connecting_) { + // nothing to send, or we're still waiting for an upstream connection. + return; + } + + if (!client_->connected()) { + connecting_ = true; + client_->connect(); + return; + } + + // Creating a Fluentd Forward Protocol Specification (v1) forward mode event as specified in: + // https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#forward-mode + MessagePackBuffer buffer; + MessagePackPacker packer(buffer); + packer.pack_array(2); // 1 - tag field, 2 - entries array. + packer.pack(tag_); + packer.pack_array(entries_.size()); + + for (auto& entry : entries_) { + packer.pack_array(2); // 1 - time, 2 - record. + packer.pack(entry->time_); + const char* record_bytes = reinterpret_cast(&entry->record_[0]); + packer.pack_bin_body(record_bytes, entry->record_.size()); + } + + Buffer::OwnedImpl data(buffer.data(), buffer.size()); + client_->write(data, false); + fluentd_stats_.events_sent_.inc(); + clearBuffer(); +} + +void FluentdAccessLoggerImpl::clearBuffer() { + entries_.clear(); + approximate_message_size_bytes_ = 0; +} + +FluentdAccessLoggerCacheImpl::FluentdAccessLoggerCacheImpl( + Upstream::ClusterManager& cluster_manager, Stats::Scope& parent_scope, + ThreadLocal::SlotAllocator& tls) + : cluster_manager_(cluster_manager), + stats_scope_(parent_scope.createScope("access_logs.fluentd")), tls_slot_(tls.allocateSlot()) { + tls_slot_->set( + [](Event::Dispatcher& dispatcher) { return std::make_shared(dispatcher); }); +} + +FluentdAccessLoggerSharedPtr +FluentdAccessLoggerCacheImpl::getOrCreateLogger(const FluentdAccessLogConfigSharedPtr config) { + auto& cache = tls_slot_->getTyped(); + const auto cache_key = MessageUtil::hash(*config); + const auto it = cache.access_loggers_.find(cache_key); + if (it != cache.access_loggers_.end() && !it->second.expired()) { + return it->second.lock(); + } + + auto client = + cluster_manager_.getThreadLocalCluster(config->cluster()) + ->tcpAsyncClient(nullptr, std::make_shared(false)); + + const auto logger = std::make_shared( + std::move(client), cache.dispatcher_, *config, *stats_scope_); + cache.access_loggers_.emplace(cache_key, logger); + return logger; +} + +FluentdAccessLog::FluentdAccessLog(AccessLog::FilterPtr&& filter, FluentdFormatterPtr&& formatter, + const FluentdAccessLogConfigSharedPtr config, + ThreadLocal::SlotAllocator& tls, + FluentdAccessLoggerCacheSharedPtr access_logger_cache) + : ImplBase(std::move(filter)), formatter_(std::move(formatter)), tls_slot_(tls.allocateSlot()), + config_(config), access_logger_cache_(access_logger_cache) { + tls_slot_->set( + [config = config_, access_logger_cache = access_logger_cache_](Event::Dispatcher&) { + return std::make_shared(access_logger_cache->getOrCreateLogger(config)); + }); +} + +void FluentdAccessLog::emitLog(const Formatter::HttpFormatterContext& context, + const StreamInfo::StreamInfo& stream_info) { + auto msgpack = formatter_->format(context, stream_info); + uint64_t time = std::chrono::duration_cast( + stream_info.timeSource().systemTime().time_since_epoch()) + .count(); + tls_slot_->getTyped().logger_->log( + std::make_unique(time, std::move(msgpack))); +} + +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/fluentd/fluentd_access_log_impl.h b/source/extensions/access_loggers/fluentd/fluentd_access_log_impl.h new file mode 100644 index 000000000000..11a03530d32d --- /dev/null +++ b/source/extensions/access_loggers/fluentd/fluentd_access_log_impl.h @@ -0,0 +1,163 @@ +#pragma once + +#include + +#include "envoy/extensions/access_loggers/fluentd/v3/fluentd.pb.h" +#include "envoy/extensions/access_loggers/fluentd/v3/fluentd.pb.validate.h" + +#include "source/common/formatter/substitution_formatter.h" +#include "source/extensions/access_loggers/common/access_log_base.h" +#include "source/extensions/access_loggers/fluentd/substitution_formatter.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { + +using FluentdAccessLogConfig = + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig; +using FluentdAccessLogConfigSharedPtr = std::shared_ptr; + +// Entry represents a single Fluentd message, msgpack format based, as specified in: +// https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#entry +class Entry { +public: + Entry(const Entry&) = delete; + Entry& operator=(const Entry&) = delete; + Entry(uint64_t time, std::vector&& record) : time_(time), record_(record) {} + + const uint64_t time_; + const std::vector record_; +}; + +using EntryPtr = std::unique_ptr; + +class FluentdAccessLogger { +public: + virtual ~FluentdAccessLogger() = default; + + /** + * Send the Fluentd formatted message over the upstream TCP connection. + */ + virtual void log(EntryPtr&& entry) PURE; +}; + +using FluentdAccessLoggerWeakPtr = std::weak_ptr; +using FluentdAccessLoggerSharedPtr = std::shared_ptr; + +#define ACCESS_LOG_FLUENTD_STATS(COUNTER, GAUGE) \ + COUNTER(entries_lost) \ + COUNTER(entries_buffered) \ + COUNTER(events_sent) \ + COUNTER(connections_closed) + +struct AccessLogFluentdStats { + ACCESS_LOG_FLUENTD_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) +}; + +class FluentdAccessLoggerImpl : public Tcp::AsyncTcpClientCallbacks, + public FluentdAccessLogger, + public Logger::Loggable { +public: + FluentdAccessLoggerImpl(Tcp::AsyncTcpClientPtr client, Event::Dispatcher& dispatcher, + const FluentdAccessLogConfig& config, Stats::Scope& parent_scope); + + // Tcp::AsyncTcpClientCallbacks + void onEvent(Network::ConnectionEvent event) override; + void onAboveWriteBufferHighWatermark() override {} + void onBelowWriteBufferLowWatermark() override {} + void onData(Buffer::Instance&, bool) override {} + + // FluentdAccessLogger + void log(EntryPtr&& entry) override; + +private: + void flush(); + void clearBuffer(); + + bool disconnected_ = false; + bool connecting_ = false; + std::string tag_; + std::string id_; + const Stats::ScopeSharedPtr stats_scope_; + AccessLogFluentdStats fluentd_stats_; + std::vector entries_; + uint64_t approximate_message_size_bytes_ = 0; + const Tcp::AsyncTcpClientPtr client_; + const std::chrono::milliseconds buffer_flush_interval_msec_; + const uint64_t max_buffer_size_bytes_; + const Event::TimerPtr flush_timer_; +}; + +class FluentdAccessLoggerCache { +public: + virtual ~FluentdAccessLoggerCache() = default; + + /** + * Get existing logger or create a new one for the given configuration. + * @return FluentdAccessLoggerSharedPtr ready for logging requests. + */ + virtual FluentdAccessLoggerSharedPtr + getOrCreateLogger(const FluentdAccessLogConfigSharedPtr config) PURE; +}; + +using FluentdAccessLoggerCacheSharedPtr = std::shared_ptr; + +class FluentdAccessLoggerCacheImpl : public Singleton::Instance, public FluentdAccessLoggerCache { +public: + FluentdAccessLoggerCacheImpl(Upstream::ClusterManager& cluster_manager, + Stats::Scope& parent_scope, ThreadLocal::SlotAllocator& tls); + + FluentdAccessLoggerSharedPtr + getOrCreateLogger(const FluentdAccessLogConfigSharedPtr config) override; + +private: + /** + * Per-thread cache. + */ + struct ThreadLocalCache : public ThreadLocal::ThreadLocalObject { + ThreadLocalCache(Event::Dispatcher& dispatcher) : dispatcher_(dispatcher) {} + + Event::Dispatcher& dispatcher_; + // Access loggers indexed by the hash of logger's configuration. + absl::flat_hash_map access_loggers_; + }; + + Upstream::ClusterManager& cluster_manager_; + const Stats::ScopeSharedPtr stats_scope_; + ThreadLocal::SlotPtr tls_slot_; +}; + +/** + * Access log Instance that writes logs to a Fluentd. + */ +class FluentdAccessLog : public Common::ImplBase { +public: + FluentdAccessLog(AccessLog::FilterPtr&& filter, FluentdFormatterPtr&& formatter, + const FluentdAccessLogConfigSharedPtr config, ThreadLocal::SlotAllocator& tls, + FluentdAccessLoggerCacheSharedPtr access_logger_cache); + +private: + /** + * Per-thread cached logger. + */ + struct ThreadLocalLogger : public ThreadLocal::ThreadLocalObject { + ThreadLocalLogger(FluentdAccessLoggerSharedPtr logger) : logger_(std::move(logger)) {} + + const FluentdAccessLoggerSharedPtr logger_; + }; + + // Common::ImplBase + void emitLog(const Formatter::HttpFormatterContext& context, + const StreamInfo::StreamInfo& stream_info) override; + + FluentdFormatterPtr formatter_; + const ThreadLocal::SlotPtr tls_slot_; + const FluentdAccessLogConfigSharedPtr config_; + const FluentdAccessLoggerCacheSharedPtr access_logger_cache_; +}; + +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/fluentd/substitution_formatter.cc b/source/extensions/access_loggers/fluentd/substitution_formatter.cc new file mode 100644 index 000000000000..923719296e19 --- /dev/null +++ b/source/extensions/access_loggers/fluentd/substitution_formatter.cc @@ -0,0 +1,24 @@ +#include "source/extensions/access_loggers/fluentd/substitution_formatter.h" + +#include "envoy/stream_info/stream_info.h" + +#include "source/common/json/json_loader.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { + +FluentdFormatterImpl::FluentdFormatterImpl(Formatter::FormatterPtr json_formatter) + : json_formatter_(std::move(json_formatter)) {} + +std::vector FluentdFormatterImpl::format(const Formatter::HttpFormatterContext& context, + const StreamInfo::StreamInfo& stream_info) const { + auto json_string = json_formatter_->formatWithContext(context, stream_info); + return Json::Factory::jsonToMsgpack(json_string); +} + +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/fluentd/substitution_formatter.h b/source/extensions/access_loggers/fluentd/substitution_formatter.h new file mode 100644 index 000000000000..6c2e173ad3c6 --- /dev/null +++ b/source/extensions/access_loggers/fluentd/substitution_formatter.h @@ -0,0 +1,47 @@ +#pragma once + +#include "envoy/formatter/substitution_formatter.h" +#include "envoy/stream_info/stream_info.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { + +/** + * A formatter for Fluentd logs + */ +class FluentdFormatter { +public: + virtual ~FluentdFormatter() = default; + + /** + * @return a vector of bytes representing the Fluentd MessagePack record + */ + virtual std::vector format(const Formatter::HttpFormatterContext& context, + const StreamInfo::StreamInfo& stream_info) const PURE; +}; + +using FluentdFormatterPtr = std::unique_ptr; + +/** + * A formatter for Fluentd logs. It is expecting to receive a JSON formatter, and converts the + * JSON formatter message to MessagePack format. + * TODO(ohadvano): Improve the formatting operation by creating a dedicated formatter that + * will directly serialize the record to msgpack payload. + */ +class FluentdFormatterImpl : public FluentdFormatter { +public: + FluentdFormatterImpl(Formatter::FormatterPtr json_formatter); + + std::vector format(const Formatter::HttpFormatterContext& context, + const StreamInfo::StreamInfo& stream_info) const override; + +private: + Formatter::FormatterPtr json_formatter_; +}; + +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/grpc/grpc_access_log_impl.cc b/source/extensions/access_loggers/grpc/grpc_access_log_impl.cc index dc2ef0129428..1f74bb653da8 100644 --- a/source/extensions/access_loggers/grpc/grpc_access_log_impl.cc +++ b/source/extensions/access_loggers/grpc/grpc_access_log_impl.cc @@ -55,10 +55,12 @@ GrpcAccessLoggerImpl::SharedPtr GrpcAccessLoggerCacheImpl::createLogger( // exceptions in worker threads. Call sites of this getOrCreateLogger must check the cluster // availability via ClusterManager::checkActiveStaticCluster beforehand, and throw exceptions in // the main thread if necessary. - auto client = async_client_manager_.factoryForGrpcService(config.grpc_service(), scope_, true) - ->createUncachedRawAsyncClient(); - return std::make_shared(std::move(client), config, dispatcher, local_info_, - scope_); + auto factory_or_error = + async_client_manager_.factoryForGrpcService(config.grpc_service(), scope_, true); + THROW_IF_STATUS_NOT_OK(factory_or_error, throw); + return std::make_shared( + factory_or_error.value()->createUncachedRawAsyncClient(), config, dispatcher, local_info_, + scope_); } } // namespace GrpcCommon diff --git a/source/extensions/access_loggers/grpc/grpc_access_log_utils.cc b/source/extensions/access_loggers/grpc/grpc_access_log_utils.cc index e353949f0fea..8eb330766c37 100644 --- a/source/extensions/access_loggers/grpc/grpc_access_log_utils.cc +++ b/source/extensions/access_loggers/grpc/grpc_access_log_utils.cc @@ -271,7 +271,14 @@ void Utility::extractCommonAccessLogProperties( } if (stream_info.upstreamInfo().has_value()) { +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +#endif const auto& upstream_info = stream_info.upstreamInfo().value().get(); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif if (upstream_info.upstreamHost() != nullptr) { Network::Utility::addressToProtobufAddress( *upstream_info.upstreamHost()->address(), diff --git a/source/extensions/access_loggers/open_telemetry/grpc_access_log_impl.cc b/source/extensions/access_loggers/open_telemetry/grpc_access_log_impl.cc index 9c4a25d58367..6901c2c344d6 100644 --- a/source/extensions/access_loggers/open_telemetry/grpc_access_log_impl.cc +++ b/source/extensions/access_loggers/open_telemetry/grpc_access_log_impl.cc @@ -88,10 +88,11 @@ GrpcAccessLoggerImpl::SharedPtr GrpcAccessLoggerCacheImpl::createLogger( // We pass skip_cluster_check=true to factoryForGrpcService in order to avoid throwing // exceptions in worker threads. Call sites of this getOrCreateLogger must check the cluster // availability via ClusterManager::checkActiveStaticCluster beforehand, and throw exceptions in - // the main thread if necessary. - auto client = async_client_manager_ - .factoryForGrpcService(config.common_config().grpc_service(), scope_, true) - ->createUncachedRawAsyncClient(); + // the main thread if necessary to ensure it does not throw here. + auto factory_or_error = async_client_manager_.factoryForGrpcService( + config.common_config().grpc_service(), scope_, true); + THROW_IF_STATUS_NOT_OK(factory_or_error, throw); + auto client = factory_or_error.value()->createUncachedRawAsyncClient(); return std::make_shared(std::move(client), config, dispatcher, local_info_, scope_); } diff --git a/source/extensions/access_loggers/wasm/BUILD b/source/extensions/access_loggers/wasm/BUILD index 077e8f0239ec..cfb103eac2ed 100644 --- a/source/extensions/access_loggers/wasm/BUILD +++ b/source/extensions/access_loggers/wasm/BUILD @@ -32,6 +32,7 @@ envoy_cc_extension( "//envoy/registry", "//source/common/config:datasource_lib", "//source/common/protobuf", + "//source/extensions/common/wasm:remote_async_datasource_lib", "//source/extensions/common/wasm:wasm_lib", "@envoy_api//envoy/extensions/access_loggers/wasm/v3:pkg_cc_proto", ], diff --git a/source/extensions/access_loggers/wasm/config.h b/source/extensions/access_loggers/wasm/config.h index e6b69e951f1d..ef8257a9b3be 100644 --- a/source/extensions/access_loggers/wasm/config.h +++ b/source/extensions/access_loggers/wasm/config.h @@ -2,7 +2,7 @@ #include "envoy/access_log/access_log_config.h" -#include "source/common/config/datasource.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" namespace Envoy { namespace Extensions { @@ -25,7 +25,7 @@ class WasmAccessLogFactory : public AccessLog::AccessLogInstanceFactory, private: absl::flat_hash_map convertJsonFormatToMap(ProtobufWkt::Struct config); - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; + RemoteAsyncDataProviderPtr remote_data_provider_; }; } // namespace Wasm diff --git a/source/extensions/bootstrap/wasm/BUILD b/source/extensions/bootstrap/wasm/BUILD index 913e72fc5431..32e459c14401 100644 --- a/source/extensions/bootstrap/wasm/BUILD +++ b/source/extensions/bootstrap/wasm/BUILD @@ -25,6 +25,7 @@ envoy_cc_extension( "//source/common/common:empty_string", "//source/common/config:datasource_lib", "//source/common/protobuf:utility_lib", + "//source/extensions/common/wasm:remote_async_datasource_lib", "//source/extensions/common/wasm:wasm_lib", "@envoy_api//envoy/extensions/wasm/v3:pkg_cc_proto", ], diff --git a/source/extensions/bootstrap/wasm/config.h b/source/extensions/bootstrap/wasm/config.h index 6839792d71d8..fc24e085cc7c 100644 --- a/source/extensions/bootstrap/wasm/config.h +++ b/source/extensions/bootstrap/wasm/config.h @@ -8,6 +8,7 @@ #include "envoy/server/instance.h" #include "source/common/protobuf/protobuf.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" #include "source/extensions/common/wasm/wasm.h" namespace Envoy { @@ -64,7 +65,7 @@ class WasmServiceExtension : public Server::BootstrapExtension, Logger::Loggable envoy::extensions::wasm::v3::WasmService config_; Server::Configuration::ServerFactoryContext& context_; WasmServicePtr wasm_service_; - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; + RemoteAsyncDataProviderPtr remote_data_provider_; }; } // namespace Wasm diff --git a/source/extensions/clusters/dynamic_forward_proxy/cluster.cc b/source/extensions/clusters/dynamic_forward_proxy/cluster.cc index b6c69d79e5b6..4ce4077521cf 100644 --- a/source/extensions/clusters/dynamic_forward_proxy/cluster.cc +++ b/source/extensions/clusters/dynamic_forward_proxy/cluster.cc @@ -280,7 +280,7 @@ void Cluster::addOrUpdateHost( hosts_added.emplace_back(new_host); } - ASSERT(hosts_added.size() > 0); + ASSERT(!hosts_added.empty()); updatePriorityState(hosts_added, hosts_removed); } diff --git a/source/extensions/clusters/eds/eds.cc b/source/extensions/clusters/eds/eds.cc index 76d0b258514f..1b60873be93f 100644 --- a/source/extensions/clusters/eds/eds.cc +++ b/source/extensions/clusters/eds/eds.cc @@ -9,6 +9,7 @@ #include "source/common/common/utility.h" #include "source/common/config/api_version.h" #include "source/common/config/decoded_resource_impl.h" +#include "source/common/grpc/common.h" namespace Envoy { namespace Upstream { diff --git a/source/extensions/common/aws/metadata_fetcher.cc b/source/extensions/common/aws/metadata_fetcher.cc index d5b260a16112..f5dbe85eea55 100644 --- a/source/extensions/common/aws/metadata_fetcher.cc +++ b/source/extensions/common/aws/metadata_fetcher.cc @@ -23,7 +23,8 @@ class MetadataFetcherImpl : public MetadataFetcher, MetadataFetcherImpl(Upstream::ClusterManager& cm, absl::string_view cluster_name) : cm_(cm), cluster_name_(std::string(cluster_name)) {} - ~MetadataFetcherImpl() override { cancel(); } + // TODO(suniltheta): Verify that bypassing virtual dispatch here was intentional + ~MetadataFetcherImpl() override { MetadataFetcherImpl::cancel(); } void cancel() override { if (request_ && !complete_) { diff --git a/source/extensions/common/aws/region_provider_impl.cc b/source/extensions/common/aws/region_provider_impl.cc index 4c7bdde18d70..ca7255e00843 100644 --- a/source/extensions/common/aws/region_provider_impl.cc +++ b/source/extensions/common/aws/region_provider_impl.cc @@ -134,9 +134,10 @@ absl::optional AWSConfigFileRegionProvider::getRegionSet() { // https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html // RegionProviderChain::RegionProviderChain() { - add(createEnvironmentRegionProvider()); - add(createAWSCredentialsFileRegionProvider()); - add(createAWSConfigFileRegionProvider()); + // TODO(nbaws): Verify that bypassing virtual dispatch here was intentional + add(RegionProviderChain::createEnvironmentRegionProvider()); + add(RegionProviderChain::createAWSCredentialsFileRegionProvider()); + add(RegionProviderChain::createAWSConfigFileRegionProvider()); } absl::optional RegionProviderChain::getRegion() { diff --git a/source/extensions/common/dubbo/hessian2_utils.h b/source/extensions/common/dubbo/hessian2_utils.h index a51a224bc836..30a0f54335d6 100644 --- a/source/extensions/common/dubbo/hessian2_utils.h +++ b/source/extensions/common/dubbo/hessian2_utils.h @@ -5,7 +5,15 @@ #include "envoy/buffer/buffer.h" #include "absl/strings/string_view.h" + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +#endif #include "hessian2/basic_codec/object_codec.hpp" +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif #include "hessian2/codec.hpp" #include "hessian2/object.hpp" #include "hessian2/reader.hpp" diff --git a/source/extensions/common/dynamic_forward_proxy/BUILD b/source/extensions/common/dynamic_forward_proxy/BUILD index bb3535dab9ec..f8b68b72daad 100644 --- a/source/extensions/common/dynamic_forward_proxy/BUILD +++ b/source/extensions/common/dynamic_forward_proxy/BUILD @@ -18,6 +18,7 @@ envoy_cc_library( "//envoy/singleton:manager_interface", "//envoy/thread_local:thread_local_interface", "//envoy/upstream:resource_manager_interface", + "//source/common/http:header_utility_lib", "@envoy_api//envoy/extensions/common/dynamic_forward_proxy/v3:pkg_cc_proto", ], ) diff --git a/source/extensions/common/tap/tap_config_base.cc b/source/extensions/common/tap/tap_config_base.cc index 953d96f1c669..920505782344 100644 --- a/source/extensions/common/tap/tap_config_base.cc +++ b/source/extensions/common/tap/tap_config_base.cc @@ -64,7 +64,10 @@ TapConfigBaseImpl::TapConfigBaseImpl(const envoy::config::tap::v3::TapConfig& pr switch (sink_type_) { case ProtoOutputSink::OutputSinkTypeCase::kBufferedAdmin: - ASSERT(admin_streamer != nullptr, "admin output must be configured via admin"); + if (admin_streamer == nullptr) { + throw EnvoyException(fmt::format("Output sink type BufferedAdmin requires that the admin " + "output will be configured via admin")); + } // TODO(mattklein123): Graceful failure, error message, and test if someone specifies an // admin stream output with the wrong format. RELEASE_ASSERT( @@ -75,7 +78,10 @@ TapConfigBaseImpl::TapConfigBaseImpl(const envoy::config::tap::v3::TapConfig& pr sink_to_use_ = admin_streamer; break; case ProtoOutputSink::OutputSinkTypeCase::kStreamingAdmin: - ASSERT(admin_streamer != nullptr, "admin output must be configured via admin"); + if (admin_streamer == nullptr) { + throw EnvoyException(fmt::format("Output sink type StreamingAdmin requires that the admin " + "output will be configured via admin")); + } // TODO(mattklein123): Graceful failure, error message, and test if someone specifies an // admin stream output with the wrong format. // TODO(davidpeet8): Simple change to enable PROTO_BINARY_LENGTH_DELIMITED format - diff --git a/source/extensions/common/wasm/BUILD b/source/extensions/common/wasm/BUILD index 46001d873f7e..8022b0d74413 100644 --- a/source/extensions/common/wasm/BUILD +++ b/source/extensions/common/wasm/BUILD @@ -55,6 +55,24 @@ envoy_cc_library( alwayslink = 1, ) +envoy_cc_library( + name = "remote_async_datasource_lib", + srcs = ["remote_async_datasource.cc"], + hdrs = ["remote_async_datasource.h"], + deps = [ + "//envoy/api:api_interface", + "//envoy/init:manager_interface", + "//envoy/upstream:cluster_manager_interface", + "//source/common/common:backoff_lib", + "//source/common/common:empty_string", + "//source/common/config:remote_data_fetcher_lib", + "//source/common/config:utility_lib", + "//source/common/init:target_lib", + "//source/common/protobuf:utility_lib", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) + envoy_cc_extension( name = "wasm_lib", srcs = [ @@ -91,6 +109,7 @@ envoy_cc_extension( "//source/common/http:utility_lib", "//source/common/network/dns_resolver:dns_factory_util_lib", "//source/common/tracing:http_tracer_lib", + "//source/extensions/common/wasm:remote_async_datasource_lib", "//source/extensions/common/wasm/ext:declare_property_cc_proto", "//source/extensions/common/wasm/ext:envoy_null_vm_wasm_api", "//source/extensions/common/wasm/ext:set_envoy_filter_state_cc_proto", diff --git a/source/extensions/common/wasm/context.cc b/source/extensions/common/wasm/context.cc index c1c9bfd2868e..2b13ca94937d 100644 --- a/source/extensions/common/wasm/context.cc +++ b/source/extensions/common/wasm/context.cc @@ -995,8 +995,12 @@ WasmResult Context::grpcCall(std::string_view grpc_service, std::string_view ser auto& handler = grpc_call_request_[token]; handler.context_ = this; handler.token_ = token; - auto grpc_client = clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( + auto client_or_error = clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( service_proto, *wasm()->scope_, true /* skip_cluster_check */); + if (!client_or_error.status().ok()) { + return WasmResult::BadArgument; + } + auto grpc_client = client_or_error.value(); grpc_initial_metadata_ = buildRequestHeaderMapFromPairs(initial_metadata); // set default hash policy to be based on :authority to enable consistent hash @@ -1040,8 +1044,12 @@ WasmResult Context::grpcStream(std::string_view grpc_service, std::string_view s auto& handler = grpc_stream_[token]; handler.context_ = this; handler.token_ = token; - auto grpc_client = clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( + auto client_or_error = clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( service_proto, *wasm()->scope_, true /* skip_cluster_check */); + if (!client_or_error.status().ok()) { + return WasmResult::BadArgument; + } + auto grpc_client = client_or_error.value(); grpc_initial_metadata_ = buildRequestHeaderMapFromPairs(initial_metadata); // set default hash policy to be based on :authority to enable consistent hash diff --git a/source/extensions/common/wasm/remote_async_datasource.cc b/source/extensions/common/wasm/remote_async_datasource.cc new file mode 100644 index 000000000000..4ed28651c564 --- /dev/null +++ b/source/extensions/common/wasm/remote_async_datasource.cc @@ -0,0 +1,43 @@ +#include "source/extensions/common/wasm/remote_async_datasource.h" + +#include "envoy/config/core/v3/base.pb.h" + +#include "source/common/config/utility.h" + +#include "fmt/format.h" + +namespace Envoy { + +// Default Parameters of the jittered backoff strategy. +static constexpr uint32_t RetryInitialDelayMilliseconds = 1000; +static constexpr uint32_t RetryMaxDelayMilliseconds = 10 * 1000; +static constexpr uint32_t RetryCount = 1; + +absl::optional getPath(const envoy::config::core::v3::DataSource& source) { + return source.specifier_case() == envoy::config::core::v3::DataSource::SpecifierCase::kFilename + ? absl::make_optional(source.filename()) + : absl::nullopt; +} + +RemoteAsyncDataProvider::RemoteAsyncDataProvider( + Upstream::ClusterManager& cm, Init::Manager& manager, + const envoy::config::core::v3::RemoteDataSource& source, Event::Dispatcher& dispatcher, + Random::RandomGenerator& random, bool allow_empty, AsyncDataSourceCb&& callback) + : allow_empty_(allow_empty), callback_(std::move(callback)), + fetcher_(std::make_unique(cm, source.http_uri(), + source.sha256(), *this)), + init_target_("RemoteAsyncDataProvider", [this]() { start(); }), + retries_remaining_( + PROTOBUF_GET_WRAPPED_OR_DEFAULT(source.retry_policy(), num_retries, RetryCount)) { + + auto strategy_or_error = Config::Utility::prepareJitteredExponentialBackOffStrategy( + source, random, RetryInitialDelayMilliseconds, RetryMaxDelayMilliseconds); + THROW_IF_STATUS_NOT_OK(strategy_or_error, throw); + backoff_strategy_ = std::move(strategy_or_error.value()); + + retry_timer_ = dispatcher.createTimer([this]() -> void { start(); }); + + manager.add(init_target_); +} + +} // namespace Envoy diff --git a/source/extensions/common/wasm/remote_async_datasource.h b/source/extensions/common/wasm/remote_async_datasource.h new file mode 100644 index 000000000000..f3371269685a --- /dev/null +++ b/source/extensions/common/wasm/remote_async_datasource.h @@ -0,0 +1,81 @@ +#pragma once + +#include "envoy/api/api.h" +#include "envoy/common/random_generator.h" +#include "envoy/config/core/v3/base.pb.h" +#include "envoy/event/deferred_deletable.h" +#include "envoy/init/manager.h" +#include "envoy/upstream/cluster_manager.h" + +#include "source/common/common/backoff_strategy.h" +#include "source/common/common/empty_string.h" +#include "source/common/common/enum_to_int.h" +#include "source/common/config/remote_data_fetcher.h" +#include "source/common/init/target_impl.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" + +#include "absl/types/optional.h" + +namespace Envoy { + +/** + * Callback for async data source. + */ +using AsyncDataSourceCb = std::function; + +class RemoteAsyncDataProvider : public Event::DeferredDeletable, + public Config::DataFetcher::RemoteDataFetcherCallback, + public Logger::Loggable { +public: + RemoteAsyncDataProvider(Upstream::ClusterManager& cm, Init::Manager& manager, + const envoy::config::core::v3::RemoteDataSource& source, + Event::Dispatcher& dispatcher, Random::RandomGenerator& random, + bool allow_empty, AsyncDataSourceCb&& callback); + + ~RemoteAsyncDataProvider() override { + init_target_.ready(); + if (retry_timer_) { + retry_timer_->disableTimer(); + } + } + + // Config::DataFetcher::RemoteDataFetcherCallback + void onSuccess(const std::string& data) override { + callback_(data); + init_target_.ready(); + } + + // Config::DataFetcher::RemoteDataFetcherCallback + void onFailure(Config::DataFetcher::FailureReason failure) override { + ENVOY_LOG(debug, "Failed to fetch remote data, failure reason: {}", enumToInt(failure)); + if (retries_remaining_-- == 0) { + ENVOY_LOG(warn, "Retry limit exceeded for fetching data from remote data source."); + if (allow_empty_) { + callback_(EMPTY_STRING); + } + // We need to allow server startup to continue. + init_target_.ready(); + return; + } + + const auto retry_ms = std::chrono::milliseconds(backoff_strategy_->nextBackOffMs()); + ENVOY_LOG(debug, "Remote data provider will retry in {} ms.", retry_ms.count()); + retry_timer_->enableTimer(retry_ms); + } + +private: + void start() { fetcher_->fetch(); } + + bool allow_empty_; + AsyncDataSourceCb callback_; + const Config::DataFetcher::RemoteDataFetcherPtr fetcher_; + Init::TargetImpl init_target_; + + Event::TimerPtr retry_timer_; + BackOffStrategyPtr backoff_strategy_; + uint32_t retries_remaining_; +}; + +using RemoteAsyncDataProviderPtr = std::unique_ptr; + +} // namespace Envoy diff --git a/source/extensions/common/wasm/wasm.cc b/source/extensions/common/wasm/wasm.cc index c8e969f0793b..4e9659a30255 100644 --- a/source/extensions/common/wasm/wasm.cc +++ b/source/extensions/common/wasm/wasm.cc @@ -8,6 +8,7 @@ #include "source/common/common/logger.h" #include "source/common/network/dns_resolver/dns_factory_util.h" #include "source/extensions/common/wasm/plugin.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" #include "source/extensions/common/wasm/stats_handler.h" #include "absl/strings/str_cat.h" @@ -313,8 +314,8 @@ bool createWasm(const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scop Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager, Event::Dispatcher& dispatcher, Api::Api& api, Server::ServerLifecycleNotifier& lifecycle_notifier, - Config::DataSource::RemoteAsyncDataProviderPtr& remote_data_provider, - CreateWasmCallback&& cb, CreateContextFn create_root_context_for_testing) { + RemoteAsyncDataProviderPtr& remote_data_provider, CreateWasmCallback&& cb, + CreateContextFn create_root_context_for_testing) { auto& stats_handler = getCreateStatsHandler(); std::string source, code; auto config = plugin->wasmConfig(); @@ -374,7 +375,8 @@ bool createWasm(const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scop stats_handler.onEvent(WasmEvent::RemoteLoadCacheMiss); } } else if (vm_config.code().has_local()) { - code = Config::DataSource::read(vm_config.code().local(), true, api); + code = THROW_OR_RETURN_VALUE(Config::DataSource::read(vm_config.code().local(), true, api), + std::string); source = Config::DataSource::getPath(vm_config.code().local()) .value_or(code.empty() ? EMPTY_STRING : INLINE_STRING); } @@ -452,7 +454,7 @@ bool createWasm(const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scop cb(nullptr); return false; } else { - remote_data_provider = std::make_unique( + remote_data_provider = std::make_unique( cluster_manager, init_manager, vm_config.code().remote(), dispatcher, api.randomGenerator(), true, fetch_callback); } diff --git a/source/extensions/common/wasm/wasm.h b/source/extensions/common/wasm/wasm.h index 17cf43e028b0..9e2a10c1b7b4 100644 --- a/source/extensions/common/wasm/wasm.h +++ b/source/extensions/common/wasm/wasm.h @@ -21,6 +21,7 @@ #include "source/common/version/version.h" #include "source/extensions/common/wasm/context.h" #include "source/extensions/common/wasm/plugin.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" #include "source/extensions/common/wasm/stats_handler.h" #include "source/extensions/common/wasm/wasm_vm.h" @@ -170,8 +171,7 @@ bool createWasm(const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scop Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager, Event::Dispatcher& dispatcher, Api::Api& api, Envoy::Server::ServerLifecycleNotifier& lifecycle_notifier, - Config::DataSource::RemoteAsyncDataProviderPtr& remote_data_provider, - CreateWasmCallback&& callback, + RemoteAsyncDataProviderPtr& remote_data_provider, CreateWasmCallback&& callback, CreateContextFn create_root_context_for_testing = nullptr); PluginHandleSharedPtr diff --git a/source/extensions/compression/zstd/common/dictionary_manager.h b/source/extensions/compression/zstd/common/dictionary_manager.h index c70f2aba25b0..45501345e5ec 100644 --- a/source/extensions/compression/zstd/common/dictionary_manager.h +++ b/source/extensions/compression/zstd/common/dictionary_manager.h @@ -33,7 +33,8 @@ template class dictionary_map->reserve(dictionaries.size()); for (const auto& source : dictionaries) { - const auto data = Config::DataSource::read(source, false, api); + const auto data = + THROW_OR_RETURN_VALUE(Config::DataSource::read(source, false, api), std::string); auto dictionary = DictionarySharedPtr(builder_(data.data(), data.length())); auto id = getDictId(dictionary.get()); // If id == 0, the dictionary is not conform to Zstd specification, or empty. diff --git a/source/extensions/config_subscription/grpc/grpc_collection_subscription_factory.cc b/source/extensions/config_subscription/grpc/grpc_collection_subscription_factory.cc index ca0266efa642..a356e7a8f6c3 100644 --- a/source/extensions/config_subscription/grpc/grpc_collection_subscription_factory.cc +++ b/source/extensions/config_subscription/grpc/grpc_collection_subscription_factory.cc @@ -26,12 +26,15 @@ SubscriptionPtr DeltaGrpcCollectionConfigSubscriptionFactory::create( auto factory_or_error = Config::Utility::factoryForGrpcApiConfigSource( data.cm_.grpcAsyncClientManager(), api_config_source, data.scope_, true); THROW_IF_STATUS_NOT_OK(factory_or_error, throw); + absl::StatusOr rate_limit_settings_or_error = + Utility::parseRateLimitSettings(api_config_source); + THROW_IF_STATUS_NOT_OK(rate_limit_settings_or_error, throw); GrpcMuxContext grpc_mux_context{ factory_or_error.value()->createUncachedRawAsyncClient(), /*dispatcher_=*/data.dispatcher_, /*service_method_=*/deltaGrpcMethod(data.type_url_), /*local_info_=*/data.local_info_, - /*rate_limit_settings_=*/Utility::parseRateLimitSettings(api_config_source), + /*rate_limit_settings_=*/rate_limit_settings_or_error.value(), /*scope_=*/data.scope_, /*config_validators_=*/std::move(custom_config_validators), /*xds_resources_delegate_=*/{}, diff --git a/source/extensions/config_subscription/grpc/grpc_mux_failover.h b/source/extensions/config_subscription/grpc/grpc_mux_failover.h index 1700340aed11..90c5bf6648cf 100644 --- a/source/extensions/config_subscription/grpc/grpc_mux_failover.h +++ b/source/extensions/config_subscription/grpc/grpc_mux_failover.h @@ -102,26 +102,26 @@ template class GrpcMuxFailover { public: PrimaryGrpcStreamCallbacks(GrpcMuxFailover& parent) : parent_(parent) {} - virtual void onStreamEstablished() override { + void onStreamEstablished() override { // TODO(adisuissa): At the moment this is a pass-through method. Once the // implementation matures, this call will be updated. parent_.grpc_mux_callbacks_.onStreamEstablished(); } - virtual void onEstablishmentFailure() override { + void onEstablishmentFailure() override { // TODO(adisuissa): At the moment this is a pass-through method. Once the // implementation matures, this call will be updated. parent_.grpc_mux_callbacks_.onEstablishmentFailure(); } - virtual void onDiscoveryResponse(ResponseProtoPtr&& message, - ControlPlaneStats& control_plane_stats) override { + void onDiscoveryResponse(ResponseProtoPtr&& message, + ControlPlaneStats& control_plane_stats) override { // TODO(adisuissa): At the moment this is a pass-through method. Once the // implementation matures, this call will be updated. parent_.grpc_mux_callbacks_.onDiscoveryResponse(std::move(message), control_plane_stats); } - virtual void onWriteable() override { + void onWriteable() override { // TODO(adisuissa): At the moment this is a pass-through method. Once the // implementation matures, this call will be updated. parent_.grpc_mux_callbacks_.onWriteable(); diff --git a/source/extensions/config_subscription/grpc/grpc_mux_impl.cc b/source/extensions/config_subscription/grpc/grpc_mux_impl.cc index 3c9473dd5105..910dab4006e0 100644 --- a/source/extensions/config_subscription/grpc/grpc_mux_impl.cc +++ b/source/extensions/config_subscription/grpc/grpc_mux_impl.cc @@ -571,6 +571,9 @@ class GrpcMuxFactory : public MuxFactory { const LocalInfo::LocalInfo& local_info, CustomConfigValidatorsPtr&& config_validators, BackOffStrategyPtr&& backoff_strategy, XdsConfigTrackerOptRef xds_config_tracker, XdsResourcesDelegateOptRef xds_resources_delegate, bool use_eds_resources_cache) override { + absl::StatusOr rate_limit_settings_or_error = + Utility::parseRateLimitSettings(ads_config); + THROW_IF_STATUS_NOT_OK(rate_limit_settings_or_error, throw); GrpcMuxContext grpc_mux_context{ /*async_client_=*/std::move(async_client), /*dispatcher_=*/dispatcher, @@ -578,7 +581,7 @@ class GrpcMuxFactory : public MuxFactory { *Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"), /*local_info_=*/local_info, - /*rate_limit_settings_=*/Utility::parseRateLimitSettings(ads_config), + /*rate_limit_settings_=*/rate_limit_settings_or_error.value(), /*scope_=*/scope, /*config_validators_=*/std::move(config_validators), /*xds_resources_delegate_=*/xds_resources_delegate, diff --git a/source/extensions/config_subscription/grpc/grpc_stream_interface.h b/source/extensions/config_subscription/grpc/grpc_stream_interface.h index 3c65e3efbce5..9b49877e13b8 100644 --- a/source/extensions/config_subscription/grpc/grpc_stream_interface.h +++ b/source/extensions/config_subscription/grpc/grpc_stream_interface.h @@ -11,7 +11,7 @@ namespace Config { template class GrpcStreamInterface : public Grpc::AsyncStreamCallbacks { public: - virtual ~GrpcStreamInterface() = default; + ~GrpcStreamInterface() override = default; // Attempt to establish a new gRPC stream to the xDS server. virtual void establishNewStream() PURE; diff --git a/source/extensions/config_subscription/grpc/grpc_subscription_factory.cc b/source/extensions/config_subscription/grpc/grpc_subscription_factory.cc index aea80ca7b8f1..20efc1d418b4 100644 --- a/source/extensions/config_subscription/grpc/grpc_subscription_factory.cc +++ b/source/extensions/config_subscription/grpc/grpc_subscription_factory.cc @@ -29,12 +29,15 @@ GrpcConfigSubscriptionFactory::create(ConfigSubscriptionFactory::SubscriptionDat auto factory_or_error = Utility::factoryForGrpcApiConfigSource( data.cm_.grpcAsyncClientManager(), api_config_source, data.scope_, true); THROW_IF_STATUS_NOT_OK(factory_or_error, throw); + absl::StatusOr rate_limit_settings_or_error = + Utility::parseRateLimitSettings(api_config_source); + THROW_IF_STATUS_NOT_OK(rate_limit_settings_or_error, throw); GrpcMuxContext grpc_mux_context{ /*async_client_=*/factory_or_error.value()->createUncachedRawAsyncClient(), /*dispatcher_=*/data.dispatcher_, /*service_method_=*/sotwGrpcMethod(data.type_url_), /*local_info_=*/data.local_info_, - /*rate_limit_settings_=*/Utility::parseRateLimitSettings(api_config_source), + /*rate_limit_settings_=*/rate_limit_settings_or_error.value(), /*scope_=*/data.scope_, /*config_validators_=*/std::move(custom_config_validators), /*xds_resources_delegate_=*/data.xds_resources_delegate_, @@ -74,12 +77,15 @@ DeltaGrpcConfigSubscriptionFactory::create(ConfigSubscriptionFactory::Subscripti auto factory_or_error = Utility::factoryForGrpcApiConfigSource( data.cm_.grpcAsyncClientManager(), api_config_source, data.scope_, true); THROW_IF_STATUS_NOT_OK(factory_or_error, throw); + absl::StatusOr rate_limit_settings_or_error = + Utility::parseRateLimitSettings(api_config_source); + THROW_IF_STATUS_NOT_OK(rate_limit_settings_or_error, throw); GrpcMuxContext grpc_mux_context{ /*async_client_=*/factory_or_error.value()->createUncachedRawAsyncClient(), /*dispatcher_=*/data.dispatcher_, /*service_method_=*/deltaGrpcMethod(data.type_url_), /*local_info_=*/data.local_info_, - /*rate_limit_settings_=*/Utility::parseRateLimitSettings(api_config_source), + /*rate_limit_settings_=*/rate_limit_settings_or_error.value(), /*scope_=*/data.scope_, /*config_validators_=*/std::move(custom_config_validators), /*xds_resources_delegate_=*/{}, diff --git a/source/extensions/config_subscription/grpc/new_grpc_mux_impl.cc b/source/extensions/config_subscription/grpc/new_grpc_mux_impl.cc index e0f73f807f0b..571699f2c4c4 100644 --- a/source/extensions/config_subscription/grpc/new_grpc_mux_impl.cc +++ b/source/extensions/config_subscription/grpc/new_grpc_mux_impl.cc @@ -357,6 +357,9 @@ class NewGrpcMuxFactory : public MuxFactory { const LocalInfo::LocalInfo& local_info, CustomConfigValidatorsPtr&& config_validators, BackOffStrategyPtr&& backoff_strategy, XdsConfigTrackerOptRef xds_config_tracker, OptRef, bool use_eds_resources_cache) override { + absl::StatusOr rate_limit_settings_or_error = + Utility::parseRateLimitSettings(ads_config); + THROW_IF_STATUS_NOT_OK(rate_limit_settings_or_error, throw); GrpcMuxContext grpc_mux_context{ /*async_client_=*/std::move(async_client), /*dispatcher_=*/dispatcher, @@ -364,7 +367,7 @@ class NewGrpcMuxFactory : public MuxFactory { *Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "envoy.service.discovery.v3.AggregatedDiscoveryService.DeltaAggregatedResources"), /*local_info_=*/local_info, - /*rate_limit_settings_=*/Utility::parseRateLimitSettings(ads_config), + /*rate_limit_settings_=*/rate_limit_settings_or_error.value(), /*scope_=*/scope, /*config_validators_=*/std::move(config_validators), /*xds_resources_delegate_=*/absl::nullopt, diff --git a/source/extensions/config_subscription/grpc/xds_mux/grpc_mux_impl.cc b/source/extensions/config_subscription/grpc/xds_mux/grpc_mux_impl.cc index 7f15728b26ef..52f1eedbe909 100644 --- a/source/extensions/config_subscription/grpc/xds_mux/grpc_mux_impl.cc +++ b/source/extensions/config_subscription/grpc/xds_mux/grpc_mux_impl.cc @@ -415,6 +415,9 @@ class DeltaGrpcMuxFactory : public MuxFactory { const LocalInfo::LocalInfo& local_info, CustomConfigValidatorsPtr&& config_validators, BackOffStrategyPtr&& backoff_strategy, XdsConfigTrackerOptRef xds_config_tracker, XdsResourcesDelegateOptRef, bool use_eds_resources_cache) override { + absl::StatusOr rate_limit_settings_or_error = + Utility::parseRateLimitSettings(ads_config); + THROW_IF_STATUS_NOT_OK(rate_limit_settings_or_error, throw); GrpcMuxContext grpc_mux_context{ /*async_client_=*/std::move(async_client), /*dispatcher_=*/dispatcher, @@ -422,7 +425,7 @@ class DeltaGrpcMuxFactory : public MuxFactory { *Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "envoy.service.discovery.v3.AggregatedDiscoveryService.DeltaAggregatedResources"), /*local_info_=*/local_info, - /*rate_limit_settings_=*/Utility::parseRateLimitSettings(ads_config), + /*rate_limit_settings_=*/rate_limit_settings_or_error.value(), /*scope_=*/scope, /*config_validators_=*/std::move(config_validators), /*xds_resources_delegate_=*/absl::nullopt, @@ -450,6 +453,9 @@ class SotwGrpcMuxFactory : public MuxFactory { const LocalInfo::LocalInfo& local_info, CustomConfigValidatorsPtr&& config_validators, BackOffStrategyPtr&& backoff_strategy, XdsConfigTrackerOptRef xds_config_tracker, XdsResourcesDelegateOptRef, bool use_eds_resources_cache) override { + absl::StatusOr rate_limit_settings_or_error = + Utility::parseRateLimitSettings(ads_config); + THROW_IF_STATUS_NOT_OK(rate_limit_settings_or_error, throw); GrpcMuxContext grpc_mux_context{ /*async_client_=*/std::move(async_client), /*dispatcher_=*/dispatcher, @@ -457,7 +463,7 @@ class SotwGrpcMuxFactory : public MuxFactory { *Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "envoy.service.discovery.v3.AggregatedDiscoveryService.StreamAggregatedResources"), /*local_info_=*/local_info, - /*rate_limit_settings_=*/Utility::parseRateLimitSettings(ads_config), + /*rate_limit_settings_=*/rate_limit_settings_or_error.value(), /*scope_=*/scope, /*config_validators_=*/std::move(config_validators), /*xds_resources_delegate_=*/absl::nullopt, diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index a67bf3be4744..4b7ed2228f47 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -6,6 +6,7 @@ EXTENSIONS = { "envoy.access_loggers.file": "//source/extensions/access_loggers/file:config", "envoy.access_loggers.extension_filters.cel": "//source/extensions/access_loggers/filters/cel:config", + "envoy.access_loggers.fluentd" : "//source/extensions/access_loggers/fluentd:config", "envoy.access_loggers.http_grpc": "//source/extensions/access_loggers/grpc:http_config", "envoy.access_loggers.tcp_grpc": "//source/extensions/access_loggers/grpc:tcp_config", "envoy.access_loggers.open_telemetry": "//source/extensions/access_loggers/open_telemetry:config", @@ -278,6 +279,7 @@ EXTENSIONS = { # "envoy.tracers.opentelemetry.samplers.always_on": "//source/extensions/tracers/opentelemetry/samplers/always_on:config", + "envoy.tracers.opentelemetry.samplers.dynatrace": "//source/extensions/tracers/opentelemetry/samplers/dynatrace:config", # # Transport sockets diff --git a/source/extensions/extensions_metadata.yaml b/source/extensions/extensions_metadata.yaml index 7efa3acdb2ae..2822b8e21329 100644 --- a/source/extensions/extensions_metadata.yaml +++ b/source/extensions/extensions_metadata.yaml @@ -12,6 +12,13 @@ envoy.access_loggers.extension_filters.cel: status: alpha type_urls: - envoy.extensions.access_loggers.filters.cel.v3.ExpressionFilter +envoy.access_loggers.fluentd: + categories: + - envoy.access_loggers + security_posture: robust_to_untrusted_downstream + status: alpha + type_urls: + - envoy.extensions.access_loggers.fluentd.v3.FluentdAccessLogConfig envoy.access_loggers.http_grpc: categories: - envoy.access_loggers @@ -1173,6 +1180,13 @@ envoy.tracers.opentelemetry.samplers.always_on: status: wip type_urls: - envoy.extensions.tracers.opentelemetry.samplers.v3.AlwaysOnSamplerConfig +envoy.tracers.opentelemetry.samplers.dynatrace: + categories: + - envoy.tracers.opentelemetry.samplers + security_posture: unknown + status: wip + type_urls: + - envoy.extensions.tracers.opentelemetry.samplers.v3.DynatraceSamplerConfig envoy.tracers.skywalking: categories: - envoy.tracers diff --git a/source/extensions/filters/common/ratelimit/ratelimit_impl.cc b/source/extensions/filters/common/ratelimit/ratelimit_impl.cc index 3097f1b62e5e..a72fa1b81661 100644 --- a/source/extensions/filters/common/ratelimit/ratelimit_impl.cc +++ b/source/extensions/filters/common/ratelimit/ratelimit_impl.cc @@ -127,12 +127,14 @@ ClientPtr rateLimitClient(Server::Configuration::FactoryContext& context, const std::chrono::milliseconds timeout) { // TODO(ramaraochavali): register client to singleton when GrpcClientImpl supports concurrent // requests. - return std::make_unique( + auto client_or_error = context.serverFactoryContext() .clusterManager() .grpcAsyncClientManager() - .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context.scope(), true), - timeout); + .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context.scope(), true); + THROW_IF_STATUS_NOT_OK(client_or_error, throw); + return std::make_unique(client_or_error.value(), + timeout); } } // namespace RateLimit diff --git a/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc b/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc index f291f35ae700..7258f7d4006d 100644 --- a/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc +++ b/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc @@ -135,7 +135,7 @@ void Filter::resolveSettings() { if (auto route_settings = getRouteSpecificSettings()) { payload_passthrough_ = route_settings->payloadPassthrough(); invocation_mode_ = route_settings->invocationMode(); - arn_ = std::move(route_settings)->arn(); + arn_ = route_settings->arn(); host_rewrite_ = route_settings->hostRewrite(); } else { payload_passthrough_ = settings_.payloadPassthrough(); diff --git a/source/extensions/filters/http/basic_auth/BUILD b/source/extensions/filters/http/basic_auth/BUILD index f610d4fee905..7f47e0226048 100644 --- a/source/extensions/filters/http/basic_auth/BUILD +++ b/source/extensions/filters/http/basic_auth/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( "//source/common/common:base64_lib", "//source/common/config:utility_lib", "//source/common/http:header_map_lib", + "//source/common/http:header_utility_lib", "//source/common/protobuf:utility_lib", "//source/extensions/filters/http/common:pass_through_filter_lib", ], diff --git a/source/extensions/filters/http/basic_auth/config.cc b/source/extensions/filters/http/basic_auth/config.cc index d7064730bccb..0b0332d8ec99 100644 --- a/source/extensions/filters/http/basic_auth/config.cc +++ b/source/extensions/filters/http/basic_auth/config.cc @@ -63,8 +63,9 @@ UserMap readHtpasswd(const std::string& htpasswd) { Http::FilterFactoryCb BasicAuthFilterFactory::createFilterFactoryFromProtoTyped( const BasicAuth& proto_config, const std::string& stats_prefix, Server::Configuration::FactoryContext& context) { - UserMap users = readHtpasswd( - Config::DataSource::read(proto_config.users(), false, context.serverFactoryContext().api())); + UserMap users = readHtpasswd(THROW_OR_RETURN_VALUE( + Config::DataSource::read(proto_config.users(), false, context.serverFactoryContext().api()), + std::string)); FilterConfigConstSharedPtr config = std::make_unique(std::move(users), stats_prefix, context.scope()); return [config](Http::FilterChainFactoryCallbacks& callbacks) -> void { diff --git a/source/extensions/filters/http/cache/cache_filter.cc b/source/extensions/filters/http/cache/cache_filter.cc index c17486d360c2..a920ac3ddbb2 100644 --- a/source/extensions/filters/http/cache/cache_filter.cc +++ b/source/extensions/filters/http/cache/cache_filter.cc @@ -23,6 +23,16 @@ namespace { inline bool isResponseNotModified(const Http::ResponseHeaderMap& response_headers) { return Http::Utility::getResponseStatus(response_headers) == enumToInt(Http::Code::NotModified); } + +// This value is only used if there is no encoderBufferLimit on the stream; +// without *some* constraint here, a very large chunk can be requested and +// attempt to load into a memory buffer. +// +// This default is quite large to minimize the chance of being a surprise +// behavioral change when a constraint is added. +// +// And everyone knows 64MB should be enough for anyone. +static const size_t MAX_BYTES_TO_FETCH_FROM_CACHE_PER_REQUEST = 64 * 1024 * 1024; } // namespace struct CacheResponseCodeDetailValues { @@ -326,10 +336,21 @@ void CacheFilter::getBody() { // posted callback. CacheFilterWeakPtr self = weak_from_this(); + // We don't want to request more than a buffer-size at a time from the cache. + uint64_t fetch_size_limit = encoder_callbacks_->encoderBufferLimit(); + // If there is no buffer size limit, we still want *some* constraint. + if (fetch_size_limit == 0) { + fetch_size_limit = MAX_BYTES_TO_FETCH_FROM_CACHE_PER_REQUEST; + } + AdjustedByteRange fetch_range = {remaining_ranges_[0].begin(), + (remaining_ranges_[0].length() > fetch_size_limit) + ? (remaining_ranges_[0].begin() + fetch_size_limit) + : remaining_ranges_[0].end()}; + // The dispatcher needs to be captured because there's no guarantee that // decoder_callbacks_->dispatcher() is thread-safe. - lookup_->getBody(remaining_ranges_[0], [self, &dispatcher = decoder_callbacks_->dispatcher()]( - Buffer::InstancePtr&& body) { + lookup_->getBody(fetch_range, [self, &dispatcher = decoder_callbacks_->dispatcher()]( + Buffer::InstancePtr&& body) { // The callback is posted to the dispatcher to make sure it is called on the worker thread. dispatcher.post([self, body = std::move(body)]() mutable { if (CacheFilterSharedPtr cache_filter = self.lock()) { diff --git a/source/extensions/filters/http/composite/filter.cc b/source/extensions/filters/http/composite/filter.cc index 77475283214e..99c28e0bec52 100644 --- a/source/extensions/filters/http/composite/filter.cc +++ b/source/extensions/filters/http/composite/filter.cc @@ -105,26 +105,26 @@ void Filter::onMatchCallback(const Matcher::Action& action) { wrapper.errors_, [](const auto& status) { return status.ToString(); })); return; } - std::string actionName = composite_action.actionName(); + const std::string& action_name = composite_action.actionName(); if (wrapper.filter_to_inject_.has_value()) { stats_.filter_delegation_success_.inc(); auto createDelegatedFilterFn = Overloaded{ - [this, actionName](Http::StreamDecoderFilterSharedPtr filter) { + [this, action_name](Http::StreamDecoderFilterSharedPtr filter) { delegated_filter_ = std::make_shared(std::move(filter)); updateFilterState(decoder_callbacks_, std::string(decoder_callbacks_->filterConfigName()), - actionName); + action_name); }, - [this, actionName](Http::StreamEncoderFilterSharedPtr filter) { + [this, action_name](Http::StreamEncoderFilterSharedPtr filter) { delegated_filter_ = std::make_shared(std::move(filter)); updateFilterState(encoder_callbacks_, std::string(encoder_callbacks_->filterConfigName()), - actionName); + action_name); }, - [this, actionName](Http::StreamFilterSharedPtr filter) { + [this, action_name](Http::StreamFilterSharedPtr filter) { delegated_filter_ = std::move(filter); updateFilterState(decoder_callbacks_, std::string(decoder_callbacks_->filterConfigName()), - actionName); + action_name); }}; absl::visit(createDelegatedFilterFn, std::move(wrapper.filter_to_inject_.value())); diff --git a/source/extensions/filters/http/composite/filter.h b/source/extensions/filters/http/composite/filter.h index 76d2010430a5..3a07d7015c31 100644 --- a/source/extensions/filters/http/composite/filter.h +++ b/source/extensions/filters/http/composite/filter.h @@ -39,7 +39,7 @@ class MatchedActionInfo : public StreamInfo::FilterState::Object { ProtobufTypes::MessagePtr serializeAsProto() const override { return buildProtoStruct(); } absl::optional serializeAsString() const override { - return Json::Factory::loadFromProtobufStruct(*buildProtoStruct().get())->asJsonString(); + return Json::Factory::loadFromProtobufStruct(*buildProtoStruct())->asJsonString(); } void setFilterAction(const std::string& filter, const std::string& action) { diff --git a/source/extensions/filters/http/ext_authz/config.cc b/source/extensions/filters/http/ext_authz/config.cc index bbb99f63cc82..881609481e96 100644 --- a/source/extensions/filters/http/ext_authz/config.cc +++ b/source/extensions/filters/http/ext_authz/config.cc @@ -55,12 +55,14 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped( Envoy::Grpc::GrpcServiceConfigWithHashKey(proto_config.grpc_service()); callback = [&context, filter_config, timeout_ms, config_with_hash_key](Http::FilterChainFactoryCallbacks& callbacks) { - auto client = std::make_unique( + auto client_or_error = context.serverFactoryContext() .clusterManager() .grpcAsyncClientManager() - .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context.scope(), true), - std::chrono::milliseconds(timeout_ms)); + .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, 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))); }; } diff --git a/source/extensions/filters/http/ext_proc/BUILD b/source/extensions/filters/http/ext_proc/BUILD index 976de7b294b8..49ceffc502fe 100644 --- a/source/extensions/filters/http/ext_proc/BUILD +++ b/source/extensions/filters/http/ext_proc/BUILD @@ -35,6 +35,7 @@ envoy_cc_library( "//source/extensions/filters/http/common:pass_through_filter_lib", "@com_google_absl//absl/status", "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/strings:string_view", "@envoy_api//envoy/config/common/mutation_rules/v3:pkg_cc_proto", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/filters/http/ext_proc/v3:pkg_cc_proto", diff --git a/source/extensions/filters/http/ext_proc/client_impl.cc b/source/extensions/filters/http/ext_proc/client_impl.cc index 80ccd31189db..184c2b2ceb35 100644 --- a/source/extensions/filters/http/ext_proc/client_impl.cc +++ b/source/extensions/filters/http/ext_proc/client_impl.cc @@ -15,8 +15,10 @@ ExternalProcessorStreamPtr ExternalProcessorClientImpl::start(ExternalProcessorCallbacks& callbacks, const Grpc::GrpcServiceConfigWithHashKey& config_with_hash_key, const StreamInfo::StreamInfo& stream_info) { - Grpc::AsyncClient grpcClient( - client_manager_.getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, scope_, true)); + auto client_or_error = + client_manager_.getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, scope_, true); + THROW_IF_STATUS_NOT_OK(client_or_error, throw); + Grpc::AsyncClient grpcClient(client_or_error.value()); return ExternalProcessorStreamImpl::create(std::move(grpcClient), callbacks, stream_info); } diff --git a/source/extensions/filters/http/ext_proc/ext_proc.cc b/source/extensions/filters/http/ext_proc/ext_proc.cc index 3e68fcae7568..f2fe47e90070 100644 --- a/source/extensions/filters/http/ext_proc/ext_proc.cc +++ b/source/extensions/filters/http/ext_proc/ext_proc.cc @@ -11,11 +11,13 @@ #include "source/extensions/filters/http/ext_proc/mutation_utils.h" #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" namespace Envoy { namespace Extensions { namespace HttpFilters { namespace ExternalProcessing { +namespace { using envoy::config::common::mutation_rules::v3::HeaderMutationRules; using envoy::extensions::filters::http::ext_proc::v3::ExtProcPerRoute; @@ -35,9 +37,114 @@ using Http::RequestTrailerMap; using Http::ResponseHeaderMap; using Http::ResponseTrailerMap; -static const std::string ErrorPrefix = "ext_proc_error"; -static const int DefaultImmediateStatus = 200; -static const std::string FilterName = "envoy.filters.http.ext_proc"; +constexpr absl::string_view ErrorPrefix = "ext_proc_error"; +constexpr int DefaultImmediateStatus = 200; +constexpr absl::string_view FilterName = "envoy.filters.http.ext_proc"; + +absl::optional initProcessingMode(const ExtProcPerRoute& config) { + if (!config.disabled() && config.has_overrides() && config.overrides().has_processing_mode()) { + return config.overrides().processing_mode(); + } + return absl::nullopt; +} + +absl::optional +initGrpcService(const ExtProcPerRoute& config) { + if (config.has_overrides() && config.overrides().has_grpc_service()) { + return config.overrides().grpc_service(); + } + return absl::nullopt; +} + +std::vector initNamespaces(const Protobuf::RepeatedPtrField& ns) { + std::vector namespaces; + for (const auto& single_ns : ns) { + namespaces.emplace_back(single_ns); + } + return namespaces; +} + +absl::optional> +initUntypedForwardingNamespaces(const ExtProcPerRoute& config) { + if (!config.has_overrides() || !config.overrides().has_metadata_options() || + !config.overrides().metadata_options().has_forwarding_namespaces()) { + return absl::nullopt; + } + + return {initNamespaces(config.overrides().metadata_options().forwarding_namespaces().untyped())}; +} + +absl::optional> +initTypedForwardingNamespaces(const ExtProcPerRoute& config) { + if (!config.has_overrides() || !config.overrides().has_metadata_options() || + !config.overrides().metadata_options().has_forwarding_namespaces()) { + return absl::nullopt; + } + + return {initNamespaces(config.overrides().metadata_options().forwarding_namespaces().typed())}; +} + +absl::optional> +initUntypedReceivingNamespaces(const ExtProcPerRoute& config) { + if (!config.has_overrides() || !config.overrides().has_metadata_options() || + !config.overrides().metadata_options().has_receiving_namespaces()) { + return absl::nullopt; + } + + return {initNamespaces(config.overrides().metadata_options().receiving_namespaces().untyped())}; +} + +absl::optional mergeProcessingMode(const FilterConfigPerRoute& less_specific, + const FilterConfigPerRoute& more_specific) { + if (more_specific.disabled()) { + return absl::nullopt; + } + return more_specific.processingMode().has_value() ? more_specific.processingMode() + : less_specific.processingMode(); +} + +// Replaces all entries with the same name or append one. +void mergeHeaderValues(std::vector& metadata, + const envoy::config::core::v3::HeaderValue& header) { + bool has_key = false; + for (auto& dest : metadata) { + if (dest.key() == header.key()) { + dest.CopyFrom(header); + has_key = true; + } + } + if (!has_key) { + metadata.emplace_back(header); + } +} + +std::vector +mergeGrpcInitialMetadata(const FilterConfigPerRoute& less_specific, + const FilterConfigPerRoute& more_specific) { + std::vector metadata(less_specific.grpcInitialMetadata()); + + for (const auto& header : more_specific.grpcInitialMetadata()) { + mergeHeaderValues(metadata, header); + } + + return metadata; +} + +// Replaces all entries with the same name or append one. +void mergeHeaderValuesField( + Protobuf::RepeatedPtrField<::envoy::config::core::v3::HeaderValue>& metadata, + const envoy::config::core::v3::HeaderValue& header) { + bool has_key = false; + for (auto& dest : metadata) { + if (dest.key() == header.key()) { + dest.CopyFrom(header); + has_key = true; + } + } + if (!has_key) { + metadata.Add()->CopyFrom(header); + } +} // Changes to headers are normally tested against the MutationRules supplied // with configuration. When writing an immediate response message, however, @@ -60,6 +167,19 @@ class ImmediateMutationChecker { std::unique_ptr rule_checker_; }; +const ImmediateMutationChecker& immediateResponseChecker() { + CONSTRUCT_ON_FIRST_USE(ImmediateMutationChecker); +} + +ProcessingMode allDisabledMode() { + ProcessingMode pm; + pm.set_request_header_mode(ProcessingMode::SKIP); + pm.set_response_header_mode(ProcessingMode::SKIP); + return pm; +} + +} // namespace + void ExtProcLoggingInfo::recordGrpcCall( std::chrono::microseconds latency, Grpc::Status::GrpcStatus call_status, ProcessorState::CallbackState callback_state, @@ -117,77 +237,11 @@ ExtProcLoggingInfo::grpcCalls(envoy::config::core::v3::TrafficDirection traffic_ : encoding_processor_grpc_calls_; } -std::vector -FilterConfigPerRoute::initNamespaces(const Protobuf::RepeatedPtrField& ns) { - if (ns.empty()) { - return {}; - } - - std::vector namespaces; - for (const auto& single_ns : ns) { - namespaces.emplace_back(single_ns); - } - return namespaces; -} - -absl::optional> -FilterConfigPerRoute::initUntypedForwardingNamespaces(const ExtProcPerRoute& config) { - if (!config.has_overrides() || !config.overrides().has_metadata_options() || - !config.overrides().metadata_options().has_forwarding_namespaces()) { - return absl::nullopt; - } - - return {initNamespaces(config.overrides().metadata_options().forwarding_namespaces().untyped())}; -} - -absl::optional> -FilterConfigPerRoute::initTypedForwardingNamespaces(const ExtProcPerRoute& config) { - if (!config.has_overrides() || !config.overrides().has_metadata_options() || - !config.overrides().metadata_options().has_forwarding_namespaces()) { - return absl::nullopt; - } - - return {initNamespaces(config.overrides().metadata_options().forwarding_namespaces().typed())}; -} - -absl::optional> -FilterConfigPerRoute::initUntypedReceivingNamespaces(const ExtProcPerRoute& config) { - if (!config.has_overrides() || !config.overrides().has_metadata_options() || - !config.overrides().metadata_options().has_receiving_namespaces()) { - return absl::nullopt; - } - - return {initNamespaces(config.overrides().metadata_options().receiving_namespaces().untyped())}; -} - -absl::optional -FilterConfigPerRoute::initProcessingMode(const ExtProcPerRoute& config) { - if (!config.disabled() && config.has_overrides() && config.overrides().has_processing_mode()) { - return config.overrides().processing_mode(); - } - return absl::nullopt; -} -absl::optional -FilterConfigPerRoute::initGrpcService(const ExtProcPerRoute& config) { - if (config.has_overrides() && config.overrides().has_grpc_service()) { - return config.overrides().grpc_service(); - } - return absl::nullopt; -} - -absl::optional -FilterConfigPerRoute::mergeProcessingMode(const FilterConfigPerRoute& less_specific, - const FilterConfigPerRoute& more_specific) { - if (more_specific.disabled()) { - return absl::nullopt; - } - return more_specific.processingMode().has_value() ? more_specific.processingMode() - : less_specific.processingMode(); -} - FilterConfigPerRoute::FilterConfigPerRoute(const ExtProcPerRoute& config) : disabled_(config.disabled()), processing_mode_(initProcessingMode(config)), grpc_service_(initGrpcService(config)), + grpc_initial_metadata_(config.overrides().grpc_initial_metadata().begin(), + config.overrides().grpc_initial_metadata().end()), untyped_forwarding_namespaces_(initUntypedForwardingNamespaces(config)), typed_forwarding_namespaces_(initTypedForwardingNamespaces(config)), untyped_receiving_namespaces_(initUntypedReceivingNamespaces(config)) {} @@ -198,6 +252,7 @@ FilterConfigPerRoute::FilterConfigPerRoute(const FilterConfigPerRoute& less_spec processing_mode_(mergeProcessingMode(less_specific, more_specific)), grpc_service_(more_specific.grpcService().has_value() ? more_specific.grpcService() : less_specific.grpcService()), + grpc_initial_metadata_(mergeGrpcInitialMetadata(less_specific, more_specific)), untyped_forwarding_namespaces_(more_specific.untypedForwardingMetadataNamespaces().has_value() ? more_specific.untypedForwardingMetadataNamespaces() : less_specific.untypedForwardingMetadataNamespaces()), @@ -995,10 +1050,6 @@ void Filter::onFinishProcessorCalls(Grpc::Status::GrpcStatus call_status) { encoding_state_.onFinishProcessorCall(call_status); } -static const ImmediateMutationChecker& immediateResponseChecker() { - CONSTRUCT_ON_FIRST_USE(ImmediateMutationChecker); -} - void Filter::sendImmediateResponse(const ImmediateResponse& response) { auto status_code = response.has_status() ? response.status().code() : DefaultImmediateStatus; if (!MutationUtils::isValidHttpStatus(status_code)) { @@ -1036,13 +1087,6 @@ void Filter::sendImmediateResponse(const ImmediateResponse& response) { mutate_headers, grpc_status, details); } -static ProcessingMode allDisabledMode() { - ProcessingMode pm; - pm.set_request_header_mode(ProcessingMode::SKIP); - pm.set_response_header_mode(ProcessingMode::SKIP); - return pm; -} - void Filter::mergePerRouteConfig() { if (route_config_merged_) { return; @@ -1089,6 +1133,16 @@ void Filter::mergePerRouteConfig() { grpc_service_ = *merged_config->grpcService(); config_with_hash_key_.setConfig(*merged_config->grpcService()); } + if (!merged_config->grpcInitialMetadata().empty()) { + ENVOY_LOG(trace, "Overriding grpc initial metadata from per-route configuration"); + envoy::config::core::v3::GrpcService config = config_with_hash_key_.config(); + auto ptr = config.mutable_initial_metadata(); + for (const auto& header : merged_config->grpcInitialMetadata()) { + ENVOY_LOG(trace, "Setting grpc initial metadata {} = {}", header.key(), header.value()); + mergeHeaderValuesField(*ptr, header); + } + config_with_hash_key_.setConfig(config); + } // For metadata namespaces, we only override the existing value if we have a // value from our merged config. We indicate a lack of value from the merged diff --git a/source/extensions/filters/http/ext_proc/ext_proc.h b/source/extensions/filters/http/ext_proc/ext_proc.h index 1ef14a7c2e81..689b1e322872 100644 --- a/source/extensions/filters/http/ext_proc/ext_proc.h +++ b/source/extensions/filters/http/ext_proc/ext_proc.h @@ -247,6 +247,9 @@ class FilterConfigPerRoute : public Router::RouteSpecificFilterConfig { const absl::optional& grpcService() const { return grpc_service_; } + const std::vector& grpcInitialMetadata() const { + return grpc_initial_metadata_; + } const absl::optional>& untypedForwardingMetadataNamespaces() const { @@ -260,31 +263,11 @@ class FilterConfigPerRoute : public Router::RouteSpecificFilterConfig { } private: - absl::optional - initProcessingMode(const envoy::extensions::filters::http::ext_proc::v3::ExtProcPerRoute& config); - - absl::optional - initGrpcService(const envoy::extensions::filters::http::ext_proc::v3::ExtProcPerRoute& config); - - std::vector initNamespaces(const Protobuf::RepeatedPtrField& ns); - - absl::optional> initUntypedForwardingNamespaces( - const envoy::extensions::filters::http::ext_proc::v3::ExtProcPerRoute& config); - - absl::optional> initTypedForwardingNamespaces( - const envoy::extensions::filters::http::ext_proc::v3::ExtProcPerRoute& config); - - absl::optional> initUntypedReceivingNamespaces( - const envoy::extensions::filters::http::ext_proc::v3::ExtProcPerRoute& config); - - absl::optional - mergeProcessingMode(const FilterConfigPerRoute& less_specific, - const FilterConfigPerRoute& more_specific); - const bool disabled_; const absl::optional processing_mode_; const absl::optional grpc_service_; + std::vector grpc_initial_metadata_; const absl::optional> untyped_forwarding_namespaces_; const absl::optional> typed_forwarding_namespaces_; @@ -321,6 +304,9 @@ class Filter : public Logger::Loggable, config->untypedReceivingMetadataNamespaces()) {} const FilterConfig& config() const { return *config_; } + const envoy::config::core::v3::GrpcService& grpc_service_config() const { + return config_with_hash_key_.config(); + } ExtProcFilterStats& stats() { return stats_; } ExtProcLoggingInfo* loggingInfo() { return logging_info_; } diff --git a/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc b/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc index 56d1eebe5a62..a97d79bd9eac 100644 --- a/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc +++ b/source/extensions/filters/http/grpc_http1_bridge/http1_bridge_filter.cc @@ -24,7 +24,7 @@ namespace GrpcHttp1Bridge { // query params here. void Http1BridgeFilter::ignoreQueryParams(Http::RequestHeaderMap& headers) { absl::string_view path = headers.getPathValue(); - size_t pos = path.find("?"); + size_t pos = path.find('?'); if (pos != absl::string_view::npos) { absl::string_view new_path = path.substr(0, pos); headers.setPath(new_path); diff --git a/source/extensions/filters/http/jwt_authn/authenticator.cc b/source/extensions/filters/http/jwt_authn/authenticator.cc index 84cdc150ba07..56f72f426837 100644 --- a/source/extensions/filters/http/jwt_authn/authenticator.cc +++ b/source/extensions/filters/http/jwt_authn/authenticator.cc @@ -412,7 +412,7 @@ void AuthenticatorImpl::handleGoodJwt(bool cache_hit) { void AuthenticatorImpl::setPayloadMetadata(const ProtobufWkt::Struct& jwt_payload) { const auto& provider = jwks_data_->getJwtProvider(); const auto& normalize = provider.normalize_payload_in_metadata(); - if (normalize.space_delimited_claims().size() == 0) { + if (normalize.space_delimited_claims().empty()) { set_extracted_jwt_data_cb_(provider.payload_in_metadata(), jwt_payload); } // Make a temporary copy to normalize the JWT struct. diff --git a/source/extensions/filters/http/jwt_authn/filter_factory.cc b/source/extensions/filters/http/jwt_authn/filter_factory.cc index 5bb39e47477e..abbf4ac34d21 100644 --- a/source/extensions/filters/http/jwt_authn/filter_factory.cc +++ b/source/extensions/filters/http/jwt_authn/filter_factory.cc @@ -24,7 +24,8 @@ namespace { */ void validateJwtConfig(const JwtAuthentication& proto_config, Api::Api& api) { for (const auto& [name, provider] : proto_config.providers()) { - const auto inline_jwks = Config::DataSource::read(provider.local_jwks(), true, api); + const auto inline_jwks = THROW_OR_RETURN_VALUE( + Config::DataSource::read(provider.local_jwks(), true, api), std::string); if (!inline_jwks.empty()) { auto jwks_obj = Jwks::createFrom(inline_jwks, Jwks::JWKS); if (jwks_obj->getStatus() != Status::Ok) { diff --git a/source/extensions/filters/http/jwt_authn/jwks_cache.cc b/source/extensions/filters/http/jwt_authn/jwks_cache.cc index d2a7979ac47f..9df261ce2a4b 100644 --- a/source/extensions/filters/http/jwt_authn/jwks_cache.cc +++ b/source/extensions/filters/http/jwt_authn/jwks_cache.cc @@ -70,8 +70,10 @@ class JwksDataImpl : public JwksCache::JwksData, public Logger::Loggable(enable_jwt_cache, config, dispatcher.timeSource()); }); - const auto inline_jwks = Config::DataSource::read(jwt_provider_.local_jwks(), true, - context.serverFactoryContext().api()); + const auto inline_jwks = + THROW_OR_RETURN_VALUE(Config::DataSource::read(jwt_provider_.local_jwks(), true, + context.serverFactoryContext().api()), + std::string); if (!inline_jwks.empty()) { auto jwks = ::google::jwt_verify::Jwks::createFrom(inline_jwks, ::google::jwt_verify::Jwks::JWKS); diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index 0f4b53f22934..a941b889a505 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -808,15 +808,16 @@ FilterConfig::FilterConfig(const envoy::extensions::filters::http::lua::v3::Lua& "for the Lua filter."); } - const std::string code = - Config::DataSource::read(proto_config.default_source_code(), true, api); + const std::string code = THROW_OR_RETURN_VALUE( + Config::DataSource::read(proto_config.default_source_code(), true, api), std::string); default_lua_code_setup_ = std::make_unique(code, tls); } else if (!proto_config.inline_code().empty()) { default_lua_code_setup_ = std::make_unique(proto_config.inline_code(), tls); } for (const auto& source : proto_config.source_codes()) { - const std::string code = Config::DataSource::read(source.second, true, api); + const std::string code = + THROW_OR_RETURN_VALUE(Config::DataSource::read(source.second, true, api), std::string); auto per_lua_code_setup_ptr = std::make_unique(code, tls); if (!per_lua_code_setup_ptr) { continue; @@ -834,7 +835,8 @@ FilterConfigPerRoute::FilterConfigPerRoute( return; } // Read and parse the inline Lua code defined in the route configuration. - const std::string code_str = Config::DataSource::read(config.source_code(), true, context.api()); + const std::string code_str = THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.source_code(), true, context.api()), std::string); per_lua_code_setup_ptr_ = std::make_unique(code_str, context.threadLocal()); } diff --git a/source/extensions/filters/http/oauth2/BUILD b/source/extensions/filters/http/oauth2/BUILD index 936579f59266..a236dfa7583f 100644 --- a/source/extensions/filters/http/oauth2/BUILD +++ b/source/extensions/filters/http/oauth2/BUILD @@ -49,10 +49,10 @@ envoy_cc_library( "//envoy/server:filter_config_interface", "//source/common/common:assert_lib", "//source/common/common:empty_string", - "//source/common/config:datasource_lib", "//source/common/crypto:utility_lib", "//source/common/formatter:substitution_formatter_lib", "//source/common/protobuf:utility_lib", + "//source/common/secret:secret_provider_impl_lib", "//source/extensions/filters/http/common:pass_through_filter_lib", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/filters/http/oauth2/v3:pkg_cc_proto", diff --git a/source/extensions/filters/http/oauth2/config.cc b/source/extensions/filters/http/oauth2/config.cc index 98fd1f7dd6d8..1a7878b92f26 100644 --- a/source/extensions/filters/http/oauth2/config.cc +++ b/source/extensions/filters/http/oauth2/config.cc @@ -64,9 +64,9 @@ Http::FilterFactoryCb OAuth2Config::createFilterFactoryFromProtoTyped( throw EnvoyException("invalid HMAC secret configuration"); } - auto secret_reader = - std::make_shared(secret_provider_token_secret, secret_provider_hmac_secret, - context.serverFactoryContext().api()); + auto secret_reader = std::make_shared( + std::move(secret_provider_token_secret), std::move(secret_provider_hmac_secret), + context.serverFactoryContext().threadLocal(), context.serverFactoryContext().api()); auto config = std::make_shared(proto_config, cluster_manager, secret_reader, context.scope(), stats_prefix); diff --git a/source/extensions/filters/http/oauth2/filter.cc b/source/extensions/filters/http/oauth2/filter.cc index d451be546e9d..ddf129b802df 100644 --- a/source/extensions/filters/http/oauth2/filter.cc +++ b/source/extensions/filters/http/oauth2/filter.cc @@ -258,8 +258,8 @@ bool OAuth2CookieValidator::isValid() const { return hmacIsValid() && timestampI OAuth2Filter::OAuth2Filter(FilterConfigSharedPtr config, std::unique_ptr&& oauth_client, TimeSource& time_source) : validator_(std::make_shared(time_source, config->cookieNames())), - was_refresh_token_flow_(false), oauth_client_(std::move(oauth_client)), - config_(std::move(config)), time_source_(time_source) { + oauth_client_(std::move(oauth_client)), config_(std::move(config)), + time_source_(time_source) { oauth_client_->setCallbacks(*this); } diff --git a/source/extensions/filters/http/oauth2/filter.h b/source/extensions/filters/http/oauth2/filter.h index 3e86351fc98b..d2a594241a35 100644 --- a/source/extensions/filters/http/oauth2/filter.h +++ b/source/extensions/filters/http/oauth2/filter.h @@ -16,11 +16,11 @@ #include "source/common/common/assert.h" #include "source/common/common/matchers.h" -#include "source/common/config/datasource.h" #include "source/common/formatter/substitution_formatter.h" #include "source/common/http/header_map_impl.h" #include "source/common/http/header_utility.h" #include "source/common/http/utility.h" +#include "source/common/secret/secret_provider_impl.h" #include "source/extensions/filters/http/common/pass_through_filter.h" #include "source/extensions/filters/http/oauth2/oauth.h" #include "source/extensions/filters/http/oauth2/oauth_client.h" @@ -45,37 +45,17 @@ class SecretReader { class SDSSecretReader : public SecretReader { public: - SDSSecretReader(Secret::GenericSecretConfigProviderSharedPtr client_secret_provider, - Secret::GenericSecretConfigProviderSharedPtr token_secret_provider, Api::Api& api) - : update_callback_client_(readAndWatchSecret(client_secret_, client_secret_provider, api)), - update_callback_token_(readAndWatchSecret(token_secret_, token_secret_provider, api)) {} - - const std::string& clientSecret() const override { return client_secret_; } - - const std::string& tokenSecret() const override { return token_secret_; } + SDSSecretReader(Secret::GenericSecretConfigProviderSharedPtr&& client_secret_provider, + Secret::GenericSecretConfigProviderSharedPtr&& token_secret_provider, + ThreadLocal::SlotAllocator& tls, Api::Api& api) + : client_secret_(std::move(client_secret_provider), tls, api), + token_secret_(std::move(token_secret_provider), tls, api) {} + const std::string& clientSecret() const override { return client_secret_.secret(); } + const std::string& tokenSecret() const override { return token_secret_.secret(); } private: - Envoy::Common::CallbackHandlePtr - readAndWatchSecret(std::string& value, - Secret::GenericSecretConfigProviderSharedPtr& secret_provider, Api::Api& api) { - const auto* secret = secret_provider->secret(); - if (secret != nullptr) { - value = Config::DataSource::read(secret->secret(), true, api); - } - - return secret_provider->addUpdateCallback([secret_provider, &api, &value]() { - const auto* secret = secret_provider->secret(); - if (secret != nullptr) { - value = Config::DataSource::read(secret->secret(), true, api); - } - }); - } - - std::string client_secret_; - std::string token_secret_; - - Envoy::Common::CallbackHandlePtr update_callback_client_; - Envoy::Common::CallbackHandlePtr update_callback_token_; + Secret::ThreadLocalGenericSecretProvider client_secret_; + Secret::ThreadLocalGenericSecretProvider token_secret_; }; /** @@ -285,7 +265,7 @@ class OAuth2Filter : public Http::PassThroughFilter, absl::string_view host_; std::string state_; Http::RequestHeaderMap* request_headers_{nullptr}; - bool was_refresh_token_flow_; + bool was_refresh_token_flow_{false}; std::unique_ptr oauth_client_; FilterConfigSharedPtr config_; 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 36af6a35b4fb..33069f17e4cd 100644 --- a/source/extensions/filters/http/rate_limit_quota/client_impl.cc +++ b/source/extensions/filters/http/rate_limit_quota/client_impl.cc @@ -7,6 +7,25 @@ namespace Extensions { namespace HttpFilters { namespace RateLimitQuota { +Grpc::RawAsyncClientSharedPtr +getOrThrow(absl::StatusOr client_or_error) { + THROW_IF_STATUS_NOT_OK(client_or_error, throw); + return client_or_error.value(); +} + +RateLimitClientImpl::RateLimitClientImpl( + const Grpc::GrpcServiceConfigWithHashKey& config_with_hash_key, + Server::Configuration::FactoryContext& context, absl::string_view domain_name, + RateLimitQuotaCallbacks* callbacks, BucketsCache& quota_buckets) + : domain_name_(domain_name), + aync_client_(getOrThrow( + context.serverFactoryContext() + .clusterManager() + .grpcAsyncClientManager() + .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context.scope(), true))), + rlqs_callback_(callbacks), quota_buckets_(quota_buckets), + time_source_(context.serverFactoryContext().mainThreadDispatcher().timeSource()) {} + RateLimitQuotaUsageReports RateLimitClientImpl::buildReport(absl::optional bucket_id) { RateLimitQuotaUsageReports report; // Build the report from quota bucket cache. @@ -15,6 +34,7 @@ RateLimitQuotaUsageReports RateLimitClientImpl::buildReport(absl::optionalmutable_bucket_id() = bucket->bucket_id; usage->set_num_requests_allowed(bucket->quota_usage.num_requests_allowed); usage->set_num_requests_denied(bucket->quota_usage.num_requests_denied); + auto now = std::chrono::duration_cast( time_source_.monotonicTime().time_since_epoch()); // For the newly created bucket (i.e., `bucket_id` input is not null), its time @@ -29,6 +49,10 @@ RateLimitQuotaUsageReports RateLimitClientImpl::buildReport(absl::optionalquota_usage.last_report = now; + // Reset the number of request allowed/denied. The RLQS server expects the client to report + // those two usage numbers only for last report period. + bucket->quota_usage.num_requests_allowed = 0; + bucket->quota_usage.num_requests_denied = 0; } // Set the domain name. @@ -57,11 +81,13 @@ void RateLimitClientImpl::onReceiveMessage(RateLimitQuotaResponsePtr&& response) // Get the hash id value from BucketId in the response. const size_t bucket_id = MessageUtil::hash(action.bucket_id()); + ENVOY_LOG(trace, + "Received a response for bucket id proto :\n {}, and generated " + "the associated hashed bucket id: {}", + action.bucket_id().DebugString(), bucket_id); if (quota_buckets_.find(bucket_id) == quota_buckets_.end()) { // The response should be matched to the report we sent. - ENVOY_LOG(error, - "Received a response, but but it is not matched any quota " - "cache entry: ", + ENVOY_LOG(error, "The received response is not matched to any quota cache entry: ", response->ShortDebugString()); } else { quota_buckets_[bucket_id]->bucket_action = action; @@ -79,9 +105,14 @@ void RateLimitClientImpl::onReceiveMessage(RateLimitQuotaResponsePtr&& response) double fill_rate_per_sec = static_cast(rate_limit_strategy.token_bucket().tokens_per_fill().value()) / fill_interval_sec; - - quota_buckets_[bucket_id]->token_bucket_limiter = std::make_unique( - rate_limit_strategy.token_bucket().max_tokens(), time_source_, fill_rate_per_sec); + uint32_t max_tokens = rate_limit_strategy.token_bucket().max_tokens(); + ENVOY_LOG( + trace, + "Created the token bucket limiter for hashed bucket id: {}, with max_tokens: {}; " + "fill_interval_sec: {}; fill_rate_per_sec: {}.", + bucket_id, max_tokens, fill_interval_sec, fill_rate_per_sec); + quota_buckets_[bucket_id]->token_bucket_limiter = + std::make_unique(max_tokens, time_source_, fill_rate_per_sec); } } } 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 eb7c0f6a6685..4999ef62f9ca 100644 --- a/source/extensions/filters/http/rate_limit_quota/client_impl.h +++ b/source/extensions/filters/http/rate_limit_quota/client_impl.h @@ -34,15 +34,7 @@ class RateLimitClientImpl : public RateLimitClient, public: RateLimitClientImpl(const Grpc::GrpcServiceConfigWithHashKey& config_with_hash_key, Server::Configuration::FactoryContext& context, absl::string_view domain_name, - RateLimitQuotaCallbacks* callbacks, BucketsCache& quota_buckets) - : domain_name_(domain_name), - aync_client_( - context.serverFactoryContext() - .clusterManager() - .grpcAsyncClientManager() - .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context.scope(), true)), - rlqs_callback_(callbacks), quota_buckets_(quota_buckets), - time_source_(context.serverFactoryContext().mainThreadDispatcher().timeSource()) {} + RateLimitQuotaCallbacks* callbacks, BucketsCache& quota_buckets); void onReceiveMessage(RateLimitQuotaResponsePtr&& response) override; diff --git a/source/extensions/filters/http/rate_limit_quota/filter.cc b/source/extensions/filters/http/rate_limit_quota/filter.cc index 48dc20ee61e1..ec83101c8ea2 100644 --- a/source/extensions/filters/http/rate_limit_quota/filter.cc +++ b/source/extensions/filters/http/rate_limit_quota/filter.cc @@ -38,6 +38,8 @@ Http::FilterHeadersStatus RateLimitQuotaFilter::decodeHeaders(Http::RequestHeade BucketId bucket_id_proto = ret.value(); 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()); 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. @@ -190,9 +192,13 @@ Http::FilterHeadersStatus RateLimitQuotaFilter::processCachedBucket(size_t bucke if (limiter->consume(1, /*allow_partial=*/false)) { // Request is allowed. quota_buckets_[bucket_id]->quota_usage.num_requests_allowed += 1; + ENVOY_LOG(trace, "Request with hashed bucket_id {} is allowed by token bucket limiter.", + bucket_id); } else { // Request is throttled. quota_buckets_[bucket_id]->quota_usage.num_requests_denied += 1; + ENVOY_LOG(trace, "Request with hashed bucket_id {} is throttled by token bucket limiter", + bucket_id); // TODO(tyxia) Build the customized response based on `DenyResponseSettings` if it is // configured. callbacks_->sendLocalReply(Envoy::Http::Code::TooManyRequests, "", nullptr, absl::nullopt, diff --git a/source/extensions/filters/http/wasm/BUILD b/source/extensions/filters/http/wasm/BUILD index b9eb2641e9ab..16b2a37264e1 100644 --- a/source/extensions/filters/http/wasm/BUILD +++ b/source/extensions/filters/http/wasm/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( "//envoy/http:codes_interface", "//envoy/server:filter_config_interface", "//envoy/upstream:cluster_manager_interface", + "//source/extensions/common/wasm:remote_async_datasource_lib", "//source/extensions/common/wasm:wasm_lib", "@envoy_api//envoy/extensions/filters/http/wasm/v3:pkg_cc_proto", ], diff --git a/source/extensions/filters/http/wasm/wasm_filter.h b/source/extensions/filters/http/wasm/wasm_filter.h index 6dd63140e9e8..7221ec94fcb4 100644 --- a/source/extensions/filters/http/wasm/wasm_filter.h +++ b/source/extensions/filters/http/wasm/wasm_filter.h @@ -8,6 +8,7 @@ #include "envoy/upstream/cluster_manager.h" #include "source/extensions/common/wasm/plugin.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" #include "source/extensions/common/wasm/wasm.h" namespace Envoy { @@ -51,7 +52,7 @@ class FilterConfig : Logger::Loggable { private: ThreadLocal::TypedSlotPtr tls_slot_; - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; + RemoteAsyncDataProviderPtr remote_data_provider_; }; using FilterConfigSharedPtr = std::shared_ptr; diff --git a/source/extensions/filters/network/direct_response/config.cc b/source/extensions/filters/network/direct_response/config.cc index 5d39492f590a..37f08ce2687b 100644 --- a/source/extensions/filters/network/direct_response/config.cc +++ b/source/extensions/filters/network/direct_response/config.cc @@ -25,8 +25,9 @@ class DirectResponseConfigFactory Network::FilterFactoryCb createFilterFactoryFromProtoTyped( const envoy::extensions::filters::network::direct_response::v3::Config& config, Server::Configuration::FactoryContext& context) override { - auto content = - Config::DataSource::read(config.response(), true, context.serverFactoryContext().api()); + auto content = THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.response(), true, context.serverFactoryContext().api()), + std::string); return [content](Network::FilterManager& filter_manager) -> void { filter_manager.addReadFilter(std::make_shared(content)); diff --git a/source/extensions/filters/network/dubbo_proxy/hessian_utils.h b/source/extensions/filters/network/dubbo_proxy/hessian_utils.h index 8385eb37c0a4..da30248da3b2 100644 --- a/source/extensions/filters/network/dubbo_proxy/hessian_utils.h +++ b/source/extensions/filters/network/dubbo_proxy/hessian_utils.h @@ -5,7 +5,16 @@ #include "envoy/buffer/buffer.h" #include "absl/strings/string_view.h" + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +#endif #include "hessian2/basic_codec/object_codec.hpp" +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + #include "hessian2/codec.hpp" #include "hessian2/object.hpp" #include "hessian2/reader.hpp" diff --git a/source/extensions/filters/network/dubbo_proxy/router/BUILD b/source/extensions/filters/network/dubbo_proxy/router/BUILD index f75fc1d75d62..0901f4a09516 100644 --- a/source/extensions/filters/network/dubbo_proxy/router/BUILD +++ b/source/extensions/filters/network/dubbo_proxy/router/BUILD @@ -26,6 +26,7 @@ envoy_cc_library( "//envoy/router:router_interface", "//source/common/common:logger_lib", "//source/common/common:matchers_lib", + "//source/common/config:well_known_names", "//source/common/http:header_utility_lib", "//source/common/protobuf:utility_lib", "//source/common/router:metadatamatchcriteria_lib", @@ -63,6 +64,7 @@ envoy_cc_library( "//envoy/upstream:load_balancer_interface", "//envoy/upstream:thread_local_cluster_interface", "//source/common/common:logger_lib", + "//source/common/config:well_known_names", "//source/common/http:header_utility_lib", "//source/common/router:metadatamatchcriteria_lib", "//source/common/upstream:load_balancer_lib", diff --git a/source/extensions/filters/network/ext_authz/config.cc b/source/extensions/filters/network/ext_authz/config.cc index fe385b77c24a..28efb8fb9605 100644 --- a/source/extensions/filters/network/ext_authz/config.cc +++ b/source/extensions/filters/network/ext_authz/config.cc @@ -30,13 +30,13 @@ Network::FilterFactoryCb ExtAuthzConfigFactory::createFilterFactoryFromProtoType THROW_IF_NOT_OK(Envoy::Config::Utility::checkTransportVersion(proto_config)); return [grpc_service = proto_config.grpc_service(), &context, ext_authz_config, timeout_ms](Network::FilterManager& filter_manager) -> void { - auto async_client_factory = context.serverFactoryContext() - .clusterManager() - .grpcAsyncClientManager() - .factoryForGrpcService(grpc_service, context.scope(), true); - + auto factory_or_error = context.serverFactoryContext() + .clusterManager() + .grpcAsyncClientManager() + .factoryForGrpcService(grpc_service, context.scope(), true); + THROW_IF_STATUS_NOT_OK(factory_or_error, throw); auto client = std::make_unique( - async_client_factory->createUncachedRawAsyncClient(), + factory_or_error.value()->createUncachedRawAsyncClient(), std::chrono::milliseconds(timeout_ms)); filter_manager.addReadFilter(Network::ReadFilterSharedPtr{ std::make_shared(ext_authz_config, std::move(client))}); diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index 9d94281cbc33..a016f5058240 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -398,6 +398,7 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( config.proxy_status_config()) : nullptr), header_validator_factory_(createHeaderValidatorFactory(config, context)), + append_local_overload_(config.append_local_overload()), append_x_forwarded_port_(config.append_x_forwarded_port()), add_proxy_protocol_connection_state_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, add_proxy_protocol_connection_state, true)) { diff --git a/source/extensions/filters/network/http_connection_manager/config.h b/source/extensions/filters/network/http_connection_manager/config.h index b0a29a0f009b..b03d65e22c1c 100644 --- a/source/extensions/filters/network/http_connection_manager/config.h +++ b/source/extensions/filters/network/http_connection_manager/config.h @@ -263,6 +263,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, return nullptr; #endif } + bool appendLocalOverload() const override { return append_local_overload_; } bool appendXForwardedPort() const override { return append_x_forwarded_port_; } bool addProxyProtocolConnectionState() const override { return add_proxy_protocol_connection_state_; @@ -359,6 +360,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, const uint64_t max_requests_per_connection_; const std::unique_ptr proxy_status_config_; const Http::HeaderValidatorFactoryPtr header_validator_factory_; + const bool append_local_overload_; const bool append_x_forwarded_port_; const bool add_proxy_protocol_connection_state_; }; diff --git a/source/extensions/filters/network/redis_proxy/config.h b/source/extensions/filters/network/redis_proxy/config.h index fc32de5163bc..ac2a873ed951 100644 --- a/source/extensions/filters/network/redis_proxy/config.h +++ b/source/extensions/filters/network/redis_proxy/config.h @@ -27,11 +27,11 @@ class ProtocolOptionsConfigImpl : public Upstream::ProtocolOptionsConfig { } std::string authUsername(Api::Api& api) const { - return Config::DataSource::read(auth_username_, true, api); + return THROW_OR_RETURN_VALUE(Config::DataSource::read(auth_username_, true, api), std::string); } std::string authPassword(Api::Api& api) const { - return Config::DataSource::read(auth_password_, true, api); + return THROW_OR_RETURN_VALUE(Config::DataSource::read(auth_password_, true, api), std::string); } static const std::string authUsername(const Upstream::ClusterInfoConstSharedPtr info, diff --git a/source/extensions/filters/network/redis_proxy/proxy_filter.cc b/source/extensions/filters/network/redis_proxy/proxy_filter.cc index eff64deae428..3426239991cd 100644 --- a/source/extensions/filters/network/redis_proxy/proxy_filter.cc +++ b/source/extensions/filters/network/redis_proxy/proxy_filter.cc @@ -24,8 +24,8 @@ ProxyFilterConfig::ProxyFilterConfig( : drain_decision_(drain_decision), runtime_(runtime), stat_prefix_(fmt::format("redis.{}.", config.stat_prefix())), stats_(generateStats(stat_prefix_, scope)), - downstream_auth_username_( - Config::DataSource::read(config.downstream_auth_username(), true, api)), + downstream_auth_username_(THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.downstream_auth_username(), true, api), std::string)), dns_cache_manager_(cache_manager_factory.get()), dns_cache_(getCache(config)) { if (config.settings().enable_redirection() && !config.settings().has_dns_cache_config()) { @@ -33,8 +33,8 @@ ProxyFilterConfig::ProxyFilterConfig( "dns_cache_config field within the connection pool settings to avoid them"); } - auto downstream_auth_password = - Config::DataSource::read(config.downstream_auth_password(), true, api); + auto downstream_auth_password = THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.downstream_auth_password(), true, api), std::string); if (!downstream_auth_password.empty()) { downstream_auth_passwords_.emplace_back(downstream_auth_password); } @@ -43,7 +43,8 @@ ProxyFilterConfig::ProxyFilterConfig( downstream_auth_passwords_.reserve(downstream_auth_passwords_.size() + config.downstream_auth_passwords().size()); for (const auto& source : config.downstream_auth_passwords()) { - const auto p = Config::DataSource::read(source, true, api); + const auto p = + THROW_OR_RETURN_VALUE(Config::DataSource::read(source, true, api), std::string); if (!p.empty()) { downstream_auth_passwords_.emplace_back(p); } diff --git a/source/extensions/filters/network/thrift_proxy/filters/header_to_metadata/BUILD b/source/extensions/filters/network/thrift_proxy/filters/header_to_metadata/BUILD index 810944a4ac04..76be28f0b1fd 100644 --- a/source/extensions/filters/network/thrift_proxy/filters/header_to_metadata/BUILD +++ b/source/extensions/filters/network/thrift_proxy/filters/header_to_metadata/BUILD @@ -27,6 +27,9 @@ envoy_cc_library( hdrs = ["header_to_metadata_filter.h"], deps = [ "//envoy/server:filter_config_interface", + "//source/common/common:base64_lib", + "//source/common/common:matchers_lib", + "//source/common/network:utility_lib", "//source/extensions/filters/network/thrift_proxy/filters:pass_through_filter_lib", "@envoy_api//envoy/extensions/filters/network/thrift_proxy/filters/header_to_metadata/v3:pkg_cc_proto", ], diff --git a/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/BUILD b/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/BUILD index cc6eeb8630a0..8597af0e12e7 100644 --- a/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/BUILD +++ b/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/BUILD @@ -27,6 +27,8 @@ envoy_cc_library( hdrs = ["payload_to_metadata_filter.h"], deps = [ "//envoy/server:filter_config_interface", + "//source/common/common:matchers_lib", + "//source/common/network:utility_lib", "//source/extensions/filters/network/thrift_proxy:auto_protocol_lib", "//source/extensions/filters/network/thrift_proxy:auto_transport_lib", "//source/extensions/filters/network/thrift_proxy:decoder_lib", diff --git a/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.cc b/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.cc index 64d30c4a3d77..bb22658d10a1 100644 --- a/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.cc +++ b/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.cc @@ -102,6 +102,7 @@ bool Rule::matches(const ThriftProxy::MessageMetadata& metadata) const { } FilterStatus TrieMatchHandler::messageEnd() { + ASSERT(steps_ == 0); ENVOY_LOG(trace, "TrieMatchHandler messageEnd"); parent_.handleOnMissing(); complete_ = true; @@ -110,13 +111,12 @@ FilterStatus TrieMatchHandler::messageEnd() { FilterStatus TrieMatchHandler::structBegin(absl::string_view) { ENVOY_LOG(trace, "TrieMatchHandler structBegin id: {}, steps: {}", - last_field_id_.has_value() ? std::to_string(last_field_id_.value()) - : "top_level_struct", - steps_); + field_ids_.empty() ? "top_level_struct" : std::to_string(field_ids_.back()), steps_); + ASSERT(steps_ >= 0); assertNode(); - if (last_field_id_.has_value()) { - if (steps_ == 0 && node_->children_.find(last_field_id_.value()) != node_->children_.end()) { - node_ = node_->children_[last_field_id_.value()]; + if (!field_ids_.empty()) { + if (steps_ == 0 && node_->children_.find(field_ids_.back()) != node_->children_.end()) { + node_ = node_->children_[field_ids_.back()]; ENVOY_LOG(trace, "name: {}", node_->name_); } else { steps_++; @@ -136,37 +136,41 @@ FilterStatus TrieMatchHandler::structEnd() { // last decoder event node_ = nullptr; } + ASSERT(steps_ >= 0); return FilterStatus::Continue; } FilterStatus TrieMatchHandler::fieldBegin(absl::string_view, FieldType&, int16_t& field_id) { - last_field_id_ = field_id; + ENVOY_LOG(trace, "TrieMatchHandler fieldBegin id: {}", field_id); + field_ids_.push_back(field_id); return FilterStatus::Continue; } FilterStatus TrieMatchHandler::fieldEnd() { - last_field_id_.reset(); + ENVOY_LOG(trace, "TrieMatchHandler fieldEnd"); + field_ids_.pop_back(); return FilterStatus::Continue; } FilterStatus TrieMatchHandler::stringValue(absl::string_view value) { assertLastFieldId(); - ENVOY_LOG(trace, "TrieMatchHandler stringValue id:{} value:{}", last_field_id_.value(), value); + ENVOY_LOG(trace, "TrieMatchHandler stringValue id:{} value:{}", field_ids_.back(), value); return handleString(static_cast(value)); } template FilterStatus TrieMatchHandler::numberValue(NumberType value) { assertLastFieldId(); - ENVOY_LOG(trace, "TrieMatchHandler numberValue id:{} value:{}", last_field_id_.value(), value); + ENVOY_LOG(trace, "TrieMatchHandler numberValue id:{} value:{}", field_ids_.back(), value); return handleString(std::to_string(value)); } FilterStatus TrieMatchHandler::handleString(std::string value) { + ASSERT(steps_ >= 0); assertNode(); assertLastFieldId(); - if (steps_ == 0 && node_->children_.find(last_field_id_.value()) != node_->children_.end() && - !node_->children_[last_field_id_.value()]->rule_ids_.empty()) { - auto on_present_node = node_->children_[last_field_id_.value()]; + if (steps_ == 0 && node_->children_.find(field_ids_.back()) != node_->children_.end() && + !node_->children_[field_ids_.back()]->rule_ids_.empty()) { + auto on_present_node = node_->children_[field_ids_.back()]; ENVOY_LOG(trace, "name: {}", on_present_node->name_); parent_.handleOnPresent(std::move(value), on_present_node->rule_ids_); } @@ -180,8 +184,8 @@ void TrieMatchHandler::assertNode() { } void TrieMatchHandler::assertLastFieldId() { - if (!last_field_id_.has_value()) { - throw EnvoyException("payload to metadata filter: invalid trie state, last_field_id is null"); + if (field_ids_.empty()) { + throw EnvoyException("payload to metadata filter: invalid trie state, field_ids_ is null"); } } @@ -314,7 +318,7 @@ FilterStatus PayloadToMetadataFilter::messageBegin(MessageMetadataSharedPtr meta return FilterStatus::Continue; } -static std::string get_hex_representation(Buffer::Instance& data) { +static std::string getHexRepresentation(Buffer::Instance& data) { void* buf = data.linearize(static_cast(data.length())); const unsigned char* linearized_data = static_cast(buf); std::stringstream hex_stream; @@ -348,7 +352,7 @@ FilterStatus PayloadToMetadataFilter::passthroughData(Buffer::Instance& data) { END_TRY CATCH(const EnvoyException& e, { IS_ENVOY_BUG(fmt::format("decoding error, error_message: {}, payload: {}", e.what(), - get_hex_representation(data))); + getHexRepresentation(data))); if (!handler.isComplete()) { handleOnMissing(); } diff --git a/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.h b/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.h index 5ca1dc8135c9..ffd39ab87d74 100644 --- a/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.h +++ b/source/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter.h @@ -135,6 +135,7 @@ class TrieMatchHandler : public DecoderCallbacks, } FilterStatus handleContainerEnd() { + ASSERT(steps_ > 0, "unmatched container end"); steps_--; return FilterStatus::Continue; } @@ -142,8 +143,8 @@ class TrieMatchHandler : public DecoderCallbacks, MetadataHandler& parent_; TrieSharedPtr node_; bool complete_{false}; - absl::optional last_field_id_; - uint16_t steps_{0}; + std::vector field_ids_; + int16_t steps_{0}; }; const uint32_t MAX_PAYLOAD_VALUE_LEN = 8 * 1024; diff --git a/source/extensions/filters/network/thrift_proxy/router/router.h b/source/extensions/filters/network/thrift_proxy/router/router.h index 0ffff508c81f..851f04ccc06a 100644 --- a/source/extensions/filters/network/thrift_proxy/router/router.h +++ b/source/extensions/filters/network/thrift_proxy/router/router.h @@ -129,9 +129,10 @@ class RouterStats { public: RouterStats(const std::string& stat_prefix, Stats::Scope& scope, const LocalInfo::LocalInfo& local_info) - : named_(RouterNamedStats::generateStats(stat_prefix, scope)), - stat_name_set_(scope.symbolTable().makeSet("thrift_proxy")), - symbol_table_(scope.symbolTable()), + : stats_scope_(scope.createScope("")), + named_(RouterNamedStats::generateStats(stat_prefix, *stats_scope_)), + stat_name_set_(stats_scope_->symbolTable().makeSet("thrift_proxy")), + symbol_table_(stats_scope_->symbolTable()), upstream_rq_call_(stat_name_set_->add("thrift.upstream_rq_call")), upstream_rq_oneway_(stat_name_set_->add("thrift.upstream_rq_oneway")), upstream_rq_invalid_type_(stat_name_set_->add("thrift.upstream_rq_invalid_type")), @@ -340,7 +341,7 @@ class RouterStats { Stats::Histogram::Unit::Milliseconds, value); } - const RouterNamedStats named_; + const RouterNamedStats& routerStats() const { return named_; } private: void incClusterScopeCounter(const Upstream::ClusterInfo& cluster, @@ -385,6 +386,8 @@ class RouterStats { return symbol_table_.join({zone_, local_zone_name_, upstream_zone_name, stat_name}); } + Stats::ScopeSharedPtr stats_scope_; + const RouterNamedStats named_; Stats::StatNameSetPtr stat_name_set_; Stats::SymbolTable& symbol_table_; const Stats::StatName upstream_rq_call_; @@ -506,7 +509,7 @@ class RequestOwner : public ProtocolConverter, public Logger::LoggablemaintenanceMode()) { - stats().named_.upstream_rq_maintenance_mode_.inc(); + stats().routerStats().upstream_rq_maintenance_mode_.inc(); if (metadata->messageType() == MessageType::Call) { stats().incResponseLocalException(*cluster_); } @@ -551,7 +554,7 @@ class RequestOwner : public ProtocolConverter, public Logger::LoggabletcpConnPool(Upstream::ResourcePriority::Default, lb_context); if (!conn_pool_data) { - stats().named_.no_healthy_upstream_.inc(); + stats().routerStats().no_healthy_upstream_.inc(); if (metadata->messageType() == MessageType::Call) { stats().incResponseLocalException(*cluster_); } diff --git a/source/extensions/filters/network/thrift_proxy/router/router_impl.cc b/source/extensions/filters/network/thrift_proxy/router/router_impl.cc index 4075376459c8..445a23690b39 100644 --- a/source/extensions/filters/network/thrift_proxy/router/router_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/router_impl.cc @@ -278,7 +278,7 @@ FilterStatus Router::messageBegin(MessageMetadataSharedPtr metadata) { route_ = callbacks_->route(); if (!route_) { ENVOY_STREAM_LOG(debug, "no route match for method '{}'", *callbacks_, metadata->methodName()); - stats().named_.route_missing_.inc(); + stats().routerStats().route_missing_.inc(); callbacks_->sendLocalReply( AppException(AppExceptionType::UnknownMethod, fmt::format("no route for method '{}'", metadata->methodName())), diff --git a/source/extensions/filters/network/thrift_proxy/router/shadow_writer_impl.cc b/source/extensions/filters/network/thrift_proxy/router/shadow_writer_impl.cc index 7c27c675d55f..2ab6544b1a0a 100644 --- a/source/extensions/filters/network/thrift_proxy/router/shadow_writer_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/shadow_writer_impl.cc @@ -22,7 +22,7 @@ OptRef ShadowWriterImpl::submit(const std::string& cluster_n original_transport, original_protocol); const bool created = shadow_router->createUpstreamRequest(); if (!created || !tls_.get().has_value()) { - stats_.named_.shadow_request_submit_failure_.inc(); + stats_.routerStats().shadow_request_submit_failure_.inc(); return absl::nullopt; } diff --git a/source/extensions/filters/network/wasm/BUILD b/source/extensions/filters/network/wasm/BUILD index c3cee216c2e9..b4f3b1172342 100644 --- a/source/extensions/filters/network/wasm/BUILD +++ b/source/extensions/filters/network/wasm/BUILD @@ -18,6 +18,7 @@ envoy_cc_library( deps = [ "//envoy/server:filter_config_interface", "//envoy/upstream:cluster_manager_interface", + "//source/extensions/common/wasm:remote_async_datasource_lib", "//source/extensions/common/wasm:wasm_lib", "//source/extensions/filters/network:well_known_names", "@envoy_api//envoy/extensions/filters/network/wasm/v3:pkg_cc_proto", diff --git a/source/extensions/filters/network/wasm/wasm_filter.h b/source/extensions/filters/network/wasm/wasm_filter.h index dffd08b0c620..521c227fcf0f 100644 --- a/source/extensions/filters/network/wasm/wasm_filter.h +++ b/source/extensions/filters/network/wasm/wasm_filter.h @@ -7,6 +7,7 @@ #include "envoy/server/filter_config.h" #include "envoy/upstream/cluster_manager.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" #include "source/extensions/common/wasm/wasm.h" #include "source/extensions/filters/network/well_known_names.h" @@ -53,7 +54,7 @@ class FilterConfig : Logger::Loggable { private: ThreadLocal::TypedSlotPtr tls_slot_; - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; + RemoteAsyncDataProviderPtr remote_data_provider_; }; using FilterConfigSharedPtr = std::shared_ptr; diff --git a/source/extensions/filters/network/zookeeper_proxy/decoder.cc b/source/extensions/filters/network/zookeeper_proxy/decoder.cc index ec5edd68ea0c..58303e75cd31 100644 --- a/source/extensions/filters/network/zookeeper_proxy/decoder.cc +++ b/source/extensions/filters/network/zookeeper_proxy/decoder.cc @@ -137,8 +137,11 @@ absl::StatusOr> DecoderImpl::decodeOnData(Buffer::Instan status, fmt::format("parseGetDataRequest: {}", status.message())); break; case OpCodes::Create: + ABSL_FALLTHROUGH_INTENDED; case OpCodes::Create2: + ABSL_FALLTHROUGH_INTENDED; case OpCodes::CreateContainer: + ABSL_FALLTHROUGH_INTENDED; case OpCodes::CreateTtl: status = parseCreateRequest(data, offset, len.value(), opcode); RETURN_INVALID_ARG_ERR_IF_STATUS_NOT_OK( @@ -642,22 +645,37 @@ absl::Status DecoderImpl::parseMultiRequest(Buffer::Instance& data, uint64_t& of break; } - switch (static_cast(opcode.value())) { + const auto op = static_cast(opcode.value()); + switch (op) { case OpCodes::Create: - status = parseCreateRequest(data, offset, len, OpCodes::Create); - EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, OpCodes::Create); + ABSL_FALLTHROUGH_INTENDED; + case OpCodes::Create2: + ABSL_FALLTHROUGH_INTENDED; + case OpCodes::CreateContainer: + ABSL_FALLTHROUGH_INTENDED; + case OpCodes::CreateTtl: + status = parseCreateRequest(data, offset, len, op); + EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, op); break; case OpCodes::SetData: status = parseSetRequest(data, offset, len); - EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, OpCodes::SetData); + EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, op); break; case OpCodes::Check: status = parseCheckRequest(data, offset, len); - EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, OpCodes::Check); + EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, op); break; case OpCodes::Delete: status = parseDeleteRequest(data, offset, len); - EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, OpCodes::Delete); + EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, op); + break; + case OpCodes::GetChildren: + status = parseGetChildrenRequest(data, offset, len, false); + EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, op); + break; + case OpCodes::GetData: + status = parseGetDataRequest(data, offset, len); + EMIT_DECODER_ERR_AND_RETURN_IF_STATUS_NOT_OK(status, op); break; default: callbacks_.onDecodeError(absl::nullopt); diff --git a/source/extensions/filters/udp/dns_filter/dns_filter.cc b/source/extensions/filters/udp/dns_filter/dns_filter.cc index 211f9d95a13c..1da684d586d7 100644 --- a/source/extensions/filters/udp/dns_filter/dns_filter.cc +++ b/source/extensions/filters/udp/dns_filter/dns_filter.cc @@ -250,7 +250,7 @@ DnsFilter::DnsFilter(Network::UdpReadFilterCallbacks& callbacks, for (const auto& ip : iplist) { incrementExternalQueryTypeAnswerCount(query->type_); const std::chrono::seconds ttl = getDomainTTL(query->name_); - message_parser_.storeDnsAnswerRecord(context, *query, ttl, std::move(ip)); + message_parser_.storeDnsAnswerRecord(context, *query, ttl, ip); } sendDnsResponse(std::move(context)); }; diff --git a/source/extensions/filters/udp/udp_proxy/config.cc b/source/extensions/filters/udp/udp_proxy/config.cc index 3f8e76230464..5675cdc4c537 100644 --- a/source/extensions/filters/udp/udp_proxy/config.cc +++ b/source/extensions/filters/udp/udp_proxy/config.cc @@ -33,7 +33,7 @@ const std::string& TunnelResponseTrailers::key() { TunnelingConfigImpl::TunnelingConfigImpl(const TunnelingConfig& config, Server::Configuration::FactoryContext& context) : header_parser_(Envoy::Router::HeaderParser::configure(config.headers_to_add())), - proxy_port_(), target_port_(config.default_target_port()), use_post_(config.use_post()), + target_port_(config.default_target_port()), use_post_(config.use_post()), post_path_(config.post_path()), max_connect_attempts_(config.has_retry_options() ? PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.retry_options(), @@ -59,7 +59,7 @@ TunnelingConfigImpl::TunnelingConfigImpl(const TunnelingConfig& config, if (post_path_.empty()) { post_path_ = "/"; - } else if (post_path_.rfind("/", 0) != 0) { + } else if (!absl::StartsWith(post_path_, "/")) { throw EnvoyException("Path must start with '/'"); } diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/filter.h b/source/extensions/filters/udp/udp_proxy/session_filters/filter.h index f9d5af16215e..8cedad217b15 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/filter.h +++ b/source/extensions/filters/udp/udp_proxy/session_filters/filter.h @@ -90,7 +90,7 @@ class FilterBase { */ class ReadFilter : public virtual FilterBase { public: - virtual ~ReadFilter() = default; + ~ReadFilter() override = default; /** * Called when a new UDP session is first established. Filters should do one time long term @@ -136,7 +136,7 @@ enum class WriteFilterStatus { */ class WriteFilter : public virtual FilterBase { public: - virtual ~WriteFilter() = default; + ~WriteFilter() override = default; /** * Called when data is to be written on the UDP session. diff --git a/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.cc b/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.cc index 65402058363f..7e8ba256ebc5 100644 --- a/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.cc +++ b/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.cc @@ -284,7 +284,7 @@ UdpProxyFilter::ActiveSession::ActiveSession(ClusterInfo& cluster, idle_timer_(cluster.filter_.read_callbacks_->udpListener().dispatcher().createTimer( [this] { onIdleTimer(); })), udp_session_info_(StreamInfo::StreamInfoImpl(cluster_.filter_.config_->timeSource(), - CreateDownstreamConnectionInfoProvider())) { + createDownstreamConnectionInfoProvider())) { udp_session_info_.setUpstreamInfo(std::make_shared()); cluster_.filter_.config_->stats().downstream_sess_total_.inc(); cluster_.filter_.config_->stats().downstream_sess_active_.inc(); @@ -338,7 +338,7 @@ void UdpProxyFilter::ActiveSession::onSessionComplete() { } std::shared_ptr -UdpProxyFilter::ActiveSession::CreateDownstreamConnectionInfoProvider() { +UdpProxyFilter::ActiveSession::createDownstreamConnectionInfoProvider() { auto downstream_connection_info_provider = std::make_shared(addresses_.local_, addresses_.peer_); downstream_connection_info_provider->setConnectionID(session_id_); 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 9f7da664bc97..01d76a739ae0 100644 --- a/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h +++ b/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h @@ -612,7 +612,7 @@ class UdpProxyFilter : public Network::UdpListenerReadFilter, std::list write_filters_; private: - std::shared_ptr CreateDownstreamConnectionInfoProvider(); + std::shared_ptr createDownstreamConnectionInfoProvider(); void onAccessLogFlushInterval(); void rearmAccessLogFlushTimer(); void disableAccessLogFlushTimer(); diff --git a/source/extensions/geoip_providers/maxmind/geoip_provider.h b/source/extensions/geoip_providers/maxmind/geoip_provider.h index db5ae83f72c9..25f5c11b3a51 100644 --- a/source/extensions/geoip_providers/maxmind/geoip_provider.h +++ b/source/extensions/geoip_providers/maxmind/geoip_provider.h @@ -88,7 +88,7 @@ class GeoipProvider : public Envoy::Geolocation::Driver, anon_db_ = initMaxMindDb(config_->anonDbPath()); }; - ~GeoipProvider(); + ~GeoipProvider() override; // Envoy::Geolocation::Driver void lookup(Geolocation::LookupRequest&&, Geolocation::LookupGeoHeadersCallback&&) const override; diff --git a/source/extensions/grpc_credentials/aws_iam/config.cc b/source/extensions/grpc_credentials/aws_iam/config.cc index e1daa71d3b79..4e8127a19749 100644 --- a/source/extensions/grpc_credentials/aws_iam/config.cc +++ b/source/extensions/grpc_credentials/aws_iam/config.cc @@ -105,9 +105,7 @@ AwsIamHeaderAuthenticator::GetMetadata(grpc::string_ref service_url, grpc::strin absl::string_view(method_name.data(), method_name.length())); TRY_NEEDS_AUDIT { signer_->sign(message, false); } - END_TRY catch (const EnvoyException& e) { - return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); - } + END_TRY catch (const EnvoyException& e) { return {grpc::StatusCode::INTERNAL, e.what()}; } signedHeadersToMetadata(message.headers(), *metadata); diff --git a/source/extensions/grpc_credentials/file_based_metadata/config.cc b/source/extensions/grpc_credentials/file_based_metadata/config.cc index 1fa300a2f711..266adbf96443 100644 --- a/source/extensions/grpc_credentials/file_based_metadata/config.cc +++ b/source/extensions/grpc_credentials/file_based_metadata/config.cc @@ -72,7 +72,8 @@ FileBasedMetadataAuthenticator::GetMetadata(grpc::string_ref, grpc::string_ref, // TODO(#14320): avoid using an exception here or find some way of doing this // in the main thread. TRY_NEEDS_AUDIT { - std::string header_value = Envoy::Config::DataSource::read(config_.secret_data(), true, api_); + std::string header_value = THROW_OR_RETURN_VALUE( + Envoy::Config::DataSource::read(config_.secret_data(), true, api_), std::string); metadata->insert(std::make_pair(header_key, header_prefix + header_value)); } END_TRY diff --git a/source/extensions/health_checkers/grpc/health_checker_impl.cc b/source/extensions/health_checkers/grpc/health_checker_impl.cc index 3d6906995553..ee9b4a047ae8 100644 --- a/source/extensions/health_checkers/grpc/health_checker_impl.cc +++ b/source/extensions/health_checkers/grpc/health_checker_impl.cc @@ -195,8 +195,15 @@ void GrpcHealthCheckerImpl::GrpcActiveHealthCheckSession::onInterval() { request_encoder_ = &client_->newStream(*this); request_encoder_->getStream().addCallbacks(*this); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +#endif const std::string& authority = getHostname(host_, parent_.authority_value_, parent_.cluster_.info()); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif auto headers_message = Grpc::Common::prepareHeaders(authority, parent_.service_method_.service()->full_name(), parent_.service_method_.name(), absl::nullopt); diff --git a/source/extensions/health_checkers/http/health_checker_impl.cc b/source/extensions/health_checkers/http/health_checker_impl.cc index 49b07984222e..608dd8d7556e 100644 --- a/source/extensions/health_checkers/http/health_checker_impl.cc +++ b/source/extensions/health_checkers/http/health_checker_impl.cc @@ -183,7 +183,6 @@ HttpHealthCheckerImpl::HttpActiveHealthCheckSession::HttpActiveHealthCheckSessio response_body_(std::make_unique()), hostname_( HealthCheckerFactory::getHostname(host, parent_.host_value_, parent_.cluster_.info())), - local_connection_info_provider_(std::make_shared( Network::Utility::getCanonicalIpv4LoopbackAddress(), Network::Utility::getCanonicalIpv4LoopbackAddress())), diff --git a/source/extensions/health_checkers/http/health_checker_impl.h b/source/extensions/health_checkers/http/health_checker_impl.h index f5e5c2c5a1d7..4403b11f559f 100644 --- a/source/extensions/health_checkers/http/health_checker_impl.h +++ b/source/extensions/health_checkers/http/health_checker_impl.h @@ -141,7 +141,14 @@ class HttpHealthCheckerImpl : public HealthCheckerImplBase { Http::CodecClientPtr client_; Http::ResponseHeaderMapPtr response_headers_; Buffer::InstancePtr response_body_; +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +#endif const std::string& hostname_; +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif Network::ConnectionInfoProviderSharedPtr local_connection_info_provider_; // Keep small members (bools and enums) at the end of class, to reduce alignment overhead. const Http::Protocol protocol_; diff --git a/source/extensions/health_checkers/thrift/thrift.h b/source/extensions/health_checkers/thrift/thrift.h index 9c75e9df56d7..329a01e9d08d 100644 --- a/source/extensions/health_checkers/thrift/thrift.h +++ b/source/extensions/health_checkers/thrift/thrift.h @@ -57,7 +57,14 @@ class ThriftHealthChecker : public Upstream::HealthCheckerImplBase { private: ThriftHealthChecker& parent_; +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +#endif const std::string& hostname_; +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif ClientPtr client_; bool expect_close_{}; }; diff --git a/source/extensions/http/custom_response/local_response_policy/local_response_policy.cc b/source/extensions/http/custom_response/local_response_policy/local_response_policy.cc index 80c98d28b2a3..8f94f6373fe0 100644 --- a/source/extensions/http/custom_response/local_response_policy/local_response_policy.cc +++ b/source/extensions/http/custom_response/local_response_policy/local_response_policy.cc @@ -21,9 +21,11 @@ LocalResponsePolicy::LocalResponsePolicy( const envoy::extensions::http::custom_response::local_response_policy::v3::LocalResponsePolicy& config, Server::Configuration::ServerFactoryContext& context) - : local_body_{config.has_body() ? absl::optional(Config::DataSource::read( - config.body(), true, context.api())) - : absl::optional{}}, + : local_body_{config.has_body() + ? absl::optional(THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.body(), true, context.api()), + std::string)) + : absl::optional{}}, status_code_{config.has_status_code() ? absl::optional( static_cast(config.status_code().value())) diff --git a/source/extensions/http/stateful_session/cookie/cookie.cc b/source/extensions/http/stateful_session/cookie/cookie.cc index 631249b763ea..21a508e7370e 100644 --- a/source/extensions/http/stateful_session/cookie/cookie.cc +++ b/source/extensions/http/stateful_session/cookie/cookie.cc @@ -16,12 +16,15 @@ void CookieBasedSessionStateFactory::SessionStateImpl::onUpdate( if (!upstream_address_.has_value() || host_address != upstream_address_.value()) { if (Runtime::runtimeFeatureEnabled( "envoy.reloadable_features.stateful_session_encode_ttl_in_cookie")) { - auto expiry_time = std::chrono::duration_cast( - (time_source_.monotonicTime() + std::chrono::seconds(factory_.ttl_)).time_since_epoch()); // Build proto message envoy::Cookie cookie; cookie.set_address(std::string(host_address)); - cookie.set_expires(expiry_time.count()); + if (factory_.ttl_ != std::chrono::seconds::zero()) { + const auto expiry_time = std::chrono::duration_cast( + (time_source_.monotonicTime() + std::chrono::seconds(factory_.ttl_)) + .time_since_epoch()); + cookie.set_expires(expiry_time.count()); + } std::string proto_string; cookie.SerializeToString(&proto_string); diff --git a/source/extensions/http/stateful_session/cookie/cookie.h b/source/extensions/http/stateful_session/cookie/cookie.h index dc580395ae00..0ba898bf4c5b 100644 --- a/source/extensions/http/stateful_session/cookie/cookie.h +++ b/source/extensions/http/stateful_session/cookie/cookie.h @@ -69,17 +69,19 @@ class CookieBasedSessionStateFactory : public Envoy::Http::SessionStateFactory { envoy::Cookie cookie; if (cookie.ParseFromString(decoded_value)) { address = cookie.address(); - if (address.empty() || (cookie.expires() == 0)) { + if (address.empty()) { return absl::nullopt; } - std::chrono::seconds expiry_time(cookie.expires()); - auto now = std::chrono::duration_cast( - (time_source_.monotonicTime()).time_since_epoch()); - if (now > expiry_time) { - // Ignore the address extracted from the cookie. This will cause - // upstream cluster to select a new host and new cookie will be generated. - return absl::nullopt; + if (cookie.expires() != 0) { + const std::chrono::seconds expiry_time(cookie.expires()); + const auto now = std::chrono::duration_cast( + (time_source_.monotonicTime()).time_since_epoch()); + if (now > expiry_time) { + // Ignore the address extracted from the cookie. This will cause + // upstream cluster to select a new host and new cookie will be generated. + return absl::nullopt; + } } } else { ENVOY_LOG_ONCE_MISC( diff --git a/source/extensions/network/dns_resolver/getaddrinfo/BUILD b/source/extensions/network/dns_resolver/getaddrinfo/BUILD index e2b26df7941c..05b119daa59c 100644 --- a/source/extensions/network/dns_resolver/getaddrinfo/BUILD +++ b/source/extensions/network/dns_resolver/getaddrinfo/BUILD @@ -15,6 +15,7 @@ envoy_cc_extension( deps = [ "//envoy/network:dns_resolver_interface", "//envoy/registry", + "//source/common/api:os_sys_calls_lib", "@envoy_api//envoy/extensions/network/dns_resolver/getaddrinfo/v3:pkg_cc_proto", ], ) diff --git a/source/extensions/router/cluster_specifiers/lua/lua_cluster_specifier.cc b/source/extensions/router/cluster_specifiers/lua/lua_cluster_specifier.cc index c226a78c4a0a..5c33df45813b 100644 --- a/source/extensions/router/cluster_specifiers/lua/lua_cluster_specifier.cc +++ b/source/extensions/router/cluster_specifiers/lua/lua_cluster_specifier.cc @@ -48,7 +48,8 @@ LuaClusterSpecifierConfig::LuaClusterSpecifierConfig( Server::Configuration::CommonFactoryContext& context) : main_thread_dispatcher_(context.mainThreadDispatcher()), default_cluster_(config.default_cluster()) { - const std::string code_str = Config::DataSource::read(config.source_code(), true, context.api()); + const std::string code_str = THROW_OR_RETURN_VALUE( + Config::DataSource::read(config.source_code(), true, context.api()), std::string); per_lua_code_setup_ptr_ = std::make_unique(code_str, context.threadLocal()); } diff --git a/source/extensions/stat_sinks/common/statsd/BUILD b/source/extensions/stat_sinks/common/statsd/BUILD index 2d74e42869e9..54fe8b9ac588 100644 --- a/source/extensions/stat_sinks/common/statsd/BUILD +++ b/source/extensions/stat_sinks/common/statsd/BUILD @@ -30,5 +30,7 @@ envoy_cc_library( "//source/common/common:utility_lib", "//source/common/config:utility_lib", "//source/common/network:address_lib", + "//source/common/network:default_socket_interface_lib", + "//source/common/network:utility_lib", ], ) diff --git a/source/extensions/stat_sinks/common/statsd/statsd.cc b/source/extensions/stat_sinks/common/statsd/statsd.cc index 6236fd67a866..25872589ca74 100644 --- a/source/extensions/stat_sinks/common/statsd/statsd.cc +++ b/source/extensions/stat_sinks/common/statsd/statsd.cc @@ -198,7 +198,7 @@ TcpStatsdSink::TcpStatsdSink(const LocalInfo::LocalInfo& local_info, const auto cluster_or_error = Config::Utility::checkCluster("tcp statsd", cluster_name, cluster_manager); THROW_IF_STATUS_NOT_OK(cluster_or_error, throw); - const auto cluster = std::move(cluster_or_error.value()); + const auto cluster = cluster_or_error.value(); cluster_info_ = cluster->get().info(); tls_->set([this](Event::Dispatcher& dispatcher) -> ThreadLocal::ThreadLocalObjectSharedPtr { return std::make_shared(*this, dispatcher); diff --git a/source/extensions/stat_sinks/metrics_service/config.cc b/source/extensions/stat_sinks/metrics_service/config.cc index db823131e0cd..791f81508f31 100644 --- a/source/extensions/stat_sinks/metrics_service/config.cc +++ b/source/extensions/stat_sinks/metrics_service/config.cc @@ -28,12 +28,13 @@ MetricsServiceSinkFactory::createStatsSink(const Protobuf::Message& config, THROW_IF_NOT_OK(Config::Utility::checkTransportVersion(sink_config)); ENVOY_LOG(debug, "Metrics Service gRPC service configuration: {}", grpc_service.DebugString()); + auto client_or_error = server.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( + grpc_service, server.scope(), false); + THROW_IF_STATUS_NOT_OK(client_or_error, throw); std::shared_ptr> - grpc_metrics_streamer = std::make_shared( - server.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( - grpc_service, server.scope(), false), - server.localInfo()); + grpc_metrics_streamer = + std::make_shared(client_or_error.value(), server.localInfo()); return std::make_unique>( diff --git a/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc b/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc index 2b74663df397..f1f593a83aa6 100644 --- a/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc +++ b/source/extensions/stat_sinks/metrics_service/grpc_metrics_service_impl.cc @@ -135,6 +135,7 @@ void MetricsFlusher::flushSummary(io::prometheus::client::MetricFamily& metrics_ quantile->set_value(hist_stats.computedQuantiles()[i]); } summary->set_sample_count(hist_stats.sampleCount()); + summary->set_sample_sum(hist_stats.sampleSum()); } io::prometheus::client::Metric* diff --git a/source/extensions/stat_sinks/open_telemetry/config.cc b/source/extensions/stat_sinks/open_telemetry/config.cc index f7e1487c5ea3..2dc66d339aef 100644 --- a/source/extensions/stat_sinks/open_telemetry/config.cc +++ b/source/extensions/stat_sinks/open_telemetry/config.cc @@ -26,11 +26,13 @@ OpenTelemetrySinkFactory::createStatsSink(const Protobuf::Message& config, case SinkConfig::ProtocolSpecifierCase::kGrpcService: { const auto& grpc_service = sink_config.grpc_service(); + auto client_or_error = + server.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( + grpc_service, server.scope(), false); + THROW_IF_STATUS_NOT_OK(client_or_error, throw); std::shared_ptr grpc_metrics_exporter = - std::make_shared( - otlp_options, - server.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( - grpc_service, server.scope(), false)); + std::make_shared(otlp_options, + client_or_error.value()); return std::make_unique(otlp_metrics_flusher, grpc_metrics_exporter); } diff --git a/source/extensions/stat_sinks/wasm/BUILD b/source/extensions/stat_sinks/wasm/BUILD index 71c6a09f50ef..781953be2a19 100644 --- a/source/extensions/stat_sinks/wasm/BUILD +++ b/source/extensions/stat_sinks/wasm/BUILD @@ -20,6 +20,7 @@ envoy_cc_extension( "//envoy/registry", "//envoy/server:factory_context_interface", "//envoy/server:instance_interface", + "//source/extensions/common/wasm:remote_async_datasource_lib", "//source/extensions/common/wasm:wasm_lib", "//source/server:configuration_lib", "@envoy_api//envoy/extensions/stat_sinks/wasm/v3:pkg_cc_proto", diff --git a/source/extensions/stat_sinks/wasm/config.h b/source/extensions/stat_sinks/wasm/config.h index 5df22470829f..f27c520f9073 100644 --- a/source/extensions/stat_sinks/wasm/config.h +++ b/source/extensions/stat_sinks/wasm/config.h @@ -6,6 +6,7 @@ #include "envoy/server/instance.h" #include "source/common/config/datasource.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" #include "source/server/configuration_impl.h" namespace Envoy { @@ -31,7 +32,7 @@ class WasmSinkFactory : Logger::Loggable, std::string name() const override; private: - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; + RemoteAsyncDataProviderPtr remote_data_provider_; }; } // namespace Wasm diff --git a/source/extensions/tracers/datadog/BUILD b/source/extensions/tracers/datadog/BUILD index da0862389706..cd7327a67d09 100644 --- a/source/extensions/tracers/datadog/BUILD +++ b/source/extensions/tracers/datadog/BUILD @@ -43,6 +43,8 @@ envoy_cc_library( deps = [ "//source/common/config:utility_lib", "//source/common/http:async_client_utility_lib", + "//source/common/http:message_lib", + "//source/common/http:utility_lib", "//source/common/tracing:common_values_lib", "//source/common/tracing:null_span_lib", "//source/common/tracing:trace_context_lib", diff --git a/source/extensions/tracers/datadog/tracer.cc b/source/extensions/tracers/datadog/tracer.cc index e01c30911899..280647595558 100644 --- a/source/extensions/tracers/datadog/tracer.cc +++ b/source/extensions/tracers/datadog/tracer.cc @@ -100,7 +100,7 @@ Tracing::SpanPtr Tracer::startSpan(const Tracing::Config&, Tracing::TraceContext TraceContextReader reader{trace_context}; datadog::tracing::Span span = - extract_or_create_span(*thread_local_tracer.tracer, span_config, reader); + extractOrCreateSpan(*thread_local_tracer.tracer, span_config, reader); // If we did not extract a sampling decision, and if Envoy is telling us to // drop the trace, then we treat that as a "user drop" (manual override). @@ -115,10 +115,9 @@ Tracing::SpanPtr Tracer::startSpan(const Tracing::Config&, Tracing::TraceContext return std::make_unique(std::move(span)); } -datadog::tracing::Span -Tracer::extract_or_create_span(datadog::tracing::Tracer& tracer, - const datadog::tracing::SpanConfig& span_config, - const datadog::tracing::DictReader& reader) { +datadog::tracing::Span Tracer::extractOrCreateSpan(datadog::tracing::Tracer& tracer, + const datadog::tracing::SpanConfig& span_config, + const datadog::tracing::DictReader& reader) { datadog::tracing::Expected maybe_span = tracer.extract_span(reader, span_config); if (datadog::tracing::Error* error = maybe_span.if_error()) { diff --git a/source/extensions/tracers/datadog/tracer.h b/source/extensions/tracers/datadog/tracer.h index 7baf3d6c1277..697fd09f5d9b 100644 --- a/source/extensions/tracers/datadog/tracer.h +++ b/source/extensions/tracers/datadog/tracer.h @@ -98,9 +98,9 @@ class Tracer : public Tracing::Driver, private Logger::Loggable thread_local_slot_; diff --git a/source/extensions/tracers/opentelemetry/BUILD b/source/extensions/tracers/opentelemetry/BUILD index e84423ccf272..a4ee2ed5e51b 100644 --- a/source/extensions/tracers/opentelemetry/BUILD +++ b/source/extensions/tracers/opentelemetry/BUILD @@ -35,6 +35,12 @@ envoy_cc_library( "span_context_extractor.h", "tracer.h", ], + copts = [ + # Make sure that headers included from opentelemetry-api use Abseil from Envoy + # https://github.com/open-telemetry/opentelemetry-cpp/blob/v1.14.0/api/BUILD#L32 + "-DHAVE_ABSEIL", + ], + external_deps = ["opentelemetry_api"], deps = [ ":trace_exporter", "//envoy/thread_local:thread_local_interface", diff --git a/source/extensions/tracers/opentelemetry/opentelemetry_tracer_impl.cc b/source/extensions/tracers/opentelemetry/opentelemetry_tracer_impl.cc index 46ce3c35ae77..d3fe8624c65d 100644 --- a/source/extensions/tracers/opentelemetry/opentelemetry_tracer_impl.cc +++ b/source/extensions/tracers/opentelemetry/opentelemetry_tracer_impl.cc @@ -89,9 +89,11 @@ Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetr sampler](Event::Dispatcher& dispatcher) { OpenTelemetryTraceExporterPtr exporter; if (opentelemetry_config.has_grpc_service()) { - Grpc::AsyncClientFactoryPtr&& factory = + auto factory_or_error = factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( opentelemetry_config.grpc_service(), factory_context.scope(), true); + THROW_IF_STATUS_NOT_OK(factory_or_error, throw); + Grpc::AsyncClientFactoryPtr&& factory = std::move(factory_or_error.value()); const Grpc::RawAsyncClientSharedPtr& async_client_shared_ptr = factory->createUncachedRawAsyncClient(); exporter = std::make_unique(async_client_shared_ptr); diff --git a/source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector.cc b/source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector.cc index b8c98d81201b..fdfd03b7c385 100644 --- a/source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector.cc +++ b/source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector.cc @@ -35,10 +35,19 @@ Resource DynatraceResourceDetector::detect() { addAttributes(content, resource); } } - END_TRY catch (const EnvoyException&) { failure_count++; } + END_TRY catch (const EnvoyException& e) { + failure_count++; + ENVOY_LOG( + warn, + "Failed to detect resource attributes from the Dynatrace enrichment file: {}, error: {}.", + file_name, e.what()); + } } - if (failure_count > 0) { + // Only log if it failed to detect attributes from all enrichment files + // This means Dynatrace is not correctly deployed. + if (static_cast::size_type>(failure_count) == + DynatraceResourceDetector::dynatraceMetadataFiles().size()) { ENVOY_LOG( warn, "Dynatrace OpenTelemetry resource detector is configured but could not detect attributes. " diff --git a/source/extensions/tracers/opentelemetry/resource_detectors/environment/environment_resource_detector.cc b/source/extensions/tracers/opentelemetry/resource_detectors/environment/environment_resource_detector.cc index 0a5592df94f6..70ddb8defd92 100644 --- a/source/extensions/tracers/opentelemetry/resource_detectors/environment/environment_resource_detector.cc +++ b/source/extensions/tracers/opentelemetry/resource_detectors/environment/environment_resource_detector.cc @@ -30,7 +30,8 @@ Resource EnvironmentResourceDetector::detect() { std::string attributes_str = ""; TRY_NEEDS_AUDIT { - attributes_str = Config::DataSource::read(ds, true, context_.serverFactoryContext().api()); + attributes_str = THROW_OR_RETURN_VALUE( + Config::DataSource::read(ds, true, context_.serverFactoryContext().api()), std::string); } END_TRY catch (const EnvoyException& e) { ENVOY_LOG(warn, "Failed to detect resource attributes from the environment: {}.", e.what()); diff --git a/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.cc b/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.cc index 8d06116cceb3..d1965b7812de 100644 --- a/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.cc +++ b/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.cc @@ -18,7 +18,7 @@ SamplingResult AlwaysOnSampler::shouldSample(const absl::optional p OptRef /*trace_context*/, const std::vector& /*links*/) { SamplingResult result; - result.decision = Decision::RECORD_AND_SAMPLE; + result.decision = Decision::RecordAndSample; if (parent_context.has_value()) { result.tracestate = parent_context.value().tracestate(); } diff --git a/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.h b/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.h index c70864b078a0..cb0bb42deefe 100644 --- a/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.h +++ b/source/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler.h @@ -14,7 +14,7 @@ namespace OpenTelemetry { /** * @brief A sampler which samples every span. * https://opentelemetry.io/docs/specs/otel/trace/sdk/#alwayson - * - Returns RECORD_AND_SAMPLE always. + * - Returns RecordAndSample always. * - Description MUST be AlwaysOnSampler. * */ diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD b/source/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD new file mode 100644 index 000000000000..629674856083 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD @@ -0,0 +1,46 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + deps = [ + ":dynatrace_sampler_lib", + "//envoy/registry", + "//source/common/config:utility_lib", + "@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto", + ], +) + +envoy_cc_library( + name = "dynatrace_sampler_lib", + srcs = [ + "dynatrace_sampler.cc", + "sampler_config.cc", + "sampler_config_provider.cc", + "sampling_controller.cc", + ], + hdrs = [ + "dynatrace_sampler.h", + "sampler_config.h", + "sampler_config_provider.h", + "sampling_controller.h", + "stream_summary.h", + "tenant_id.h", + ], + deps = [ + "//source/common/config:datasource_lib", + "//source/extensions/tracers/opentelemetry:opentelemetry_tracer_lib", + "//source/extensions/tracers/opentelemetry/samplers:sampler_lib", + "@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/config.cc b/source/extensions/tracers/opentelemetry/samplers/dynatrace/config.cc new file mode 100644 index 000000000000..bfcfb2d382f9 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/config.cc @@ -0,0 +1,38 @@ +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/config.h" + +#include + +#include "envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.pb.validate.h" + +#include "source/common/config/utility.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +SamplerSharedPtr +DynatraceSamplerFactory::createSampler(const Protobuf::Message& config, + Server::Configuration::TracerFactoryContext& context) { + auto mptr = Envoy::Config::Utility::translateAnyToFactoryConfig( + dynamic_cast(config), context.messageValidationVisitor(), *this); + + const auto& proto_config = MessageUtil::downcastAndValidate< + const envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig&>( + *mptr, context.messageValidationVisitor()); + + SamplerConfigProviderPtr cf = std::make_unique(context, proto_config); + return std::make_shared(proto_config, context, std::move(cf)); +} + +/** + * Static registration for the Dynatrace sampler factory. @see RegisterFactory. + */ +REGISTER_FACTORY(DynatraceSamplerFactory, SamplerFactory); + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/config.h b/source/extensions/tracers/opentelemetry/samplers/dynatrace/config.h new file mode 100644 index 000000000000..c317416dbfd7 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/config.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.pb.h" +#include "envoy/registry/registry.h" + +#include "source/extensions/tracers/opentelemetry/samplers/sampler.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +/** + * Config registration for the DynatraceSampler. @see SamplerFactory. + */ +class DynatraceSamplerFactory : public SamplerFactory { +public: + /** + * @brief Creates a Dynatrace sampler + * + * @param config The sampler configuration + * @param context The tracer factory context. + * @return SamplerSharedPtr + */ + SamplerSharedPtr createSampler(const Protobuf::Message& config, + Server::Configuration::TracerFactoryContext& context) override; + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique< + envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig>(); + } + std::string name() const override { return "envoy.tracers.opentelemetry.samplers.dynatrace"; } +}; + +DECLARE_FACTORY(DynatraceSamplerFactory); + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.cc b/source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.cc new file mode 100644 index 000000000000..5853d86e7650 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.cc @@ -0,0 +1,188 @@ +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h" + +#include +#include +#include + +#include "source/common/common/hash.h" +#include "source/common/config/datasource.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id.h" +#include "source/extensions/tracers/opentelemetry/samplers/sampler.h" +#include "source/extensions/tracers/opentelemetry/span_context.h" + +#include "absl/strings/str_cat.h" +#include "opentelemetry/trace/trace_state.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +namespace { + +constexpr std::chrono::minutes SAMPLING_UPDATE_TIMER_DURATION{1}; + +/** + * @brief Helper for creating and reading the Dynatrace tag in the tracestate http header + * This tag has at least 8 values delimited by semicolon: + * - tag[0]: version (currently version 4) + * - tag[1] - tag[4]: unused in the sampler (always 0) + * - tag[5]: ignored field. 1 if a span is ignored (not sampled), 0 otherwise + * - tag[6]: sampling exponent + * - tag[7]: path info + */ +class DynatraceTag { +public: + static DynatraceTag createInvalid() { return {false, false, 0, 0}; } + + // Creates a tag using the given values. + static DynatraceTag create(bool ignored, uint32_t sampling_exponent, uint32_t path_info) { + return {true, ignored, sampling_exponent, path_info}; + } + + // Creates a tag from a string. + static DynatraceTag create(const std::string& value) { + std::vector tracestate_components = + absl::StrSplit(value, ';', absl::AllowEmpty()); + if (tracestate_components.size() < 8) { + return createInvalid(); + } + + if (tracestate_components[0] != "fw4") { + return createInvalid(); + } + bool ignored = tracestate_components[5] == "1"; + uint32_t sampling_exponent; + uint32_t path_info; + if (absl::SimpleAtoi(tracestate_components[6], &sampling_exponent) && + absl::SimpleHexAtoi(tracestate_components[7], &path_info)) { + return {true, ignored, sampling_exponent, path_info}; + } + return createInvalid(); + } + + // Returns a Dynatrace tag as string. + std::string asString() const { + std::string ret = absl::StrCat("fw4;0;0;0;0;", ignored_ ? "1" : "0", ";", sampling_exponent_, + ";", absl::Hex(path_info_)); + return ret; + } + + // Returns true if parsing was successful. + bool isValid() const { return valid_; }; + bool isIgnored() const { return ignored_; }; + uint32_t getSamplingExponent() const { return sampling_exponent_; }; + +private: + DynatraceTag(bool valid, bool ignored, uint32_t sampling_exponent, uint32_t path_info) + : valid_(valid), ignored_(ignored), sampling_exponent_(sampling_exponent), + path_info_(path_info) {} + + bool valid_; + bool ignored_; + uint32_t sampling_exponent_; + uint32_t path_info_; +}; + +// add Dynatrace specific span attributes +void addSamplingAttributes(uint32_t sampling_exponent, + std::map& attributes) { + + const auto multiplicity = SamplingState::toMultiplicity(sampling_exponent); + // The denominator of the sampling ratio. If, for example, the Dynatrace OneAgent samples with a + // probability of 1/16, the value of supportability sampling ratio would be 16. + // Note: Ratio is also known as multiplicity. + attributes["supportability.atm_sampling_ratio"] = std::to_string(multiplicity); + + if (multiplicity > 1) { + static constexpr uint64_t two_pow_56 = 1llu << 56; // 2^56 + // The sampling probability can be interpreted as the number of spans + // that are discarded out of 2^56. The attribute is only available if the sampling.threshold is + // not 0 and therefore sampling happened. + const uint64_t sampling_threshold = two_pow_56 - two_pow_56 / multiplicity; + attributes["sampling.threshold"] = std::to_string(sampling_threshold); + } +} + +} // namespace + +DynatraceSampler::DynatraceSampler( + const envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig& config, + Server::Configuration::TracerFactoryContext& context, + SamplerConfigProviderPtr sampler_config_provider) + : dt_tracestate_key_(absl::StrCat(calculateTenantId(config.tenant()), "-", + absl::Hex(config.cluster_id()), "@dt")), + sampling_controller_(std::move(sampler_config_provider)) { + + // start a timer to periodically recalculate the sampling exponents + timer_ = context.serverFactoryContext().mainThreadDispatcher().createTimer([this]() -> void { + sampling_controller_.update(); + timer_->enableTimer(SAMPLING_UPDATE_TIMER_DURATION); + }); + timer_->enableTimer(SAMPLING_UPDATE_TIMER_DURATION); +} + +SamplingResult DynatraceSampler::shouldSample(const absl::optional parent_context, + const std::string& trace_id, + const std::string& /*name*/, OTelSpanKind /*kind*/, + OptRef trace_context, + const std::vector& /*links*/) { + + SamplingResult result; + std::map att; + + // trace_context->path() returns path and query. query part is removed in getSamplingKey() + const std::string sampling_key = + trace_context.has_value() + ? sampling_controller_.getSamplingKey(trace_context->path(), trace_context->method()) + : ""; + + sampling_controller_.offer(sampling_key); + + auto trace_state = opentelemetry::trace::TraceState::FromHeader( + parent_context.has_value() ? parent_context->tracestate() : ""); + + std::string trace_state_value; + bool is_root_span = true; + + if (trace_state->Get(dt_tracestate_key_, trace_state_value)) { + // we found a Dynatrace tag in the tracestate header. Respect the sampling decision in the tag. + if (DynatraceTag dynatrace_tag = DynatraceTag::create(trace_state_value); + dynatrace_tag.isValid()) { + result.decision = dynatrace_tag.isIgnored() ? Decision::Drop : Decision::RecordAndSample; + addSamplingAttributes(dynatrace_tag.getSamplingExponent(), att); + result.tracestate = parent_context->tracestate(); + is_root_span = false; + } + } + + if (is_root_span) { + // do a decision based on the calculated exponent + // we use a hash of the trace_id as random number + const auto hash = MurmurHash::murmurHash2(trace_id); + const auto sampling_state = sampling_controller_.getSamplingState(sampling_key); + const bool sample = sampling_state.shouldSample(hash); + const auto sampling_exponent = sampling_state.getExponent(); + + addSamplingAttributes(sampling_exponent, att); + + result.decision = sample ? Decision::RecordAndSample : Decision::Drop; + // create a new Dynatrace tag and add it to tracestate + DynatraceTag new_tag = + DynatraceTag::create(!sample, sampling_exponent, static_cast(hash)); + trace_state = trace_state->Set(dt_tracestate_key_, new_tag.asString()); + result.tracestate = trace_state->ToHeader(); + } + + if (!att.empty()) { + result.attributes = std::make_unique>(std::move(att)); + } + return result; +} + +std::string DynatraceSampler::getDescription() const { return "DynatraceSampler"; } + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h b/source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h new file mode 100644 index 000000000000..80711ef77b3d --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +#include "envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.pb.h" +#include "envoy/server/factory_context.h" + +#include "source/common/common/logger.h" +#include "source/common/config/datasource.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary.h" +#include "source/extensions/tracers/opentelemetry/samplers/sampler.h" + +#include "absl/synchronization/mutex.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +/** + * @brief A Dynatrace specific sampler. + * + * For sampling, the requests are categorized based on the http method and the http path. + * A sampling multiplicity is calculated for every request category based on the + * number of requests. A Dynatrace specific tag is added to the http tracestate header. + */ +class DynatraceSampler : public Sampler, Logger::Loggable { +public: + DynatraceSampler( + const envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig& config, + Server::Configuration::TracerFactoryContext& context, + SamplerConfigProviderPtr sampler_config_provider); + + /** @see Sampler#shouldSample */ + SamplingResult shouldSample(const absl::optional parent_context, + const std::string& trace_id, const std::string& name, + OTelSpanKind spankind, + OptRef trace_context, + const std::vector& links) override; + + std::string getDescription() const override; + +private: + std::string dt_tracestate_key_; // used as key in the http tracestate header + Event::TimerPtr timer_; // used to periodically calculate sampling multiplicity + SamplingController sampling_controller_; +}; + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.cc b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.cc new file mode 100644 index 000000000000..b3a6f2b91c45 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.cc @@ -0,0 +1,28 @@ +#include + +#include "source/common/json/json_loader.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +void SamplerConfig::parse(const std::string& json) { + const auto result = Envoy::Json::Factory::loadFromStringNoThrow(json); + if (result.ok()) { + const auto& obj = result.value(); + if (obj->hasObject("rootSpansPerMinute")) { + const auto value = obj->getInteger("rootSpansPerMinute", default_root_spans_per_minute_); + root_spans_per_minute_.store(value); + return; + } + } + // Didn't get a value, reset to default + root_spans_per_minute_.store(default_root_spans_per_minute_); +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.h b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.h new file mode 100644 index 000000000000..6f576b2d5afb --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +/** + * @brief Contains the configuration for the sampler. Might be extended in a future version + * + */ +class SamplerConfig { +public: + static constexpr uint32_t ROOT_SPANS_PER_MINUTE_DEFAULT = 1000; + + explicit SamplerConfig(uint32_t default_root_spans_per_minute) + : default_root_spans_per_minute_(default_root_spans_per_minute > 0 + ? default_root_spans_per_minute + : ROOT_SPANS_PER_MINUTE_DEFAULT), + root_spans_per_minute_(default_root_spans_per_minute_) {} + /** + * @brief Parses a json string containing the expected root spans per minute. + * + * @param json A string containing the configuration. + */ + void parse(const std::string& json); + + /** + * @brief Returns wanted root spans per minute + * + * @return uint32_t wanted root spans per minute + */ + uint32_t getRootSpansPerMinute() const { return root_spans_per_minute_.load(); } + +private: + const uint32_t default_root_spans_per_minute_; + std::atomic root_spans_per_minute_; +}; + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.cc b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.cc new file mode 100644 index 000000000000..465cb9e1bd5f --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.cc @@ -0,0 +1,21 @@ +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h" + +#include "source/common/common/enum_to_int.h" +#include "source/common/http/utility.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +SamplerConfigProviderImpl::SamplerConfigProviderImpl( + Server::Configuration::TracerFactoryContext& /*context*/, + const envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig& config) + : sampler_config_(config.root_spans_per_minute()) {} + +const SamplerConfig& SamplerConfigProviderImpl::getSamplerConfig() const { return sampler_config_; } + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h new file mode 100644 index 000000000000..6dd464d4f6c7 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include + +#include "envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.pb.h" +#include "envoy/http/async_client.h" +#include "envoy/http/message.h" +#include "envoy/server/tracer_config.h" + +#include "source/common/http/async_client_impl.h" +#include "source/common/http/async_client_utility.h" +#include "source/common/http/headers.h" +#include "source/common/http/message_impl.h" +#include "source/common/http/utility.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +/** + * @brief The Dynatrace sampling configuration provider. + * + * The configuration provider obtains sampling configuration from the Dynatrace API + * in order to dynamically tune up/down the sampling rate of spans. + */ +class SamplerConfigProvider { +public: + virtual ~SamplerConfigProvider() = default; + + /** + * @brief Get the Dynatrace Sampler configuration. + * + * @return const SamplerConfig& + */ + virtual const SamplerConfig& getSamplerConfig() const = 0; +}; + +class SamplerConfigProviderImpl : public SamplerConfigProvider, + public Logger::Loggable { +public: + SamplerConfigProviderImpl( + Server::Configuration::TracerFactoryContext& context, + const envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig& + config); + + const SamplerConfig& getSamplerConfig() const override; + + ~SamplerConfigProviderImpl() override = default; + +private: + SamplerConfig sampler_config_; +}; + +using SamplerConfigProviderPtr = std::unique_ptr; + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.cc b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.cc new file mode 100644 index 000000000000..e14ad0fa3493 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.cc @@ -0,0 +1,166 @@ +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +namespace {} + +void SamplingController::update() { + absl::WriterMutexLock lock{&stream_summary_mutex_}; + const auto top_k = stream_summary_->getTopK(); + const auto last_period_count = stream_summary_->getN(); + + // update sampling exponents + update(top_k, last_period_count, + sampler_config_provider_->getSamplerConfig().getRootSpansPerMinute()); + // Note: getTopK() returns references to values in StreamSummary. + // Do not destroy it while top_k is used! + stream_summary_ = std::make_unique(STREAM_SUMMARY_SIZE); +} + +void SamplingController::update(const TopKListT& top_k, uint64_t last_period_count, + uint32_t total_wanted) { + + SamplingExponentsT new_sampling_exponents; + // start with sampling exponent 0, which means multiplicity == 1 (every span is sampled) + for (auto const& counter : top_k) { + new_sampling_exponents[counter.getItem()] = SamplingState(0); + } + + // use the last entry as "rest bucket", which is used for new/unknown requests + rest_bucket_key_ = (!top_k.empty()) ? top_k.back().getItem() : ""; + + calculateSamplingExponents(top_k, total_wanted, new_sampling_exponents); + last_effective_count_ = calculateEffectiveCount(top_k, new_sampling_exponents); + logSamplingInfo(top_k, new_sampling_exponents, last_period_count, total_wanted); + + absl::WriterMutexLock lock{&sampling_exponents_mutex_}; + sampling_exponents_ = std::move(new_sampling_exponents); +} + +uint64_t SamplingController::getEffectiveCount() const { + absl::ReaderMutexLock lock{&stream_summary_mutex_}; + return last_effective_count_; +} + +void SamplingController::offer(const std::string& sampling_key) { + if (!sampling_key.empty()) { + absl::WriterMutexLock lock{&stream_summary_mutex_}; + stream_summary_->offer(sampling_key); + } +} + +SamplingState SamplingController::getSamplingState(const std::string& sampling_key) const { + { // scope for lock + absl::ReaderMutexLock sax_lock{&sampling_exponents_mutex_}; + auto iter = sampling_exponents_.find(sampling_key); + if (iter != sampling_exponents_.end()) { + return iter->second; + } + + // try to use "rest bucket" + auto rest_bucket_iter = sampling_exponents_.find(rest_bucket_key_); + if (rest_bucket_iter != sampling_exponents_.end()) { + return rest_bucket_iter->second; + } + } + + // If we can't find a sampling exponent, we calculate it based on the total number of requests + // in this period. This should also handle the "warm up phase" where no top_k is available + const auto divisor = sampler_config_provider_->getSamplerConfig().getRootSpansPerMinute() / 2; + if (divisor == 0) { + return SamplingState{MAX_SAMPLING_EXPONENT}; + } + absl::ReaderMutexLock ss_lock{&stream_summary_mutex_}; + const uint32_t exp = stream_summary_->getN() / divisor; + return SamplingState{exp}; +} + +std::string SamplingController::getSamplingKey(const absl::string_view path_query, + const absl::string_view method) { + // remove query part (truncate after first '?') + const size_t query_offset = path_query.find('?'); + auto path = + path_query.substr(0, query_offset != path_query.npos ? query_offset : path_query.size()); + return absl::StrCat(method, "_", path); +} + +void SamplingController::logSamplingInfo(const TopKListT& top_k, + const SamplingExponentsT& new_sampling_exponents, + uint64_t last_period_count, uint32_t total_wanted) const { + ENVOY_LOG(debug, + "Updating sampling info. top_k.size(): {}, last_period_count: {}, total_wanted: {}", + top_k.size(), last_period_count, total_wanted); + for (auto const& counter : top_k) { + auto sampling_state = new_sampling_exponents.find(counter.getItem()); + ENVOY_LOG(debug, "- {}: value: {}, exponent: {}", counter.getItem(), counter.getValue(), + sampling_state->second.getExponent()); + } +} + +uint64_t SamplingController::calculateEffectiveCount(const TopKListT& top_k, + const SamplingExponentsT& sampling_exponents) { + uint64_t cnt = 0; + for (auto const& counter : top_k) { + auto sampling_state = sampling_exponents.find(counter.getItem()); + if (sampling_state != sampling_exponents.end()) { + auto counterVal = counter.getValue(); + auto mul = sampling_state->second.getMultiplicity(); + auto res = counterVal / mul; + cnt += res; + } + } + return cnt; +} + +void SamplingController::calculateSamplingExponents( + const TopKListT& top_k, uint32_t total_wanted, + SamplingExponentsT& new_sampling_exponents) const { + const auto top_k_size = top_k.size(); + if (top_k_size == 0 || total_wanted == 0) { + return; + } + + // number of requests which are allowed for every entry + const uint32_t allowed_per_entry = total_wanted / top_k_size; + + for (auto& counter : top_k) { + // allowed multiplicity for this entry + auto wanted_multiplicity = counter.getValue() / allowed_per_entry; + auto sampling_state = new_sampling_exponents.find(counter.getItem()); + // sampling exponent has to be a power of 2. Find the exponent to have multiplicity near to + // wanted_multiplicity + while (wanted_multiplicity > sampling_state->second.getMultiplicity() && + sampling_state->second.getExponent() < MAX_SAMPLING_EXPONENT) { + sampling_state->second.increaseExponent(); + } + if (wanted_multiplicity < sampling_state->second.getMultiplicity()) { + // we want to have multiplicity <= wanted_multiplicity, therefore exponent is decreased once. + sampling_state->second.decreaseExponent(); + } + } + + auto effective_count = calculateEffectiveCount(top_k, new_sampling_exponents); + // There might be entries where allowed_per_entry is greater than their count. + // Therefore, we would sample less than total_wanted. + // To avoid this, we decrease the exponent of other entries if possible + if (effective_count < total_wanted) { + for (int i = 0; i < 5; i++) { // max tries + for (auto reverse_it = top_k.rbegin(); reverse_it != top_k.rend(); + ++reverse_it) { // start with lowest frequency + auto rev_sampling_state = new_sampling_exponents.find(reverse_it->getItem()); + rev_sampling_state->second.decreaseExponent(); + effective_count = calculateEffectiveCount(top_k, new_sampling_exponents); + if (effective_count >= total_wanted) { // we are done + return; + } + } + } + } +} +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.h b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.h new file mode 100644 index 000000000000..b5871d4d4b6e --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include + +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary.h" + +#include "absl/synchronization/mutex.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +/** + * @brief Container for sampling exponent / multiplicity. + * based on the "Space Saving algorithm", AKA "HeavyHitter" + * See: + * https://cse.hkust.edu.hk/~raywong/comp5331/References/EfficientComputationOfFrequentAndTop-kElementsInDataStreams.pdf + * + */ +class SamplingState { +public: + // Convert exponent to multiplicity + [[nodiscard]] static uint32_t toMultiplicity(uint32_t exponent) { return 1 << exponent; } + [[nodiscard]] uint32_t getExponent() const { return exponent_; } + [[nodiscard]] uint32_t getMultiplicity() const { return toMultiplicity(exponent_); } + void increaseExponent() { exponent_++; } + void decreaseExponent() { + if (exponent_ > 0) { + exponent_--; + } + } + + explicit SamplingState(uint32_t exponent) : exponent_(exponent){}; + + SamplingState() = default; + + /** + * @brief Does a sampling decision based on random number attribute and multiplicity + * + * @param random_nr Random number used for sampling decision. + * @return true if request should be sampled, false otherwise + */ + bool shouldSample(const uint64_t random_nr) const { return (random_nr % getMultiplicity() == 0); } + +private: + uint32_t exponent_{0}; +}; + +using StreamSummaryT = StreamSummary; +using TopKListT = std::list>; + +/** + * @brief Counts the requests per sampling key in the current period. Calculates the sampling + * exponents based on the request count in the latest period. + * + */ +class SamplingController : public Logger::Loggable { + +public: + explicit SamplingController(SamplerConfigProviderPtr sampler_config_provider) + : stream_summary_(std::make_unique(STREAM_SUMMARY_SIZE)), + sampler_config_provider_(std::move(sampler_config_provider)) {} + + /** + * @brief Trigger calculating the sampling exponents based on the request count since last update + * + */ + void update(); + + /** + * @brief Get the Sampling State object for a sampling key + * + * @param sampling_key Sampling Key to search for + * @return SamplingState Current Sampling State for key + */ + SamplingState getSamplingState(const std::string& sampling_key) const; + + /** + * @brief Returns the number of spans which would have been sampled in the last period using the + * current sampling states + * + * @return effective count + */ + uint64_t getEffectiveCount() const; + + /** + * @brief Counts the occurrence of sampling_key + * + * @param sampling_key Sampling Key used to categorize the request + */ + void offer(const std::string& sampling_key); + + /** + * @brief Creates the Sampling Key which is used to categorize a request + * + * @param path_query The request path. May contain the query. + * @param method The request method. + * @return The sampling key. + */ + static std::string getSamplingKey(const absl::string_view path_query, + const absl::string_view method); + + static constexpr size_t STREAM_SUMMARY_SIZE{100}; + static constexpr uint32_t MAX_SAMPLING_EXPONENT = (1 << 4) - 1; // 15 + +private: + using SamplingExponentsT = absl::flat_hash_map; + SamplingExponentsT sampling_exponents_; + mutable absl::Mutex sampling_exponents_mutex_{}; + std::string rest_bucket_key_{}; + std::unique_ptr stream_summary_; + uint64_t last_effective_count_{}; + mutable absl::Mutex stream_summary_mutex_{}; + SamplerConfigProviderPtr sampler_config_provider_; + + void logSamplingInfo(const TopKListT& top_k, const SamplingExponentsT& new_sampling_exponents, + uint64_t last_period_count, uint32_t total_wanted) const; + + static uint64_t calculateEffectiveCount(const TopKListT& top_k, + const SamplingExponentsT& sampling_exponents); + + void calculateSamplingExponents(const TopKListT& top_k, uint32_t total_wanted, + SamplingExponentsT& new_sampling_exponents) const; + + void update(const TopKListT& top_k, uint64_t last_period_count, uint32_t total_wanted); +}; + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary.h b/source/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary.h new file mode 100644 index 000000000000..b6385c91313d --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary.h @@ -0,0 +1,204 @@ +#pragma once + +#include +#include +#include + +#include "source/common/common/assert.h" + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/types/optional.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +namespace detail { + +template struct Bucket; + +template using BucketIterator = typename std::list>::iterator; + +template struct Counter { + BucketIterator bucket; + absl::optional item{}; + uint64_t value{}; + uint64_t error{}; + + explicit Counter(BucketIterator bucket) : bucket(bucket) {} + Counter(Counter const&) = delete; + Counter& operator=(Counter const&) = delete; +}; + +template using CounterIterator = typename std::list>::iterator; + +template struct Bucket { + uint64_t value; + std::list> children{}; + + explicit Bucket(uint64_t value) : value(value) {} + Bucket(Bucket const&) = delete; + Bucket& operator=(Bucket const&) = delete; +}; + +} // namespace detail + +template class Counter { +private: + T const& item_; + uint64_t value_; + uint64_t error_; + +public: + Counter(detail::Counter const& c) : item_(*c.item), value_(c.value), error_(c.error) {} + + T const& getItem() const { return item_; } + uint64_t getValue() const { return value_; } + uint64_t getError() const { return error_; } +}; + +/** + * @brief Space Saving algorithm implementation also know as "HeavyHitter". + * based on the "Space Saving algorithm", AKA "HeavyHitter" + * See: + * https://cse.hkust.edu.hk/~raywong/comp5331/References/EfficientComputationOfFrequentAndTop-kElementsInDataStreams.pdf + * https://github.com/fzakaria/space-saving/tree/master + * + */ +template class StreamSummary { +private: + const size_t capacity_; + uint64_t n_{}; + absl::flat_hash_map> cache_{}; + std::list> buckets_{}; + + typename detail::CounterIterator incrementCounter(detail::CounterIterator counter_iter, + uint64_t increment) { + auto const bucket = counter_iter->bucket; + auto bucket_next = std::prev(bucket); + counter_iter->value += increment; + + detail::CounterIterator elem; + if (bucket_next != buckets_.end() && counter_iter->value == bucket_next->value) { + counter_iter->bucket = bucket_next; + bucket_next->children.splice(bucket_next->children.end(), bucket->children, counter_iter); + elem = std::prev(bucket_next->children.end()); + } else { + auto bucket_new = buckets_.emplace(bucket, counter_iter->value); + counter_iter->bucket = bucket_new; + bucket_new->children.splice(bucket_new->children.end(), bucket->children, counter_iter); + elem = std::prev(bucket_new->children.end()); + } + if (bucket->children.empty()) { + buckets_.erase(bucket); + } + return elem; + } + + absl::Status validateInternal() const { + auto cache_copy = cache_; + auto current_bucket = buckets_.begin(); + uint64_t value_sum = 0; + while (current_bucket != buckets_.end()) { + auto prev = std::prev(current_bucket); + if (prev != buckets_.end() && prev->value <= current_bucket->value) { + return absl::InternalError("buckets should be in descending order."); + } + auto current_child = current_bucket->children.begin(); + while (current_child != current_bucket->children.end()) { + if (current_child->bucket != current_bucket || + current_child->value != current_bucket->value) { + return absl::InternalError("entry does not point to a bucket with the same value."); + } + if (current_child->item) { + auto old_iter = cache_copy.find(*current_child->item); + if (old_iter != cache_copy.end()) { + cache_copy.erase(old_iter); + } + } + value_sum += current_child->value; + current_child++; + } + current_bucket++; + } + if (!cache_copy.empty() || cache_.size() > capacity_ || value_sum != n_) { + return absl::InternalError("unexpected size."); + } + return absl::OkStatus(); + } + + inline void validateDbg() { +#if !defined(NDEBUG) + ASSERT(validate().ok()); +#endif + } + +public: + explicit StreamSummary(size_t capacity) : capacity_(capacity) { + auto& new_bucket = buckets_.emplace_back(0); + for (size_t i = 0; i < capacity; ++i) { + // initialize with empty counters, optional item will not be set + new_bucket.children.emplace_back(buckets_.begin()); + } + validateDbg(); + } + + size_t getCapacity() const { return capacity_; } + + absl::Status validate() const { return validateInternal(); } + + Counter offer(T const& item, uint64_t increment = 1) { + ++n_; + auto iter = cache_.find(item); + if (iter != cache_.end()) { + iter->second = incrementCounter(iter->second, increment); + validateDbg(); + return *iter->second; + } else { + auto min_element = std::prev(buckets_.back().children.end()); + auto original_min_value = min_element->value; + if (min_element + ->item) { // element was already used (otherwise optional item would be not set) + // remove old from cache + auto old_iter = cache_.find(*min_element->item); + if (old_iter != cache_.end()) { + cache_.erase(old_iter); + } + } + min_element->item = item; + min_element = incrementCounter(min_element, increment); + cache_[item] = min_element; + if (cache_.size() <= capacity_) { + // should always be true, but keep it to be aligned to reference implementation + // originalMinValue will be 0 if element wasn't already used + min_element->error = original_min_value; + } + validateDbg(); + return *min_element; + } + } + + uint64_t getN() const { return n_; } + + typename std::list> getTopK(size_t k = SIZE_MAX) const { + std::list> r; + for (auto const& bucket : buckets_) { + for (auto const& child : bucket.children) { + if (child.item) { + r.emplace_back(child); + if (r.size() == k) { + return r; + } + } + } + } + return r; + } +}; + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id.h b/source/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id.h new file mode 100644 index 000000000000..e87e55f8c8d1 --- /dev/null +++ b/source/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +#include "absl/strings/str_cat.h" +#include "openssl/md5.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +namespace { + +/** + * @brief Calculates a Dynatrace specific tenant id which is used in the Dynatrace tag added to the + * tracestate header. + * + * @param file_name The tenant as received via config file + * @return the tenant id as Hex + */ +absl::Hex calculateTenantId(std::string tenant_uuid) { + if (tenant_uuid.empty()) { + return absl::Hex(0); + } + + for (char& c : tenant_uuid) { + if (c & 0x80) { + c = 0x3f; // '?' + } + } + + uint8_t digest[16]; + MD5(reinterpret_cast(tenant_uuid.data()), tenant_uuid.size(), digest); + + int32_t hash = 0; + for (int i = 0; i < 16; i++) { + const int shift_for_target_byte = (3 - (i % 4)) * 8; + // 24, 16, 8, 0 respectively + hash ^= + (static_cast(digest[i]) << shift_for_target_byte) & (0xff << shift_for_target_byte); + } + return absl::Hex(hash); +} +} // namespace +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/opentelemetry/samplers/sampler.h b/source/extensions/tracers/opentelemetry/samplers/sampler.h index 33794645344e..e20fc0207e77 100644 --- a/source/extensions/tracers/opentelemetry/samplers/sampler.h +++ b/source/extensions/tracers/opentelemetry/samplers/sampler.h @@ -23,11 +23,11 @@ class SpanContext; enum class Decision { // IsRecording will be false, the Span will not be recorded and all events and attributes will be // dropped. - DROP, + Drop, // IsRecording will be true, but the Sampled flag MUST NOT be set. - RECORD_ONLY, + RecordOnly, // IsRecording will be true and the Sampled flag MUST be set. - RECORD_AND_SAMPLE + RecordAndSample }; /** @@ -48,10 +48,10 @@ struct SamplingResult { std::string tracestate; inline bool isRecording() const { - return decision == Decision::RECORD_ONLY || decision == Decision::RECORD_AND_SAMPLE; + return decision == Decision::RecordOnly || decision == Decision::RecordAndSample; } - inline bool isSampled() const { return decision == Decision::RECORD_AND_SAMPLE; } + inline bool isSampled() const { return decision == Decision::RecordAndSample; } }; /** diff --git a/source/extensions/tracers/opentelemetry/tracer.cc b/source/extensions/tracers/opentelemetry/tracer.cc index 8c8553015510..ec28f6f69b18 100644 --- a/source/extensions/tracers/opentelemetry/tracer.cc +++ b/source/extensions/tracers/opentelemetry/tracer.cc @@ -38,7 +38,7 @@ void callSampler(SamplerSharedPtr sampler, const absl::optional spa return; } const auto sampling_result = - sampler->shouldSample(span_context, operation_name, new_span.getTraceIdAsHex(), + sampler->shouldSample(span_context, new_span.getTraceIdAsHex(), operation_name, new_span.spankind(), trace_context, {}); new_span.setSampled(sampling_result.isSampled()); diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index 33c9f67051e3..aa8b6d2d0cee 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -35,11 +35,13 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, tracing_context_factory_ = std::make_unique(config_); auto& factory_context = context.serverFactoryContext(); tls_slot_ptr_->set([proto_config, &factory_context, this](Event::Dispatcher& dispatcher) { - TracerPtr tracer = std::make_unique(std::make_unique( + auto factory_or_error = factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( - proto_config.grpc_service(), factory_context.scope(), true), - dispatcher, factory_context.api().randomGenerator(), tracing_stats_, - config_.delayed_buffer_size(), config_.token())); + proto_config.grpc_service(), factory_context.scope(), true); + THROW_IF_STATUS_NOT_OK(factory_or_error, throw); + TracerPtr tracer = std::make_unique(std::make_unique( + std::move(factory_or_error.value()), dispatcher, factory_context.api().randomGenerator(), + tracing_stats_, config_.delayed_buffer_size(), config_.token())); return std::make_shared(std::move(tracer)); }); } diff --git a/source/extensions/tracers/xray/config.cc b/source/extensions/tracers/xray/config.cc index 9421eb0678e0..805a900a1f3d 100644 --- a/source/extensions/tracers/xray/config.cc +++ b/source/extensions/tracers/xray/config.cc @@ -23,8 +23,10 @@ XRayTracerFactory::createTracerDriverTyped(const envoy::config::trace::v3::XRayC Server::Configuration::TracerFactoryContext& context) { std::string sampling_rules_json; TRY_NEEDS_AUDIT { - sampling_rules_json = Config::DataSource::read(proto_config.sampling_rule_manifest(), true, - context.serverFactoryContext().api()); + sampling_rules_json = + THROW_OR_RETURN_VALUE(Config::DataSource::read(proto_config.sampling_rule_manifest(), true, + context.serverFactoryContext().api()), + std::string); } END_TRY catch (EnvoyException& e) { ENVOY_LOG(error, "Failed to read sampling rules manifest because of {}.", e.what()); diff --git a/source/extensions/transport_sockets/tls/cert_validator/BUILD b/source/extensions/transport_sockets/tls/cert_validator/BUILD index c79416930672..5abc18bc2595 100644 --- a/source/extensions/transport_sockets/tls/cert_validator/BUILD +++ b/source/extensions/transport_sockets/tls/cert_validator/BUILD @@ -36,6 +36,7 @@ envoy_cc_library( "//source/common/common:assert_lib", "//source/common/common:base64_lib", "//source/common/common:hex_lib", + "//source/common/common:matchers_lib", "//source/common/common:minimal_logger_lib", "//source/common/common:utility_lib", "//source/common/config:utility_lib", diff --git a/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.cc b/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.cc index a5c67993712c..5ae1ebde5c55 100644 --- a/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.cc +++ b/source/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator.cc @@ -61,7 +61,8 @@ SPIFFEValidator::SPIFFEValidator(const Envoy::Ssl::CertificateValidationContextC "Multiple trust bundles are given for one trust domain for ", domain.name())); } - auto cert = Config::DataSource::read(domain.trust_bundle(), true, config->api()); + auto cert = THROW_OR_RETURN_VALUE( + Config::DataSource::read(domain.trust_bundle(), true, config->api()), std::string); bssl::UniquePtr bio(BIO_new_mem_buf(const_cast(cert.data()), cert.size())); RELEASE_ASSERT(bio != nullptr, ""); bssl::UniquePtr list( diff --git a/source/extensions/transport_sockets/tls/context_config_impl.cc b/source/extensions/transport_sockets/tls/context_config_impl.cc index 6322e594871f..b71736a12153 100644 --- a/source/extensions/transport_sockets/tls/context_config_impl.cc +++ b/source/extensions/transport_sockets/tls/context_config_impl.cc @@ -460,7 +460,8 @@ ServerContextConfigImpl::getSessionTicketKeys( const envoy::extensions::transport_sockets::tls::v3::TlsSessionTicketKeys& keys) { std::vector result; for (const auto& datasource : keys.keys()) { - result.emplace_back(getSessionTicketKey(Config::DataSource::read(datasource, false, api_))); + result.emplace_back(getSessionTicketKey( + THROW_OR_RETURN_VALUE(Config::DataSource::read(datasource, false, api_), std::string))); } return result; } diff --git a/source/extensions/transport_sockets/tls/io_handle_bio.cc b/source/extensions/transport_sockets/tls/io_handle_bio.cc index 08ab2655b9a6..f5faf5fec27b 100644 --- a/source/extensions/transport_sockets/tls/io_handle_bio.cc +++ b/source/extensions/transport_sockets/tls/io_handle_bio.cc @@ -15,32 +15,7 @@ namespace { // NOLINTNEXTLINE(readability-identifier-naming) inline Envoy::Network::IoHandle* bio_io_handle(BIO* bio) { - return reinterpret_cast(bio->ptr); -} - -// NOLINTNEXTLINE(readability-identifier-naming) -int io_handle_new(BIO* bio) { - bio->init = 0; - bio->num = -1; - bio->ptr = nullptr; - bio->flags = 0; - return 1; -} - -// NOLINTNEXTLINE(readability-identifier-naming) -int io_handle_free(BIO* bio) { - if (bio == nullptr) { - return 0; - } - - if (bio->shutdown) { - if (bio->init) { - bio_io_handle(bio)->close(); - } - bio->init = 0; - bio->flags = 0; - } - return 1; + return reinterpret_cast(BIO_get_data(bio)); } // NOLINTNEXTLINE(readability-identifier-naming) @@ -86,22 +61,10 @@ int io_handle_write(BIO* b, const char* in, int inl) { } // NOLINTNEXTLINE(readability-identifier-naming) -long io_handle_ctrl(BIO* b, int cmd, long num, void*) { +long io_handle_ctrl(BIO*, int cmd, long, void*) { long ret = 1; switch (cmd) { - case BIO_C_SET_FD: - RELEASE_ASSERT(false, "should not be called"); - break; - case BIO_C_GET_FD: - RELEASE_ASSERT(false, "should not be called"); - break; - case BIO_CTRL_GET_CLOSE: - ret = b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = int(num); - break; case BIO_CTRL_FLUSH: ret = 1; break; @@ -112,16 +75,18 @@ long io_handle_ctrl(BIO* b, int cmd, long num, void*) { return ret; } -const BIO_METHOD methods_io_handlep = { - BIO_TYPE_SOCKET, "io_handle", - io_handle_write, io_handle_read, - nullptr /* puts */, nullptr /* gets, */, - io_handle_ctrl, io_handle_new, - io_handle_free, nullptr /* callback_ctrl */, -}; - // NOLINTNEXTLINE(readability-identifier-naming) -const BIO_METHOD* BIO_s_io_handle(void) { return &methods_io_handlep; } +const BIO_METHOD* BIO_s_io_handle(void) { + static const BIO_METHOD* method = [&] { + BIO_METHOD* ret = BIO_meth_new(BIO_TYPE_SOCKET, "io_handle"); + RELEASE_ASSERT(ret != nullptr, ""); + RELEASE_ASSERT(BIO_meth_set_read(ret, io_handle_read), ""); + RELEASE_ASSERT(BIO_meth_set_write(ret, io_handle_write), ""); + RELEASE_ASSERT(BIO_meth_set_ctrl(ret, io_handle_ctrl), ""); + return ret; + }(); + return method; +} } // namespace @@ -133,10 +98,8 @@ BIO* BIO_new_io_handle(Envoy::Network::IoHandle* io_handle) { RELEASE_ASSERT(b != nullptr, ""); // Initialize the BIO - b->num = -1; - b->ptr = io_handle; - b->shutdown = 0; - b->init = 1; + BIO_set_data(b, io_handle); + BIO_set_init(b, 1); return b; } diff --git a/source/extensions/transport_sockets/tls/io_handle_bio.h b/source/extensions/transport_sockets/tls/io_handle_bio.h index 03c1c9636566..e2fb14512b8b 100644 --- a/source/extensions/transport_sockets/tls/io_handle_bio.h +++ b/source/extensions/transport_sockets/tls/io_handle_bio.h @@ -11,7 +11,8 @@ namespace Tls { /** * Creates a custom BIO that can read from/write to an IoHandle. It's equivalent to a socket BIO - * but instead of relying on access to an fd, it relies on IoHandle APIs for all interactions. + * but instead of relying on access to an fd, it relies on IoHandle APIs for all interactions. The + * IoHandle must remain valid for the lifetime of the BIO. */ // NOLINTNEXTLINE(readability-identifier-naming) BIO* BIO_new_io_handle(Envoy::Network::IoHandle* io_handle); diff --git a/source/extensions/upstreams/http/config.cc b/source/extensions/upstreams/http/config.cc index b1e8deaaedbd..66b31e48c632 100644 --- a/source/extensions/upstreams/http/config.cc +++ b/source/extensions/upstreams/http/config.cc @@ -228,7 +228,7 @@ ProtocolOptionsConfigImpl::ProtocolOptionsConfigImpl( use_downstream_protocol_(options.has_use_downstream_protocol_config()), use_http2_(useHttp2(options)), use_http3_(useHttp3(options)), use_alpn_(options.has_auto_config()) { - ASSERT(Http2::Utility::initializeAndValidateOptions(http2_options).status().ok()); + ASSERT(Http2::Utility::initializeAndValidateOptions(http2_options_).status().ok()); } ProtocolOptionsConfigImpl::ProtocolOptionsConfigImpl( diff --git a/source/extensions/upstreams/http/udp/upstream_request.h b/source/extensions/upstreams/http/udp/upstream_request.h index eed57dbb6eec..4d4a132411e1 100644 --- a/source/extensions/upstreams/http/udp/upstream_request.h +++ b/source/extensions/upstreams/http/udp/upstream_request.h @@ -44,9 +44,14 @@ class UdpConnPool : public Router::GenericConnPool { Upstream::HostDescriptionConstSharedPtr host() const override { return host_; } Network::SocketPtr createSocket(const Upstream::HostConstSharedPtr& host) { - return std::make_unique(Network::Socket::Type::Datagram, host->address(), - /*remote_address=*/nullptr, - Network::SocketCreationOptions{}); + auto ret = std::make_unique( + Network::Socket::Type::Datagram, host->address(), + /*remote_address=*/nullptr, Network::SocketCreationOptions{}); + if (Runtime::runtimeFeatureEnabled( + "envoy.restart_features.allow_client_socket_creation_failure")) { + RELEASE_ASSERT(ret->isOpen(), "Socket creation fail"); + } + return ret; } bool valid() const override { return host_ != nullptr; } diff --git a/source/server/BUILD b/source/server/BUILD index f0d63ba47174..7ee402750e1f 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -313,6 +313,7 @@ envoy_cc_library( "//source/common/event:scaled_range_timer_manager_lib", "//source/common/stats:symbol_table_lib", "//source/server:resource_monitor_config_lib", + "@com_google_absl//absl/container:node_hash_set", "@envoy_api//envoy/config/overload/v3:pkg_cc_proto", ], ) @@ -440,6 +441,7 @@ envoy_cc_library( "//source/common/common:mutex_tracer_lib", "//source/common/common:perf_tracing_lib", "//source/common/common:utility_lib", + "//source/common/config:stats_utility_lib", "//source/common/config:utility_lib", "//source/common/config:xds_resource_lib", "//source/common/grpc:async_client_manager_lib", diff --git a/source/server/admin/admin.h b/source/server/admin/admin.h index c77be2b2b92b..86c6ab7f57d3 100644 --- a/source/server/admin/admin.h +++ b/source/server/admin/admin.h @@ -235,6 +235,7 @@ class AdminImpl : public Admin, return nullptr; #endif } + bool appendLocalOverload() const override { return false; } bool appendXForwardedPort() const override { return false; } bool addProxyProtocolConnectionState() const override { return true; } diff --git a/source/server/config_validation/server.cc b/source/server/config_validation/server.cc index 47cc069270bd..054cb3f11b24 100644 --- a/source/server/config_validation/server.cc +++ b/source/server/config_validation/server.cc @@ -5,6 +5,7 @@ #include "envoy/config/bootstrap/v3/bootstrap.pb.h" #include "source/common/common/utility.h" +#include "source/common/config/stats_utility.h" #include "source/common/config/utility.h" #include "source/common/config/well_known_names.h" #include "source/common/event/real_time_system.h" @@ -100,7 +101,7 @@ void ValidationInstance::initialize(const Options& options, Regex::EnginePtr regex_engine = createRegexEngine( bootstrap_, messageValidationContext().staticValidationVisitor(), serverFactoryContext()); - Config::Utility::createTagProducer(bootstrap_, options_.statsTags()); + Config::StatsUtility::createTagProducer(bootstrap_, options_.statsTags()); if (!bootstrap_.node().user_agent_build_version().has_version()) { *bootstrap_.mutable_node()->mutable_user_agent_build_version() = VersionInfo::buildVersion(); } @@ -114,7 +115,7 @@ void ValidationInstance::initialize(const Options& options, messageValidationContext().staticValidationVisitor(), *api_, options_); absl::Status creation_status = absl::OkStatus(); Configuration::InitialImpl initial_config(bootstrap_, creation_status); - THROW_IF_NOT_OK(creation_status); + THROW_IF_NOT_OK_REF(creation_status); AdminFactoryContext factory_context(*this, std::make_shared()); initial_config.initAdminAccessLog(bootstrap_, factory_context); admin_ = std::make_unique(initial_config.admin().address()); diff --git a/source/server/server.cc b/source/server/server.cc index ce41536f6563..376ebb48e829 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -29,6 +29,7 @@ #include "source/common/common/enum_to_int.h" #include "source/common/common/mutex_tracer_impl.h" #include "source/common/common/utility.h" +#include "source/common/config/stats_utility.h" #include "source/common/config/utility.h" #include "source/common/config/well_known_names.h" #include "source/common/config/xds_resource.h" @@ -500,7 +501,8 @@ void InstanceBase::initializeOrThrow(Network::Address::InstanceConstSharedPtr lo // Needs to happen as early as possible in the instantiation to preempt the objects that require // stats. - stats_store_.setTagProducer(Config::Utility::createTagProducer(bootstrap_, options_.statsTags())); + stats_store_.setTagProducer( + Config::StatsUtility::createTagProducer(bootstrap_, options_.statsTags())); stats_store_.setStatsMatcher(std::make_unique( bootstrap_.stats_config(), stats_store_.symbolTable())); stats_store_.setHistogramSettings( @@ -585,7 +587,7 @@ void InstanceBase::initializeOrThrow(Network::Address::InstanceConstSharedPtr lo absl::Status creation_status; Configuration::InitialImpl initial_config(bootstrap_, creation_status); - THROW_IF_NOT_OK(creation_status); + THROW_IF_NOT_OK_REF(creation_status); // Learn original_start_time_ if our parent is still around to inform us of it. const auto parent_admin_shutdown_response = restarter_.sendParentAdminShutdownRequest(); @@ -823,6 +825,15 @@ void InstanceBase::onRuntimeReady() { shutdown(); }); } + + // TODO (nezdolik): Fully deprecate this runtime key in the next release. + if (runtime().snapshot().get(Runtime::Keys::GlobalMaxCxRuntimeKey)) { + ENVOY_LOG(warn, + "Usage of the deprecated runtime key {}, consider switching to " + "`envoy.resource_monitors.downstream_connections` instead." + "This runtime key will be removed in future.", + Runtime::Keys::GlobalMaxCxRuntimeKey); + } } void InstanceBase::startWorkers() { @@ -908,8 +919,7 @@ RunHelper::RunHelper(Instance& instance, const Options& options, Event::Dispatch // If there is no global limit to the number of active connections, warn on startup. if (!overload_manager.getThreadLocalOverloadState().isResourceMonitorEnabled( - Server::OverloadProactiveResourceName::GlobalDownstreamMaxConnections) && - !instance.runtime().snapshot().get(Runtime::Keys::GlobalMaxCxRuntimeKey)) { + Server::OverloadProactiveResourceName::GlobalDownstreamMaxConnections)) { ENVOY_LOG(warn, "There is no configured limit to the number of allowed active downstream " "connections. Configure a " "limit in `envoy.resource_monitors.downstream_connections` resource monitor."); diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 08fb0d1208eb..2aef53b1499b 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -126,6 +126,7 @@ envoy_cc_test( external_deps = ["abseil_optional"], deps = [ "//source/common/config:api_version_lib", + "//source/common/config:stats_utility_lib", "//source/common/config:utility_lib", "//source/common/config:well_known_names", "//source/common/stats:stats_lib", diff --git a/test/common/config/datasource_test.cc b/test/common/config/datasource_test.cc index 070ff1631024..13f96416867b 100644 --- a/test/common/config/datasource_test.cc +++ b/test/common/config/datasource_test.cc @@ -37,9 +37,6 @@ class AsyncDataSourceTest : public testing::Test { Event::TimerCb retry_timer_cb_; NiceMock request_{&cm_.thread_local_cluster_.async_client_}; - Config::DataSource::LocalAsyncDataProviderPtr local_data_provider_; - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; - using AsyncClientSendFunc = std::function; @@ -76,499 +73,6 @@ class AsyncDataSourceTest : public testing::Test { } }; -TEST_F(AsyncDataSourceTest, LoadLocalDataSource) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - local: - inline_string: - xxxxxx - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_local()); - - std::string async_data; - - EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { - init_target_handle_ = target.createHandle("test"); - })); - - local_data_provider_ = std::make_unique( - init_manager_, config.local(), true, *api_, [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, "xxxxxx"); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - - init_target_handle_->initialize(init_watcher_); - EXPECT_EQ(async_data, "xxxxxx"); -} - -TEST_F(AsyncDataSourceTest, LoadLocalEmptyDataSource) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - local: - inline_string: "" - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_local()); - - std::string async_data; - - EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { - init_target_handle_ = target.createHandle("test"); - })); - - local_data_provider_ = std::make_unique( - init_manager_, config.local(), true, *api_, [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, ""); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - - init_target_handle_->initialize(init_watcher_); - EXPECT_EQ(async_data, ""); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceNoCluster) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - xxxxxx - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - initialize(nullptr); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, EMPTY_STRING); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - EXPECT_CALL(*retry_timer_, enableTimer(_, _)) - .WillOnce(Invoke( - [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, EMPTY_STRING); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceReturnFailure) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - xxxxxx - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - cm_.initializeThreadLocalClusters({"cluster_1"}); - initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - callbacks.onFailure(request_, Envoy::Http::AsyncClient::FailureReason::Reset); - return nullptr; - }); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, EMPTY_STRING); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - EXPECT_CALL(*retry_timer_, enableTimer(_, _)) - .WillOnce(Invoke( - [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, EMPTY_STRING); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccessWith503) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - xxxxxx - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - cm_.initializeThreadLocalClusters({"cluster_1"}); - initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - callbacks.onSuccess( - request_, Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ - new Http::TestResponseHeaderMapImpl{{":status", "503"}}})}); - return nullptr; - }); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, EMPTY_STRING); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - EXPECT_CALL(*retry_timer_, enableTimer(_, _)) - .WillOnce(Invoke( - [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, EMPTY_STRING); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccessWithEmptyBody) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - xxxxxx - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - cm_.initializeThreadLocalClusters({"cluster_1"}); - initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - callbacks.onSuccess( - request_, Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ - new Http::TestResponseHeaderMapImpl{{":status", "200"}}})}); - return nullptr; - }); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, EMPTY_STRING); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - EXPECT_CALL(*retry_timer_, enableTimer(_, _)) - .WillOnce(Invoke( - [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, EMPTY_STRING); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccessIncorrectSha256) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - xxxxxx - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - const std::string body = "hello world"; - - cm_.initializeThreadLocalClusters({"cluster_1"}); - initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - Http::ResponseMessagePtr response(new Http::ResponseMessageImpl( - Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); - response->body().add(body); - - callbacks.onSuccess(request_, std::move(response)); - return nullptr; - }); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, EMPTY_STRING); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - EXPECT_CALL(*retry_timer_, enableTimer(_, _)) - .WillOnce(Invoke( - [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, EMPTY_STRING); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccess) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - cm_.initializeThreadLocalClusters({"cluster_1"}); - const std::string body = "hello world"; - initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - Http::ResponseMessagePtr response(new Http::ResponseMessageImpl( - Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); - response->body().add(body); - - callbacks.onSuccess(request_, std::move(response)); - return nullptr; - }); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, body); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, body); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceDoNotAllowEmpty) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - xxxxxx - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - cm_.initializeThreadLocalClusters({"cluster_1"}); - initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - callbacks.onSuccess( - request_, Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ - new Http::TestResponseHeaderMapImpl{{":status", "503"}}})}); - return nullptr; - }); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, false, - [&](const std::string& data) { async_data = data; }); - - EXPECT_CALL(init_watcher_, ready()); - EXPECT_CALL(*retry_timer_, enableTimer(_, _)) - .WillOnce(Invoke( - [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, "non-empty"); -} - -TEST_F(AsyncDataSourceTest, DatasourceReleasedBeforeFetchingData) { - const std::string body = "hello world"; - std::string async_data = "non-empty"; - - { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - cm_.initializeThreadLocalClusters({"cluster_1"}); - initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - Http::ResponseMessagePtr response(new Http::ResponseMessageImpl( - Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); - response->body().add(body); - - callbacks.onSuccess(request_, std::move(response)); - return nullptr; - }); - - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, body); - async_data = data; - }); - } - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - init_target_handle_->initialize(init_watcher_); - EXPECT_EQ(async_data, body); -} - -TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceWithRetry) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 - retry_policy: - retry_back_off: - base_interval: 1s - num_retries: 3 - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - cm_.initializeThreadLocalClusters({"cluster_1"}); - const std::string body = "hello world"; - int num_retries = 3; - - initialize( - [&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - callbacks.onSuccess( - request_, - Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ - new Http::TestResponseHeaderMapImpl{{":status", "503"}}})}); - return nullptr; - }, - num_retries); - - std::string async_data = "non-empty"; - remote_data_provider_ = std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string& data) { - EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); - EXPECT_EQ(data, body); - async_data = data; - }); - - EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); - EXPECT_CALL(init_watcher_, ready()); - EXPECT_CALL(*retry_timer_, enableTimer(_, _)) - .WillRepeatedly(Invoke([&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { - if (--num_retries == 0) { - EXPECT_CALL(cm_.thread_local_cluster_.async_client_, send_(_, _, _)) - .WillOnce(Invoke( - [&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, - const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { - Http::ResponseMessagePtr response( - new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ - new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); - response->body().add(body); - - callbacks.onSuccess(request_, std::move(response)); - return nullptr; - })); - } - - retry_timer_cb_(); - })); - init_target_handle_->initialize(init_watcher_); - - EXPECT_EQ(async_data, body); -} - -TEST_F(AsyncDataSourceTest, BaseIntervalGreaterThanMaxInterval) { - AsyncDataSourcePb config; - - std::string yaml = R"EOF( - remote: - http_uri: - uri: https://example.com/data - cluster: cluster_1 - timeout: 1s - sha256: - b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 - retry_policy: - retry_back_off: - base_interval: 10s - max_interval: 1s - num_retries: 3 - )EOF"; - TestUtility::loadFromYamlAndValidate(yaml, config); - EXPECT_TRUE(config.has_remote()); - - EXPECT_THROW_WITH_MESSAGE(std::make_unique( - cm_, init_manager_, config.remote(), dispatcher_, random_, true, - [&](const std::string&) {}), - EnvoyException, - "max_interval must be greater than or equal to the base_interval"); -} - TEST_F(AsyncDataSourceTest, BaseIntervalTest) { AsyncDataSourcePb config; @@ -601,7 +105,7 @@ TEST(DataSourceTest, WellKnownEnvironmentVariableTest) { config.specifier_case()); EXPECT_EQ(config.environment_variable(), "PATH"); Api::ApiPtr api = Api::createApiForTest(); - const auto path_data = DataSource::read(config, false, *api); + const auto path_data = DataSource::read(config, false, *api).value(); EXPECT_FALSE(path_data.empty()); } @@ -618,10 +122,10 @@ TEST(DataSourceTest, MissingEnvironmentVariableTest) { config.specifier_case()); EXPECT_EQ(config.environment_variable(), "ThisVariableDoesntExist"); Api::ApiPtr api = Api::createApiForTest(); - EXPECT_THROW_WITH_MESSAGE(DataSource::read(config, false, *api), EnvoyException, - "Environment variable doesn't exist: ThisVariableDoesntExist"); - EXPECT_THROW_WITH_MESSAGE(DataSource::read(config, true, *api), EnvoyException, - "Environment variable doesn't exist: ThisVariableDoesntExist"); + EXPECT_EQ(DataSource::read(config, false, *api).status().message(), + "Environment variable doesn't exist: ThisVariableDoesntExist"); + EXPECT_EQ(DataSource::read(config, true, *api).status().message(), + "Environment variable doesn't exist: ThisVariableDoesntExist"); } TEST(DataSourceTest, EmptyEnvironmentVariableTest) { @@ -641,14 +145,13 @@ TEST(DataSourceTest, EmptyEnvironmentVariableTest) { Api::ApiPtr api = Api::createApiForTest(); #ifdef WIN32 // Windows doesn't support empty environment variables. - EXPECT_THROW_WITH_MESSAGE(DataSource::read(config, false, *api), EnvoyException, - "Environment variable doesn't exist: ThisVariableIsEmpty"); - EXPECT_THROW_WITH_MESSAGE(DataSource::read(config, true, *api), EnvoyException, - "Environment variable doesn't exist: ThisVariableIsEmpty"); + EXPECT_EQ(DataSource::read(config, false, *api).status().message(), + "Environment variable doesn't exist: ThisVariableIsEmpty"); + EXPECT_EQ(DataSource::read(config, true, *api).status().message(), + "Environment variable doesn't exist: ThisVariableIsEmpty"); #else - EXPECT_THROW_WITH_MESSAGE(DataSource::read(config, false, *api), EnvoyException, - "DataSource cannot be empty"); - const auto environment_variable = DataSource::read(config, true, *api); + EXPECT_EQ(DataSource::read(config, false, *api).status().message(), "DataSource cannot be empty"); + const auto environment_variable = DataSource::read(config, true, *api).value(); EXPECT_TRUE(environment_variable.empty()); #endif } diff --git a/test/common/config/utility_test.cc b/test/common/config/utility_test.cc index b4f13d5195c8..2d313ca1f981 100644 --- a/test/common/config/utility_test.cc +++ b/test/common/config/utility_test.cc @@ -8,6 +8,7 @@ #include "source/common/common/fmt.h" #include "source/common/config/api_version.h" +#include "source/common/config/stats_utility.h" #include "source/common/config/utility.h" #include "source/common/config/well_known_names.h" #include "source/common/protobuf/protobuf.h" @@ -57,7 +58,7 @@ TEST(UtilityTest, ConfigSourceInitFetchTimeout) { TEST(UtilityTest, createTagProducer) { envoy::config::bootstrap::v3::Bootstrap bootstrap; - auto producer = Utility::createTagProducer(bootstrap, {}); + auto producer = StatsUtility::createTagProducer(bootstrap, {}); ASSERT_TRUE(producer != nullptr); Stats::TagVector tags; auto extracted_name = producer->produceTags("http.config_test.rq_total", tags); @@ -67,7 +68,7 @@ TEST(UtilityTest, createTagProducer) { TEST(UtilityTest, createTagProducerWithDefaultTgs) { envoy::config::bootstrap::v3::Bootstrap bootstrap; - auto producer = Utility::createTagProducer(bootstrap, {{"foo", "bar"}}); + auto producer = StatsUtility::createTagProducer(bootstrap, {{"foo", "bar"}}); ASSERT_TRUE(producer != nullptr); Stats::TagVector tags; auto extracted_name = producer->produceTags("http.config_test.rq_total", tags); @@ -86,19 +87,23 @@ TEST(UtilityTest, CheckFilesystemSubscriptionBackingPath) { TEST(UtilityTest, ParseDefaultRateLimitSettings) { envoy::config::core::v3::ApiConfigSource api_config_source; - const RateLimitSettings& rate_limit_settings = Utility::parseRateLimitSettings(api_config_source); - EXPECT_EQ(false, rate_limit_settings.enabled_); - EXPECT_EQ(100, rate_limit_settings.max_tokens_); - EXPECT_EQ(10, rate_limit_settings.fill_rate_); + const absl::StatusOr rate_limit_settings = + Utility::parseRateLimitSettings(api_config_source); + EXPECT_TRUE(rate_limit_settings.ok()); + EXPECT_EQ(false, rate_limit_settings->enabled_); + EXPECT_EQ(100, rate_limit_settings->max_tokens_); + EXPECT_EQ(10, rate_limit_settings->fill_rate_); } TEST(UtilityTest, ParseEmptyRateLimitSettings) { envoy::config::core::v3::ApiConfigSource api_config_source; api_config_source.mutable_rate_limit_settings(); - const RateLimitSettings& rate_limit_settings = Utility::parseRateLimitSettings(api_config_source); - EXPECT_EQ(true, rate_limit_settings.enabled_); - EXPECT_EQ(100, rate_limit_settings.max_tokens_); - EXPECT_EQ(10, rate_limit_settings.fill_rate_); + const absl::StatusOr rate_limit_settings = + Utility::parseRateLimitSettings(api_config_source); + EXPECT_TRUE(rate_limit_settings.ok()); + EXPECT_EQ(true, rate_limit_settings->enabled_); + EXPECT_EQ(100, rate_limit_settings->max_tokens_); + EXPECT_EQ(10, rate_limit_settings->fill_rate_); } TEST(UtilityTest, ParseRateLimitSettings) { @@ -107,10 +112,38 @@ TEST(UtilityTest, ParseRateLimitSettings) { api_config_source.mutable_rate_limit_settings(); rate_limits->mutable_max_tokens()->set_value(500); rate_limits->mutable_fill_rate()->set_value(4); - const RateLimitSettings& rate_limit_settings = Utility::parseRateLimitSettings(api_config_source); - EXPECT_EQ(true, rate_limit_settings.enabled_); - EXPECT_EQ(500, rate_limit_settings.max_tokens_); - EXPECT_EQ(4, rate_limit_settings.fill_rate_); + const absl::StatusOr rate_limit_settings = + Utility::parseRateLimitSettings(api_config_source); + EXPECT_TRUE(rate_limit_settings.ok()); + EXPECT_EQ(true, rate_limit_settings->enabled_); + EXPECT_EQ(500, rate_limit_settings->max_tokens_); + EXPECT_EQ(4, rate_limit_settings->fill_rate_); +} + +TEST(UtilityTest, ParseNanFillRateLimitSettings) { + envoy::config::core::v3::ApiConfigSource api_config_source; + envoy::config::core::v3::RateLimitSettings* rate_limits = + api_config_source.mutable_rate_limit_settings(); + rate_limits->mutable_max_tokens()->set_value(500); + rate_limits->mutable_fill_rate()->set_value(std::numeric_limits::quiet_NaN()); + const absl::StatusOr rate_limit_settings = + Utility::parseRateLimitSettings(api_config_source); + EXPECT_FALSE(rate_limit_settings.ok()); + EXPECT_EQ(rate_limit_settings.status().message(), + "The value of fill_rate in RateLimitSettings (nan) must not be NaN nor Inf"); +} + +TEST(UtilityTest, ParseInfiniteFillRateLimitSettings) { + envoy::config::core::v3::ApiConfigSource api_config_source; + envoy::config::core::v3::RateLimitSettings* rate_limits = + api_config_source.mutable_rate_limit_settings(); + rate_limits->mutable_max_tokens()->set_value(500); + rate_limits->mutable_fill_rate()->set_value(std::numeric_limits::infinity()); + const absl::StatusOr rate_limit_settings = + Utility::parseRateLimitSettings(api_config_source); + EXPECT_FALSE(rate_limit_settings.ok()); + EXPECT_EQ(rate_limit_settings.status().message(), + "The value of fill_rate in RateLimitSettings (inf) must not be NaN nor Inf"); } // TEST(UtilityTest, FactoryForGrpcApiConfigSource) should catch misconfigured diff --git a/test/common/grpc/BUILD b/test/common/grpc/BUILD index a40a85d8fb8b..cbf20b2ab3c4 100644 --- a/test/common/grpc/BUILD +++ b/test/common/grpc/BUILD @@ -179,6 +179,7 @@ envoy_cc_test( ":grpc_client_integration_test_harness_lib", "//source/common/grpc:async_client_lib", "//source/extensions/grpc_credentials/example:config", + "//test/test_common:test_runtime_lib", ] + envoy_select_google_grpc(["//source/common/grpc:google_async_client_lib"]), ) diff --git a/test/common/grpc/async_client_manager_benchmark.cc b/test/common/grpc/async_client_manager_benchmark.cc index ca316d777cdf..5b62f6c270b5 100644 --- a/test/common/grpc/async_client_manager_benchmark.cc +++ b/test/common/grpc/async_client_manager_benchmark.cc @@ -53,8 +53,9 @@ void testGetOrCreateAsyncClientWithConfig(::benchmark::State& state) { UNREFERENCED_PARAMETER(_); for (int i = 0; i < 1000; i++) { RawAsyncClientSharedPtr foo_client0 = - async_client_man_test.async_client_manager_.getOrCreateRawAsyncClient( - grpc_service, async_client_man_test.scope_, true); + async_client_man_test.async_client_manager_ + .getOrCreateRawAsyncClient(grpc_service, async_client_man_test.scope_, true) + .value(); } } } @@ -70,8 +71,10 @@ void testGetOrCreateAsyncClientWithHashConfig(::benchmark::State& state) { UNREFERENCED_PARAMETER(_); for (int i = 0; i < 1000; i++) { RawAsyncClientSharedPtr foo_client0 = - async_client_man_test.async_client_manager_.getOrCreateRawAsyncClientWithHashKey( - config_with_hash_key_a, async_client_man_test.scope_, true); + async_client_man_test.async_client_manager_ + .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key_a, + async_client_man_test.scope_, true) + .value(); } } } diff --git a/test/common/grpc/async_client_manager_impl_test.cc b/test/common/grpc/async_client_manager_impl_test.cc index 4e89ac6f296b..8cbcd82c5c5d 100644 --- a/test/common/grpc/async_client_manager_impl_test.cc +++ b/test/common/grpc/async_client_manager_impl_test.cc @@ -231,7 +231,7 @@ TEST_F(AsyncClientManagerImplTest, EnvoyGrpcOk) { envoy::config::core::v3::GrpcService grpc_service; grpc_service.mutable_envoy_grpc()->set_cluster_name("foo"); EXPECT_CALL(cm_, checkActiveStaticCluster("foo")).WillOnce(Return(absl::OkStatus())); - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false); + ASSERT_TRUE(async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).ok()); } TEST_F(AsyncClientManagerImplTest, GrpcServiceConfigWithHashKeyTest) { @@ -266,16 +266,16 @@ TEST_F(AsyncClientManagerImplTest, RawAsyncClientCacheWithSecondsConfig) { initialize(aync_manager_config); RawAsyncClientSharedPtr foo_client_0 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); RawAsyncClientSharedPtr foo_client_1 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_EQ(foo_client_0.get(), foo_client_1.get()); time_system_.advanceTimeAndRun(std::chrono::seconds(19), *dispatcher_, Event::Dispatcher::RunType::NonBlock); RawAsyncClientSharedPtr foo_client_2 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_EQ(foo_client_1.get(), foo_client_2.get()); // Here we want to test behavior with a specific sequence of events, where each timer @@ -286,7 +286,7 @@ TEST_F(AsyncClientManagerImplTest, RawAsyncClientCacheWithSecondsConfig) { } RawAsyncClientSharedPtr foo_client_3 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_NE(foo_client_2.get(), foo_client_3.get()); } @@ -302,16 +302,16 @@ TEST_F(AsyncClientManagerImplTest, RawAsyncClientCacheWithMilliConfig) { initialize(aync_manager_config); RawAsyncClientSharedPtr foo_client_0 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); RawAsyncClientSharedPtr foo_client_1 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_EQ(foo_client_0.get(), foo_client_1.get()); time_system_.advanceTimeAndRun(std::chrono::milliseconds(29999), *dispatcher_, Event::Dispatcher::RunType::NonBlock); RawAsyncClientSharedPtr foo_client_2 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_EQ(foo_client_1.get(), foo_client_2.get()); // Here we want to test behavior with a specific sequence of events, where each timer @@ -322,7 +322,7 @@ TEST_F(AsyncClientManagerImplTest, RawAsyncClientCacheWithMilliConfig) { } RawAsyncClientSharedPtr foo_client_3 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_NE(foo_client_2.get(), foo_client_3.get()); } @@ -333,15 +333,15 @@ TEST_F(AsyncClientManagerImplTest, RawAsyncClientCache) { // Use cache when runtime is enabled. RawAsyncClientSharedPtr foo_client0 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); RawAsyncClientSharedPtr foo_client1 = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_EQ(foo_client0.get(), foo_client1.get()); // Get a different raw async client with different cluster config. grpc_service.mutable_envoy_grpc()->set_cluster_name("bar"); RawAsyncClientSharedPtr bar_client = - async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true); + async_client_manager_->getOrCreateRawAsyncClient(grpc_service, scope_, true).value(); EXPECT_NE(foo_client1.get(), bar_client.get()); } @@ -352,8 +352,8 @@ TEST_F(AsyncClientManagerImplTest, EnvoyGrpcInvalid) { EXPECT_CALL(cm_, checkActiveStaticCluster("foo")).WillOnce(Invoke([](const std::string&) { return absl::InvalidArgumentError("failure"); })); - EXPECT_THROW_WITH_MESSAGE( - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false), EnvoyException, + EXPECT_EQ( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).status().message(), "failure"); } @@ -364,10 +364,11 @@ TEST_F(AsyncClientManagerImplTest, GoogleGrpc) { grpc_service.mutable_google_grpc()->set_stat_prefix("foo"); #ifdef ENVOY_GOOGLE_GRPC - EXPECT_NE(nullptr, async_client_manager_->factoryForGrpcService(grpc_service, scope_, false)); + EXPECT_NE(nullptr, + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).value()); #else - EXPECT_THROW_WITH_MESSAGE( - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false), EnvoyException, + EXPECT_EQ( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).status().message(), "Google C++ gRPC client is not linked"); #endif } @@ -383,12 +384,12 @@ TEST_F(AsyncClientManagerImplTest, GoogleGrpcIllegalCharsInKey) { metadata.set_value("value"); #ifdef ENVOY_GOOGLE_GRPC - EXPECT_THROW_WITH_MESSAGE( - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false), EnvoyException, + EXPECT_EQ( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).status().message(), "Illegal characters in gRPC initial metadata header key: illegalcharacter;."); #else - EXPECT_THROW_WITH_MESSAGE( - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false), EnvoyException, + EXPECT_EQ( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).status().message(), "Google C++ gRPC client is not linked"); #endif } @@ -404,10 +405,11 @@ TEST_F(AsyncClientManagerImplTest, LegalGoogleGrpcChar) { metadata.set_value("value"); #ifdef ENVOY_GOOGLE_GRPC - EXPECT_NE(nullptr, async_client_manager_->factoryForGrpcService(grpc_service, scope_, false)); + EXPECT_NE(nullptr, + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).value()); #else - EXPECT_THROW_WITH_MESSAGE( - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false), EnvoyException, + EXPECT_EQ( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).status().message(), "Google C++ gRPC client is not linked"); #endif } @@ -423,12 +425,12 @@ TEST_F(AsyncClientManagerImplTest, GoogleGrpcIllegalCharsInValue) { metadata.set_value("NonAsciValue.भारत"); #ifdef ENVOY_GOOGLE_GRPC - EXPECT_THROW_WITH_MESSAGE( - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false), EnvoyException, + EXPECT_EQ( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).status().message(), "Illegal ASCII value for gRPC initial metadata header key: legal-key."); #else - EXPECT_THROW_WITH_MESSAGE( - async_client_manager_->factoryForGrpcService(grpc_service, scope_, false), EnvoyException, + EXPECT_EQ( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, false).status().message(), "Google C++ gRPC client is not linked"); #endif } @@ -439,7 +441,8 @@ TEST_F(AsyncClientManagerImplTest, EnvoyGrpcUnknownSkipClusterCheck) { grpc_service.mutable_envoy_grpc()->set_cluster_name("foo"); EXPECT_CALL(cm_, checkActiveStaticCluster(_)).Times(0); - ASSERT_NO_THROW(async_client_manager_->factoryForGrpcService(grpc_service, scope_, true)); + ASSERT_TRUE( + async_client_manager_->factoryForGrpcService(grpc_service, scope_, true).status().ok()); } } // namespace diff --git a/test/common/grpc/grpc_client_integration_test.cc b/test/common/grpc/grpc_client_integration_test.cc index 8cf420e1e1a1..f3fe4bea09ac 100644 --- a/test/common/grpc/grpc_client_integration_test.cc +++ b/test/common/grpc/grpc_client_integration_test.cc @@ -5,6 +5,7 @@ #endif +#include "test/test_common/test_runtime.h" #include "test/common/grpc/grpc_client_integration_test_harness.h" using testing::Eq; @@ -499,6 +500,29 @@ TEST_P(GrpcSslClientIntegrationTest, BasicSslRequestWithClientCert) { dispatcher_helper_.runDispatcher(); } +// Validate TLS version mismatch between the client and the server. +TEST_P(GrpcSslClientIntegrationTest, BasicSslRequestHandshakeFailure) { + SKIP_IF_GRPC_CLIENT(ClientType::EnvoyGrpc); + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues({{"envoy.reloadable_features.google_grpc_disable_tls_13", "true"}}); + use_server_tls_13_ = true; + initialize(); + auto request = createRequest(empty_metadata_, false); + EXPECT_CALL(*request->child_span_, setTag(Eq(Tracing::Tags::get().GrpcStatusCode), Eq("13"))); + EXPECT_CALL(*request->child_span_, + setTag(Eq(Tracing::Tags::get().Error), Eq(Tracing::Tags::get().True))); + EXPECT_CALL(*request, onFailure(Status::Internal, "", _)).WillOnce(InvokeWithoutArgs([this]() { + dispatcher_helper_.dispatcher_.exit(); + })); + EXPECT_CALL(*request->child_span_, finishSpan()); + FakeRawConnectionPtr fake_connection; + ASSERT_TRUE(fake_upstream_->waitForRawConnection(fake_connection)); + if (fake_connection->connected()) { + ASSERT_TRUE(fake_connection->waitForDisconnect()); + } + dispatcher_helper_.dispatcher_.run(Event::Dispatcher::RunType::Block); +} + #ifdef ENVOY_GOOGLE_GRPC // AccessToken credential validation tests. class GrpcAccessTokenClientIntegrationTest : public GrpcSslClientIntegrationTest { diff --git a/test/common/grpc/grpc_client_integration_test_harness.h b/test/common/grpc/grpc_client_integration_test_harness.h index 8b5a9c444227..799bd4f8da4b 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -394,7 +394,8 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest { virtual void expectExtraHeaders(FakeStream&) {} - HelloworldRequestPtr createRequest(const TestMetadata& initial_metadata) { + HelloworldRequestPtr createRequest(const TestMetadata& initial_metadata, + bool expect_upstream_request = true) { auto request = std::make_unique(dispatcher_helper_); EXPECT_CALL(*request, onCreateInitialMetadata(_)) .WillOnce(Invoke([&initial_metadata](Http::HeaderMap& headers) { @@ -421,6 +422,10 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest { active_span, Http::AsyncClient::RequestOptions()); EXPECT_NE(request->grpc_request_, nullptr); + if (!expect_upstream_request) { + return request; + } + if (!fake_connection_) { AssertionResult result = fake_upstream_->waitForHttpConnection(*dispatcher_, fake_connection_); @@ -556,6 +561,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { tls_cert->mutable_private_key()->set_filename( TestEnvironment::runfilesPath("test/config/integration/certs/clientkey.pem")); } + auto cfg = std::make_unique( tls_context, factory_context_); @@ -587,6 +593,13 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { validation_context->mutable_trusted_ca()->set_filename( TestEnvironment::runfilesPath("test/config/integration/certs/cacert.pem")); } + if (use_server_tls_13_) { + auto* tls_params = common_tls_context->mutable_tls_params(); + tls_params->set_tls_minimum_protocol_version( + envoy::extensions::transport_sockets::tls::v3::TlsParameters::TLSv1_3); + tls_params->set_tls_maximum_protocol_version( + envoy::extensions::transport_sockets::tls::v3::TlsParameters::TLSv1_3); + } auto cfg = std::make_unique( tls_context, factory_context_); @@ -598,6 +611,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { } bool use_client_cert_{}; + bool use_server_tls_13_{false}; testing::NiceMock factory_context_; }; diff --git a/test/common/http/async_client_impl_test.cc b/test/common/http/async_client_impl_test.cc index 1d706dbe24aa..ea7327da21a6 100644 --- a/test/common/http/async_client_impl_test.cc +++ b/test/common/http/async_client_impl_test.cc @@ -369,6 +369,50 @@ TEST_F(AsyncClientImplTest, OngoingRequestWithWatermarkingAndReset) { stream_encoder_.getStream().resetStream(StreamResetReason::RemoteReset); } +TEST_F(AsyncClientImplTest, OngoingRequestWithResetAfterCompletion) { + auto headers = std::make_unique(); + HttpTestUtility::addDefaultHeaders(*headers); + TestRequestHeaderMapImpl headers_copy = *headers; + + Buffer::OwnedImpl data("test data"); + const Buffer::OwnedImpl data_copy(data.toString()); + + EXPECT_CALL(cm_.thread_local_cluster_.conn_pool_, newStream(_, _, _)) + .WillOnce(Invoke( + [&](ResponseDecoder& decoder, ConnectionPool::Callbacks& callbacks, + const ConnectionPool::Instance::StreamOptions&) -> ConnectionPool::Cancellable* { + callbacks.onPoolReady(stream_encoder_, cm_.thread_local_cluster_.conn_pool_.host_, + stream_info_, {}); + response_decoder_ = &decoder; + return nullptr; + })); + + headers_copy.addCopy("x-envoy-internal", "true"); + headers_copy.addCopy("x-forwarded-for", "127.0.0.1"); + + EXPECT_CALL(stream_encoder_, encodeHeaders(HeaderMapEqualRef(&headers_copy), false)); + EXPECT_CALL(stream_encoder_, encodeData(BufferEqual(&data_copy), true)); + + AsyncClient::OngoingRequest* request = + client_.startRequest(std::move(headers), callbacks_, AsyncClient::RequestOptions()); + EXPECT_NE(request, nullptr); + + request->sendData(data, true); + + expectSuccess(request, 200); + + ResponseHeaderMapPtr response_headers(new TestResponseHeaderMapImpl{{":status", "200"}}); + response_decoder_->decodeHeaders(std::move(response_headers), true); + + request->reset(); + EXPECT_EQ( + 1UL, + cm_.thread_local_cluster_.cluster_.info_->stats_store_.counter("upstream_rq_200").value()); + EXPECT_EQ(1UL, cm_.thread_local_cluster_.cluster_.info_->stats_store_ + .counter("internal.upstream_rq_200") + .value()); +} + TEST_F(AsyncClientImplTracingTest, Basic) { Tracing::MockSpan* child_span{new Tracing::MockSpan()}; message_->body().add("test body"); @@ -1444,6 +1488,50 @@ TEST_F(AsyncClientImplTracingTest, CancelRequest) { request->cancel(); } +TEST_F(AsyncClientImplTracingTest, CancelRequestAfterComplete) { + Tracing::MockSpan* child_span{new Tracing::MockSpan()}; + EXPECT_CALL(cm_.thread_local_cluster_.conn_pool_, newStream(_, _, _)) + .WillOnce(Invoke( + [&](StreamDecoder&, ConnectionPool::Callbacks& callbacks, + const ConnectionPool::Instance::StreamOptions&) -> ConnectionPool::Cancellable* { + callbacks.onPoolReady(stream_encoder_, cm_.thread_local_cluster_.conn_pool_.host_, + stream_info_, {}); + return nullptr; + })); + + EXPECT_CALL(parent_span_, spawnChild_(_, "async fake_cluster egress", _)) + .WillOnce(Return(child_span)); + + AsyncClient::RequestOptions options = AsyncClient::RequestOptions().setParentSpan(parent_span_); + EXPECT_CALL(*child_span, setSampled(true)); + EXPECT_CALL(*child_span, injectContext(_, _)); + EXPECT_CALL(callbacks_, onBeforeFinalizeUpstreamSpan(_, _)) + .WillOnce(Invoke([](Tracing::Span& span, const Http::ResponseHeaderMap* response_headers) { + span.setTag("onBeforeFinalizeUpstreamSpan", "called"); + // Since this is a failure, we expect no response headers. + ASSERT_EQ(nullptr, response_headers); + })); + AsyncClient::Request* request = client_.send(std::move(message_), callbacks_, options); + + EXPECT_CALL(*child_span, setTag(Eq("onBeforeFinalizeUpstreamSpan"), Eq("called"))); + EXPECT_CALL(*child_span, + setTag(Eq(Tracing::Tags::get().Component), Eq(Tracing::Tags::get().Proxy))); + EXPECT_CALL(*child_span, setTag(Eq(Tracing::Tags::get().HttpProtocol), Eq("HTTP/1.1"))); + EXPECT_CALL(*child_span, setTag(Eq(Tracing::Tags::get().UpstreamAddress), Eq("10.0.0.1:443"))); + EXPECT_CALL(*child_span, setTag(Eq(Tracing::Tags::get().PeerAddress), Eq("10.0.0.1:443"))); + + EXPECT_CALL(*child_span, setTag(Eq(Tracing::Tags::get().UpstreamCluster), Eq("fake_cluster"))); + EXPECT_CALL(*child_span, + setTag(Eq(Tracing::Tags::get().UpstreamClusterName), Eq("observability_name"))); + EXPECT_CALL(*child_span, setTag(Eq(Tracing::Tags::get().HttpStatusCode), Eq("0"))); + EXPECT_CALL(*child_span, setTag(Eq(Tracing::Tags::get().ResponseFlags), Eq("-"))); + EXPECT_CALL(*child_span, setTag(Eq(Tracing::Tags::get().Error), Eq(Tracing::Tags::get().True))); + EXPECT_CALL(*child_span, + setTag(Eq(Tracing::Tags::get().Canceled), Eq(Tracing::Tags::get().True))); + EXPECT_CALL(*child_span, finishSpan()); + request->cancel(); +} + TEST_F(AsyncClientImplTest, DestroyWithActiveStream) { EXPECT_CALL(cm_.thread_local_cluster_.conn_pool_, newStream(_, _, _)) .WillOnce(Invoke( diff --git a/test/common/http/conn_manager_impl_corpus/clusterfuzz-testcase-minimized-conn_manager_impl_fuzz_test-5160321246167040 b/test/common/http/conn_manager_impl_corpus/clusterfuzz-testcase-minimized-conn_manager_impl_fuzz_test-5160321246167040 new file mode 100644 index 000000000000..6d064ff30a6b --- /dev/null +++ b/test/common/http/conn_manager_impl_corpus/clusterfuzz-testcase-minimized-conn_manager_impl_fuzz_test-5160321246167040 @@ -0,0 +1,37 @@ +actions { + new_stream { + request_headers { + headers { + key: ":path" + value: "/" + } + } + } +} +actions { + new_stream { + } +} +actions { + new_stream { + request_headers { + headers { + key: ":path" + value: "/" + } + headers { + key: "upgrade" + value: "connect-udp" + } + } + } +} +actions { + stream_action { + stream_id: 128 + response { + continue_headers { + } + } + } +} diff --git a/test/common/http/conn_manager_impl_fuzz_test.cc b/test/common/http/conn_manager_impl_fuzz_test.cc index d8ce2ffbfa45..cf11c952f996 100644 --- a/test/common/http/conn_manager_impl_fuzz_test.cc +++ b/test/common/http/conn_manager_impl_fuzz_test.cc @@ -94,7 +94,7 @@ class FuzzConfig : public ConnectionManagerConfig { callbacks.streamInfo().setResponseCodeDetails(""); })); EXPECT_CALL(*encoder_filter_, setEncoderFilterCallbacks(_)); - EXPECT_CALL(filter_factory_, createUpgradeFilterChain("WebSocket", _, _)) + EXPECT_CALL(filter_factory_, createUpgradeFilterChain(_, _, _)) .WillRepeatedly(Invoke([&](absl::string_view, const Http::FilterChainFactory::UpgradeMap*, FilterChainManager& manager) -> bool { return filter_factory_.createFilterChain(manager); @@ -239,6 +239,7 @@ class FuzzConfig : public ConnectionManagerConfig { // be changed too return nullptr; } + bool appendLocalOverload() const override { return false; } bool appendXForwardedPort() const override { return false; } bool addProxyProtocolConnectionState() const override { return true; } @@ -341,6 +342,11 @@ class FuzzStream { response_state_ = end_stream ? StreamState::Closed : StreamState::PendingDataOrTrailers; })); + ON_CALL(encoder_, encodeData(_, true)) + .WillByDefault(Invoke([this](const Buffer::Instance&, bool end_stream) -> void { + response_state_ = + end_stream ? StreamState::Closed : StreamState::PendingDataOrTrailers; + })); decoder_->decodeHeaders(std::move(headers), end_stream); return Http::okStatus(); })); diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index 7f9f1f897d52..bd4b458d40f1 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -4430,6 +4430,43 @@ TEST_F(ProxyStatusTest, PopulateProxyStatusWithDetailsAndResponseCode) { EXPECT_EQ(altered_headers->getStatusValue(), "504"); } +TEST_F(ProxyStatusTest, PopulateUnauthorizedProxyStatus) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "true"}}); + proxy_status_config_ = std::make_unique(); + proxy_status_config_->set_remove_details(false); + + initialize(); + + const ResponseHeaderMap* altered_headers = sendRequestWith( + 403, StreamInfo::CoreResponseFlag::UnauthorizedExternalService, /*details=*/"bar"); + + ASSERT_TRUE(altered_headers); + ASSERT_TRUE(altered_headers->ProxyStatus()); + EXPECT_EQ(altered_headers->getProxyStatusValue(), + "custom_server_name; error=connection_refused; details=\"bar; UAEX\""); + EXPECT_EQ(altered_headers->getStatusValue(), "403"); +} + +TEST_F(ProxyStatusTest, NoPopulateUnauthorizedProxyStatus) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "false"}}); + proxy_status_config_ = std::make_unique(); + proxy_status_config_->set_remove_details(false); + + initialize(); + + const ResponseHeaderMap* altered_headers = sendRequestWith( + 403, StreamInfo::CoreResponseFlag::UnauthorizedExternalService, /*details=*/"bar"); + + ASSERT_TRUE(altered_headers); + ASSERT_FALSE(altered_headers->ProxyStatus()); + EXPECT_EQ(altered_headers->getProxyStatusValue(), ""); + EXPECT_EQ(altered_headers->getStatusValue(), "403"); +} + TEST_F(ProxyStatusTest, PopulateProxyStatusWithDetails) { TestScopedRuntime scoped_runtime; scoped_runtime.mergeValues( diff --git a/test/common/http/conn_manager_impl_test_2.cc b/test/common/http/conn_manager_impl_test_2.cc index 287507afa2a1..83b3971523f7 100644 --- a/test/common/http/conn_manager_impl_test_2.cc +++ b/test/common/http/conn_manager_impl_test_2.cc @@ -2489,10 +2489,64 @@ TEST_F(HttpConnectionManagerImplTest, DisableHttp2KeepAliveWhenOverloaded) { EXPECT_EQ(1, stats_.named_.downstream_cx_overload_disable_keepalive_.value()); } +TEST_F(HttpConnectionManagerImplTest, CodecCreationLoadShedPointCanCloseConnection) { + Server::MockLoadShedPoint close_connection_creating_codec_point; + EXPECT_CALL(overload_manager_, + getLoadShedPoint(Server::LoadShedPointName::get().HcmCodecCreation)) + .WillOnce(Return(&close_connection_creating_codec_point)); + EXPECT_CALL(overload_manager_, + getLoadShedPoint(Server::LoadShedPointName::get().HcmDecodeHeaders)) + .WillOnce(Return(nullptr)); + + setup(false, ""); + + EXPECT_CALL(close_connection_creating_codec_point, shouldShedLoad()).WillOnce(Return(true)); + EXPECT_CALL(filter_callbacks_.connection_, close(_, _)); + + Buffer::OwnedImpl fake_input("hello"); + conn_manager_->onData(fake_input, false); + + delete codec_; + EXPECT_EQ(1U, stats_.named_.downstream_rq_overload_close_.value()); + EXPECT_TRUE(filter_callbacks_.connection().streamInfo().hasResponseFlag( + StreamInfo::CoreResponseFlag::OverloadManager)); +} + +TEST_F(HttpConnectionManagerImplTest, CodecCreationLoadShedPointBypasscheck) { + Server::MockLoadShedPoint close_connection_creating_codec_point; + EXPECT_CALL(overload_manager_, + getLoadShedPoint(Server::LoadShedPointName::get().HcmCodecCreation)) + .WillOnce(Return(&close_connection_creating_codec_point)); + EXPECT_CALL(overload_manager_, + getLoadShedPoint(Server::LoadShedPointName::get().HcmDecodeHeaders)) + .WillOnce(Return(nullptr)); + + setup(false, ""); + + EXPECT_CALL(close_connection_creating_codec_point, shouldShedLoad()).WillOnce(Return(false)); + + EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { + conn_manager_->newStream(response_encoder_); + data.drain(2); + return Http::okStatus(); + })); + + Buffer::OwnedImpl fake_input("12"); + conn_manager_->onData(fake_input, false); + conn_manager_->onEvent(Network::ConnectionEvent::RemoteClose); + EXPECT_EQ(0U, stats_.named_.downstream_rq_overload_close_.value()); + EXPECT_FALSE(filter_callbacks_.connection().streamInfo().hasResponseFlag( + StreamInfo::CoreResponseFlag::OverloadManager)); +} + TEST_F(HttpConnectionManagerImplTest, DecodeHeaderLoadShedPointCanRejectNewStreams) { Server::MockLoadShedPoint accept_new_stream_point; - EXPECT_CALL(overload_manager_, getLoadShedPoint(testing::_)) + EXPECT_CALL(overload_manager_, + getLoadShedPoint(Server::LoadShedPointName::get().HcmDecodeHeaders)) .WillOnce(Return(&accept_new_stream_point)); + EXPECT_CALL(overload_manager_, + getLoadShedPoint(Server::LoadShedPointName::get().HcmCodecCreation)) + .WillOnce(Return(nullptr)); setup(false, ""); setupFilterChain(1, 0); diff --git a/test/common/http/conn_manager_impl_test_base.h b/test/common/http/conn_manager_impl_test_base.h index 0ebaebd46bd1..35f474d385c6 100644 --- a/test/common/http/conn_manager_impl_test_base.h +++ b/test/common/http/conn_manager_impl_test_base.h @@ -172,6 +172,7 @@ class HttpConnectionManagerImplMixin : public ConnectionManagerConfig { ServerHeaderValidatorPtr makeHeaderValidator(Protocol protocol) override { return header_validator_factory_.createServerHeaderValidator(protocol, header_validator_stats_); } + bool appendLocalOverload() const override { return false; } bool appendXForwardedPort() const override { return false; } bool addProxyProtocolConnectionState() const override { return add_proxy_protocol_connection_state_; diff --git a/test/common/http/conn_pool_grid_test.cc b/test/common/http/conn_pool_grid_test.cc index afb1fb2c9a70..d9b1fff1fdf6 100644 --- a/test/common/http/conn_pool_grid_test.cc +++ b/test/common/http/conn_pool_grid_test.cc @@ -13,6 +13,7 @@ #include "test/mocks/http/stream_decoder.h" #include "test/mocks/http/stream_encoder.h" #include "test/mocks/network/connection.h" +#include "test/mocks/server/transport_socket_factory_context.h" #include "test/mocks/ssl/mocks.h" #include "test/mocks/upstream/cluster_info.h" #include "test/test_common/simulated_time_system.h" @@ -131,7 +132,10 @@ class ConnectivityGridTest : public Event::TestUsingSimulatedTime, public testin options_({Http::Protocol::Http11, Http::Protocol::Http2, Http::Protocol::Http3}), alternate_protocols_(std::make_shared( dispatcher_, std::vector(), nullptr, 10)), - quic_stat_names_(store_.symbolTable()) {} + quic_stat_names_(store_.symbolTable()) { + ON_CALL(factory_context_.server_context_, threadLocal()) + .WillByDefault(ReturnRef(thread_local_)); + } void initialize() { quic_connection_persistent_info_ = @@ -194,6 +198,9 @@ class ConnectivityGridTest : public Event::TestUsingSimulatedTime, public testin StreamInfo::MockStreamInfo info_; NiceMock encoder_; + + NiceMock factory_context_; + testing::NiceMock thread_local_; }; // Test the first pool successfully connecting. @@ -560,6 +567,22 @@ TEST_F(ConnectivityGridTest, TestCancel) { cancel->cancel(Envoy::ConnectionPool::CancelPolicy::CloseExcess); } +// Test tearing down the grid with active connections. +TEST_F(ConnectivityGridTest, TestTeardown) { + initialize(); + addHttp3AlternateProtocol(); + EXPECT_EQ(grid_->first(), nullptr); + + grid_->newStream(decoder_, callbacks_, + {/*can_send_early_data_=*/false, + /*can_use_http3_=*/true}); + EXPECT_NE(grid_->first(), nullptr); + + // When the grid is reset, pool failure should be called. + EXPECT_CALL(callbacks_.pool_failure_, ready()); + grid_.reset(); +} + // Make sure drains get sent to all active pools. TEST_F(ConnectivityGridTest, Drain) { initialize(); @@ -599,20 +622,18 @@ TEST_F(ConnectivityGridTest, DrainCallbacks) { // The first time a drain is started, both pools should start draining. { EXPECT_CALL(*grid_->first(), - drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete)); + drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainExistingConnections)); EXPECT_CALL(*grid_->second(), - drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete)); - grid_->drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete); + drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainExistingConnections)); + grid_->drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainExistingConnections); } - // The second time, the pools will not see any change. + // The second time a drain is started, both pools should still be notified. { EXPECT_CALL(*grid_->first(), - drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete)) - .Times(0); + drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete)); EXPECT_CALL(*grid_->second(), - drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete)) - .Times(0); + drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete)); grid_->drainConnections(Envoy::ConnectionPool::DrainBehavior::DrainAndDelete); } { @@ -931,7 +952,6 @@ TEST_F(ConnectivityGridTest, Http3FailedH2SuceedsInline) { } // namespace Http } // namespace Envoy -#include "test/mocks/server/transport_socket_factory_context.h" #include "source/common/quic/quic_client_transport_socket_factory.h" namespace Envoy { namespace Http { @@ -943,9 +963,8 @@ TEST_F(ConnectivityGridTest, RealGrid) { dispatcher_.allow_null_callback_ = true; // Set the cluster up to have a quic transport socket. Envoy::Ssl::ClientContextConfigPtr config(new NiceMock()); - NiceMock factory_context; auto factory = - std::make_unique(std::move(config), factory_context); + std::make_unique(std::move(config), factory_context_); factory->initialize(); auto& matcher = static_cast(*cluster_->transport_socket_matcher_); @@ -985,12 +1004,11 @@ TEST_F(ConnectivityGridTest, ConnectionCloseDuringAysnConnect) { dispatcher_.allow_null_callback_ = true; // Set the cluster up to have a quic transport socket. Envoy::Ssl::ClientContextConfigPtr config(new NiceMock()); - NiceMock factory_context; Ssl::ClientContextSharedPtr ssl_context(new Ssl::MockClientContext()); - EXPECT_CALL(factory_context.context_manager_, createSslClientContext(_, _)) + EXPECT_CALL(factory_context_.context_manager_, createSslClientContext(_, _)) .WillOnce(Return(ssl_context)); auto factory = - std::make_unique(std::move(config), factory_context); + std::make_unique(std::move(config), factory_context_); factory->initialize(); auto& matcher = static_cast(*cluster_->transport_socket_matcher_); diff --git a/test/common/http/http2/response_header_corpus/clusterfuzz-testcase-minimized-response_header_fuzz_test-6305229339426816 b/test/common/http/http2/response_header_corpus/clusterfuzz-testcase-minimized-response_header_fuzz_test-6305229339426816 new file mode 100644 index 000000000000..f139d0ad01ed Binary files /dev/null and b/test/common/http/http2/response_header_corpus/clusterfuzz-testcase-minimized-response_header_fuzz_test-6305229339426816 differ diff --git a/test/common/http/http3/conn_pool_test.cc b/test/common/http/http3/conn_pool_test.cc index 75f82c9336e5..9ccccb2f37ec 100644 --- a/test/common/http/http3/conn_pool_test.cc +++ b/test/common/http/http3/conn_pool_test.cc @@ -39,6 +39,7 @@ class MockPoolConnectResultCallback : public PoolConnectResultCallback { class Http3ConnPoolImplTest : public Event::TestUsingSimulatedTime, public testing::Test { public: Http3ConnPoolImplTest() { + ON_CALL(context_.server_context_, threadLocal()).WillByDefault(ReturnRef(thread_local_)); EXPECT_CALL(context_.context_manager_, createSslClientContext(_, _)) .WillRepeatedly(Return(ssl_context_)); factory_.emplace(std::unique_ptr( @@ -86,6 +87,7 @@ class Http3ConnPoolImplTest : public Event::TestUsingSimulatedTime, public testi std::unique_ptr pool_; MockPoolConnectResultCallback connect_result_callback_; std::shared_ptr socket_option_{new Network::MockSocketOption()}; + testing::NiceMock thread_local_; }; class MockQuicClientTransportSocketFactory : public Quic::QuicClientTransportSocketFactory { diff --git a/test/common/json/json_loader_test.cc b/test/common/json/json_loader_test.cc index ecdf90d7135b..ad85fd3e0c21 100644 --- a/test/common/json/json_loader_test.cc +++ b/test/common/json/json_loader_test.cc @@ -510,6 +510,21 @@ TEST_F(JsonLoaderTest, LoadFromStructUnknownValueCase) { "Protobuf value case not implemented"); } +TEST_F(JsonLoaderTest, JsonToMsgpack) { + std::vector msgpack = Factory::jsonToMsgpack("{\"hello\":\"world\"}"); + std::vector expected_bytes = {0x81, 0xA5, 0x68, 0x65, 0x6C, 0x6C, 0x6F, + 0xA5, 0x77, 0x6F, 0x72, 0x6C, 0x64}; + EXPECT_EQ(msgpack, expected_bytes); +} + +TEST_F(JsonLoaderTest, InvalidJsonToMsgpack) { + EXPECT_EQ(0, Factory::jsonToMsgpack("").size()); + EXPECT_EQ(0, Factory::jsonToMsgpack("{").size()); + EXPECT_EQ(0, Factory::jsonToMsgpack("{\"hello\":}").size()); + EXPECT_EQ(0, Factory::jsonToMsgpack("\"hello\":\"world\"}").size()); + EXPECT_EQ(0, Factory::jsonToMsgpack("{\"hello\":\"world\"").size()); +} + } // namespace } // namespace Json } // namespace Envoy diff --git a/test/common/network/connection_impl_test.cc b/test/common/network/connection_impl_test.cc index ee72edec49b4..99661b7e46ca 100644 --- a/test/common/network/connection_impl_test.cc +++ b/test/common/network/connection_impl_test.cc @@ -136,11 +136,11 @@ TEST_P(ConnectionImplDeathTest, BadFd) { Event::DispatcherPtr dispatcher(api->allocateDispatcher("test_thread")); IoHandlePtr io_handle = std::make_unique(); StreamInfo::StreamInfoImpl stream_info(dispatcher->timeSource(), nullptr); - EXPECT_DEATH( + EXPECT_ENVOY_BUG( ConnectionImpl(*dispatcher, std::make_unique(std::move(io_handle), nullptr, nullptr), Network::Test::createRawBufferSocket(), stream_info, false), - ".*assert failure: SOCKET_VALID\\(fd\\)"); + "Client socket failure"); } class TestClientConnectionImpl : public Network::ClientConnectionImpl { diff --git a/test/common/quic/client_connection_factory_impl_test.cc b/test/common/quic/client_connection_factory_impl_test.cc index 6b8f77ae0691..50e5468a2215 100644 --- a/test/common/quic/client_connection_factory_impl_test.cc +++ b/test/common/quic/client_connection_factory_impl_test.cc @@ -27,6 +27,7 @@ class QuicNetworkConnectionTest : public Event::TestUsingSimulatedTime, public testing::TestWithParam { protected: void initialize() { + ON_CALL(context_.server_context_, threadLocal()).WillByDefault(ReturnRef(thread_local_)); EXPECT_CALL(*cluster_, perConnectionBufferLimitBytes()).WillOnce(Return(45)); EXPECT_CALL(*cluster_, connectTimeout).WillOnce(Return(std::chrono::seconds(10))); auto* protocol_options = cluster_->http3_options_.mutable_quic_protocol_options(); @@ -88,6 +89,7 @@ class QuicNetworkConnectionTest : public Event::TestUsingSimulatedTime, QuicStatNames quic_stat_names_{store_.symbolTable()}; quic::DeterministicConnectionIdGenerator connection_id_generator_{ quic::kQuicDefaultConnectionIdLength}; + testing::NiceMock thread_local_; }; TEST_P(QuicNetworkConnectionTest, BufferLimits) { diff --git a/test/common/quic/envoy_quic_proof_verifier_test.cc b/test/common/quic/envoy_quic_proof_verifier_test.cc index f6f7423c9fce..c7eef7189ac1 100644 --- a/test/common/quic/envoy_quic_proof_verifier_test.cc +++ b/test/common/quic/envoy_quic_proof_verifier_test.cc @@ -35,7 +35,7 @@ class EnvoyQuicProofVerifierTest : public testing::Test { public: EnvoyQuicProofVerifierTest() : root_ca_cert_(cert_chain_.substr(cert_chain_.rfind("-----BEGIN CERTIFICATE-----"))), - leaf_cert_([=]() { + leaf_cert_([this]() { std::stringstream pem_stream(cert_chain_); std::vector chain = quic::CertificateView::LoadPemFromStream(&pem_stream); return chain[0]; @@ -399,6 +399,45 @@ TEST_F(EnvoyQuicProofVerifierTest, VerifySubjectAltNameListOverrideFailure) { EXPECT_FALSE(static_cast(*verify_details).isValid()); } +TEST_F(EnvoyQuicProofVerifierTest, VerifyX509v1Cert) { + std::string cert_v1 = R"text( +-----BEGIN CERTIFICATE----- +MIICpDCCAYwCCQClUY4hwG3eCTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlx +dWljLnRlc3QwHhcNMjQwMTMxMDUxNDI1WhcNMjUwMTMwMDUxNDI1WjAUMRIwEAYD +VQQDDAlxdWljLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw +PmbxO63dR1i7yCADA0Q2N6vWzkZ53lsKktSNeAoV5RM6hbH9zt5BR6blZSJ87Ybl +otMUioTb3DIF2z99k/QB8xpXevurZ09z9bMricsIM2LiS1hNyF09h1yPnRCy3BB5 +wEwbovKqDaFbCe09iefvsxGMENyDLA+uoisgxgRGfNJwggGy5WTSvpmnn1iEDmHR +4kEOxlDVHhmWIvr3nGFNuO/YEgPcDVdhu+UVCHan2RDjGX7KfkfNvt6aTLIgq+rO +CnF5/hFYRO4ypn2Lsw1me1n3H3hEm/5MuY7XdTK8tl/ezaIEHjUt5ExnKy0N2AS9 +LcMpoD4L0DFunxMdH72HAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADNHjJNzozcS +APuVQCQnrdw7Drou3AyO47F2kxzheh8iqDU77MaH8aWhwmcpdg1vxhTCGkPRNKD8 +7XUpkh7kdpvfzQex12c3DDnVvgsa26aEXsbyxtV3ty+tiIRzRGAEEH4j5n0322Vd +kcd96WKVplBaYncSiSFCyomAymd+eqhBsVEXDGcf+YtEq8TwGZJ3o0RNm7AfDTu6 +vuvcjdfSQSjwxshGMLq/70K+lYoKKVw6/AaxypJ/YYIHSUtNzu85bO9yW7lG2kov +Ti7PYy9cxmZTjNqHI7Kghk3FLry/6P2bbclZxdtzJAPzZ9nw6N9xGfj2D8+3VALl +wYsML58R3P8= +-----END CERTIFICATE----- +)text"; + + // NOLINTNEXTLINE(modernize-make-shared) + transport_socket_options_.reset(new Network::TransportSocketOptionsImpl("", {"non-example.com"})); + configCertVerificationDetails(true); + const std::string ocsp_response; + const std::string cert_sct; + std::string error_details; + std::unique_ptr verify_details; + std::stringstream pem_stream(cert_v1); + std::vector chain = quic::CertificateView::LoadPemFromStream(&pem_stream); + EXPECT_EQ(quic::QUIC_FAILURE, + verifier_->VerifyCertChain("localhost", 54321, chain, ocsp_response, cert_sct, + &verify_context_, &error_details, &verify_details, nullptr, + nullptr)) + << error_details; + EXPECT_EQ("unable to parse certificate", error_details); + EXPECT_EQ(verify_details, nullptr); +} + TEST_F(EnvoyQuicProofVerifierTest, VerifyProof) { configCertVerificationDetails(true); EXPECT_DEATH(verifier_->VerifyProof("", 0, "", quic::QUIC_VERSION_IETF_RFC_V1, "", {}, "", "", diff --git a/test/common/quic/quic_transport_socket_factory_test.cc b/test/common/quic/quic_transport_socket_factory_test.cc index e2cc6998af3c..154cfb59afea 100644 --- a/test/common/quic/quic_transport_socket_factory_test.cc +++ b/test/common/quic/quic_transport_socket_factory_test.cc @@ -19,6 +19,7 @@ class QuicServerTransportSocketFactoryConfigTest : public Event::TestUsingSimula QuicServerTransportSocketFactoryConfigTest() : server_api_(Api::createApiForTest(server_stats_store_, simTime())) { ON_CALL(context_.server_context_, api()).WillByDefault(ReturnRef(*server_api_)); + ON_CALL(context_.server_context_, threadLocal()).WillByDefault(ReturnRef(thread_local_)); } void verifyQuicServerTransportSocketFactory(std::string yaml, bool expect_early_data) { @@ -35,6 +36,7 @@ class QuicServerTransportSocketFactoryConfigTest : public Event::TestUsingSimula Stats::TestUtil::TestStore server_stats_store_; Api::ApiPtr server_api_; NiceMock context_; + testing::NiceMock thread_local_; }; TEST_F(QuicServerTransportSocketFactoryConfigTest, EarlyDataEnabledByDefault) { @@ -113,6 +115,7 @@ TEST_F(QuicServerTransportSocketFactoryConfigTest, ClientAuthUnsupported) { class QuicClientTransportSocketFactoryTest : public testing::Test { public: QuicClientTransportSocketFactoryTest() { + ON_CALL(context_.server_context_, threadLocal()).WillByDefault(ReturnRef(thread_local_)); EXPECT_CALL(context_.context_manager_, createSslClientContext(_, _)).WillOnce(Return(nullptr)); EXPECT_CALL(*context_config_, setSecretUpdateCallback(_)) .WillOnce(testing::SaveArg<0>(&update_callback_)); @@ -125,6 +128,7 @@ class QuicClientTransportSocketFactoryTest : public testing::Test { NiceMock* context_config_{ new NiceMock}; std::function update_callback_; + testing::NiceMock thread_local_; }; TEST_F(QuicClientTransportSocketFactoryTest, SupportedAlpns) { diff --git a/test/common/router/BUILD b/test/common/router/BUILD index 23037518759d..3a5d4e8ec5c8 100644 --- a/test/common/router/BUILD +++ b/test/common/router/BUILD @@ -276,6 +276,8 @@ envoy_cc_fuzz_test( size = "large", srcs = ["route_fuzz_test.cc"], corpus = ":route_corpus", + # The :config_impl_test_static target does not build with coverage + tags = ["nocoverage"], deps = [ ":route_fuzz_proto_cc_proto", "//source/common/router:config_lib", diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index 32485d71500c..e867650b01e9 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -7570,9 +7570,10 @@ TEST_F(ConfigUtilityTest, ParseDirectResponseBody) { ConfigUtility::parseDirectResponseBody(route, *api_, MaxResponseBodySizeBytes).value()); route.mutable_direct_response()->mutable_body()->set_filename("missing_file"); - EXPECT_THROW_WITH_MESSAGE( - ConfigUtility::parseDirectResponseBody(route, *api_, MaxResponseBodySizeBytes).IgnoreError(), - EnvoyException, "file missing_file does not exist"); + EXPECT_EQ(ConfigUtility::parseDirectResponseBody(route, *api_, MaxResponseBodySizeBytes) + .status() + .message(), + "file missing_file does not exist"); // The default max body size in bytes is 4096 (MaxResponseBodySizeBytes). const std::string body(MaxResponseBodySizeBytes + 1, '*'); @@ -7587,10 +7588,10 @@ TEST_F(ConfigUtilityTest, ParseDirectResponseBody) { auto filename = TestEnvironment::writeStringToFileForTest("body", body); route.mutable_direct_response()->mutable_body()->set_filename(filename); expected_message = "file " + filename + " size is 4097 bytes; maximum is 2048"; - EXPECT_THROW_WITH_MESSAGE( - ConfigUtility::parseDirectResponseBody(route, *api_, MaxResponseBodySizeBytes / 2) - .IgnoreError(), - EnvoyException, expected_message); + EXPECT_EQ(ConfigUtility::parseDirectResponseBody(route, *api_, MaxResponseBodySizeBytes / 2) + .status() + .message(), + expected_message); // Update the max body size to 4098 bytes (MaxResponseBodySizeBytes + 2), hence the parsing is // successful. diff --git a/test/common/router/header_parser_corpus/empty_filter_metadata_key b/test/common/router/header_parser_corpus/empty_filter_metadata_key new file mode 100644 index 000000000000..14515621b572 --- /dev/null +++ b/test/common/router/header_parser_corpus/empty_filter_metadata_key @@ -0,0 +1,22 @@ +headers_to_add { + header { + key: "@" + value: "%START_TIME()%%DYNAMIC_METADATA(:)%" + } +} +stream_info { + dynamic_metadata { + filter_metadata { + key: "" + value { + fields { + key: "" + value { + string_value: "\n#\022\034type.geco_nosode {\n lueList\n\001\'80\n%\032\001]\022\034type.geco_nedsoo {\n lueList\n\00080\n\"\022\034type.geco_nosode {\n lueList\n\00080" + } + } + } + } + } + requested_server_name: "file.Optio^s" +} diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index 1fce4783c62a..841e0380d39e 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -2737,6 +2737,69 @@ TEST_F(RouterTest, RetryRequestDuringBodyDataBetweenAttemptsNotEndStream) { EXPECT_TRUE(verifyHostUpstreamStats(1, 1)); } +// Test when the upstream request gets reset while the client is sending the body +// with more data arriving but not buffering any data. +TEST_F(RouterTest, UpstreamResetDuringBodyDataTransferNotBufferingNotEndStream) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.send_local_reply_when_no_buffer_and_upstream_request", "true"}}); + + Buffer::OwnedImpl decoding_buffer; + EXPECT_CALL(callbacks_, decodingBuffer()).WillRepeatedly(Return(&decoding_buffer)); + EXPECT_CALL(callbacks_, addDecodedData(_, true)) + .WillRepeatedly(Invoke([&](Buffer::Instance& data, bool) { decoding_buffer.move(data); })); + + NiceMock encoder1; + Http::ResponseDecoder* response_decoder = nullptr; + expectNewStreamWithImmediateEncoder(encoder1, &response_decoder, Http::Protocol::Http10); + + Http::TestRequestHeaderMapImpl headers{{"x-envoy-internal", "true"}, {"myheader", "present"}}; + HttpTestUtility::addDefaultHeaders(headers); + router_->decodeHeaders(headers, false); + const std::string body1("body1"); + Buffer::OwnedImpl buf1(body1); + + // Send data while the upstream request is reset, should not have any failure. + encoder1.stream_.resetStream(Http::StreamResetReason::RemoteReset); + router_->decodeData(buf1, false); + + EXPECT_EQ(callbacks_.details(), "upstream_reset_before_response_started"); + EXPECT_TRUE(verifyHostUpstreamStats(0, 1)); +} + +// Test the original branch when local_reply_when_no_buffer_and_upstream_request runtime is false. +TEST_F(RouterTest, NormalPathUpstreamResetDuringBodyDataTransferNotBuffering) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.send_local_reply_when_no_buffer_and_upstream_request", + "false"}}); + + Buffer::OwnedImpl decoding_buffer; + EXPECT_CALL(callbacks_, decodingBuffer()).WillRepeatedly(Return(&decoding_buffer)); + EXPECT_CALL(callbacks_, addDecodedData(_, true)) + .WillRepeatedly(Invoke([&](Buffer::Instance& data, bool) { decoding_buffer.move(data); })); + + NiceMock encoder1; + Http::ResponseDecoder* response_decoder = nullptr; + expectNewStreamWithImmediateEncoder(encoder1, &response_decoder, Http::Protocol::Http10); + + Http::TestRequestHeaderMapImpl headers{{"x-envoy-internal", "true"}, {"myheader", "present"}}; + HttpTestUtility::addDefaultHeaders(headers); + router_->decodeHeaders(headers, false); + + const std::string body1("body1"); + Buffer::OwnedImpl buf1(body1); + router_->decodeData(buf1, true); + EXPECT_EQ(1U, + callbacks_.route_->route_entry_.virtual_cluster_.stats().upstream_rq_total_.value()); + + Http::ResponseHeaderMapPtr response_headers( + new Http::TestResponseHeaderMapImpl{{":status", "200"}}); + response_decoder->decodeHeaders(std::move(response_headers), true); + + EXPECT_TRUE(verifyHostUpstreamStats(1, 0)); +} + // Test retrying a request, when the first attempt fails while the client // is sending the body, with the rest of the request arriving in between upstream // request attempts. diff --git a/test/common/runtime/runtime_impl_test.cc b/test/common/runtime/runtime_impl_test.cc index f040aedfbcf8..38616f014735 100644 --- a/test/common/runtime/runtime_impl_test.cc +++ b/test/common/runtime/runtime_impl_test.cc @@ -550,12 +550,12 @@ TEST_F(StaticLoaderImplTest, QuicheReloadableFlags) { envoy.reloadable_features.FLAGS_envoy_quic_reloadable_flag_quic_testonly_default_true: false envoy.reloadable_features.FLAGS_envoy_quic_reloadable_flag_spdy_testonly_default_false: false )EOF"); - SetQuicReloadableFlag(spdy_testonly_default_false, true); - EXPECT_TRUE(GetQuicReloadableFlag(spdy_testonly_default_false)); + SetQuicheReloadableFlag(spdy, spdy_testonly_default_false, true); + EXPECT_TRUE(GetQuicheReloadableFlag(spdy, spdy_testonly_default_false)); setup(); EXPECT_TRUE(GetQuicReloadableFlag(quic_testonly_default_false)); EXPECT_FALSE(GetQuicReloadableFlag(quic_testonly_default_true)); - EXPECT_FALSE(GetQuicReloadableFlag(spdy_testonly_default_false)); + EXPECT_FALSE(GetQuicheReloadableFlag(spdy, spdy_testonly_default_false)); // Test that Quiche flags can be overwritten again. base_ = TestUtility::parseYaml(R"EOF( @@ -564,7 +564,7 @@ TEST_F(StaticLoaderImplTest, QuicheReloadableFlags) { setup(); EXPECT_TRUE(GetQuicReloadableFlag(quic_testonly_default_false)); EXPECT_TRUE(GetQuicReloadableFlag(quic_testonly_default_true)); - EXPECT_FALSE(GetQuicReloadableFlag(spdy_testonly_default_false)); + EXPECT_FALSE(GetQuicheReloadableFlag(spdy, spdy_testonly_default_false)); } #endif @@ -987,8 +987,8 @@ TEST_F(RtdsLoaderImplTest, UnexpectedSizeEmpty) { EXPECT_CALL(rtds_init_callback_, Call()); EXPECT_EQ(rtds_callbacks_[0]->onConfigUpdate({}, "").message(), - "Unexpected RTDS resource length, number of added recources 0, number " - "of removed recources 0"); + "Unexpected RTDS resource length, number of added resources 0, number of removed " + "resources 0"); EXPECT_EQ(0, store_.counter("runtime.load_error").value()); EXPECT_EQ(1, store_.counter("runtime.load_success").value()); @@ -1005,8 +1005,8 @@ TEST_F(RtdsLoaderImplTest, UnexpectedSizeTooMany) { EXPECT_CALL(rtds_init_callback_, Call()); EXPECT_EQ(rtds_callbacks_[0]->onConfigUpdate(decoded_resources.refvec_, "").message(), - "Unexpected RTDS resource length, number of added recources 2, number " - "of removed recources 0"); + "Unexpected RTDS resource length, number of added resources 2, number of removed " + "resources 0"); EXPECT_EQ(0, store_.counter("runtime.load_error").value()); EXPECT_EQ(1, store_.counter("runtime.load_success").value()); diff --git a/test/common/secret/sds_api_test.cc b/test/common/secret/sds_api_test.cc index 7ea7109e68e9..2cb819a4c02a 100644 --- a/test/common/secret/sds_api_test.cc +++ b/test/common/secret/sds_api_test.cc @@ -793,7 +793,7 @@ name: "encryption_key" const std::string secret_path = "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/aes_128_key"; EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(secret_path)), - Config::DataSource::read(generic_secret.secret(), true, *api_)); + Config::DataSource::read(generic_secret.secret(), true, *api_).value()); } // Validate that SdsApi throws exception if an empty secret is passed to onConfigUpdate(). diff --git a/test/common/stream_info/uint32_accessor_impl_test.cc b/test/common/stream_info/uint32_accessor_impl_test.cc index 156d89a3e3ca..62f5b542e233 100644 --- a/test/common/stream_info/uint32_accessor_impl_test.cc +++ b/test/common/stream_info/uint32_accessor_impl_test.cc @@ -19,6 +19,25 @@ TEST(UInt32AccessorImplTest, IncrementValue) { EXPECT_EQ(0xdeadbef0, accessor.value()); } +TEST(UInt32AccessorImplTest, TestProto) { + uint32_t init_value = 0xdeadbeef; + UInt32AccessorImpl accessor(init_value); + auto message = accessor.serializeAsProto(); + EXPECT_NE(nullptr, message); + + auto* uint32_struct = dynamic_cast(message.get()); + EXPECT_NE(nullptr, uint32_struct); + EXPECT_EQ(init_value, uint32_struct->value()); +} + +TEST(UInt32AccessorImplTest, TestString) { + uint32_t init_value = 0xdeadbeef; + UInt32AccessorImpl accessor(init_value); + absl::optional value = accessor.serializeAsString(); + ASSERT_TRUE(value.has_value()); + EXPECT_EQ(value, std::to_string(init_value)); +} + } // namespace } // namespace StreamInfo } // namespace Envoy diff --git a/test/common/stream_info/uint64_accessor_impl_test.cc b/test/common/stream_info/uint64_accessor_impl_test.cc index 8f143429339e..876700191938 100644 --- a/test/common/stream_info/uint64_accessor_impl_test.cc +++ b/test/common/stream_info/uint64_accessor_impl_test.cc @@ -31,6 +31,14 @@ TEST(UInt64AccessorImplTest, TestProto) { EXPECT_EQ(init_value, uint64_struct->value()); } +TEST(UInt64AccessorImplTest, TestString) { + uint64_t init_value = 0xdeadbeefdeadbeef; + UInt64AccessorImpl accessor(init_value); + absl::optional value = accessor.serializeAsString(); + ASSERT_TRUE(value.has_value()); + EXPECT_EQ(value, std::to_string(init_value)); +} + } // namespace } // namespace StreamInfo } // namespace Envoy diff --git a/test/common/stream_info/utility_test.cc b/test/common/stream_info/utility_test.cc index 21e6f69c6877..60ec543ab3b5 100644 --- a/test/common/stream_info/utility_test.cc +++ b/test/common/stream_info/utility_test.cc @@ -368,16 +368,61 @@ TEST(ProxyStatusFromStreamInfo, TestAll) { TestScopedRuntime scoped_runtime; scoped_runtime.mergeValues( {{"envoy.reloadable_features.proxy_status_upstream_request_timeout", "true"}}); + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "false"}}); + for (const auto& [response_flag, proxy_status_error] : + std::vector>{ + {CoreResponseFlag::FailedLocalHealthCheck, ProxyStatusError::DestinationUnavailable}, + {CoreResponseFlag::NoHealthyUpstream, ProxyStatusError::DestinationUnavailable}, + {CoreResponseFlag::UpstreamRequestTimeout, ProxyStatusError::HttpResponseTimeout}, + {CoreResponseFlag::LocalReset, ProxyStatusError::ConnectionTimeout}, + {CoreResponseFlag::UpstreamRemoteReset, ProxyStatusError::ConnectionTerminated}, + {CoreResponseFlag::UpstreamConnectionFailure, ProxyStatusError::ConnectionRefused}, + {CoreResponseFlag::UpstreamConnectionTermination, + ProxyStatusError::ConnectionTerminated}, + {CoreResponseFlag::UpstreamOverflow, ProxyStatusError::ConnectionLimitReached}, + {CoreResponseFlag::NoRouteFound, ProxyStatusError::DestinationNotFound}, + {CoreResponseFlag::RateLimited, ProxyStatusError::ConnectionLimitReached}, + {CoreResponseFlag::RateLimitServiceError, ProxyStatusError::ConnectionLimitReached}, + {CoreResponseFlag::UpstreamRetryLimitExceeded, ProxyStatusError::DestinationUnavailable}, + {CoreResponseFlag::StreamIdleTimeout, ProxyStatusError::HttpResponseTimeout}, + {CoreResponseFlag::InvalidEnvoyRequestHeaders, ProxyStatusError::HttpRequestError}, + {CoreResponseFlag::DownstreamProtocolError, ProxyStatusError::HttpRequestError}, + {CoreResponseFlag::UpstreamMaxStreamDurationReached, + ProxyStatusError::HttpResponseTimeout}, + {CoreResponseFlag::NoFilterConfigFound, ProxyStatusError::ProxyConfigurationError}, + {CoreResponseFlag::UpstreamProtocolError, ProxyStatusError::HttpProtocolError}, + {CoreResponseFlag::NoClusterFound, ProxyStatusError::DestinationUnavailable}, + {CoreResponseFlag::DnsResolutionFailed, ProxyStatusError::DnsError}}) { + NiceMock stream_info; + ON_CALL(stream_info, hasResponseFlag(response_flag)).WillByDefault(Return(true)); + EXPECT_THAT(ProxyStatusUtils::fromStreamInfo(stream_info), proxy_status_error); + } +} + +TEST(ProxyStatusFromStreamInfo, TestNewAll) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.proxy_status_upstream_request_timeout", "true"}}); + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.proxy_status_mapping_more_core_response_flags", "true"}}); for (const auto& [response_flag, proxy_status_error] : std::vector>{ {CoreResponseFlag::FailedLocalHealthCheck, ProxyStatusError::DestinationUnavailable}, {CoreResponseFlag::NoHealthyUpstream, ProxyStatusError::DestinationUnavailable}, {CoreResponseFlag::UpstreamRequestTimeout, ProxyStatusError::HttpResponseTimeout}, + {CoreResponseFlag::DurationTimeout, ProxyStatusError::ConnectionTimeout}, {CoreResponseFlag::LocalReset, ProxyStatusError::ConnectionTimeout}, {CoreResponseFlag::UpstreamRemoteReset, ProxyStatusError::ConnectionTerminated}, {CoreResponseFlag::UpstreamConnectionFailure, ProxyStatusError::ConnectionRefused}, + {CoreResponseFlag::UnauthorizedExternalService, ProxyStatusError::ConnectionRefused}, {CoreResponseFlag::UpstreamConnectionTermination, ProxyStatusError::ConnectionTerminated}, + {CoreResponseFlag::DownstreamConnectionTermination, + ProxyStatusError::ConnectionTerminated}, + {CoreResponseFlag::OverloadManager, ProxyStatusError::ConnectionLimitReached}, + {CoreResponseFlag::DropOverLoad, ProxyStatusError::ConnectionLimitReached}, + {CoreResponseFlag::FaultInjected, ProxyStatusError::HttpRequestError}, {CoreResponseFlag::UpstreamOverflow, ProxyStatusError::ConnectionLimitReached}, {CoreResponseFlag::NoRouteFound, ProxyStatusError::DestinationNotFound}, {CoreResponseFlag::RateLimited, ProxyStatusError::ConnectionLimitReached}, diff --git a/test/common/tcp/async_tcp_client_impl_test.cc b/test/common/tcp/async_tcp_client_impl_test.cc index a08a1e7576df..97e5d64c5129 100644 --- a/test/common/tcp/async_tcp_client_impl_test.cc +++ b/test/common/tcp/async_tcp_client_impl_test.cc @@ -245,10 +245,47 @@ TEST_F(AsyncTcpClientImplTest, TestActiveCx) { expectCreateConnection(); EXPECT_EQ(1UL, cluster_manager_.thread_local_cluster_.cluster_.info_->traffic_stats_ ->upstream_cx_active_.value()); - client_.reset(); + EXPECT_CALL(callbacks_, onEvent(Network::ConnectionEvent::LocalClose)); + connection_->raiseEvent(Network::ConnectionEvent::LocalClose); + EXPECT_EQ(0UL, cluster_manager_.thread_local_cluster_.cluster_.info_->traffic_stats_ + ->upstream_cx_active_.value()); +} + +TEST_F(AsyncTcpClientImplTest, TestActiveCxWhileNotConnected) { + setUpClient(); + expectCreateConnection(false); + EXPECT_EQ(1UL, cluster_manager_.thread_local_cluster_.cluster_.info_->traffic_stats_ + ->upstream_cx_active_.value()); + EXPECT_CALL(callbacks_, onEvent(Network::ConnectionEvent::LocalClose)); + connection_->raiseEvent(Network::ConnectionEvent::LocalClose); EXPECT_EQ(0UL, cluster_manager_.thread_local_cluster_.cluster_.info_->traffic_stats_ ->upstream_cx_active_.value()); } +TEST_F(AsyncTcpClientImplTest, ReconnectWhileClientConnected) { + setUpClient(); + expectCreateConnection(); + EXPECT_FALSE(client_->connect()); +} + +TEST_F(AsyncTcpClientImplTest, ReconnectWhileClientConnecting) { + setUpClient(); + expectCreateConnection(false); + EXPECT_FALSE(client_->connect()); +} + +TEST_F(AsyncTcpClientImplTest, ReconnectAfterClientDisconnected) { + setUpClient(); + expectCreateConnection(); + + EXPECT_CALL(callbacks_, onEvent(Network::ConnectionEvent::LocalClose)); + connection_->raiseEvent(Network::ConnectionEvent::LocalClose); + connect_timer_ = new NiceMock(&dispatcher_); + expectCreateConnection(); + + EXPECT_EQ(2UL, cluster_manager_.thread_local_cluster_.cluster_.info_->traffic_stats_ + ->upstream_cx_total_.value()); +} + } // namespace Tcp } // namespace Envoy diff --git a/test/common/tcp_proxy/tcp_proxy_test.cc b/test/common/tcp_proxy/tcp_proxy_test.cc index 41a2ce805c99..41ad163dba41 100644 --- a/test/common/tcp_proxy/tcp_proxy_test.cc +++ b/test/common/tcp_proxy/tcp_proxy_test.cc @@ -21,6 +21,7 @@ #include "source/common/network/upstream_socket_options_filter_state.h" #include "source/common/network/win32_redirect_records_option_impl.h" #include "source/common/router/metadatamatchcriteria_impl.h" +#include "source/common/stream_info/uint64_accessor_impl.h" #include "source/common/tcp_proxy/tcp_proxy.h" #include "source/common/upstream/upstream_impl.h" @@ -102,7 +103,7 @@ class TcpProxyTest : public TcpProxyTestBase { .RetiresOnSaturation(); EXPECT_CALL(conn_pool_, newConnection(_)) .WillOnce(Invoke( - [=](Tcp::ConnectionPool::Callbacks& cb) -> Tcp::ConnectionPool::Cancellable* { + [=, this](Tcp::ConnectionPool::Callbacks& cb) -> Tcp::ConnectionPool::Cancellable* { conn_pool_callbacks_.push_back(&cb); return onNewConnection(conn_pool_handles_.at(i).get()); })) @@ -815,6 +816,65 @@ TEST_F(TcpProxyTest, UpstreamConnectionLimit) { EXPECT_EQ(access_log_data_, "UO"); } +TEST_F(TcpProxyTest, IdleTimeoutObjectFactory) { + const std::string name = "envoy.tcp_proxy.per_connection_idle_timeout_ms"; + auto* factory = + Registry::FactoryRegistry::getFactory(name); + ASSERT_NE(nullptr, factory); + EXPECT_EQ(name, factory->name()); + const std::string duration_in_milliseconds = std::to_string(1234); + auto object = factory->createFromBytes(duration_in_milliseconds); + ASSERT_NE(nullptr, object); + EXPECT_EQ(duration_in_milliseconds, object->serializeAsString()); +} + +TEST_F(TcpProxyTest, InvalidIdleTimeoutObjectFactory) { + const std::string name = "envoy.tcp_proxy.per_connection_idle_timeout_ms"; + auto* factory = + Registry::FactoryRegistry::getFactory(name); + ASSERT_NE(nullptr, factory); + EXPECT_EQ(name, factory->name()); + ASSERT_EQ(nullptr, factory->createFromBytes("not_a_number")); +} + +TEST_F(TcpProxyTest, IdleTimeoutWithFilterStateOverride) { + envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy config = defaultConfig(); + config.mutable_idle_timeout()->set_seconds(1); + setup(1, config); + + uint64_t idle_timeout_override = 5000; + + // Although the configured idle timeout is 1 second, overriding the value through filter state + // so the expected idle timeout is 5 seconds instead. + filter_callbacks_.connection_.streamInfo().filterState()->setData( + TcpProxy::PerConnectionIdleTimeoutMs, + std::make_unique(idle_timeout_override), + StreamInfo::FilterState::StateType::ReadOnly, StreamInfo::FilterState::LifeSpan::Connection); + + Event::MockTimer* idle_timer = new Event::MockTimer(&filter_callbacks_.connection_.dispatcher_); + EXPECT_CALL(*idle_timer, enableTimer(std::chrono::milliseconds(idle_timeout_override), _)); + raiseEventUpstreamConnected(0); + + Buffer::OwnedImpl buffer("hello"); + EXPECT_CALL(*idle_timer, enableTimer(std::chrono::milliseconds(idle_timeout_override), _)); + filter_->onData(buffer, false); + + buffer.add("hello2"); + EXPECT_CALL(*idle_timer, enableTimer(std::chrono::milliseconds(idle_timeout_override), _)); + upstream_callbacks_->onUpstreamData(buffer, false); + + EXPECT_CALL(*idle_timer, enableTimer(std::chrono::milliseconds(idle_timeout_override), _)); + filter_callbacks_.connection_.raiseBytesSentCallbacks(1); + + EXPECT_CALL(*idle_timer, enableTimer(std::chrono::milliseconds(idle_timeout_override), _)); + upstream_connections_.at(0)->raiseBytesSentCallbacks(2); + + EXPECT_CALL(*upstream_connections_.at(0), close(Network::ConnectionCloseType::NoFlush, _)); + EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::NoFlush, _)); + EXPECT_CALL(*idle_timer, disableTimer()); + idle_timer->invokeCallback(); +} + // Tests that the idle timer closes both connections, and gets updated when either // connection has activity. TEST_F(TcpProxyTest, IdleTimeout) { diff --git a/test/common/tcp_proxy/tcp_proxy_test_base.h b/test/common/tcp_proxy/tcp_proxy_test_base.h index fa621fccf6b2..9816df3871d9 100644 --- a/test/common/tcp_proxy/tcp_proxy_test_base.h +++ b/test/common/tcp_proxy/tcp_proxy_test_base.h @@ -121,7 +121,7 @@ class TcpProxyTestBase : public testing::Test { void raiseEventUpstreamConnected(uint32_t conn_index) { EXPECT_CALL(filter_callbacks_.connection_, readDisable(false)); EXPECT_CALL(*upstream_connection_data_.at(conn_index), addUpstreamCallbacks(_)) - .WillOnce(Invoke([=](Tcp::ConnectionPool::UpstreamCallbacks& cb) -> void { + .WillOnce(Invoke([=, this](Tcp::ConnectionPool::UpstreamCallbacks& cb) -> void { upstream_callbacks_ = &cb; // Simulate TCP conn pool upstream callbacks. This is safe because the TCP proxy never diff --git a/test/common/tcp_proxy/upstream_test.cc b/test/common/tcp_proxy/upstream_test.cc index 7b27fecdf266..d48d9690c602 100644 --- a/test/common/tcp_proxy/upstream_test.cc +++ b/test/common/tcp_proxy/upstream_test.cc @@ -201,6 +201,28 @@ TEST_P(HttpUpstreamTest, UpstreamTrailersMarksDoneReading) { this->upstream_->responseDecoder().decodeTrailers(std::move(trailers)); } +TEST_P(HttpUpstreamTest, UpstreamTrailersPropagateFinDownstream) { + setupUpstream(); + EXPECT_CALL(encoder_.stream_, resetStream(_)).Times(0); + upstream_->doneWriting(); + EXPECT_CALL(callbacks_, onUpstreamData(BufferStringEqual(""), true)); + Http::ResponseTrailerMapPtr trailers{new Http::TestResponseTrailerMapImpl{{"key", "value"}}}; + upstream_->responseDecoder().decodeTrailers(std::move(trailers)); +} + +TEST_P(HttpUpstreamTest, UpstreamTrailersDontPropagateFinDownstreamWhenFeatureDisabled) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.tcp_tunneling_send_downstream_fin_on_upstream_trailers", + "false"}}); + setupUpstream(); + EXPECT_CALL(encoder_.stream_, resetStream(_)).Times(0); + upstream_->doneWriting(); + EXPECT_CALL(callbacks_, onUpstreamData(_, _)).Times(0); + Http::ResponseTrailerMapPtr trailers{new Http::TestResponseTrailerMapImpl{{"key", "value"}}}; + upstream_->responseDecoder().decodeTrailers(std::move(trailers)); +} + class HttpUpstreamRequestEncoderTest : public testing::TestWithParam { public: HttpUpstreamRequestEncoderTest() { diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index 4ed88b7652e0..54831d77d75d 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -1097,12 +1097,12 @@ TEST_P(RoundRobinLoadBalancerTest, Weighted) { hostSet().healthy_hosts_[1]->weight(1); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); + EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); // Add a host, it should participate in next round of scheduling. hostSet().healthy_hosts_.push_back(makeTestHost(info_, "tcp://127.0.0.1:82", simTime(), 3)); hostSet().hosts_.push_back(hostSet().healthy_hosts_.back()); @@ -1116,9 +1116,9 @@ TEST_P(RoundRobinLoadBalancerTest, Weighted) { EXPECT_EQ(hostSet().healthy_hosts_[2], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[2], lb_->chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[2], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); + EXPECT_EQ(hostSet().healthy_hosts_[2], lb_->chooseHost(nullptr)); // Remove last two hosts, add a new one with different weights. HostVector removed_hosts = {hostSet().hosts_[1], hostSet().hosts_[2]}; hostSet().healthy_hosts_.pop_back(); @@ -1157,6 +1157,68 @@ TEST_P(RoundRobinLoadBalancerTest, WeightedSeed) { EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); } +// Validate that the RNG seed influences pick order when weighted RR without +// the envoy.reloadable_features.edf_lb_host_scheduler_init_fix. +// This test should be removed once +// envoy.reloadable_features.edf_lb_host_scheduler_init_fix is deprecated. +TEST_P(RoundRobinLoadBalancerTest, WeightedSeedOldInit) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.edf_lb_host_scheduler_init_fix", "false"}}); + hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", simTime(), 1), + makeTestHost(info_, "tcp://127.0.0.1:81", simTime(), 2)}; + hostSet().hosts_ = hostSet().healthy_hosts_; + EXPECT_CALL(random_, random()).WillRepeatedly(Return(1)); + init(false); + // Initial weights respected. + EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); + EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); + EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); + EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); + EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); + EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); +} + +// Validate that low weighted hosts will be chosen when the LB is created. +TEST_P(RoundRobinLoadBalancerTest, WeightedInitializationPicksAllHosts) { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues({{"envoy.reloadable_features.locality_routing_use_new_routing_logic", + GetParam().use_new_locality_routing ? "true" : "false"}}); + // This test should be kept just the runtime override removed once the + // feature-flag is deprecated. + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.edf_lb_host_scheduler_init_fix", "true"}}); + // Add 3 hosts with weights {6, 3, 1}. Out of 10 refreshes with consecutive + // random value, 6 times the first host will be chosen, 3 times the second + // host will be chosen, and 1 time the third host will be chosen. + hostSet().healthy_hosts_ = { + makeTestHost(info_, "tcp://127.0.0.1:80", simTime(), 6), + makeTestHost(info_, "tcp://127.0.0.1:81", simTime(), 3), + makeTestHost(info_, "tcp://127.0.0.1:82", simTime(), 1), + }; + hostSet().hosts_ = hostSet().healthy_hosts_; + absl::flat_hash_map host_picked_count_map; + for (const auto& host : hostSet().healthy_hosts_) { + host_picked_count_map[host] = 0; + } + // When random returns x, the initialization of the lb will invoke pickAndAdd + // x times. The test validates the result of the next call (the x+1 call). + // Initiate 10 load-balancers with different random values. + for (int i = 0; i < 10; ++i) { + EXPECT_CALL(random_, random()).Times(2).WillRepeatedly(Return(i)); + RoundRobinLoadBalancer lb(priority_set_, local_priority_set_.get(), stats_, runtime_, random_, + common_config_, round_robin_lb_config_, simTime()); + const auto& host = lb.chooseHost(nullptr); + host_picked_count_map[host]++; + } + // Ensure that the number of times each host was picked is as expected. + { + EXPECT_EQ(host_picked_count_map[hostSet().healthy_hosts_[0]], 6); + EXPECT_EQ(host_picked_count_map[hostSet().healthy_hosts_[1]], 3); + EXPECT_EQ(host_picked_count_map[hostSet().healthy_hosts_[2]], 1); + } +} + TEST_P(RoundRobinLoadBalancerTest, MaxUnhealthyPanic) { hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", simTime()), makeTestHost(info_, "tcp://127.0.0.1:81", simTime())}; diff --git a/test/config_test/config_test.cc b/test/config_test/config_test.cc index c61c3168e8b8..c1e484675815 100644 --- a/test/config_test/config_test.cc +++ b/test/config_test/config_test.cc @@ -101,7 +101,7 @@ class ConfigTest { bootstrap, options_, server_.messageValidationContext().staticValidationVisitor(), *api_); absl::Status creation_status; Server::Configuration::InitialImpl initial_config(bootstrap, creation_status); - THROW_IF_NOT_OK(creation_status); + THROW_IF_NOT_OK_REF(creation_status); Server::Configuration::MainImpl main_config; // Emulate main implementation of initializing bootstrap extensions. diff --git a/test/extensions/access_loggers/common/grpc_access_logger_test.cc b/test/extensions/access_loggers/common/grpc_access_logger_test.cc index ad9f890b76ad..0c151f01192d 100644 --- a/test/extensions/access_loggers/common/grpc_access_logger_test.cc +++ b/test/extensions/access_loggers/common/grpc_access_logger_test.cc @@ -484,6 +484,7 @@ class MockGrpcAccessLoggerCache createLogger(const envoy::extensions::access_loggers::grpc::v3::CommonGrpcAccessLogConfig& config, Event::Dispatcher& dispatcher) override { auto client = async_client_manager_.factoryForGrpcService(config.grpc_service(), scope_, true) + .value() ->createUncachedRawAsyncClient(); return std::make_shared(std::move(client), config, dispatcher, scope_, "mock_access_log_prefix.", diff --git a/test/extensions/access_loggers/fluentd/BUILD b/test/extensions/access_loggers/fluentd/BUILD new file mode 100644 index 000000000000..288f23d47fb7 --- /dev/null +++ b/test/extensions/access_loggers/fluentd/BUILD @@ -0,0 +1,58 @@ +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 = "fluentd_access_log_impl_test", + srcs = ["fluentd_access_log_impl_test.cc"], + extension_names = ["envoy.access_loggers.fluentd"], + external_deps = [ + "msgpack", + ], + deps = [ + "//source/extensions/access_loggers/fluentd:config", + "//test/mocks/server:factory_context_mocks", + "//test/test_common:environment_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/accesslog/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/access_loggers/fluentd/v3:pkg_cc_proto", + ], +) + +envoy_extension_cc_test( + name = "substitution_formatter_test", + srcs = ["substitution_formatter_test.cc"], + extension_names = ["envoy.access_loggers.fluentd"], + deps = [ + "//source/extensions/access_loggers/fluentd:substitution_formatter_lib", + "//test/mocks/server:factory_context_mocks", + "//test/test_common:environment_lib", + "//test/test_common:utility_lib", + ], +) + +envoy_extension_cc_test( + name = "fluentd_access_log_integration_test", + size = "large", + srcs = ["fluentd_access_log_integration_test.cc"], + extension_names = ["envoy.access_loggers.fluentd"], + deps = [ + "//source/extensions/access_loggers/fluentd:config", + "//source/extensions/filters/network/tcp_proxy:config", + "//test/integration:integration_lib", + "//test/test_common:registry_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/access_loggers/fluentd/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/network/tcp_proxy/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/access_loggers/fluentd/fluentd_access_log_impl_test.cc b/test/extensions/access_loggers/fluentd/fluentd_access_log_impl_test.cc new file mode 100644 index 000000000000..a058c22dcf07 --- /dev/null +++ b/test/extensions/access_loggers/fluentd/fluentd_access_log_impl_test.cc @@ -0,0 +1,321 @@ +#include "envoy/common/time.h" +#include "envoy/config/accesslog/v3/accesslog.pb.h" +#include "envoy/extensions/access_loggers/fluentd/v3/fluentd.pb.h" +#include "envoy/registry/registry.h" + +#include "source/common/access_log/access_log_impl.h" +#include "source/common/protobuf/protobuf.h" +#include "source/extensions/access_loggers/fluentd/config.h" +#include "source/extensions/access_loggers/fluentd/fluentd_access_log_impl.h" + +#include "test/mocks/access_log/mocks.h" +#include "test/mocks/server/factory_context.h" +#include "test/mocks/stream_info/mocks.h" +#include "test/test_common/test_time.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "msgpack.hpp" + +using testing::Return; +using testing::ReturnRef; + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { +namespace { + +class FluentdAccessLoggerImplTest : public testing::Test { +public: + FluentdAccessLoggerImplTest() + : async_client_(new Tcp::AsyncClient::MockAsyncTcpClient()), + timer_(new Event::MockTimer(&dispatcher_)) {} + + void init(int buffer_size_bytes = 0) { + EXPECT_CALL(*async_client_, setAsyncTcpClientCallbacks(_)); + EXPECT_CALL(*timer_, enableTimer(_, _)); + + config_.set_tag(tag_); + config_.mutable_buffer_size_bytes()->set_value(buffer_size_bytes); + logger_ = std::make_unique( + Tcp::AsyncTcpClientPtr{async_client_}, dispatcher_, config_, *stats_store_.rootScope()); + } + + std::string getExpectedMsgpackPayload(int entries_count) { + msgpack::sbuffer buffer; + msgpack::packer packer(buffer); + packer.pack_array(2); + packer.pack(tag_); + packer.pack_array(entries_count); + for (int idx = 0; idx < entries_count; idx++) { + packer.pack_array(2); + packer.pack(time_); + const char* record_bytes = reinterpret_cast(&data_[0]); + packer.pack_bin_body(record_bytes, data_.size()); + } + + return std::string(buffer.data(), buffer.size()); + } + + std::string tag_ = "test.tag"; + uint64_t time_ = 123; + std::vector data_ = {10, 20}; + Tcp::AsyncClient::MockAsyncTcpClient* async_client_; + Stats::IsolatedStoreImpl stats_store_; + Event::MockDispatcher dispatcher_; + Event::MockTimer* timer_; + std::unique_ptr logger_; + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig config_; +}; + +TEST_F(FluentdAccessLoggerImplTest, NoWriteOnLogIfNotConnectedToUpstream) { + init(); + EXPECT_CALL(*async_client_, connect()).WillOnce(Return(true)); + EXPECT_CALL(*async_client_, connected()).WillOnce(Return(false)); + EXPECT_CALL(*async_client_, write(_, _)).Times(0); + logger_->log(std::make_unique(time_, std::move(data_))); +} + +TEST_F(FluentdAccessLoggerImplTest, NoWriteOnLogIfBufferLimitNotPassed) { + init(100); + EXPECT_CALL(*async_client_, connect()).Times(0); + EXPECT_CALL(*async_client_, connected()).Times(0); + EXPECT_CALL(*async_client_, write(_, _)).Times(0); + logger_->log(std::make_unique(time_, std::move(data_))); +} + +TEST_F(FluentdAccessLoggerImplTest, NoWriteOnLogIfDisconnectedByRemote) { + init(); + EXPECT_CALL(*timer_, disableTimer()); + EXPECT_CALL(*async_client_, write(_, _)).Times(0); + EXPECT_CALL(*async_client_, connected()).WillOnce(Return(false)); + EXPECT_CALL(*async_client_, connect()).WillOnce(Invoke([this]() -> bool { + logger_->onEvent(Network::ConnectionEvent::RemoteClose); + return true; + })); + + logger_->log(std::make_unique(time_, std::move(data_))); +} + +TEST_F(FluentdAccessLoggerImplTest, NoWriteOnLogIfDisconnectedByLocal) { + init(); + EXPECT_CALL(*timer_, disableTimer()); + EXPECT_CALL(*async_client_, write(_, _)).Times(0); + EXPECT_CALL(*async_client_, connected()).WillOnce(Return(false)); + EXPECT_CALL(*async_client_, connect()).WillOnce(Invoke([this]() -> bool { + logger_->onEvent(Network::ConnectionEvent::LocalClose); + return true; + })); + + logger_->log(std::make_unique(time_, std::move(data_))); +} + +TEST_F(FluentdAccessLoggerImplTest, LogSingleEntry) { + init(); // Default buffer limit is 0 so single entry should be flushed immediately. + EXPECT_CALL(*async_client_, connected()).WillOnce(Return(false)).WillOnce(Return(true)); + EXPECT_CALL(*async_client_, connect()).WillOnce(Invoke([this]() -> bool { + logger_->onEvent(Network::ConnectionEvent::Connected); + return true; + })); + EXPECT_CALL(*async_client_, write(_, _)) + .WillOnce(Invoke([&](Buffer::Instance& buffer, bool end_stream) { + EXPECT_FALSE(end_stream); + std::string expected_payload = getExpectedMsgpackPayload(1); + EXPECT_EQ(expected_payload, buffer.toString()); + })); + + logger_->log(std::make_unique(time_, std::move(data_))); +} + +TEST_F(FluentdAccessLoggerImplTest, LogTwoEntries) { + init(12); // First entry is 10 bytes, so first entry should not cause the logger to flush. + + // First log should not be flushed. + EXPECT_CALL(*async_client_, connected()).Times(0); + EXPECT_CALL(*async_client_, write(_, _)).Times(0); + logger_->log(std::make_unique(time_, std::move(data_))); + + // Expect second entry to cause all entries to flush. + EXPECT_CALL(*async_client_, connected()).WillOnce(Return(false)).WillOnce(Return(true)); + EXPECT_CALL(*async_client_, connect()).WillOnce(Invoke([this]() -> bool { + logger_->onEvent(Network::ConnectionEvent::Connected); + return true; + })); + EXPECT_CALL(*async_client_, write(_, _)) + .WillOnce(Invoke([&](Buffer::Instance& buffer, bool end_stream) { + EXPECT_FALSE(end_stream); + std::string expected_payload = getExpectedMsgpackPayload(2); + EXPECT_EQ(expected_payload, buffer.toString()); + })); + logger_->log(std::make_unique(time_, std::move(data_))); +} + +TEST_F(FluentdAccessLoggerImplTest, CallbacksTest) { + init(); + EXPECT_CALL(*async_client_, connect()).WillOnce(Return(true)); + EXPECT_CALL(*async_client_, connected()).WillOnce(Return(false)); + EXPECT_CALL(*async_client_, write(_, _)).Times(0); + logger_->log(std::make_unique(time_, std::move(data_))); + EXPECT_NO_THROW(logger_->onAboveWriteBufferHighWatermark()); + EXPECT_NO_THROW(logger_->onBelowWriteBufferLowWatermark()); + Buffer::OwnedImpl buffer; + EXPECT_NO_THROW(logger_->onData(buffer, false)); +} + +class FluentdAccessLoggerCacheImplTest : public testing::Test { +public: + FluentdAccessLoggerCacheImplTest() : logger_cache_(cluster_manager_, scope_, tls_) {} + + void init(bool second_logger = false) { + async_client1_ = new Tcp::AsyncClient::MockAsyncTcpClient(); + EXPECT_CALL(*async_client1_, setAsyncTcpClientCallbacks(_)); + + if (second_logger) { + async_client2_ = new Tcp::AsyncClient::MockAsyncTcpClient(); + EXPECT_CALL(*async_client2_, setAsyncTcpClientCallbacks(_)); + } + } + + std::string cluster_name_ = "test_cluster"; + NiceMock cluster_; + NiceMock cluster_manager_; + Tcp::AsyncClient::MockAsyncTcpClient* async_client1_; + Tcp::AsyncClient::MockAsyncTcpClient* async_client2_; + NiceMock store_; + Stats::Scope& scope_{*store_.rootScope()}; + NiceMock tls_; + FluentdAccessLoggerCacheImpl logger_cache_; +}; + +TEST_F(FluentdAccessLoggerCacheImplTest, CreateNonExistingLogger) { + init(); + EXPECT_CALL(cluster_manager_, getThreadLocalCluster(cluster_name_)).WillOnce(Return(&cluster_)); + EXPECT_CALL(cluster_, tcpAsyncClient(_, _)).WillOnce(Invoke([&] { + return Tcp::AsyncTcpClientPtr{async_client1_}; + })); + + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig config; + config.set_cluster(cluster_name_); + config.set_tag("test.tag"); + config.mutable_buffer_size_bytes()->set_value(123); + auto logger = logger_cache_.getOrCreateLogger(std::make_shared(config)); + EXPECT_TRUE(logger != nullptr); +} + +TEST_F(FluentdAccessLoggerCacheImplTest, CreateTwoLoggersSameHash) { + init(); + EXPECT_CALL(cluster_manager_, getThreadLocalCluster(cluster_name_)).WillOnce(Return(&cluster_)); + EXPECT_CALL(cluster_, tcpAsyncClient(_, _)).WillRepeatedly(Invoke([&] { + return Tcp::AsyncTcpClientPtr{async_client1_}; + })); + + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig config1; + config1.set_cluster(cluster_name_); + config1.set_tag("test.tag"); + config1.mutable_buffer_size_bytes()->set_value(123); + auto logger1 = logger_cache_.getOrCreateLogger(std::make_shared(config1)); + EXPECT_TRUE(logger1 != nullptr); + + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig config2; + config2.set_cluster(cluster_name_); // config hash will be different than config1 + config2.set_tag("test.tag"); + config2.mutable_buffer_size_bytes()->set_value(123); + auto logger2 = logger_cache_.getOrCreateLogger(std::make_shared(config2)); + EXPECT_TRUE(logger2 != nullptr); + + // Make sure we got the same logger + EXPECT_EQ(logger1, logger2); +} + +TEST_F(FluentdAccessLoggerCacheImplTest, CreateTwoLoggersDifferentHash) { + init(true); + EXPECT_CALL(cluster_manager_, getThreadLocalCluster(_)) + .WillOnce(Return(&cluster_)) + .WillOnce(Return(&cluster_)); + + EXPECT_CALL(cluster_, tcpAsyncClient(_, _)) + .WillOnce(Invoke([&] { return Tcp::AsyncTcpClientPtr{async_client1_}; })) + .WillOnce(Invoke([&] { return Tcp::AsyncTcpClientPtr{async_client2_}; })); + + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig config1; + config1.set_cluster(cluster_name_); + config1.set_tag("test.tag"); + config1.mutable_buffer_size_bytes()->set_value(123); + auto logger1 = logger_cache_.getOrCreateLogger(std::make_shared(config1)); + EXPECT_TRUE(logger1 != nullptr); + + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig config2; + config2.set_cluster("different_cluster"); // config hash will be different than config1 + config2.set_tag("test.tag"); + config2.mutable_buffer_size_bytes()->set_value(123); + auto logger2 = logger_cache_.getOrCreateLogger(std::make_shared(config2)); + EXPECT_TRUE(logger2 != nullptr); + + // Make sure we got two different loggers + EXPECT_NE(logger1, logger2); +} + +class MockFluentdAccessLogger : public FluentdAccessLogger { +public: + MOCK_METHOD(void, log, (EntryPtr &&)); +}; + +class MockFluentdAccessLoggerCache : public FluentdAccessLoggerCache { +public: + MOCK_METHOD(FluentdAccessLoggerSharedPtr, getOrCreateLogger, + (const FluentdAccessLogConfigSharedPtr)); +}; + +class MockFluentdFormatter : public FluentdFormatter { +public: + MOCK_METHOD(std::vector, format, + (const Formatter::HttpFormatterContext& context, + const StreamInfo::StreamInfo& stream_info), + (const)); +}; + +using FilterPtr = Envoy::AccessLog::FilterPtr; + +class FluentdAccessLogTest : public testing::Test { +public: + FluentdAccessLogTest() { + ON_CALL(*filter_, evaluate(_, _)).WillByDefault(Return(true)); + EXPECT_CALL(*logger_cache_, getOrCreateLogger(_)).WillOnce(Return(logger_)); + } + + AccessLog::MockFilter* filter_{new NiceMock()}; + NiceMock tls_; + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig config_; + MockFluentdFormatter* formatter_{new NiceMock()}; + std::shared_ptr logger_{new MockFluentdAccessLogger()}; + std::shared_ptr logger_cache_{new MockFluentdAccessLoggerCache()}; +}; + +TEST_F(FluentdAccessLogTest, CreateAndLog) { + auto access_log = + FluentdAccessLog(AccessLog::FilterPtr{filter_}, FluentdFormatterPtr{formatter_}, + std::make_shared(config_), tls_, logger_cache_); + + MockTimeSystem time_system; + EXPECT_CALL(time_system, systemTime).WillOnce(Return(SystemTime(std::chrono::seconds(200)))); + NiceMock stream_info; + EXPECT_CALL(stream_info, timeSource()).WillOnce(ReturnRef(time_system)); + + EXPECT_CALL(*formatter_, format(_, _)).WillOnce(Return(std::vector{10, 20})); + EXPECT_CALL(*logger_, log(_)).WillOnce(Invoke([](EntryPtr&& entry) { + EXPECT_EQ(200, entry->time_); + ASSERT_EQ(2, entry->record_.size()); + EXPECT_EQ(uint8_t(10), entry->record_[0]); + EXPECT_EQ(uint8_t(20), entry->record_[1]); + })); + + access_log.log({}, stream_info); +} + +} // namespace +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/access_loggers/fluentd/fluentd_access_log_integration_test.cc b/test/extensions/access_loggers/fluentd/fluentd_access_log_integration_test.cc new file mode 100644 index 000000000000..933ac3fe1369 --- /dev/null +++ b/test/extensions/access_loggers/fluentd/fluentd_access_log_integration_test.cc @@ -0,0 +1,214 @@ +#include "envoy/config/bootstrap/v3/bootstrap.pb.h" +#include "envoy/extensions/access_loggers/fluentd/v3/fluentd.pb.h" +#include "envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.pb.h" + +#include "source/common/network/utility.h" +#include "source/extensions/filters/network/common/factory_base.h" + +#include "test/integration/integration.h" +#include "test/integration/utility.h" +#include "test/test_common/registry.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" +#include "msgpack.hpp" + +using testing::AssertionResult; + +namespace Envoy { +namespace { + +constexpr char default_cluster_name[] = "fluentd_cluster"; +constexpr char default_tag[] = "fluentd_cluster"; +constexpr char default_stat_prefix[] = "fluentd_1"; + +class FluentdAccessLogIntegrationTest : public testing::Test, public BaseIntegrationTest { +public: + FluentdAccessLogIntegrationTest() + : BaseIntegrationTest(Network::Address::IpVersion::v4, ConfigHelper::tcpProxyConfig()) { + skip_tag_extraction_rule_check_ = true; + enableHalfClose(true); + } + + void init(const std::string cluster_name = default_cluster_name, + bool flush_access_log_on_connected = false, + absl::optional buffer_size_bytes = absl::nullopt) { + setUpstreamCount(2); + config_helper_.renameListener("tcp_proxy"); + config_helper_.addConfigModifier( + [&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* access_log_cluster = bootstrap.mutable_static_resources()->add_clusters(); + access_log_cluster->MergeFrom(bootstrap.static_resources().clusters()[0]); + access_log_cluster->set_name(default_cluster_name); + + auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0); + auto* filter_chain = listener->mutable_filter_chains(0); + auto* config_blob = filter_chain->mutable_filters(0)->mutable_typed_config(); + + ASSERT_TRUE( + config_blob->Is()); + auto tcp_proxy_config = + MessageUtil::anyConvert( + *config_blob); + + tcp_proxy_config.mutable_access_log_options()->set_flush_access_log_on_connected( + flush_access_log_on_connected); + auto* access_log = tcp_proxy_config.add_access_log(); + access_log->set_name("access_log.fluentd"); + envoy::extensions::access_loggers::fluentd::v3::FluentdAccessLogConfig access_log_config; + access_log_config.set_cluster(cluster_name); + access_log_config.set_tag(default_tag); + access_log_config.set_stat_prefix(default_stat_prefix); + + if (buffer_size_bytes.has_value()) { + access_log_config.mutable_buffer_size_bytes()->set_value(buffer_size_bytes.value()); + } + + auto* record = access_log_config.mutable_record(); + (*record->mutable_fields())["Message"].set_string_value("SomeValue"); + (*record->mutable_fields())["LogType"].set_string_value("%ACCESS_LOG_TYPE%"); + + access_log->mutable_typed_config()->PackFrom(access_log_config); + config_blob->PackFrom(tcp_proxy_config); + }); + + BaseIntegrationTest::initialize(); + } + + // The Fluentd records are msgpack serialized, but for testing convenience, we expect + // the records as JSON strings and later converting while comparing the values. + void validateFluentdPayload(const std::string& tcp_data, bool* validated, + std::vector> expected_entries) { + msgpack::unpacker unpacker; + unpacker.reserve_buffer(tcp_data.size()); + std::memcpy(unpacker.buffer(), tcp_data.data(), tcp_data.size()); + unpacker.buffer_consumed(tcp_data.size()); + + size_t entry_index = 0; + msgpack::object_handle handle; + while (unpacker.next(handle)) { + auto& expected_records_as_json = expected_entries[entry_index++]; + + msgpack::object message = handle.get(); + ASSERT_EQ(msgpack::type::object_type::ARRAY, message.type); + ASSERT_EQ(msgpack::type::STR, message.via.array.ptr[0].type); + ASSERT_EQ(default_tag, message.via.array.ptr[0].as()); + ASSERT_EQ(msgpack::type::object_type::ARRAY, message.via.array.ptr[1].type); + + ASSERT_EQ(expected_records_as_json.size(), message.via.array.ptr[1].via.array.size); + for (size_t idx = 0; idx < expected_records_as_json.size(); idx++) { + auto& record = message.via.array.ptr[1].via.array.ptr[idx]; + ASSERT_EQ(msgpack::type::object_type::ARRAY, record.type); + ASSERT_EQ(msgpack::type::object_type::POSITIVE_INTEGER, record.via.array.ptr[0].type); + ASSERT_GT(record.via.array.ptr[0].as(), 0); + ASSERT_EQ(msgpack::type::object_type::MAP, record.via.array.ptr[1].type); + + std::stringstream stream; // msgpack will stream map type of fields as JSON string + stream << record.via.array.ptr[1]; + std::string record_as_json = stream.str(); + + ASSERT_TRUE(TestUtility::jsonStringEqual(expected_records_as_json[idx], record_as_json)) + << fmt::format("expected: {}, actual: {}", expected_records_as_json[idx], + record_as_json); + } + } + + if (expected_entries.size() == entry_index) { + *validated = true; + } + } + + void sendBidirectionalData() { + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(tcp_client->write("hello", true)); + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_tcp_connection_)); + ASSERT_TRUE(fake_tcp_connection_->waitForData(5)); + ASSERT_TRUE(fake_tcp_connection_->write("world", true)); + tcp_client->waitForData("world"); + ASSERT_TRUE(fake_tcp_connection_->waitForDisconnect()); + tcp_client->waitForDisconnect(); + } + + FakeRawConnectionPtr fake_tcp_connection_; + FakeRawConnectionPtr fake_access_log_connection_; +}; + +TEST_F(FluentdAccessLogIntegrationTest, UnknownCluster) { + EXPECT_DEATH(init("unknown_cluster"), ""); +} + +TEST_F(FluentdAccessLogIntegrationTest, SingleEntrySingleRecord) { + init(); + sendBidirectionalData(); + + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.entries_buffered", 1); + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.events_sent", 1); + + ASSERT_TRUE(fake_upstreams_[1]->waitForRawConnection(fake_access_log_connection_)); + EXPECT_TRUE(fake_access_log_connection_->waitForData([&](const std::string& tcp_data) -> bool { + bool validated = false; + validateFluentdPayload(tcp_data, &validated, + {{"{\"Message\":\"SomeValue\",\"LogType\":\"TcpConnectionEnd\"}"}}); + return validated; + })); +} + +TEST_F(FluentdAccessLogIntegrationTest, SingleEntryTwoRecords) { + init(default_cluster_name, /*flush_access_log_on_connected = */ true); + sendBidirectionalData(); + + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.entries_buffered", 2); + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.events_sent", 1); + + ASSERT_TRUE(fake_upstreams_[1]->waitForRawConnection(fake_access_log_connection_)); + EXPECT_TRUE(fake_access_log_connection_->waitForData([&](const std::string& tcp_data) -> bool { + bool validated = false; + validateFluentdPayload(tcp_data, &validated, + {{"{\"Message\":\"SomeValue\",\"LogType\":\"TcpUpstreamConnected\"}", + "{\"Message\":\"SomeValue\",\"LogType\":\"TcpConnectionEnd\"}"}}); + return validated; + })); +} + +TEST_F(FluentdAccessLogIntegrationTest, TwoEntries) { + init(default_cluster_name, /*flush_access_log_on_connected = */ true, /*buffer_size_bytes = */ 0); + sendBidirectionalData(); + + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.entries_buffered", 2); + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.events_sent", 2); + + ASSERT_TRUE(fake_upstreams_[1]->waitForRawConnection(fake_access_log_connection_)); + EXPECT_TRUE(fake_access_log_connection_->waitForData([&](const std::string& tcp_data) -> bool { + bool validated = false; + validateFluentdPayload(tcp_data, &validated, + {{"{\"Message\":\"SomeValue\",\"LogType\":\"TcpUpstreamConnected\"}"}, + {"{\"Message\":\"SomeValue\",\"LogType\":\"TcpConnectionEnd\"}"}}); + return validated; + })); +} + +TEST_F(FluentdAccessLogIntegrationTest, UpstreamConnectionClosed) { + init(); + sendBidirectionalData(); + + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.entries_buffered", 1); + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.events_sent", 1); + + ASSERT_TRUE(fake_upstreams_[1]->waitForRawConnection(fake_access_log_connection_)); + EXPECT_TRUE(fake_access_log_connection_->waitForData([&](const std::string& tcp_data) -> bool { + bool validated = false; + validateFluentdPayload(tcp_data, &validated, + {{"{\"Message\":\"SomeValue\",\"LogType\":\"TcpConnectionEnd\"}"}}); + return validated; + })); + + ASSERT_TRUE(fake_access_log_connection_->close()); + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.connections_closed", 1); + + // New access log would be discarded because the connection is closed. + sendBidirectionalData(); + test_server_->waitForCounterEq("access_logs.fluentd.fluentd_1.entries_lost", 1); +} + +} // namespace +} // namespace Envoy diff --git a/test/extensions/access_loggers/fluentd/substitution_formatter_test.cc b/test/extensions/access_loggers/fluentd/substitution_formatter_test.cc new file mode 100644 index 000000000000..a98a0e2b58f6 --- /dev/null +++ b/test/extensions/access_loggers/fluentd/substitution_formatter_test.cc @@ -0,0 +1,46 @@ +#include "envoy/registry/registry.h" + +#include "source/common/formatter/substitution_format_string.h" +#include "source/common/json/json_loader.h" +#include "source/extensions/access_loggers/fluentd/substitution_formatter.h" + +#include "test/mocks/access_log/mocks.h" +#include "test/mocks/server/factory_context.h" +#include "test/mocks/stream_info/mocks.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::Return; + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Fluentd { +namespace { + +TEST(FluentdFormatterImplTest, FormatMsgpack) { + ProtobufWkt::Struct log_struct; + (*log_struct.mutable_fields())["Message"].set_string_value("SomeValue"); + (*log_struct.mutable_fields())["LogType"].set_string_value("%ACCESS_LOG_TYPE%"); + + auto json_formatter = + Formatter::SubstitutionFormatStringUtils::createJsonFormatter(log_struct, true, false, true); + + auto fluentd_formatter = FluentdFormatterImpl(std::move(json_formatter)); + auto expected_json = "{\"Message\":\"SomeValue\",\"LogType\":\"NotSet\"}"; + auto expected_msgpack = Json::Factory::jsonToMsgpack(expected_json); + + NiceMock stream_info; + std::vector msgpack = fluentd_formatter.format({}, stream_info); + std::string expected_msgpack_str(expected_msgpack.begin(), expected_msgpack.end()); + std::string msgpack_str(msgpack.begin(), msgpack.end()); + EXPECT_EQ(expected_msgpack_str, msgpack_str); +} + +} // namespace +} // namespace Fluentd +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/bootstrap/wasm/test_data/stats_cpp.cc b/test/extensions/bootstrap/wasm/test_data/stats_cpp.cc index 51b21a4c28bc..885c91c3e7aa 100644 --- a/test/extensions/bootstrap/wasm/test_data/stats_cpp.cc +++ b/test/extensions/bootstrap/wasm/test_data/stats_cpp.cc @@ -96,16 +96,16 @@ WASM_EXPORT(void, proxy_on_log, (uint32_t /* context_zero */)) { auto simple_h = complete_h->resolve("test_tag", true); logError(std::string("h_id = ") + complete_h->nameFromIdSlow(simple_h.metric_id)); - Counter stack_c("test_counter", "string_tag", "int_tag", "bool_tag"); + Counter stack_c("test_counter", MetricTagDescriptor("string_tag"), MetricTagDescriptor("int_tag"), MetricTagDescriptor("bool_tag")); stack_c.increment(1, "test_tag_stack", 7, true); logError(std::string("stack_c = ") + std::to_string(stack_c.get("test_tag_stack", 7, true))); - Gauge stack_g("test_gauge", "string_tag1", "string_tag2"); + Gauge stack_g("test_gauge", MetricTagDescriptor("string_tag1"), MetricTagDescriptor("string_tag2")); stack_g.record(2, "stack_test_tag1", "test_tag2"); logError(std::string("stack_g = ") + std::to_string(stack_g.get("stack_test_tag1", "test_tag2"))); std::string_view int_tag = "int_tag"; - Histogram stack_h("test_histogram", int_tag, "string_tag", "bool_tag"); + Histogram stack_h("test_histogram", MetricTagDescriptor(int_tag), MetricTagDescriptor("string_tag"), MetricTagDescriptor("bool_tag")); std::string_view stack_test_tag = "stack_test_tag"; stack_h.record(3, 7, stack_test_tag, true); } diff --git a/test/extensions/common/tap/admin_test.cc b/test/extensions/common/tap/admin_test.cc index df3aa2783c15..8978529f5606 100644 --- a/test/extensions/common/tap/admin_test.cc +++ b/test/extensions/common/tap/admin_test.cc @@ -170,7 +170,6 @@ class TestConfigImpl : public TapConfigBaseImpl { }; TEST(TypedExtensionConfigTest, AddTestConfigHttpContext) { - const std::string tap_config_yaml = R"EOF( match: @@ -204,7 +203,6 @@ TEST(TypedExtensionConfigTest, AddTestConfigHttpContext) { } TEST(TypedExtensionConfigTest, AddTestConfigTransportSocketContext) { - const std::string tap_config_yaml = R"EOF( match: @@ -237,6 +235,62 @@ TEST(TypedExtensionConfigTest, AddTestConfigTransportSocketContext) { TestConfigImpl(tap_config, nullptr, factory_context); } +// Validates that a BufferedAdmin tap config that is passed without an admin +// streamer is rejected. +TEST(TypedExtensionConfigTest, BufferedAdminNoAdminStreamerRejected) { + const std::string tap_config_yaml = + R"EOF( + match: + any_match: true + output_config: + sinks: + - buffered_admin: {} +)EOF"; + envoy::config::tap::v3::TapConfig tap_config; + TestUtility::loadFromYaml(tap_config_yaml, tap_config); + + MockTapSinkFactory factory_impl; + EXPECT_CALL(factory_impl, name).Times(AtLeast(1)); + EXPECT_CALL(factory_impl, createEmptyConfigProto) + .WillRepeatedly(Invoke([]() -> ProtobufTypes::MessagePtr { + return std::make_unique(); + })); + Registry::InjectFactory factory(factory_impl); + + NiceMock factory_context; + EXPECT_THROW_WITH_MESSAGE( + TestConfigImpl(tap_config, nullptr, factory_context), EnvoyException, + "Output sink type BufferedAdmin requires that the admin output will be configured via admin"); +} + +// Validates that a StreamingAdmin tap config that is passed without an admin +// streamer is rejected. +TEST(TypedExtensionConfigTest, StreamingAdminNoAdminStreamerRejected) { + const std::string tap_config_yaml = + R"EOF( + match: + any_match: true + output_config: + sinks: + - streaming_admin: {} +)EOF"; + envoy::config::tap::v3::TapConfig tap_config; + TestUtility::loadFromYaml(tap_config_yaml, tap_config); + + MockTapSinkFactory factory_impl; + EXPECT_CALL(factory_impl, name).Times(AtLeast(1)); + EXPECT_CALL(factory_impl, createEmptyConfigProto) + .WillRepeatedly(Invoke([]() -> ProtobufTypes::MessagePtr { + return std::make_unique(); + })); + Registry::InjectFactory factory(factory_impl); + + NiceMock factory_context; + EXPECT_THROW_WITH_MESSAGE(TestConfigImpl(tap_config, nullptr, factory_context), EnvoyException, + "Output sink type StreamingAdmin requires that the admin output will " + "be configured via admin"); +} + // Make sure warn if using a pipe address for the admin handler. TEST_F(AdminHandlerTest, AdminWithPipeSocket) { EXPECT_LOG_CONTAINS( diff --git a/test/extensions/common/wasm/BUILD b/test/extensions/common/wasm/BUILD index 14791f4599cd..62daee5c4c16 100644 --- a/test/extensions/common/wasm/BUILD +++ b/test/extensions/common/wasm/BUILD @@ -152,3 +152,21 @@ envoy_cc_test( "@proxy_wasm_cpp_host//:base_lib", ], ) + +envoy_cc_test( + name = "remote_async_datasource_test", + srcs = ["remote_async_datasource_test.cc"], + deps = [ + "//source/common/common:empty_string", + "//source/common/crypto:utility_lib", + "//source/common/http:message_lib", + "//source/common/protobuf:utility_lib", + "//source/extensions/common/wasm:remote_async_datasource_lib", + "//test/mocks/event:event_mocks", + "//test/mocks/init:init_mocks", + "//test/mocks/runtime:runtime_mocks", + "//test/mocks/upstream:cluster_manager_mocks", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/common/wasm/remote_async_datasource_test.cc b/test/extensions/common/wasm/remote_async_datasource_test.cc new file mode 100644 index 000000000000..15be73e5873f --- /dev/null +++ b/test/extensions/common/wasm/remote_async_datasource_test.cc @@ -0,0 +1,529 @@ +#include "envoy/config/core/v3/base.pb.h" +#include "envoy/config/core/v3/base.pb.validate.h" + +#include "source/common/common/cleanup.h" +#include "source/common/common/empty_string.h" +#include "source/common/config/datasource.h" +#include "source/common/http/message_impl.h" +#include "source/common/protobuf/protobuf.h" +#include "source/extensions/common/wasm/remote_async_datasource.h" + +#include "test/mocks/event/mocks.h" +#include "test/mocks/init/mocks.h" +#include "test/mocks/upstream/cluster_manager.h" +#include "test/test_common/environment.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace { +using ::testing::AtLeast; +using ::testing::NiceMock; +using ::testing::Return; + +class AsyncDataSourceTest : public testing::Test { +protected: + using AsyncDataSourcePb = envoy::config::core::v3::AsyncDataSource; + + NiceMock cm_; + Init::MockManager init_manager_; + Init::ExpectableWatcherImpl init_watcher_; + Init::TargetHandlePtr init_target_handle_; + Api::ApiPtr api_{Api::createApiForTest()}; + NiceMock random_; + Event::MockDispatcher dispatcher_; + Event::MockTimer* retry_timer_; + Event::TimerCb retry_timer_cb_; + NiceMock request_{&cm_.thread_local_cluster_.async_client_}; + + RemoteAsyncDataProviderPtr remote_data_provider_; + + using AsyncClientSendFunc = std::function; + + void initialize(AsyncClientSendFunc func, int num_retries = 1) { + retry_timer_ = new Event::MockTimer(); + EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) { + init_target_handle_ = target.createHandle("test"); + })); + + EXPECT_CALL(dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { + retry_timer_cb_ = timer_cb; + return retry_timer_; + })); + + EXPECT_CALL(*retry_timer_, disableTimer()); + if (!func) { + return; + } + + EXPECT_CALL(cm_.thread_local_cluster_, httpAsyncClient()) + .Times(AtLeast(1)) + .WillRepeatedly(ReturnRef(cm_.thread_local_cluster_.async_client_)); + + if (num_retries == 1) { + EXPECT_CALL(cm_.thread_local_cluster_.async_client_, send_(_, _, _)) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(func)); + } else { + EXPECT_CALL(cm_.thread_local_cluster_.async_client_, send_(_, _, _)) + .Times(num_retries) + .WillRepeatedly(Invoke(func)); + } + } +}; + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceNoCluster) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + initialize(nullptr); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + EXPECT_CALL(*retry_timer_, enableTimer(_, _)) + .WillOnce(Invoke( + [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, EMPTY_STRING); +} + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceReturnFailure) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + cm_.initializeThreadLocalClusters({"cluster_1"}); + initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onFailure(request_, Envoy::Http::AsyncClient::FailureReason::Reset); + return nullptr; + }); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + EXPECT_CALL(*retry_timer_, enableTimer(_, _)) + .WillOnce(Invoke( + [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, EMPTY_STRING); +} + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccessWith503) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + cm_.initializeThreadLocalClusters({"cluster_1"}); + initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onSuccess( + request_, Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ + new Http::TestResponseHeaderMapImpl{{":status", "503"}}})}); + return nullptr; + }); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + EXPECT_CALL(*retry_timer_, enableTimer(_, _)) + .WillOnce(Invoke( + [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, EMPTY_STRING); +} + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccessWithEmptyBody) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + cm_.initializeThreadLocalClusters({"cluster_1"}); + initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onSuccess( + request_, Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ + new Http::TestResponseHeaderMapImpl{{":status", "200"}}})}); + return nullptr; + }); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + EXPECT_CALL(*retry_timer_, enableTimer(_, _)) + .WillOnce(Invoke( + [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, EMPTY_STRING); +} + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccessIncorrectSha256) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + const std::string body = "hello world"; + + cm_.initializeThreadLocalClusters({"cluster_1"}); + initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + Http::ResponseMessagePtr response(new Http::ResponseMessageImpl( + Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); + response->body().add(body); + + callbacks.onSuccess(request_, std::move(response)); + return nullptr; + }); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, EMPTY_STRING); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + EXPECT_CALL(*retry_timer_, enableTimer(_, _)) + .WillOnce(Invoke( + [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, EMPTY_STRING); +} + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceSuccess) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + cm_.initializeThreadLocalClusters({"cluster_1"}); + const std::string body = "hello world"; + initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + Http::ResponseMessagePtr response(new Http::ResponseMessageImpl( + Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); + response->body().add(body); + + callbacks.onSuccess(request_, std::move(response)); + return nullptr; + }); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, body); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, body); +} + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceDoNotAllowEmpty) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + xxxxxx + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + cm_.initializeThreadLocalClusters({"cluster_1"}); + initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onSuccess( + request_, Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ + new Http::TestResponseHeaderMapImpl{{":status", "503"}}})}); + return nullptr; + }); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, false, + [&](const std::string& data) { async_data = data; }); + + EXPECT_CALL(init_watcher_, ready()); + EXPECT_CALL(*retry_timer_, enableTimer(_, _)) + .WillOnce(Invoke( + [&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { retry_timer_cb_(); })); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, "non-empty"); +} + +TEST_F(AsyncDataSourceTest, DatasourceReleasedBeforeFetchingData) { + const std::string body = "hello world"; + std::string async_data = "non-empty"; + + { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + cm_.initializeThreadLocalClusters({"cluster_1"}); + initialize([&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + Http::ResponseMessagePtr response(new Http::ResponseMessageImpl( + Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); + response->body().add(body); + + callbacks.onSuccess(request_, std::move(response)); + return nullptr; + }); + + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, body); + async_data = data; + }); + } + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + init_target_handle_->initialize(init_watcher_); + EXPECT_EQ(async_data, body); +} + +TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceWithRetry) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + retry_policy: + retry_back_off: + base_interval: 1s + num_retries: 3 + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + cm_.initializeThreadLocalClusters({"cluster_1"}); + const std::string body = "hello world"; + int num_retries = 3; + + initialize( + [&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + callbacks.onSuccess( + request_, + Http::ResponseMessagePtr{new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ + new Http::TestResponseHeaderMapImpl{{":status", "503"}}})}); + return nullptr; + }, + num_retries); + + std::string async_data = "non-empty"; + remote_data_provider_ = std::make_unique( + cm_, init_manager_, config.remote(), dispatcher_, random_, true, + [&](const std::string& data) { + EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing); + EXPECT_EQ(data, body); + async_data = data; + }); + + EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing)); + EXPECT_CALL(init_watcher_, ready()); + EXPECT_CALL(*retry_timer_, enableTimer(_, _)) + .WillRepeatedly(Invoke([&](const std::chrono::milliseconds&, const ScopeTrackedObject*) { + if (--num_retries == 0) { + EXPECT_CALL(cm_.thread_local_cluster_.async_client_, send_(_, _, _)) + .WillOnce(Invoke( + [&](Http::RequestMessagePtr&, Http::AsyncClient::Callbacks& callbacks, + const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { + Http::ResponseMessagePtr response( + new Http::ResponseMessageImpl(Http::ResponseHeaderMapPtr{ + new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); + response->body().add(body); + + callbacks.onSuccess(request_, std::move(response)); + return nullptr; + })); + } + + retry_timer_cb_(); + })); + init_target_handle_->initialize(init_watcher_); + + EXPECT_EQ(async_data, body); +} + +TEST_F(AsyncDataSourceTest, BaseIntervalGreaterThanMaxInterval) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + retry_policy: + retry_back_off: + base_interval: 10s + max_interval: 1s + num_retries: 3 + )EOF"; + TestUtility::loadFromYamlAndValidate(yaml, config); + EXPECT_TRUE(config.has_remote()); + + EXPECT_THROW_WITH_MESSAGE( + std::make_unique(cm_, init_manager_, config.remote(), dispatcher_, + random_, true, [&](const std::string&) {}), + EnvoyException, "max_interval must be greater than or equal to the base_interval"); +} + +TEST_F(AsyncDataSourceTest, BaseIntervalTest) { + AsyncDataSourcePb config; + + std::string yaml = R"EOF( + remote: + http_uri: + uri: https://example.com/data + cluster: cluster_1 + timeout: 1s + sha256: + xxx + retry_policy: + retry_back_off: + base_interval: 0.0001s + num_retries: 3 + )EOF"; + EXPECT_THROW(TestUtility::loadFromYamlAndValidate(yaml, config), EnvoyException); +} + +} // namespace +} // namespace Envoy diff --git a/test/extensions/common/wasm/wasm_test.cc b/test/extensions/common/wasm/wasm_test.cc index f5e763e4851a..312d2c559774 100644 --- a/test/extensions/common/wasm/wasm_test.cc +++ b/test/extensions/common/wasm/wasm_test.cc @@ -638,7 +638,7 @@ TEST_P(WasmCommonTest, VmCache) { NiceMock init_manager; NiceMock lifecycle_notifier; Event::DispatcherPtr dispatcher(api->allocateDispatcher("wasm_test")); - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider; + RemoteAsyncDataProviderPtr remote_data_provider; auto scope = Stats::ScopeSharedPtr(stats_store.createScope("wasm.")); NiceMock local_info; auto vm_configuration = "vm_cache"; @@ -737,7 +737,7 @@ TEST_P(WasmCommonTest, RemoteCode) { NiceMock lifecycle_notifier; Init::ExpectableWatcherImpl init_watcher; Event::DispatcherPtr dispatcher(api->allocateDispatcher("wasm_test")); - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider; + RemoteAsyncDataProviderPtr remote_data_provider; auto scope = Stats::ScopeSharedPtr(stats_store.createScope("wasm.")); NiceMock local_info; auto vm_configuration = "vm_cache"; @@ -851,7 +851,7 @@ TEST_P(WasmCommonTest, RemoteCodeMultipleRetry) { NiceMock lifecycle_notifier; Init::ExpectableWatcherImpl init_watcher; Event::DispatcherPtr dispatcher(api->allocateDispatcher("wasm_test")); - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider; + RemoteAsyncDataProviderPtr remote_data_provider; auto scope = Stats::ScopeSharedPtr(stats_store.createScope("wasm.")); NiceMock local_info; auto vm_configuration = "vm_cache"; 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 a4e5ff3a71a0..660d21cbe577 100644 --- a/test/extensions/config_subscription/grpc/grpc_mux_failover_test.cc +++ b/test/extensions/config_subscription/grpc/grpc_mux_failover_test.cc @@ -24,7 +24,7 @@ class GrpcMuxFailoverTest : public testing::Test { GrpcMuxFailoverTest() // The GrpcMuxFailover test uses a the GrpcMuxFailover with mocked GrpcStream objects. : primary_stream_owner_(std::make_unique>()), - primary_stream_(*primary_stream_owner_.get()), + primary_stream_(*primary_stream_owner_), grpc_mux_failover_( /*primary_stream_creator=*/ [this](GrpcStreamCallbacks* callbacks) diff --git a/test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc b/test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc index 0dec36a101b0..65e31acc9947 100644 --- a/test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc +++ b/test/extensions/config_subscription/grpc/grpc_mux_impl_test.cc @@ -1386,6 +1386,24 @@ TEST_F(NullGrpcMuxImplTest, OnDiscoveryResponseImplemented) { EXPECT_NO_THROW(null_mux_.onDiscoveryResponse(std::move(response), cp_stats)); } +TEST(GrpcMuxFactoryTest, InvalidRateLimit) { + auto* factory = + Config::Utility::getFactoryByName("envoy.config_mux.grpc_mux_factory"); + NiceMock dispatcher; + NiceMock random; + NiceMock store; + Stats::MockScope& scope{store.mockScope()}; + NiceMock local_info; + envoy::config::core::v3::ApiConfigSource ads_config; + ads_config.mutable_rate_limit_settings()->mutable_max_tokens()->set_value(100); + ads_config.mutable_rate_limit_settings()->mutable_fill_rate()->set_value( + std::numeric_limits::quiet_NaN()); + EXPECT_THROW(factory->create(std::make_unique(), dispatcher, random, scope, + ads_config, local_info, nullptr, nullptr, absl::nullopt, + absl::nullopt, false), + EnvoyException); +} + } // namespace } // namespace Config } // namespace Envoy diff --git a/test/extensions/config_subscription/grpc/mocks.h b/test/extensions/config_subscription/grpc/mocks.h index a4dea348a144..dededb9937d6 100644 --- a/test/extensions/config_subscription/grpc/mocks.h +++ b/test/extensions/config_subscription/grpc/mocks.h @@ -10,7 +10,7 @@ namespace Config { template class MockGrpcStream : public GrpcStreamInterface { public: - MockGrpcStream() {} + MockGrpcStream() = default; ~MockGrpcStream() override = default; MOCK_METHOD(void, establishNewStream, ()); diff --git a/test/extensions/config_subscription/grpc/new_grpc_mux_impl_test.cc b/test/extensions/config_subscription/grpc/new_grpc_mux_impl_test.cc index 9888a26b6e45..fe04f30f7a8a 100644 --- a/test/extensions/config_subscription/grpc/new_grpc_mux_impl_test.cc +++ b/test/extensions/config_subscription/grpc/new_grpc_mux_impl_test.cc @@ -1,5 +1,6 @@ #include +#include "envoy/common/exception.h" #include "envoy/config/endpoint/v3/endpoint.pb.h" #include "envoy/config/endpoint/v3/endpoint.pb.validate.h" #include "envoy/config/xds_config_tracker.h" @@ -23,6 +24,7 @@ #include "test/mocks/grpc/mocks.h" #include "test/mocks/local_info/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/stats/mocks.h" #include "test/test_common/logging.h" #include "test/test_common/resources.h" #include "test/test_common/simulated_time_system.h" @@ -763,6 +765,24 @@ TEST_P(NewGrpcMuxImplTest, AddRemoveSubscriptions) { } } +TEST(NewGrpcMuxFactoryTest, InvalidRateLimit) { + auto* factory = Config::Utility::getFactoryByName( + "envoy.config_mux.new_grpc_mux_factory"); + NiceMock dispatcher; + NiceMock random; + NiceMock store; + Stats::MockScope& scope{store.mockScope()}; + NiceMock local_info; + envoy::config::core::v3::ApiConfigSource ads_config; + ads_config.mutable_rate_limit_settings()->mutable_max_tokens()->set_value(100); + ads_config.mutable_rate_limit_settings()->mutable_fill_rate()->set_value( + std::numeric_limits::quiet_NaN()); + EXPECT_THROW(factory->create(std::make_unique(), dispatcher, random, scope, + ads_config, local_info, nullptr, nullptr, absl::nullopt, + absl::nullopt, false), + EnvoyException); +} + } // namespace } // namespace Config } // namespace Envoy diff --git a/test/extensions/config_subscription/grpc/xds_grpc_mux_impl_test.cc b/test/extensions/config_subscription/grpc/xds_grpc_mux_impl_test.cc index 819c55381c20..ec78e9d4bed4 100644 --- a/test/extensions/config_subscription/grpc/xds_grpc_mux_impl_test.cc +++ b/test/extensions/config_subscription/grpc/xds_grpc_mux_impl_test.cc @@ -1300,6 +1300,42 @@ TEST_F(NullGrpcMuxImplTest, AddWatchRaisesException) { TEST_F(NullGrpcMuxImplTest, NoEdsResourcesCache) { EXPECT_EQ({}, null_mux_->edsResourcesCache()); } +TEST(UnifiedSotwGrpcMuxFactoryTest, InvalidRateLimit) { + auto* factory = Config::Utility::getFactoryByName( + "envoy.config_mux.sotw_grpc_mux_factory"); + NiceMock dispatcher; + NiceMock random; + NiceMock store; + Stats::MockScope& scope{store.mockScope()}; + NiceMock local_info; + envoy::config::core::v3::ApiConfigSource ads_config; + ads_config.mutable_rate_limit_settings()->mutable_max_tokens()->set_value(100); + ads_config.mutable_rate_limit_settings()->mutable_fill_rate()->set_value( + std::numeric_limits::quiet_NaN()); + EXPECT_THROW(factory->create(std::make_unique(), dispatcher, random, scope, + ads_config, local_info, nullptr, nullptr, absl::nullopt, + absl::nullopt, false), + EnvoyException); +} + +TEST(UnifiedDeltaGrpcMuxFactoryTest, InvalidRateLimit) { + auto* factory = Config::Utility::getFactoryByName( + "envoy.config_mux.delta_grpc_mux_factory"); + NiceMock dispatcher; + NiceMock random; + NiceMock store; + Stats::MockScope& scope{store.mockScope()}; + NiceMock local_info; + envoy::config::core::v3::ApiConfigSource ads_config; + ads_config.mutable_rate_limit_settings()->mutable_max_tokens()->set_value(100); + ads_config.mutable_rate_limit_settings()->mutable_fill_rate()->set_value( + std::numeric_limits::quiet_NaN()); + EXPECT_THROW(factory->create(std::make_unique(), dispatcher, random, scope, + ads_config, local_info, nullptr, nullptr, absl::nullopt, + absl::nullopt, false), + EnvoyException); +} + } // namespace } // namespace XdsMux } // namespace Config diff --git a/test/extensions/filters/common/expr/evaluator_corpus/incorrect_address b/test/extensions/filters/common/expr/evaluator_corpus/incorrect_address new file mode 100644 index 000000000000..480a72878d73 --- /dev/null +++ b/test/extensions/filters/common/expr/evaluator_corpus/incorrect_address @@ -0,0 +1 @@ +expression { } stream_info { address { socket_address { address: " " named_port: " " } } } \ No newline at end of file diff --git a/test/extensions/filters/http/alternate_protocols_cache/filter_integration_test.cc b/test/extensions/filters/http/alternate_protocols_cache/filter_integration_test.cc index 6994b20314ab..2f38ff058105 100644 --- a/test/extensions/filters/http/alternate_protocols_cache/filter_integration_test.cc +++ b/test/extensions/filters/http/alternate_protocols_cache/filter_integration_test.cc @@ -261,8 +261,7 @@ TEST_P(FilterIntegrationTest, AltSvcCachedH3Slow) { 100); } -// TODO(32151): Figure out why it's flaky and re-enable. -TEST_P(FilterIntegrationTest, DISABLED_AltSvcCachedH2Slow) { +TEST_P(FilterIntegrationTest, AltSvcCachedH2Slow) { #ifdef WIN32 // TODO: sort out what race only happens on windows and GCC. GTEST_SKIP() << "Skipping on Windows"; diff --git a/test/extensions/filters/http/cache/cache_filter_test.cc b/test/extensions/filters/http/cache/cache_filter_test.cc index d5a91f1a719b..9c4e1afb273d 100644 --- a/test/extensions/filters/http/cache/cache_filter_test.cc +++ b/test/extensions/filters/http/cache/cache_filter_test.cc @@ -490,6 +490,69 @@ TEST_F(CacheFilterTest, FilterDestroyedWhileWatermarkedSendsLowWatermarkEvent) { } } +MATCHER_P2(RangeMatcher, begin, end, "") { + return testing::ExplainMatchResult(begin, arg.begin(), result_listener) && + testing::ExplainMatchResult(end, arg.end(), result_listener); +} + +TEST_F(CacheFilterTest, BodyReadFromCacheLimitedToBufferSizeChunks) { + request_headers_.setHost("CacheHitWithBody"); + // Set the buffer limit to 5 bytes, and we will have the file be of size + // 8 bytes. + EXPECT_CALL(encoder_callbacks_, encoderBufferLimit()).WillRepeatedly(::testing::Return(5)); + 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}); + }); + EXPECT_CALL(*mock_lookup_context, getBody(RangeMatcher(0, 5), _)) + .WillOnce([&](const AdjustedByteRange&, LookupBodyCallback&& cb) { + cb(std::make_unique("abcde")); + }); + EXPECT_CALL(*mock_lookup_context, getBody(RangeMatcher(5, 8), _)) + .WillOnce([&](const AdjustedByteRange&, LookupBodyCallback&& cb) { + cb(std::make_unique("fgh")); + }); + EXPECT_CALL(*mock_lookup_context, onDestroy()); + + CacheFilterSharedPtr filter = makeFilter(mock_http_cache, false); + + // The filter should encode cached headers. + EXPECT_CALL(decoder_callbacks_, encodeHeaders_(IsSupersetOfHeaders(response_headers_), false)); + + // The filter should encode cached data in two pieces. + EXPECT_CALL( + decoder_callbacks_, + encodeData(testing::Property(&Buffer::Instance::toString, testing::Eq("abcde")), false)); + EXPECT_CALL(decoder_callbacks_, + encodeData(testing::Property(&Buffer::Instance::toString, testing::Eq("fgh")), true)); + + // The filter should stop decoding iteration when decodeHeaders is called as a cache lookup is + // in progress. + EXPECT_EQ(filter->decodeHeaders(request_headers_, true), + Http::FilterHeadersStatus::StopAllIterationAndWatermark); + + // The filter should not continue decoding when the cache lookup result is ready, as the + // expected result is a hit. + EXPECT_CALL(decoder_callbacks_, continueDecoding).Times(0); + + // The cache lookup callback should be posted to the dispatcher. + // Run events on the dispatcher so that the callback is invoked. + // The posted lookup callback will cause another callback to be posted (when getBody() is + // called) which should also be invoked. + dispatcher_->run(Event::Dispatcher::RunType::Block); + + filter->onDestroy(); + filter.reset(); +} + TEST_F(CacheFilterTest, CacheInsertAbortedByCache) { request_headers_.setHost("CacheHitWithBody"); const std::string body = "abc"; diff --git a/test/extensions/filters/http/common/fuzz/filter_corpus/create_filter_factory_from_proto_not_ok b/test/extensions/filters/http/common/fuzz/filter_corpus/create_filter_factory_from_proto_not_ok new file mode 100644 index 000000000000..869ab118fa71 --- /dev/null +++ b/test/extensions/filters/http/common/fuzz/filter_corpus/create_filter_factory_from_proto_not_ok @@ -0,0 +1,7 @@ +config { + name: "envoy.filters.http.decompressor" + typed_config { + type_url: "type.googleapis.com/envoy.extensions.filters.http.decompressor.v3.Decompressor" + value: "\nU\n\001t\022P\nNtype.googleapis.com/envoy.extensions.filters.http.decompressor.v3.Decompressor" + } +} diff --git a/test/extensions/filters/http/common/fuzz/filter_corpus/tap_filter_admin b/test/extensions/filters/http/common/fuzz/filter_corpus/tap_filter_admin new file mode 100644 index 000000000000..983d9999d725 --- /dev/null +++ b/test/extensions/filters/http/common/fuzz/filter_corpus/tap_filter_admin @@ -0,0 +1,7 @@ +config { + name: "envoy.filters.http.match_delegate" + typed_config { + type_url: "type.googleapis.com/envoy.extensions.common.matching.v3.ExtensionWithMatcher" + value: "\022\213\002\n\001:\022\205\002\nLtype.googleapis.com/envoy.extensions.common.matching.v3.ExtensionWithMatcher\022\264\001\022\261\001\n\001:\022\253\001\nLtype.googleapis.com/envoy.extensions.common.matching.v3.ExtensionWithMatcher\022[\022Y\n\001:\022T\n chunks = generateChunks(1, 122880); compressWith(CompressorLibs::Gzip, std::move(chunks), params, decoder_callbacks, state); } @@ -369,7 +370,8 @@ static void compressChunks16384WithGzip(benchmark::State& state) { const auto idx = state.range(0); const auto& params = gzip_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(7, 16384); compressWith(CompressorLibs::Gzip, std::move(chunks), params, decoder_callbacks, state); } @@ -385,7 +387,8 @@ static void compressChunks8192WithGzip(benchmark::State& state) { const auto idx = state.range(0); const auto& params = gzip_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(15, 8192); compressWith(CompressorLibs::Gzip, std::move(chunks), params, decoder_callbacks, state); } @@ -401,7 +404,8 @@ static void compressChunks4096WithGzip(benchmark::State& state) { const auto idx = state.range(0); const auto& params = gzip_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(30, 4096); compressWith(CompressorLibs::Gzip, std::move(chunks), params, decoder_callbacks, state); } @@ -417,7 +421,8 @@ static void compressChunks1024WithGzip(benchmark::State& state) { const auto idx = state.range(0); const auto& params = gzip_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(120, 1024); compressWith(CompressorLibs::Gzip, std::move(chunks), params, decoder_callbacks, state); } @@ -500,7 +505,8 @@ static void compressFullWithZstd(benchmark::State& state) { const auto idx = state.range(0); const auto& params = zstd_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(1, 122880); compressWith(CompressorLibs::Zstd, std::move(chunks), params, decoder_callbacks, state); } @@ -516,7 +522,8 @@ static void compressChunks16384WithZstd(benchmark::State& state) { const auto idx = state.range(0); const auto& params = zstd_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(7, 16384); compressWith(CompressorLibs::Zstd, std::move(chunks), params, decoder_callbacks, state); } @@ -532,7 +539,8 @@ static void compressChunks8192WithZstd(benchmark::State& state) { const auto idx = state.range(0); const auto& params = zstd_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(15, 8192); compressWith(CompressorLibs::Zstd, std::move(chunks), params, decoder_callbacks, state); } @@ -548,7 +556,8 @@ static void compressChunks4096WithZstd(benchmark::State& state) { const auto idx = state.range(0); const auto& params = zstd_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(30, 4096); compressWith(CompressorLibs::Zstd, std::move(chunks), params, decoder_callbacks, state); } @@ -564,7 +573,8 @@ static void compressChunks1024WithZstd(benchmark::State& state) { const auto idx = state.range(0); const auto& params = zstd_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(120, 1024); compressWith(CompressorLibs::Zstd, std::move(chunks), params, decoder_callbacks, state); } @@ -614,7 +624,8 @@ static void compressFullWithBrotli(benchmark::State& state) { const auto idx = state.range(0); const auto& params = brotli_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(1, 122880); compressWith(CompressorLibs::Brotli, std::move(chunks), params, decoder_callbacks, state); } @@ -630,7 +641,8 @@ static void compressChunks16384WithBrotli(benchmark::State& state) { const auto idx = state.range(0); const auto& params = brotli_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(7, 16384); compressWith(CompressorLibs::Brotli, std::move(chunks), params, decoder_callbacks, state); } @@ -646,7 +658,8 @@ static void compressChunks8192WithBrotli(benchmark::State& state) { const auto idx = state.range(0); const auto& params = brotli_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(15, 8192); compressWith(CompressorLibs::Brotli, std::move(chunks), params, decoder_callbacks, state); } @@ -662,7 +675,8 @@ static void compressChunks4096WithBrotli(benchmark::State& state) { const auto idx = state.range(0); const auto& params = brotli_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(30, 4096); compressWith(CompressorLibs::Brotli, std::move(chunks), params, decoder_callbacks, state); } @@ -678,7 +692,8 @@ static void compressChunks1024WithBrotli(benchmark::State& state) { const auto idx = state.range(0); const auto& params = brotli_compression_params[idx]; - for (auto _ : state) { // NOLINT + for (auto _ : state) { + UNREFERENCED_PARAMETER(_); std::vector chunks = generateChunks(120, 1024); compressWith(CompressorLibs::Brotli, std::move(chunks), params, decoder_callbacks, state); } diff --git a/test/extensions/filters/http/ext_authz/config_test.cc b/test/extensions/filters/http/ext_authz/config_test.cc index c9d716c2dab2..62909863a5ec 100644 --- a/test/extensions/filters/http/ext_authz/config_test.cc +++ b/test/extensions/filters/http/ext_authz/config_test.cc @@ -35,8 +35,8 @@ class TestAsyncClientManagerImpl : public Grpc::AsyncClientManagerImpl { const Grpc::StatNames& stat_names, const Bootstrap::GrpcAsyncClientManagerConfig& config) : Grpc::AsyncClientManagerImpl(cm, tls, time_source, api, stat_names, config) {} - Grpc::AsyncClientFactoryPtr factoryForGrpcService(const envoy::config::core::v3::GrpcService&, - Stats::Scope&, bool) override { + absl::StatusOr + factoryForGrpcService(const envoy::config::core::v3::GrpcService&, Stats::Scope&, bool) override { return std::make_unique>(); } }; @@ -211,8 +211,9 @@ class ExtAuthzFilterGrpcTest : public ExtAuthzFilterTest { Envoy::Grpc::GrpcServiceConfigWithHashKey config_with_hash_key = Envoy::Grpc::GrpcServiceConfigWithHashKey(ext_authz_config.grpc_service()); Grpc::RawAsyncClientSharedPtr async_client = - async_client_manager_->getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, - context_.scope(), false); + async_client_manager_ + ->getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context_.scope(), false) + .value(); Grpc::MockAsyncClient* mock_async_client = dynamic_cast(async_client.get()); EXPECT_NE(mock_async_client, nullptr); diff --git a/test/extensions/filters/http/ext_proc/config_test.cc b/test/extensions/filters/http/ext_proc/config_test.cc index fb982aee9b25..5c5196af6551 100644 --- a/test/extensions/filters/http/ext_proc/config_test.cc +++ b/test/extensions/filters/http/ext_proc/config_test.cc @@ -106,6 +106,23 @@ TEST(HttpExtProcConfigTest, CorrectConfigServerContext) { cb(filter_callback); } +TEST(HttpExtProcConfigTest, CorrectRouteMetadataOnlyConfig) { + std::string yaml = R"EOF( + overrides: + grpc_initial_metadata: + - key: "a" + value: "a" + )EOF"; + + ExternalProcessingFilterConfig factory; + ProtobufTypes::MessagePtr proto_config = factory.createEmptyRouteConfigProto(); + TestUtility::loadFromYaml(yaml, *proto_config); + + testing::NiceMock context; + Router::RouteSpecificFilterConfigConstSharedPtr cb = factory.createRouteSpecificFilterConfig( + *proto_config, context, context.messageValidationVisitor()); +} + } // namespace } // namespace ExternalProcessing } // namespace HttpFilters 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 fb936314551d..02efb17e237b 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 @@ -41,6 +41,7 @@ using envoy::service::ext_proc::v3::ProcessingResponse; using envoy::service::ext_proc::v3::TrailersResponse; using Extensions::HttpFilters::ExternalProcessing::HasNoHeader; using Extensions::HttpFilters::ExternalProcessing::HeaderProtosEqual; +using Extensions::HttpFilters::ExternalProcessing::makeHeaderValue; using Extensions::HttpFilters::ExternalProcessing::SingleHeaderValueIs; using Http::LowerCaseString; @@ -2580,6 +2581,43 @@ TEST_P(ExtProcIntegrationTest, PerRouteGrpcService) { EXPECT_THAT(response->headers(), SingleHeaderValueIs("x-response-processed", "1")); } +// Set up per-route configuration that extends original metadata. +TEST_P(ExtProcIntegrationTest, PerRouteGrpcMetadata) { + initializeConfig(); + + // Override metadata from route config. + config_helper_.addConfigModifier([this](HttpConnectionManager& cm) { + // Set up "/foo" so that it will use a different GrpcService + auto* vh = cm.mutable_route_config()->mutable_virtual_hosts()->Mutable(0); + auto* route = vh->mutable_routes()->Mutable(0); + route->mutable_match()->set_path("/foo"); + ExtProcPerRoute per_route; + *per_route.mutable_overrides()->mutable_grpc_initial_metadata()->Add() = + makeHeaderValue("b", "c"); + *per_route.mutable_overrides()->mutable_grpc_initial_metadata()->Add() = + makeHeaderValue("c", "c"); + setPerRouteConfig(route, per_route); + }); + + HttpIntegrationTest::initialize(); + + // Request that matches route directed to ext_proc_server_0 + auto response = + sendDownstreamRequest([](Http::RequestHeaderMap& headers) { headers.setPath("/foo"); }); + + processRequestHeadersMessage(*grpc_upstreams_[0], true, absl::nullopt); + EXPECT_EQ( + "c", + processor_stream_->headers().get(Http::LowerCaseString("b"))[0]->value().getStringView()); + EXPECT_EQ( + "c", + processor_stream_->headers().get(Http::LowerCaseString("c"))[0]->value().getStringView()); + handleUpstreamRequest(); + + processResponseHeadersMessage(*grpc_upstreams_[0], false, absl::nullopt); + verifyDownstreamResponse(*response, 200); +} + // Sending new timeout API in both downstream request and upstream response // handling path with header mutation. TEST_P(ExtProcIntegrationTest, RequestAndResponseMessageNewTimeoutWithHeaderMutation) { diff --git a/test/extensions/filters/http/ext_proc/filter_test.cc b/test/extensions/filters/http/ext_proc/filter_test.cc index 907f52aef5c6..85c742435fe7 100644 --- a/test/extensions/filters/http/ext_proc/filter_test.cc +++ b/test/extensions/filters/http/ext_proc/filter_test.cc @@ -470,7 +470,7 @@ class HttpFilterTest : public testing::Test { } } - void StreamingSmallChunksWithBodyMutation(bool empty_last_chunk, bool mutate_last_chunk) { + void streamingSmallChunksWithBodyMutation(bool empty_last_chunk, bool mutate_last_chunk) { initialize(R"EOF( grpc_service: envoy_grpc: @@ -1502,19 +1502,19 @@ TEST_F(HttpFilterTest, StreamingDataSmallChunk) { } TEST_F(HttpFilterTest, StreamingBodyMutateLastEmptyChunk) { - StreamingSmallChunksWithBodyMutation(true, true); + streamingSmallChunksWithBodyMutation(true, true); } TEST_F(HttpFilterTest, StreamingBodyNotMutateLastEmptyChunk) { - StreamingSmallChunksWithBodyMutation(true, false); + streamingSmallChunksWithBodyMutation(true, false); } TEST_F(HttpFilterTest, StreamingBodyMutateLastChunk) { - StreamingSmallChunksWithBodyMutation(false, true); + streamingSmallChunksWithBodyMutation(false, true); } TEST_F(HttpFilterTest, StreamingBodyNotMutateLastChunk) { - StreamingSmallChunksWithBodyMutation(false, false); + streamingSmallChunksWithBodyMutation(false, false); } // gRPC call fails when streaming sends small chunk request data. @@ -2998,6 +2998,33 @@ TEST(OverrideTest, GrpcServiceNonOverride) { EXPECT_THAT(*merged_route.grpcService(), ProtoEq(cfg1.overrides().grpc_service())); } +// When merging two configurations, second metadata override only extends the first's one. +TEST(OverrideTest, GrpcMetadataOverride) { + ExtProcPerRoute cfg1; + cfg1.mutable_overrides()->mutable_grpc_initial_metadata()->Add()->CopyFrom( + makeHeaderValue("a", "a")); + cfg1.mutable_overrides()->mutable_grpc_initial_metadata()->Add()->CopyFrom( + makeHeaderValue("b", "b")); + + ExtProcPerRoute cfg2; + cfg2.mutable_overrides()->mutable_grpc_initial_metadata()->Add()->CopyFrom( + makeHeaderValue("b", "c")); + cfg2.mutable_overrides()->mutable_grpc_initial_metadata()->Add()->CopyFrom( + makeHeaderValue("c", "c")); + + FilterConfigPerRoute route1(cfg1); + FilterConfigPerRoute route2(cfg2); + FilterConfigPerRoute merged_route(route1, route2); + + ASSERT_TRUE(merged_route.grpcInitialMetadata().size() == 3); + EXPECT_THAT(merged_route.grpcInitialMetadata()[0], + ProtoEq(cfg1.overrides().grpc_initial_metadata()[0])); + EXPECT_THAT(merged_route.grpcInitialMetadata()[1], + ProtoEq(cfg2.overrides().grpc_initial_metadata()[0])); + EXPECT_THAT(merged_route.grpcInitialMetadata()[2], + ProtoEq(cfg2.overrides().grpc_initial_metadata()[1])); +} + // Verify that attempts to change headers that are not allowed to be changed // are ignored and a counter is incremented. TEST_F(HttpFilterTest, IgnoreInvalidHeaderMutations) { @@ -3853,6 +3880,63 @@ TEST_F(HttpFilter2Test, LastEncodeDataCallExceedsStreamBufferLimitWouldJustRaise conn_manager_->onData(fake_input, false); } +// Test that per route metadata override does override inherited grpc_service configuration. +TEST_F(HttpFilterTest, GrpcServiceMetadataOverride) { + initialize(R"EOF( + grpc_service: + envoy_grpc: + cluster_name: "ext_proc_server" + initial_metadata: + - key: "a" + value: "a" + - key: "b" + value: "b" + )EOF"); + + // Route configuration overrides the grpc_service metadata. + ExtProcPerRoute route_proto; + *route_proto.mutable_overrides()->mutable_grpc_initial_metadata()->Add() = + makeHeaderValue("b", "c"); + *route_proto.mutable_overrides()->mutable_grpc_initial_metadata()->Add() = + makeHeaderValue("c", "c"); + FilterConfigPerRoute route_config(route_proto); + EXPECT_CALL(decoder_callbacks_, traversePerFilterConfig(_)) + .WillOnce( + testing::Invoke([&](std::function cb) { + cb(route_config); + })); + + // Build expected merged grpc_service configuration. + { + std::string expected_config = (R"EOF( + grpc_service: + envoy_grpc: + cluster_name: "ext_proc_server" + initial_metadata: + - key: "a" + value: "a" + - key: "b" + value: "c" + - key: "c" + value: "c" + )EOF"); + envoy::extensions::filters::http::ext_proc::v3::ExternalProcessor expected_proto{}; + TestUtility::loadFromYaml(expected_config, expected_proto); + final_expected_grpc_service_.emplace(expected_proto.grpc_service()); + config_with_hash_key_.setConfig(expected_proto.grpc_service()); + } + + EXPECT_EQ(FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, true)); + processRequestHeaders(false, absl::nullopt); + + const auto& meta = filter_->grpc_service_config().initial_metadata(); + EXPECT_EQ(meta[0].value(), "a"); // a = a inherited + EXPECT_EQ(meta[1].value(), "c"); // b = c overridden + EXPECT_EQ(meta[2].value(), "c"); // c = c added + + filter_->onDestroy(); +} + } // namespace } // namespace ExternalProcessing } // namespace HttpFilters diff --git a/test/extensions/filters/http/ext_proc/streaming_integration_test.cc b/test/extensions/filters/http/ext_proc/streaming_integration_test.cc index 5ebbc8ab3225..e8b4182ecd6f 100644 --- a/test/extensions/filters/http/ext_proc/streaming_integration_test.cc +++ b/test/extensions/filters/http/ext_proc/streaming_integration_test.cc @@ -36,7 +36,9 @@ class StreamingIntegrationTest : public HttpIntegrationTest, protected: StreamingIntegrationTest() : HttpIntegrationTest(Http::CodecType::HTTP2, ipVersion()) {} - ~StreamingIntegrationTest() { TearDown(); } + // TODO(yanjunxiang-google): Verify that bypassing virtual dispatch here was intentional + // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall) + ~StreamingIntegrationTest() override { StreamingIntegrationTest::TearDown(); } void TearDown() override { cleanupUpstreamAndDownstream(); diff --git a/test/extensions/filters/http/ext_proc/utils.cc b/test/extensions/filters/http/ext_proc/utils.cc index 0e322535c08a..e3723b8b728b 100644 --- a/test/extensions/filters/http/ext_proc/utils.cc +++ b/test/extensions/filters/http/ext_proc/utils.cc @@ -29,6 +29,14 @@ bool ExtProcTestUtility::headerProtosEqualIgnoreOrder( return TestUtility::headerMapEqualIgnoreOrder(expected, actual_headers); } +envoy::config::core::v3::HeaderValue makeHeaderValue(const std::string& key, + const std::string& value) { + envoy::config::core::v3::HeaderValue v; + v.set_key(key); + v.set_value(value); + return v; +} + } // namespace ExternalProcessing } // namespace HttpFilters } // namespace Extensions diff --git a/test/extensions/filters/http/ext_proc/utils.h b/test/extensions/filters/http/ext_proc/utils.h index ba88559b9c74..858e8e7cb01d 100644 --- a/test/extensions/filters/http/ext_proc/utils.h +++ b/test/extensions/filters/http/ext_proc/utils.h @@ -50,6 +50,8 @@ MATCHER_P2(SingleProtoHeaderValueIs, key, value, return false; } +envoy::config::core::v3::HeaderValue makeHeaderValue(const std::string& key, + const std::string& value); } // namespace ExternalProcessing } // namespace HttpFilters } // namespace Extensions diff --git a/test/extensions/filters/http/geoip/BUILD b/test/extensions/filters/http/geoip/BUILD index 6e626debcd4b..d0e9ec7b20a8 100644 --- a/test/extensions/filters/http/geoip/BUILD +++ b/test/extensions/filters/http/geoip/BUILD @@ -59,6 +59,7 @@ envoy_extension_cc_test( size = "large", srcs = select({ "//bazel:linux": ["geoip_filter_integration_test.cc"], + "//bazel:darwin_any": ["geoip_filter_integration_test.cc"], "//conditions:default": [], }), data = [ diff --git a/test/extensions/filters/http/geoip/geoip_filter_integration_test.cc b/test/extensions/filters/http/geoip/geoip_filter_integration_test.cc index d315b6078472..c561e5d6e815 100644 --- a/test/extensions/filters/http/geoip/geoip_filter_integration_test.cc +++ b/test/extensions/filters/http/geoip/geoip_filter_integration_test.cc @@ -7,9 +7,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using testing::DoAll; -using testing::SaveArg; - namespace Envoy { namespace Extensions { namespace HttpFilters { diff --git a/test/extensions/filters/http/header_mutation/header_mutation_integration_test.cc b/test/extensions/filters/http/header_mutation/header_mutation_integration_test.cc index 2b758fe86d33..781c8d2d0c7a 100644 --- a/test/extensions/filters/http/header_mutation/header_mutation_integration_test.cc +++ b/test/extensions/filters/http/header_mutation/header_mutation_integration_test.cc @@ -429,7 +429,7 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, HeaderMutationIntegrationTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), TestUtility::ipTestParamsToString); -void TestResponseHeaderMutation(IntegrationStreamDecoder* response, RouteLevelFlag route_level) { +void testResponseHeaderMutation(IntegrationStreamDecoder* response, RouteLevelFlag route_level) { if (route_level.test(RouteLevel::PerRoute)) { EXPECT_EQ("downstream-per-route-flag-header-value", response->headers() @@ -545,7 +545,7 @@ TEST_P(HeaderMutationIntegrationTest, TestHeaderMutationAllLevelsApplied) { ->value() .getStringView()); - TestResponseHeaderMutation(response.get(), AllRoutesLevel); + testResponseHeaderMutation(response.get(), AllRoutesLevel); EXPECT_EQ("GET", response->headers() .get(Http::LowerCaseString("request-method-in-upstream-filter"))[0] @@ -653,7 +653,7 @@ TEST_P(HeaderMutationIntegrationTest, TestHeaderMutationPerRoute) { ->value() .getStringView()); - TestResponseHeaderMutation(response.get(), PerRouteLevel); + testResponseHeaderMutation(response.get(), PerRouteLevel); EXPECT_EQ("GET", response->headers() .get(Http::LowerCaseString("request-method-in-upstream-filter"))[0] @@ -696,7 +696,7 @@ TEST_P(HeaderMutationIntegrationTest, TestHeaderMutationPerVirtualHost) { .get(Http::LowerCaseString("upstream-global-flag-header"))[0] ->value() .getStringView()); - TestResponseHeaderMutation(response.get(), VirtualHostLevel); + testResponseHeaderMutation(response.get(), VirtualHostLevel); EXPECT_EQ("GET", response->headers() .get(Http::LowerCaseString("request-method-in-upstream-filter"))[0] @@ -740,7 +740,7 @@ TEST_P(HeaderMutationIntegrationTest, TestHeaderMutationPerRouteTable) { ->value() .getStringView()); - TestResponseHeaderMutation(response.get(), RouteTableLevel); + testResponseHeaderMutation(response.get(), RouteTableLevel); EXPECT_EQ("GET", response->headers() .get(Http::LowerCaseString("request-method-in-upstream-filter"))[0] diff --git a/test/extensions/filters/http/jwt_authn/filter_config_test.cc b/test/extensions/filters/http/jwt_authn/filter_config_test.cc index b3969774d375..c5668a038c19 100644 --- a/test/extensions/filters/http/jwt_authn/filter_config_test.cc +++ b/test/extensions/filters/http/jwt_authn/filter_config_test.cc @@ -14,7 +14,6 @@ using envoy::extensions::filters::http::jwt_authn::v3::JwtAuthentication; using envoy::extensions::filters::http::jwt_authn::v3::PerRouteConfig; using testing::HasSubstr; -using testing::ReturnRef; namespace Envoy { namespace Extensions { diff --git a/test/extensions/filters/http/oauth2/filter_test.cc b/test/extensions/filters/http/oauth2/filter_test.cc index 3ac4819bc635..231f899fd611 100644 --- a/test/extensions/filters/http/oauth2/filter_test.cc +++ b/test/extensions/filters/http/oauth2/filter_test.cc @@ -247,7 +247,9 @@ TEST_F(OAuth2Test, SdsDynamicGenericSecret) { config_source, "token", secret_context, init_manager); auto token_callback = secret_context.cluster_manager_.subscription_factory_.callbacks_; - SDSSecretReader secret_reader(client_secret_provider, token_secret_provider, *api); + NiceMock tls; + SDSSecretReader secret_reader(std::move(client_secret_provider), std::move(token_secret_provider), + tls, *api); EXPECT_TRUE(secret_reader.clientSecret().empty()); EXPECT_TRUE(secret_reader.tokenSecret().empty()); 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 7317a1fdfa0b..1a81812c975d 100644 --- a/test/extensions/filters/http/rate_limit_quota/integration_test.cc +++ b/test/extensions/filters/http/rate_limit_quota/integration_test.cc @@ -372,6 +372,16 @@ TEST_P(RateLimitQuotaIntegrationTest, BasicFlowPeriodicalReport) { // 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. @@ -408,14 +418,16 @@ TEST_P(RateLimitQuotaIntegrationTest, BasicFlowPeriodicalReport) { ASSERT_TRUE(rlqs_stream_->waitForGrpcMessage(*dispatcher_, reports)); // Verify the usage report content. - for (const auto& usage : reports.bucket_quota_usages()) { - // 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); - // time_elapsed equals to periodical reporting interval. - EXPECT_EQ(Protobuf::util::TimeUtil::DurationToSeconds(usage.time_elapsed()), - report_interval_sec); - } + 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; diff --git a/test/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter_test.cc b/test/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter_test.cc index bf5e387a9877..b1adb0cc9a49 100644 --- a/test/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter_test.cc +++ b/test/extensions/filters/network/thrift_proxy/filters/payload_to_metadata/payload_to_metadata_filter_test.cc @@ -192,7 +192,7 @@ class PayloadToMetadataTest : public testing::Test, decoder->onData(buffer, underflow); } - void writeMessageMultiStruct() { + void writeMessageMultiStruct(bool list_of_struct = false) { Buffer::OwnedImpl buffer; auto metadata_ptr = std::make_shared(); @@ -229,6 +229,25 @@ class PayloadToMetadataTest : public testing::Test, proto->writeString(msg, "qux"); proto->writeFieldEnd(msg); + if (list_of_struct) { + proto->writeFieldBegin(msg, "list_of_struct", FieldType::List, 2); + const int list_size = 4; + proto->writeListBegin(msg, FieldType::Struct, 4); + + // In the list of struct, each struct has a single field "check". + for (int i = 0; i < list_size; i++) { + proto->writeStructBegin(msg, "data"); + proto->writeFieldBegin(msg, "check", FieldType::String, 1); + proto->writeString(msg, "check" + std::to_string(i)); + proto->writeFieldEnd(msg); + proto->writeFieldBegin(msg, "", FieldType::Stop, 0); // data stop field + proto->writeStructEnd(msg); + } + + proto->writeListEnd(msg); + proto->writeFieldEnd(msg); + } + proto->writeFieldBegin(msg, "", FieldType::Stop, 0); // request stop field proto->writeStructEnd(msg); proto->writeFieldEnd(msg); @@ -1316,6 +1335,52 @@ TEST_F(PayloadToMetadataTest, MultipleRulesOnMultiStruct) { filter_->onDestroy(); } +TEST_F(PayloadToMetadataTest, MultipleRulesOnListOfStruct) { + const std::string request_config_yaml = R"EOF( +request_rules: + - method_name: unmatched_foo + field_selector: + name: request + id: 2 + child: + name: baz + id: 1 + on_present: + metadata_namespace: envoy.lb + key: baz + - method_name: unmatched_foo2 + field_selector: + name: request + id: 2 + child: + name: baz + id: 1 + on_present: + metadata_namespace: envoy.lb + key: baz + - method_name: foo + field_selector: + name: request + id: 2 + child: + name: baz + id: 1 + on_present: + metadata_namespace: envoy.lb + key: baz +)EOF"; + + const std::map expected = {{"baz", "qux"}}; + + initializeFilter(request_config_yaml); + EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected))); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); + + // Add list of struct + writeMessageMultiStruct(true); + filter_->onDestroy(); +} + TEST_F(PayloadToMetadataTest, MalformPayloadWontCrash) { const std::string request_config_yaml = R"EOF( request_rules: diff --git a/test/extensions/filters/network/zookeeper_proxy/filter_test.cc b/test/extensions/filters/network/zookeeper_proxy/filter_test.cc index 72f8bba27954..823f1e43a721 100644 --- a/test/extensions/filters/network/zookeeper_proxy/filter_test.cc +++ b/test/extensions/filters/network/zookeeper_proxy/filter_test.cc @@ -223,15 +223,18 @@ class ZooKeeperFilterTest : public testing::Test { return buffer; } - Buffer::OwnedImpl - encodePathWatch(const std::string& path, const bool watch, const int32_t xid = 1000, - const int32_t opcode = enumToSignedInt(OpCodes::GetData)) const { + Buffer::OwnedImpl encodePathWatch(const std::string& path, const bool watch, + const int32_t xid = 1000, + const int32_t opcode = enumToSignedInt(OpCodes::GetData), + const bool txn = false) const { Buffer::OwnedImpl buffer; - buffer.writeBEInt(13 + path.length()); - buffer.writeBEInt(xid); - // Opcode. - buffer.writeBEInt(opcode); + if (!txn) { + buffer.writeBEInt(13 + path.length()); + buffer.writeBEInt(xid); + buffer.writeBEInt(opcode); + } + // Path. addString(buffer, path); // Watch. @@ -311,7 +314,7 @@ class ZooKeeperFilterTest : public testing::Test { return buffer; } - Buffer::OwnedImpl encodeCreateRequestWithNegativeDataLen( + Buffer::OwnedImpl encodeCreateRequestWithoutZnodeData( const std::string& path, const int32_t create_flag_val, const bool txn = false, const int32_t opcode = enumToSignedInt(OpCodes::Create)) const { Buffer::OwnedImpl buffer; @@ -596,11 +599,11 @@ class ZooKeeperFilterTest : public testing::Test { store_.counter(absl::StrCat("test.zookeeper.", opname, "_decoder_error")).value()); } - void testCreateWithNegativeDataLen(CreateFlags flag, const int32_t flag_val, - const OpCodes opcode = OpCodes::Create) { + void testCreateWithoutZnodeData(CreateFlags flag, const int32_t flag_val, + const OpCodes opcode = OpCodes::Create) { initialize(); Buffer::OwnedImpl data = - encodeCreateRequestWithNegativeDataLen("/foo", flag_val, false, enumToSignedInt(opcode)); + encodeCreateRequestWithoutZnodeData("/foo", flag_val, false, enumToSignedInt(opcode)); std::string opname = "create"; switch (opcode) { @@ -1088,8 +1091,8 @@ TEST_F(ZooKeeperFilterTest, CreateRequestPersistent) { testResponse({{{"opname", "create_resp"}, {"zxid", "2000"}, {"error", "0"}}, {{"bytes", "20"}}}); } -TEST_F(ZooKeeperFilterTest, CreateRequestPersistentWithNegativeDataLen) { - testCreateWithNegativeDataLen(CreateFlags::Persistent, 0); +TEST_F(ZooKeeperFilterTest, CreateRequestPersistentWithoutZnodeData) { + testCreateWithoutZnodeData(CreateFlags::Persistent, 0); testResponse({{{"opname", "create_resp"}, {"zxid", "2000"}, {"error", "0"}}, {{"bytes", "20"}}}); } @@ -1283,33 +1286,50 @@ TEST_F(ZooKeeperFilterTest, CheckRequest) { TEST_F(ZooKeeperFilterTest, MultiRequest) { initialize(); - Buffer::OwnedImpl create1 = encodeCreateRequest("/foo", "1", 0, true); - Buffer::OwnedImpl create2 = encodeCreateRequest("/bar", "1", 0, true); - Buffer::OwnedImpl create3 = encodeCreateRequestWithNegativeDataLen("/baz", 0, true); - Buffer::OwnedImpl check1 = encodePathVersion("/foo", 100, enumToSignedInt(OpCodes::Check), true); - Buffer::OwnedImpl set1 = encodeSetRequest("/bar", "2", -1, true); + Buffer::OwnedImpl create1 = + encodeCreateRequest("/foo", "1", 0, true, 1000, enumToSignedInt(OpCodes::Create)); + Buffer::OwnedImpl create2 = + encodeCreateRequest("/bar", "1", 0, true, 1000, enumToSignedInt(OpCodes::Create2)); + Buffer::OwnedImpl create3 = + encodeCreateRequest("/baz", "1", 0, true, 1000, enumToSignedInt(OpCodes::CreateContainer)); + Buffer::OwnedImpl create4 = + encodeCreateRequestWithoutZnodeData("/qux", 0, true, enumToSignedInt(OpCodes::CreateTtl)); + Buffer::OwnedImpl check = encodePathVersion("/foo", 100, enumToSignedInt(OpCodes::Check), true); + Buffer::OwnedImpl set = encodeSetRequest("/bar", "2", -1, true); Buffer::OwnedImpl delete1 = encodeDeleteRequest("/abcd", 1, true); Buffer::OwnedImpl delete2 = encodeDeleteRequest("/efg", 2, true); + Buffer::OwnedImpl getchildren = + encodePathWatch("/foo", false, 1000, enumToSignedInt(OpCodes::GetChildren), true); + Buffer::OwnedImpl getdata = + encodePathWatch("/bar", true, 1000, enumToSignedInt(OpCodes::GetData), true); std::vector> ops; ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Create), std::move(create1))); - ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Create), std::move(create2))); - ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Create), std::move(create3))); - ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Check), std::move(check1))); - ops.push_back(std::make_pair(enumToSignedInt(OpCodes::SetData), std::move(set1))); + ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Create2), std::move(create2))); + ops.push_back(std::make_pair(enumToSignedInt(OpCodes::CreateContainer), std::move(create3))); + ops.push_back(std::make_pair(enumToSignedInt(OpCodes::CreateTtl), std::move(create4))); + ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Check), std::move(check))); + ops.push_back(std::make_pair(enumToSignedInt(OpCodes::SetData), std::move(set))); ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Delete), std::move(delete1))); ops.push_back(std::make_pair(enumToSignedInt(OpCodes::Delete), std::move(delete2))); + ops.push_back(std::make_pair(enumToSignedInt(OpCodes::GetChildren), std::move(getchildren))); + ops.push_back(std::make_pair(enumToSignedInt(OpCodes::GetData), std::move(getdata))); Buffer::OwnedImpl data = encodeMultiRequest(ops); EXPECT_EQ(Envoy::Network::FilterStatus::Continue, filter_->onData(data, false)); EXPECT_EQ(1UL, config_->stats().multi_rq_.value()); - EXPECT_EQ(200UL, config_->stats().request_bytes_.value()); - EXPECT_EQ(200UL, config_->stats().multi_rq_bytes_.value()); - EXPECT_EQ(3UL, config_->stats().create_rq_.value()); - EXPECT_EQ(1UL, config_->stats().setdata_rq_.value()); + EXPECT_EQ(266UL, config_->stats().request_bytes_.value()); + EXPECT_EQ(266UL, config_->stats().multi_rq_bytes_.value()); + EXPECT_EQ(1UL, config_->stats().create_rq_.value()); + EXPECT_EQ(1UL, config_->stats().create2_rq_.value()); + EXPECT_EQ(1UL, config_->stats().createcontainer_rq_.value()); + EXPECT_EQ(1UL, config_->stats().createttl_rq_.value()); EXPECT_EQ(1UL, config_->stats().check_rq_.value()); + EXPECT_EQ(1UL, config_->stats().setdata_rq_.value()); EXPECT_EQ(2UL, config_->stats().delete_rq_.value()); + EXPECT_EQ(1UL, config_->stats().getchildren_rq_.value()); + EXPECT_EQ(1UL, config_->stats().getdata_rq_.value()); EXPECT_EQ(0UL, config_->stats().decoder_error_.value()); EXPECT_EQ(0UL, config_->stats().multi_decoder_error_.value()); 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 c5a27baefdf6..d1a7fada9d12 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 @@ -20,7 +20,7 @@ envoy_proto_library( envoy_cc_test_library( name = "dfp_setter_filter_config_lib", - srcs = ["dfp_setter.h"], + hdrs = ["dfp_setter.h"], deps = [ ":dfp_setter_filter_proto_cc_proto", "//envoy/registry", diff --git a/test/extensions/geoip_providers/maxmind/BUILD b/test/extensions/geoip_providers/maxmind/BUILD index 1757c2c53c8b..c39b4eb33382 100644 --- a/test/extensions/geoip_providers/maxmind/BUILD +++ b/test/extensions/geoip_providers/maxmind/BUILD @@ -16,6 +16,7 @@ envoy_extension_cc_test( size = "small", srcs = select({ "//bazel:linux": ["config_test.cc"], + "//bazel:darwin_any": ["config_test.cc"], "//conditions:default": [], }), data = [ @@ -36,6 +37,7 @@ envoy_extension_cc_test( size = "small", srcs = select({ "//bazel:linux": ["geoip_provider_test.cc"], + "//bazel:darwin_any": ["geoip_provider_test.cc"], "//conditions:default": [], }), data = [ diff --git a/test/extensions/http/stateful_session/cookie/cookie_test.cc b/test/extensions/http/stateful_session/cookie/cookie_test.cc index 866edd4fd84a..34f3a04b3ca0 100644 --- a/test/extensions/http/stateful_session/cookie/cookie_test.cc +++ b/test/extensions/http/stateful_session/cookie/cookie_test.cc @@ -52,7 +52,7 @@ TEST(CookieBasedSessionStateFactoryTest, SessionStateTest) { if (use_proto) { envoy::Cookie cookie; cookie.set_address("1.2.3.4:80"); - cookie.set_expires(1000); + // The expiration field is not set in the cookie because TTL is 0 in the config. cookie.SerializeToString(&cookie_content); } else { cookie_content = "1.2.3.4:80"; @@ -176,13 +176,13 @@ TEST(CookieBasedSessionStateFactoryTest, SessionStateProtoCookie) { EXPECT_EQ(absl::nullopt, session_state->upstreamAddress()); // PROTO format - no "expired field" - cookie.set_expires(0); + cookie.clear_expires(); cookie.SerializeToString(&cookie_content); request_headers = {{":path", "/path"}, {"cookie", "override_host=" + Envoy::Base64::encode(cookie_content.c_str(), cookie_content.length())}}; session_state = factory.create(request_headers); - EXPECT_EQ(absl::nullopt, session_state->upstreamAddress()); + EXPECT_EQ("2.3.4.5:80", session_state->upstreamAddress().value()); // PROTO format - pass incorrect format. // The content should be treated as "old" style encoding. 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 eb77fdff8e41..d4ce05473be7 100644 --- a/test/extensions/network/dns_resolver/cares/dns_impl_test.cc +++ b/test/extensions/network/dns_resolver/cares/dns_impl_test.cc @@ -794,7 +794,7 @@ class DnsImplTest : public testing::TestWithParam { const absl::optional expected_ttl) { return resolver_->resolve( address, lookup_family, - [=](DnsResolver::ResolutionStatus status, std::list&& results) -> void { + [=, this](DnsResolver::ResolutionStatus status, std::list&& results) -> void { EXPECT_EQ(expected_status, status); std::list address_as_string_list = getAddressAsStringList(results); @@ -827,7 +827,7 @@ class DnsImplTest : public testing::TestWithParam { const DnsLookupFamily lookup_family) { return resolver_->resolve( address, lookup_family, - [=](DnsResolver::ResolutionStatus status, std::list&& results) -> void { + [=, this](DnsResolver::ResolutionStatus status, std::list&& results) -> void { EXPECT_EQ(DnsResolver::ResolutionStatus::Success, status); std::list address_as_string_list = getAddressAsStringList(results); EXPECT_EQ(0, address_as_string_list.size()); diff --git a/test/extensions/resource_monitors/downstream_connections/cx_limit_overload_integration_test.cc b/test/extensions/resource_monitors/downstream_connections/cx_limit_overload_integration_test.cc index 7242c9f89cd6..b2fa4afe9659 100644 --- a/test/extensions/resource_monitors/downstream_connections/cx_limit_overload_integration_test.cc +++ b/test/extensions/resource_monitors/downstream_connections/cx_limit_overload_integration_test.cc @@ -104,7 +104,7 @@ TEST_F(GlobalDownstreamCxLimitIntegrationTest, GlobalLimitSetViaRuntimeKeyAndOve config_helper_.addRuntimeOverride("overload.global_downstream_max_connections", "3"); initializeOverloadManager(2); const std::string log_line = - "Global downstream connections limits is configured via runtime key " + "Global downstream connections limits is configured via deprecated runtime key " "overload.global_downstream_max_connections and in " "envoy.resource_monitors.global_downstream_max_connections. Using overload manager " "config."; diff --git a/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc b/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc index 6e7dc7425ce0..59ceb061fbd4 100644 --- a/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc +++ b/test/extensions/stats_sinks/metrics_service/grpc_metrics_service_impl_test.cc @@ -344,6 +344,7 @@ TEST_F(MetricsServiceSinkTest, HistogramEmitModeBoth) { const auto& metric1 = (*metrics)[0].metric(0); EXPECT_TRUE(metric1.has_summary()); + EXPECT_TRUE(metric1.summary().has_sample_sum()); const auto& metric2 = (*metrics)[1].metric(0); EXPECT_TRUE(metric2.has_histogram()); })); @@ -364,6 +365,7 @@ TEST_F(MetricsServiceSinkTest, HistogramEmitModeSummary) { const auto& metric1 = (*metrics)[0].metric(0); EXPECT_TRUE(metric1.has_summary()); + EXPECT_TRUE(metric1.summary().has_sample_sum()); })); sink.flush(snapshot_); } diff --git a/test/extensions/tracers/datadog/config_test.cc b/test/extensions/tracers/datadog/config_test.cc index 59e1e17ecea8..2d11bd74f979 100644 --- a/test/extensions/tracers/datadog/config_test.cc +++ b/test/extensions/tracers/datadog/config_test.cc @@ -251,8 +251,8 @@ TEST_F(DatadogConfigTest, CollectorHostname) { timer_->invokeCallback(); - msg.reset(new Http::ResponseMessageImpl( - Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}})); + msg = std::make_unique( + Http::ResponseHeaderMapPtr{new Http::TestResponseHeaderMapImpl{{":status", "200"}}}); msg->body().add("{}"); callbacks->onSuccess(request, std::move(msg)); diff --git a/test/extensions/tracers/opentelemetry/BUILD b/test/extensions/tracers/opentelemetry/BUILD index 96e7e5d91537..f96040354c42 100644 --- a/test/extensions/tracers/opentelemetry/BUILD +++ b/test/extensions/tracers/opentelemetry/BUILD @@ -16,8 +16,16 @@ envoy_extension_cc_test( srcs = [ "opentelemetry_tracer_impl_test.cc", ], + copts = [ + # Make sure that headers included from opentelemetry-api use Abseil from Envoy + # https://github.com/open-telemetry/opentelemetry-cpp/blob/v1.14.0/api/BUILD#L32 + "-DHAVE_ABSEIL", + ], extension_names = ["envoy.tracers.opentelemetry"], - external_deps = ["abseil_optional"], + external_deps = [ + "abseil_optional", + "opentelemetry_api", + ], deps = [ "//envoy/common:time_interface", "//envoy/runtime:runtime_interface", diff --git a/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_metadata_file_reader_test.cc b/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_metadata_file_reader_test.cc index 58132e907064..be39a3341f2b 100644 --- a/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_metadata_file_reader_test.cc +++ b/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_metadata_file_reader_test.cc @@ -8,8 +8,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using testing::Return; - namespace Envoy { namespace Extensions { namespace Tracers { diff --git a/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector_test.cc b/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector_test.cc index 2db7439d0021..9f1d94409ee4 100644 --- a/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector_test.cc +++ b/test/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector_test.cc @@ -27,8 +27,6 @@ class MockDynatraceFileReader : public DynatraceMetadataFileReader { }; TEST(DynatraceResourceDetectorTest, DynatraceNotDeployed) { - NiceMock context; - auto dt_file_reader = std::make_unique>(); EXPECT_CALL(*dt_file_reader, readEnrichmentFile(_)).WillRepeatedly(Return("")); @@ -43,7 +41,6 @@ TEST(DynatraceResourceDetectorTest, DynatraceNotDeployed) { } TEST(DynatraceResourceDetectorTest, OnlyOneAgentInstalled) { - NiceMock context; ResourceAttributes expected_attributes = { {"dt.entity.host", "HOST-abc"}, {"dt.entity.process_group_instance", "PROCESS_GROUP_INSTANCE-abc"}}; @@ -88,7 +85,6 @@ dt.entity.process_group_instance=PROCESS_GROUP_INSTANCE-abc } TEST(DynatraceResourceDetectorTest, Dynatracek8sOperator) { - NiceMock context; ResourceAttributes expected_attributes = {{"k8s.pod.uid", "123"}, {"k8s.pod.name", "envoy"}}; auto dt_file_reader = std::make_unique>(); @@ -125,6 +121,53 @@ k8s.pod.name=envoy } } +TEST(DynatraceResourceDetectorTest, TestFailureDetectionLog) { + // No enrichment file found, should log a line + { + auto dt_file_reader = std::make_unique>(); + + EXPECT_CALL(*dt_file_reader, readEnrichmentFile(_)).WillRepeatedly(Return("")); + + envoy::extensions::tracers::opentelemetry::resource_detectors::v3:: + DynatraceResourceDetectorConfig config; + + auto detector = std::make_shared(config, std::move(dt_file_reader)); + EXPECT_LOG_CONTAINS( + "warn", + "Dynatrace OpenTelemetry resource detector is configured but could not detect attributes.", + detector->detect()); + } + + // At least one enrichment file found, should NOT log a line + { + auto dt_file_reader = std::make_unique>(); + + std::string k8s_attrs = fmt::format(R"EOF( + k8s.pod.uid=123 + k8s.pod.name=envoy + )EOF"); + + EXPECT_CALL(*dt_file_reader, + readEnrichmentFile("dt_metadata_e617c525669e072eebe3d0f08212e8f2.properties")) + .WillRepeatedly(Return("")); + EXPECT_CALL(*dt_file_reader, + readEnrichmentFile("/var/lib/dynatrace/enrichment/dt_host_metadata.properties")) + .WillRepeatedly(Return("")); + EXPECT_CALL(*dt_file_reader, + readEnrichmentFile("/var/lib/dynatrace/enrichment/dt_metadata.properties")) + .WillRepeatedly(Return(k8s_attrs)); + + envoy::extensions::tracers::opentelemetry::resource_detectors::v3:: + DynatraceResourceDetectorConfig config; + + auto detector = std::make_shared(config, std::move(dt_file_reader)); + EXPECT_LOG_NOT_CONTAINS( + "warn", + "Dynatrace OpenTelemetry resource detector is configured but could not detect attributes.", + detector->detect()); + } +} + } // namespace OpenTelemetry } // namespace Tracers } // namespace Extensions diff --git a/test/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler_test.cc b/test/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler_test.cc index 79d37ca9bfe8..81c15ff7f0e4 100644 --- a/test/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/always_on/always_on_sampler_test.cc @@ -25,7 +25,7 @@ TEST(AlwaysOnSamplerTest, TestWithInvalidParentContext) { auto sampling_result = sampler->shouldSample(absl::nullopt, "operation_name", "12345", ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); - EXPECT_EQ(sampling_result.decision, Decision::RECORD_AND_SAMPLE); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); EXPECT_EQ(sampling_result.attributes, nullptr); EXPECT_STREQ(sampling_result.tracestate.c_str(), ""); EXPECT_TRUE(sampling_result.isRecording()); @@ -43,7 +43,7 @@ TEST(AlwaysOnSamplerTest, TestWithValidParentContext) { auto sampling_result = sampler->shouldSample(span_context, "operation_name", "12345", ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); - EXPECT_EQ(sampling_result.decision, Decision::RECORD_AND_SAMPLE); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); EXPECT_EQ(sampling_result.attributes, nullptr); EXPECT_STREQ(sampling_result.tracestate.c_str(), "some_tracestate"); EXPECT_TRUE(sampling_result.isRecording()); diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD b/test/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD new file mode 100644 index 000000000000..b708876da067 --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/BUILD @@ -0,0 +1,62 @@ +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 = "config_test", + srcs = ["config_test.cc"], + extension_names = ["envoy.tracers.opentelemetry.samplers.dynatrace"], + deps = [ + "//envoy/registry", + "//source/extensions/tracers/opentelemetry/samplers/dynatrace:config", + "//source/extensions/tracers/opentelemetry/samplers/dynatrace:dynatrace_sampler_lib", + "//test/mocks/server:tracer_factory_context_mocks", + "//test/test_common:utility_lib", + ], +) + +envoy_extension_cc_test( + name = "dynatrace_sampler_test", + srcs = [ + "dynatrace_sampler_test.cc", + "sampler_config_provider_test.cc", + "sampler_config_test.cc", + "sampling_controller_test.cc", + "stream_summary_test.cc", + "tenant_id_test.cc", + ], + extension_names = ["envoy.tracers.opentelemetry.samplers.dynatrace"], + deps = [ + "//source/extensions/tracers/opentelemetry/samplers/dynatrace:dynatrace_sampler_lib", + "//test/mocks/server:tracer_factory_context_mocks", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto", + ], +) + +envoy_extension_cc_test( + name = "dynatrace_sampler_integration_test", + srcs = [ + "dynatrace_sampler_integration_test.cc", + ], + extension_names = ["envoy.tracers.opentelemetry.samplers.dynatrace"], + deps = [ + "//source/exe:main_common_lib", + "//source/extensions/tracers/opentelemetry:config", + "//source/extensions/tracers/opentelemetry/resource_detectors/dynatrace:config", + "//source/extensions/tracers/opentelemetry/samplers/dynatrace:config", + "//test/integration:http_integration_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/config_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/config_test.cc new file mode 100644 index 000000000000..6860df5c0ece --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/config_test.cc @@ -0,0 +1,38 @@ +#include "envoy/registry/registry.h" + +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/config.h" + +#include "test/mocks/server/tracer_factory_context.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +// Test creating a Dynatrace sampler via factory +TEST(DynatraceSamplerFactoryTest, Test) { + auto* factory = Registry::FactoryRegistry::getFactory( + "envoy.tracers.opentelemetry.samplers.dynatrace"); + ASSERT_NE(factory, nullptr); + EXPECT_STREQ(factory->name().c_str(), "envoy.tracers.opentelemetry.samplers.dynatrace"); + EXPECT_NE(factory->createEmptyConfigProto(), nullptr); + + envoy::config::core::v3::TypedExtensionConfig typed_config; + const std::string sampler_yaml = R"EOF( + name: envoy.tracers.opentelemetry.samplers.dynatrace + typed_config: + "@type": type.googleapis.com/envoy.extensions.tracers.opentelemetry.samplers.v3.DynatraceSamplerConfig + )EOF"; + TestUtility::loadFromYaml(sampler_yaml, typed_config); + + NiceMock context; + EXPECT_NE(factory->createSampler(typed_config.typed_config(), context), nullptr); +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_integration_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_integration_test.cc new file mode 100644 index 000000000000..a3887eaf5ab4 --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_integration_test.cc @@ -0,0 +1,151 @@ +#include +#include + +#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h" + +#include "test/integration/http_integration.h" +#include "test/test_common/utility.h" + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { +namespace { + +const char* TRACEPARENT_VALUE = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"; +const char* TRACEPARENT_VALUE_START = "00-0af7651916cd43dd8448eb211c80319c"; + +class DynatraceSamplerIntegrationTest : public Envoy::HttpIntegrationTest, + public testing::TestWithParam { +public: + DynatraceSamplerIntegrationTest() : HttpIntegrationTest(Http::CodecType::HTTP1, GetParam()) { + const std::string yaml_string = R"EOF( + 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: "a_service_name" + sampler: + name: envoy.tracers.opentelemetry.samplers.dynatrace + typed_config: + "@type": type.googleapis.com/envoy.extensions.tracers.opentelemetry.samplers.v3.DynatraceSamplerConfig + tenant: "abc12345" + cluster_id: -1743916452 + )EOF"; + + auto tracing_config = + std::make_unique<::envoy::extensions::filters::network::http_connection_manager::v3:: + HttpConnectionManager_Tracing>(); + TestUtility::loadFromYaml(yaml_string, *tracing_config.get()); + config_helper_.addConfigModifier( + [&](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& + hcm) -> void { hcm.set_allocated_tracing(tracing_config.release()); }); + + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + } +}; + +INSTANTIATE_TEST_SUITE_P(IpVersions, DynatraceSamplerIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + TestUtility::ipTestParamsToString); + +// Sends a request with traceparent and tracestate header. +TEST_P(DynatraceSamplerIntegrationTest, TestWithTraceparentAndTracestate) { + // tracestate does not contain a Dynatrace tag + Http::TestRequestHeaderMapImpl request_headers{ + {":method", "GET"}, {":path", "/test/long/url"}, {":scheme", "http"}, + {":authority", "host"}, {"tracestate", "key=value"}, {"traceparent", TRACEPARENT_VALUE}}; + + auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); + EXPECT_EQ(response->headers().getStatusValue(), "200"); + + // traceparent should be set: traceid should be re-used, span id should be different + absl::string_view traceparent_value = upstream_request_->headers() + .get(Http::LowerCaseString("traceparent"))[0] + ->value() + .getStringView(); + EXPECT_TRUE(absl::StartsWith(traceparent_value, TRACEPARENT_VALUE_START)); + EXPECT_NE(TRACEPARENT_VALUE, traceparent_value); + // Dynatrace tracestate should be added to existing tracestate + absl::string_view tracestate_value = upstream_request_->headers() + .get(Http::LowerCaseString("tracestate"))[0] + ->value() + .getStringView(); + // use StartsWith because path-info (last element in trace state) contains a random value + EXPECT_TRUE(absl::StartsWith(tracestate_value, "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;")) + << "Received tracestate: " << tracestate_value; + EXPECT_TRUE(absl::StrContains(tracestate_value, ",key=value")) + << "Received tracestate: " << tracestate_value; +} + +// Sends a request with traceparent but no tracestate header. +TEST_P(DynatraceSamplerIntegrationTest, TestWithTraceparentOnly) { + Http::TestRequestHeaderMapImpl request_headers{{":method", "GET"}, + {":path", "/test/long/url"}, + {":scheme", "http"}, + {":authority", "host"}, + {"traceparent", TRACEPARENT_VALUE}}; + auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); + EXPECT_EQ(response->headers().getStatusValue(), "200"); + + // traceparent should be set: traceid should be re-used, span id should be different + absl::string_view traceparent_value = upstream_request_->headers() + .get(Http::LowerCaseString("traceparent"))[0] + ->value() + .getStringView(); + EXPECT_TRUE(absl::StartsWith(traceparent_value, TRACEPARENT_VALUE_START)); + EXPECT_NE(TRACEPARENT_VALUE, traceparent_value); + // Dynatrace tag should be added to tracestate + absl::string_view tracestate_value = upstream_request_->headers() + .get(Http::LowerCaseString("tracestate"))[0] + ->value() + .getStringView(); + // use StartsWith because path-info (last element in trace state contains a random value) + EXPECT_TRUE(absl::StartsWith(tracestate_value, "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;")) + << "Received tracestate: " << tracestate_value; +} + +// Sends a request without traceparent and tracestate header. +TEST_P(DynatraceSamplerIntegrationTest, TestWithoutTraceparentAndTracestate) { + Http::TestRequestHeaderMapImpl request_headers{ + {":method", "GET"}, {":path", "/test/long/url"}, {":scheme", "http"}, {":authority", "host"}}; + + auto response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); + + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_TRUE(response->complete()); + EXPECT_EQ(response->headers().getStatusValue(), "200"); + + // traceparent will be added, trace_id and span_id will be generated, so there is nothing we can + // assert + EXPECT_EQ(upstream_request_->headers().get(::Envoy::Http::LowerCaseString("traceparent")).size(), + 1); + // Dynatrace tag should be added to tracestate + absl::string_view tracestate_value = upstream_request_->headers() + .get(Http::LowerCaseString("tracestate"))[0] + ->value() + .getStringView(); + EXPECT_TRUE(absl::StartsWith(tracestate_value, "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;")) + << "Received tracestate: " << tracestate_value; +} + +} // namespace +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_test.cc new file mode 100644 index 000000000000..44f09c7a600c --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler_test.cc @@ -0,0 +1,336 @@ +#include +#include + +#include "envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.pb.h" + +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h" +#include "source/extensions/tracers/opentelemetry/span_context.h" + +#include "test/mocks/server/tracer_factory_context.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +namespace { + +const char* trace_id = "67a9a23155e1741b5b35368e08e6ece5"; + +const char* parent_span_id = "9d83def9a4939b7b"; + +const char* dt_tracestate_ignored = + "5b3f9fed-980df25c@dt=fw4;4;4af38366;0;0;1;2;123;8eae;2h01;3h4af38366;4h00;5h01;" + "6h67a9a23155e1741b5b35368e08e6ece5;7h9d83def9a4939b7b"; +const char* dt_tracestate_sampled = + "5b3f9fed-980df25c@dt=fw4;4;4af38366;0;0;0;0;123;8eae;2h01;3h4af38366;4h00;5h01;" + "6h67a9a23155e1741b5b35368e08e6ece5;7h9d83def9a4939b7b"; +const char* dt_tracestate_ignored_different_tenant = + "6666ad40-980df25c@dt=fw4;4;4af38366;0;0;1;2;123;8eae;2h01;3h4af38366;4h00;5h01;" + "6h67a9a23155e1741b5b35368e08e6ece5;7h9d83def9a4939b7b"; + +} // namespace + +class MockSamplerConfigProvider : public SamplerConfigProvider { +public: + MOCK_METHOD(const SamplerConfig&, getSamplerConfig, (), (const override)); +}; + +class DynatraceSamplerTest : public testing::Test { + + const std::string yaml_string_ = R"EOF( + tenant: "abc12345" + cluster_id: -1743916452 + )EOF"; + +public: + DynatraceSamplerTest() { + TestUtility::loadFromYaml(yaml_string_, proto_config_); + auto scf = std::make_unique>(); + ON_CALL(*scf, getSamplerConfig()).WillByDefault(testing::ReturnRef(sampler_config_)); + + timer_ = new NiceMock( + &tracer_factory_context_.server_factory_context_.dispatcher_); + ON_CALL(tracer_factory_context_.server_factory_context_.dispatcher_, createTimer_(_)) + .WillByDefault(Invoke([this](Event::TimerCb) { return timer_; })); + sampler_ = + std::make_unique(proto_config_, tracer_factory_context_, std::move(scf)); + } + +protected: + NiceMock tracer_factory_context_; + envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig proto_config_; + SamplerConfig sampler_config_{SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT}; + NiceMock* timer_; + std::unique_ptr sampler_; +}; + +// Verify getDescription +TEST_F(DynatraceSamplerTest, TestGetDescription) { + EXPECT_STREQ(sampler_->getDescription().c_str(), "DynatraceSampler"); +} + +// Verify sampler being invoked with an invalid/empty span context +TEST_F(DynatraceSamplerTest, TestWithoutParentContext) { + auto sampling_result = + sampler_->shouldSample(absl::nullopt, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); + EXPECT_EQ(sampling_result.attributes->size(), 1); + EXPECT_STREQ( + sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1"); + EXPECT_STREQ(sampling_result.tracestate.c_str(), "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95"); + EXPECT_TRUE(sampling_result.isRecording()); + EXPECT_TRUE(sampling_result.isSampled()); +} + +// Verify sampler being invoked without a Dynatrace tracestate +TEST_F(DynatraceSamplerTest, TestWithUnknownParentContext) { + SpanContext parent_context("00", trace_id, parent_span_id, true, "some_vendor=some_value"); + + auto sampling_result = + sampler_->shouldSample(parent_context, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); + EXPECT_EQ(sampling_result.attributes->size(), 1); + EXPECT_STREQ( + sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1"); + // Dynatrace tracestate should be prepended + EXPECT_STREQ(sampling_result.tracestate.c_str(), + "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,some_vendor=some_value"); + EXPECT_TRUE(sampling_result.isRecording()); + EXPECT_TRUE(sampling_result.isSampled()); +} + +// Verify sampler being invoked with Dynatrace trace state +TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextSampled) { + SpanContext parent_context("00", trace_id, parent_span_id, true, dt_tracestate_sampled); + + auto sampling_result = + sampler_->shouldSample(parent_context, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); + EXPECT_EQ(sampling_result.attributes->size(), 1); + EXPECT_STREQ( + sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1"); + // tracestate should be forwarded + EXPECT_STREQ(sampling_result.tracestate.c_str(), dt_tracestate_sampled); + // sampling decision from parent should be respected + EXPECT_TRUE(sampling_result.isRecording()); + EXPECT_TRUE(sampling_result.isSampled()); +} + +// Verify sampler being invoked with an invalid Dynatrace trace state +TEST_F(DynatraceSamplerTest, TestWithInvalidDynatraceParentContext) { + const char* invalidts = "5b3f9fed-980df25c@dt=fw4;4"; + SpanContext parent_context("00", trace_id, parent_span_id, true, invalidts); + + auto sampling_result = + sampler_->shouldSample(parent_context, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); + EXPECT_STREQ(sampling_result.tracestate.c_str(), + "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,5b3f9fed-980df25c@dt=fw4;4"); + EXPECT_TRUE(sampling_result.isRecording()); + EXPECT_TRUE(sampling_result.isSampled()); +} + +// Verify sampler being invoked with an invalid Dynatrace trace state +TEST_F(DynatraceSamplerTest, TestWithInvalidDynatraceParentContext1) { + // invalid tracestate[6] has to be an int + const char* invalidts = "5b3f9fed-980df25c@dt=fw4;4;4af38366;0;0;0;X;123"; + SpanContext parent_context("00", trace_id, parent_span_id, true, invalidts); + + auto sampling_result = + sampler_->shouldSample(parent_context, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); + EXPECT_STREQ( + sampling_result.tracestate.c_str(), + "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,5b3f9fed-980df25c@dt=fw4;4;4af38366;0;0;0;X;123"); + EXPECT_TRUE(sampling_result.isRecording()); + EXPECT_TRUE(sampling_result.isSampled()); +} + +// Verify sampler being invoked with an old Dynatrace trace state version +TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextOtherVersion) { + const char* oldts = + "5b3f9fed-980df25c@dt=fw3;4;4af38366;0;0;0;0;123;8eae;2h01;3h4af38366;4h00;5h01;" + "6h67a9a23155e1741b5b35368e08e6ece5;7h9d83def9a4939b7b"; + SpanContext parent_context("00", trace_id, parent_span_id, true, oldts); + + auto sampling_result = + sampler_->shouldSample(parent_context, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); + EXPECT_STREQ( + sampling_result.tracestate.c_str(), + "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,5b3f9fed-980df25c@dt=fw3;4;4af38366;0;0;0;0;123;" + "8eae;2h01;3h4af38366;4h00;5h01;6h67a9a23155e1741b5b35368e08e6ece5;7h9d83def9a4939b7b"); + EXPECT_TRUE(sampling_result.isRecording()); + EXPECT_TRUE(sampling_result.isSampled()); +} + +// Verify sampler being invoked with Dynatrace trace parent where ignored flag is set +TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextIgnored) { + SpanContext parent_context("00", trace_id, parent_span_id, true, dt_tracestate_ignored); + + auto sampling_result = + sampler_->shouldSample(parent_context, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + EXPECT_EQ(sampling_result.decision, Decision::Drop); + EXPECT_EQ(sampling_result.attributes->size(), 2); + EXPECT_STREQ( + sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "4"); + EXPECT_STREQ(sampling_result.attributes->find("sampling.threshold")->second.c_str(), + "54043195528445952"); + // tracestate should be forwarded + EXPECT_STREQ(sampling_result.tracestate.c_str(), dt_tracestate_ignored); + // sampling decision from parent should be respected + EXPECT_FALSE(sampling_result.isRecording()); + EXPECT_FALSE(sampling_result.isSampled()); +} + +// Verify sampler being invoked with Dynatrace trace parent from a different tenant +TEST_F(DynatraceSamplerTest, TestWithDynatraceParentContextFromDifferentTenant) { + SpanContext parent_context("00", trace_id, parent_span_id, true, + dt_tracestate_ignored_different_tenant); + + auto sampling_result = + sampler_->shouldSample(parent_context, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, {}, {}); + // sampling decision on tracestate should be ignored because it is from a different tenant. + EXPECT_EQ(sampling_result.decision, Decision::RecordAndSample); + EXPECT_EQ(sampling_result.attributes->size(), 1); + EXPECT_STREQ( + sampling_result.attributes->find("supportability.atm_sampling_ratio")->second.c_str(), "1"); + // new Dynatrace tag should be prepended, already existing tag should be kept + const char* exptected = + "5b3f9fed-980df25c@dt=fw4;0;0;0;0;0;0;95,6666ad40-980df25c@dt=fw4;4;4af38366;0;0;1;2;123;" + "8eae;2h01;3h4af38366;4h00;5h01;6h67a9a23155e1741b5b35368e08e6ece5;7h9d83def9a4939b7b"; + EXPECT_STREQ(sampling_result.tracestate.c_str(), exptected); + EXPECT_TRUE(sampling_result.isRecording()); + EXPECT_TRUE(sampling_result.isSampled()); +} + +// Verify sampler being called during warm up phase (no recent top_k available) +TEST_F(DynatraceSamplerTest, TestWarmup) { + // config should allow 200 root spans per minute + sampler_config_.parse("{\n \"rootSpansPerMinute\" : 200 \n }"); + + Tracing::TestTraceContextImpl trace_context_1{}; + trace_context_1.context_method_ = "GET"; + trace_context_1.context_path_ = "/path"; + + // timer is not invoked, because we want to test warm up phase. + // we use 200 as threshold. As long as number of requests is < (threshold/2), exponent should be 0 + uint32_t ignored = 0; + uint32_t sampled = 0; + for (int i = 0; i < 99; i++) { + auto result = sampler_->shouldSample({}, std::to_string(1000 + i), "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_1, {}); + result.isSampled() ? sampled++ : ignored++; + } + EXPECT_EQ(ignored, 0); + EXPECT_EQ(sampled, 99); + + // next (threshold/2) spans will get exponent 1, every second span will be sampled + for (int i = 0; i < 100; i++) { + auto result = sampler_->shouldSample({}, std::to_string(1000 + i), "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_1, {}); + result.isSampled() ? sampled++ : ignored++; + } + // should be 50 ignored, but the used "random" in shouldSample does not produce the same odd/even + // numbers. + EXPECT_EQ(ignored, 41); + EXPECT_EQ(sampled, 158); + + // send more requests + for (int i = 0; i < 100; i++) { + auto result = sampler_->shouldSample({}, std::to_string(1000 + i), "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_1, {}); + result.isSampled() ? sampled++ : ignored++; + } + // exponent should be 2, with a perfect random we would get 25 sampled and 75 ignored. + EXPECT_EQ(ignored, 113); + EXPECT_EQ(sampled, 186); + + // send more requests. + for (int i = 0; i < 700; i++) { + auto result = sampler_->shouldSample({}, std::to_string(1000 + i), "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_1, {}); + result.isSampled() ? sampled++ : ignored++; + } + // with a perfect random, the number of sampled paths would be lower than threshold (200) + // We don't care about exceeding the threshold because it is not a hard limit + EXPECT_EQ(ignored, 791); + EXPECT_EQ(sampled, 208); +} + +// Verify sampling if number of configured spans per minute is exceeded. +TEST_F(DynatraceSamplerTest, TestSampling) { + // config should allow 200 root spans per minute + sampler_config_.parse("{\n \"rootSpansPerMinute\" : 200 \n }"); + + Tracing::TestTraceContextImpl trace_context_1{}; + trace_context_1.context_method_ = "GET"; + trace_context_1.context_path_ = "/path"; + Tracing::TestTraceContextImpl trace_context_2{}; + trace_context_2.context_method_ = "POST"; + trace_context_2.context_path_ = "/path"; + Tracing::TestTraceContextImpl trace_context_3{}; + trace_context_3.context_method_ = "POST"; + trace_context_3.context_path_ = "/another_path"; + + // simulate requests + for (int i = 0; i < 180; i++) { + sampler_->shouldSample({}, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_1, {}); + sampler_->shouldSample({}, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_2, {}); + } + + sampler_->shouldSample({}, trace_id, "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, trace_context_3, + {}); + + // sampler should update sampling exponents based on number of requests in the previous period + timer_->invokeCallback(); + + // the sampler should not sample every span for 'trace_context_1' + // we call it again 10 times. This should be enough to get at least one ignored span + // 'i' is used as 'random trace_id' + bool ignored = false; + for (int i = 0; i < 10; i++) { + auto result = sampler_->shouldSample({}, std::to_string(i), "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_1, {}); + if (!result.isSampled()) { + ignored = true; + break; + } + } + EXPECT_TRUE(ignored); + + // trace_context_3 should always be sampled. + for (int i = 0; i < 10; i++) { + auto result = sampler_->shouldSample({}, std::to_string(i), "operation_name", + ::opentelemetry::proto::trace::v1::Span::SPAN_KIND_SERVER, + trace_context_2, {}); + EXPECT_TRUE(result.isSampled()); + } +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider_test.cc new file mode 100644 index 000000000000..d5a8c68d71b8 --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider_test.cc @@ -0,0 +1,95 @@ +#include +#include +#include + +#include "envoy/config/core/v3/http_uri.pb.h" + +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_provider.h" + +#include "test/mocks/common.h" +#include "test/mocks/http/mocks.h" +#include "test/mocks/server/tracer_factory_context.h" +#include "test/mocks/tracing/mocks.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +using testing::NiceMock; +using testing::Return; +using testing::ReturnRef; + +class SamplerConfigProviderTest : public testing::Test { +public: +protected: + NiceMock tracer_factory_context_; +}; + +TEST_F(SamplerConfigProviderTest, TestValueConfigured) { + const std::string yaml_string = R"EOF( + tenant: "abc12345" + cluster_id: -1743916452 + token: "tokenval" + http_uri: + cluster: "cluster_name" + uri: "https://testhost.com/otlp/v1/traces" + timeout: 0.250s + root_spans_per_minute: 3456 + + )EOF"; + + envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig proto_config; + TestUtility::loadFromYaml(yaml_string, proto_config); + + SamplerConfigProviderImpl config_provider(tracer_factory_context_, proto_config); + EXPECT_EQ(config_provider.getSamplerConfig().getRootSpansPerMinute(), 3456); +} + +TEST_F(SamplerConfigProviderTest, TestNoValueConfigured) { + const std::string yaml_string = R"EOF( + tenant: "abc12345" + cluster_id: -1743916452 + token: "tokenval" + http_uri: + cluster: "cluster_name" + uri: "https://testhost.com/otlp/v1/traces" + timeout: 0.250s + + )EOF"; + + envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig proto_config; + TestUtility::loadFromYaml(yaml_string, proto_config); + + SamplerConfigProviderImpl config_provider(tracer_factory_context_, proto_config); + EXPECT_EQ(config_provider.getSamplerConfig().getRootSpansPerMinute(), + SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); +} + +TEST_F(SamplerConfigProviderTest, TestValueZeroConfigured) { + const std::string yaml_string = R"EOF( + tenant: "abc12345" + cluster_id: -1743916452 + token: "tokenval" + http_uri: + cluster: "cluster_name" + uri: "https://testhost.com/otlp/v1/traces" + timeout: 0.250s + root_spans_per_minute: 0 + )EOF"; + + envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig proto_config; + TestUtility::loadFromYaml(yaml_string, proto_config); + + SamplerConfigProviderImpl config_provider(tracer_factory_context_, proto_config); + EXPECT_EQ(config_provider.getSamplerConfig().getRootSpansPerMinute(), + SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_test.cc new file mode 100644 index 000000000000..8cb45a8ca3e6 --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_test.cc @@ -0,0 +1,64 @@ +#include +#include + +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +// Test sampler config json parsing +TEST(SamplerConfigTest, TestParsing) { + // default_root_spans_per_minute not set, ROOT_SPANS_PER_MINUTE_DEFAULT should be used + SamplerConfig config(0); + config.parse("{\n \"rootSpansPerMinute\" : 2000 \n }"); + EXPECT_EQ(config.getRootSpansPerMinute(), 2000u); + config.parse("{\n \"rootSpansPerMinute\" : 10000 \n }"); + EXPECT_EQ(config.getRootSpansPerMinute(), 10000u); + + // unexpected json, default value should be used + config.parse("{}"); + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + + config.parse(""); + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + + config.parse("\\"); + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + + config.parse(" { "); + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + + config.parse("{\n \"rootSpansPerMinute\" : 10000 "); // closing } is missing + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); +} + +// Test sampler config default root spans per minute +TEST(SamplerConfigTest, TestDefaultConfig) { + { + SamplerConfig config(0); + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + config.parse(" { "); // parse invalid json, default value should still be used + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + } + { + SamplerConfig config(900); + EXPECT_EQ(config.getRootSpansPerMinute(), 900); + config.parse(" { "); + EXPECT_EQ(config.getRootSpansPerMinute(), 900); + } + { + SamplerConfig config(SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + config.parse(" { "); + EXPECT_EQ(config.getRootSpansPerMinute(), SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT); + } +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller_test.cc new file mode 100644 index 000000000000..f56f2c86d4a3 --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller_test.cc @@ -0,0 +1,321 @@ +#include +#include +#include +#include +#include +#include + +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_sampler.h" +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampling_controller.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +namespace { + +// helper to offer a value multiple times to SamplingController +void offerEntry(SamplingController& sc, const std::string& value, int count) { + for (int i = 0; i < count; i++) { + sc.offer(value); + } +} + +} // namespace + +class TestSamplerConfigProvider : public SamplerConfigProvider { +public: + TestSamplerConfigProvider( + uint32_t root_spans_per_minute = SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT) + : config(root_spans_per_minute) {} + const SamplerConfig& getSamplerConfig() const override { return config; } + SamplerConfig config; +}; + +// Test with multiple different sampling keys (StreamSummary size exceeded) +TEST(SamplingControllerTest, TestStreamSummarySizeExceeded) { + auto scf = std::make_unique(); + SamplingController sc(std::move(scf)); + + offerEntry(sc, "1", 2000); + offerEntry(sc, "2", 1000); + offerEntry(sc, "3", 750); + offerEntry(sc, "4", 100); + offerEntry(sc, "5", 50); + // add unique sampling keys + for (int64_t i = 0; i < 2100; i++) { + sc.offer(std::to_string(i + 1000000)); + } + + sc.update(); + + EXPECT_EQ(sc.getEffectiveCount(), 1110); + EXPECT_EQ(sc.getSamplingState("1").getMultiplicity(), 128); + EXPECT_EQ(sc.getSamplingState("2").getMultiplicity(), 64); + EXPECT_EQ(sc.getSamplingState("3").getMultiplicity(), 64); + EXPECT_EQ(sc.getSamplingState("4").getMultiplicity(), 8); + EXPECT_EQ(sc.getSamplingState("5").getMultiplicity(), 4); + EXPECT_EQ(sc.getSamplingState("1000000").getMultiplicity(), 2); + EXPECT_EQ(sc.getSamplingState("1000001").getMultiplicity(), 2); + EXPECT_EQ(sc.getSamplingState("1000002").getMultiplicity(), 2); +} + +// Test with 0 root span per minute +TEST(SamplingControllerTest, TestWithZeroAllowedSpan) { + // using 0 does not make sense, but let's ensure there is divide by zero + auto scf = std::make_unique(0); + SamplingController sc(std::move(scf)); + EXPECT_EQ(sc.getSamplingState("1").getMultiplicity(), 1); + sc.update(); + EXPECT_EQ(sc.getSamplingState("1").getMultiplicity(), 1); + offerEntry(sc, "1", 1); + sc.update(); + EXPECT_EQ(sc.getSamplingState("1").getMultiplicity(), 1); +} + +// Test with 1 root span per minute +TEST(SamplingControllerTest, TestWithOneAllowedSpan) { + auto scf = std::make_unique(1); + SamplingController sc(std::move(scf)); + sc.update(); + EXPECT_EQ(sc.getSamplingState("1").getExponent(), SamplingController::MAX_SAMPLING_EXPONENT); + offerEntry(sc, "1", 1); + EXPECT_EQ(sc.getSamplingState("1").getExponent(), SamplingController::MAX_SAMPLING_EXPONENT); + sc.update(); + EXPECT_EQ(sc.getSamplingState("1").getMultiplicity(), 1); +} + +// Test with StreamSummary size not exceeded +TEST(SamplingControllerTest, TestStreamSummarySizeNotExceeded) { + auto scf = std::make_unique(); + SamplingController sc(std::move(scf)); + + offerEntry(sc, "1", 8600); + offerEntry(sc, "2", 5000); + offerEntry(sc, "3", 4000); + offerEntry(sc, "4", 4000); + offerEntry(sc, "5", 3000); + offerEntry(sc, "6", 30); + offerEntry(sc, "7", 3); + offerEntry(sc, "8", 1); + + sc.update(); + + EXPECT_EQ(sc.getEffectiveCount(), 1074); + EXPECT_EQ(sc.getSamplingState("1").getMultiplicity(), 64); + EXPECT_EQ(sc.getSamplingState("2").getMultiplicity(), 32); + EXPECT_EQ(sc.getSamplingState("3").getMultiplicity(), 32); + EXPECT_EQ(sc.getSamplingState("4").getMultiplicity(), 16); + EXPECT_EQ(sc.getSamplingState("5").getMultiplicity(), 8); + EXPECT_EQ(sc.getSamplingState("6").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("7").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("8").getMultiplicity(), 1); +} + +// Test with StreamSummary size not exceeded +TEST(SamplingControllerTest, TestStreamSummarySizeNotExceeded1) { + auto scf = std::make_unique(); + SamplingController sc(std::move(scf)); + + offerEntry(sc, "1", 7500); + offerEntry(sc, "2", 1000); + offerEntry(sc, "3", 1); + offerEntry(sc, "4", 1); + offerEntry(sc, "5", 1); + for (int64_t i = 0; i < 11; i++) { + sc.offer(std::to_string(i + 1000000)); + } + + sc.update(); + + EXPECT_EQ(sc.getEffectiveCount(), 1451); + EXPECT_EQ(sc.getSamplingState("1").getMultiplicity(), 8); + EXPECT_EQ(sc.getSamplingState("2").getMultiplicity(), 2); + EXPECT_EQ(sc.getSamplingState("3").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("4").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("5").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("1000000").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("1000001").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("1000002").getMultiplicity(), 1); + EXPECT_EQ(sc.getSamplingState("1000003").getMultiplicity(), 1); +} + +// Test using a sampler config having non-default root spans per minute +TEST(SamplingControllerTest, TestNonDefaultRootSpansPerMinute) { + auto scf = std::make_unique(); + scf->config.parse("{\n \"rootSpansPerMinute\" : 100 \n }"); + SamplingController sc(std::move(scf)); + + offerEntry(sc, "GET_xxxx", 300); + offerEntry(sc, "POST_asdf", 200); + offerEntry(sc, "GET_asdf", 100); + + sc.update(); + + EXPECT_EQ(sc.getSamplingState("GET_xxxx").getExponent(), 3); + EXPECT_EQ(sc.getSamplingState("GET_xxxx").getMultiplicity(), 8); + + EXPECT_EQ(sc.getSamplingState("POST_asdf").getExponent(), 2); + EXPECT_EQ(sc.getSamplingState("POST_asdf").getMultiplicity(), 4); + + EXPECT_EQ(sc.getSamplingState("GET_asdf").getExponent(), 1); + EXPECT_EQ(sc.getSamplingState("GET_asdf").getMultiplicity(), 2); +} + +// Test warm up phase (no SamplingState available) +TEST(SamplingControllerTest, TestWarmup) { + auto scf = std::make_unique(); + SamplingController sc(std::move(scf)); + + // offer entries, but don't call update(); + // sampling exponents table will be empty + // exponent will be calculated based on total count. + // same exponent for both existing and non-existing keys. + + offerEntry(sc, "GET_0", 10); + EXPECT_EQ(sc.getSamplingState("GET_0").getExponent(), 0); + EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 0); + EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 0); + + offerEntry(sc, "GET_1", 540); + // threshold/2 reached, sampling exponent is set to 1 + EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 1); + EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 1); + EXPECT_EQ(sc.getSamplingState("GET_3").getExponent(), 1); + + offerEntry(sc, "GET_2", 300); + EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 1); + EXPECT_EQ(sc.getSamplingState("GET_2").getExponent(), 1); + EXPECT_EQ(sc.getSamplingState("GET_123").getExponent(), 1); + + offerEntry(sc, "GET_4", 550); + EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 2); + EXPECT_EQ(sc.getSamplingState("GET_4").getExponent(), 2); + EXPECT_EQ(sc.getSamplingState("GET_234").getExponent(), 2); + + offerEntry(sc, "GET_5", 1000); + EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 4); + EXPECT_EQ(sc.getSamplingState("GET_5").getExponent(), 4); + EXPECT_EQ(sc.getSamplingState("GET_456").getExponent(), 4); + + offerEntry(sc, "GET_6", 2000); + EXPECT_EQ(sc.getSamplingState("GET_1").getExponent(), 8); + EXPECT_EQ(sc.getSamplingState("GET_6").getExponent(), 8); + EXPECT_EQ(sc.getSamplingState("GET_789").getExponent(), 8); +} + +// Test getting sampling state from an empty SamplingController +TEST(SamplingControllerTest, TestEmpty) { + auto scf = std::make_unique(); + SamplingController sc(std::move(scf)); + + sc.update(); + // default SamplingState is expected + EXPECT_EQ(sc.getSamplingState("GET_something").getExponent(), 0); + EXPECT_EQ(sc.getSamplingState("GET_something").getMultiplicity(), 1); +} + +// Test getting sampling state for an unknown key from a non-empty SamplingController +TEST(SamplingControllerTest, TestUnknown) { + auto scf = std::make_unique(); + SamplingController sc(std::move(scf)); + + sc.offer("key1"); + sc.update(); + + EXPECT_EQ(sc.getSamplingState("key2").getExponent(), 0); + EXPECT_EQ(sc.getSamplingState("key2").getMultiplicity(), 1); + + // Exceed capacity, + for (uint32_t i = 0; i < SamplerConfig::ROOT_SPANS_PER_MINUTE_DEFAULT * 2; i++) { + sc.offer("key1"); + } + sc.update(); + // "key1" will get exponent 1 + EXPECT_EQ(sc.getSamplingState("key1").getExponent(), 1); + // unknown "key2" will get the same exponent + EXPECT_EQ(sc.getSamplingState("key2").getExponent(), 1); +} + +// Test increasing and decreasing sampling exponent +TEST(SamplingStateTest, TestIncreaseDecrease) { + SamplingState sst{}; + EXPECT_EQ(sst.getExponent(), 0); + EXPECT_EQ(sst.getMultiplicity(), 1); + + sst.increaseExponent(); + EXPECT_EQ(sst.getExponent(), 1); + EXPECT_EQ(sst.getMultiplicity(), 2); + + sst.increaseExponent(); + EXPECT_EQ(sst.getExponent(), 2); + EXPECT_EQ(sst.getMultiplicity(), 4); + + for (int i = 0; i < 6; i++) { + sst.increaseExponent(); + } + EXPECT_EQ(sst.getExponent(), 8); + EXPECT_EQ(sst.getMultiplicity(), 256); + + sst.decreaseExponent(); + EXPECT_EQ(sst.getExponent(), 7); + EXPECT_EQ(sst.getMultiplicity(), 128); +} + +// Test SamplingState shouldSample() +TEST(SamplingStateTest, TestShouldSample) { + // default sampling state should sample every request + SamplingState sst{}; + EXPECT_TRUE(sst.shouldSample(1234)); + EXPECT_TRUE(sst.shouldSample(2345)); + EXPECT_TRUE(sst.shouldSample(3456)); + EXPECT_TRUE(sst.shouldSample(4567)); + + // exponent 1, multiplicity 2, + // we are using % for sampling decision, so even (=not odd) random numbers should be sampled + sst.increaseExponent(); + EXPECT_TRUE(sst.shouldSample(22)); + EXPECT_TRUE(sst.shouldSample(4444444)); + EXPECT_FALSE(sst.shouldSample(21)); + EXPECT_FALSE(sst.shouldSample(111111)); + + for (int i = 0; i < 9; i++) { + sst.increaseExponent(); + } + // exponent 10, multiplicity 1024, + EXPECT_TRUE(sst.shouldSample(1024)); + EXPECT_TRUE(sst.shouldSample(2048)); + EXPECT_TRUE(sst.shouldSample(4096)); + EXPECT_TRUE(sst.shouldSample(10240000000)); + EXPECT_FALSE(sst.shouldSample(1023)); + EXPECT_FALSE(sst.shouldSample(1025)); + EXPECT_FALSE(sst.shouldSample(2047)); + EXPECT_FALSE(sst.shouldSample(2049)); +} + +// Test creating sampling key used to identify a request +TEST(SamplingControllerTest, TestGetSamplingKey) { + std::string key = SamplingController::getSamplingKey("somepath", "GET"); + EXPECT_STREQ(key.c_str(), "GET_somepath"); + + key = SamplingController::getSamplingKey("somepath?withquery", "POST"); + EXPECT_STREQ(key.c_str(), "POST_somepath"); + + key = SamplingController::getSamplingKey("anotherpath", "PUT"); + EXPECT_STREQ(key.c_str(), "PUT_anotherpath"); + + key = SamplingController::getSamplingKey("", "PUT"); + EXPECT_STREQ(key.c_str(), "PUT_"); + + key = SamplingController::getSamplingKey("anotherpath", ""); + EXPECT_STREQ(key.c_str(), "_anotherpath"); +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary_test.cc new file mode 100644 index 000000000000..f7f80cf68b93 --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary_test.cc @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/stream_summary.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +namespace { + +// helper function to compare counters +template +void compareCounter(typename std::list>::iterator counter, T item, uint64_t value, + uint64_t error, int line_num) { + SCOPED_TRACE(absl::StrCat(__FUNCTION__, " called from line ", line_num)); + EXPECT_EQ(counter->getValue(), value); + EXPECT_EQ(counter->getItem(), item); + EXPECT_EQ(counter->getError(), error); +} + +} // namespace + +// Test an empty StreamSummary +TEST(StreamSummaryTest, TestEmpty) { + StreamSummary summary(4); + EXPECT_EQ(summary.getN(), 0); + auto top_k = summary.getTopK(); + EXPECT_EQ(top_k.size(), 0); + EXPECT_EQ(top_k.begin(), top_k.end()); + EXPECT_TRUE(summary.validate().ok()); +} + +// Test adding values, capacity not exceeded +TEST(StreamSummaryTest, TestSimple) { + StreamSummary summary(4); + summary.offer('a'); + summary.offer('a'); + summary.offer('b'); + summary.offer('a'); + summary.offer('c'); + summary.offer('b'); + summary.offer('a'); + summary.offer('d'); + + EXPECT_TRUE(summary.validate().ok()); + EXPECT_EQ(summary.getN(), 8); + + auto top_k = summary.getTopK(); + EXPECT_EQ(top_k.size(), 4); + auto it = top_k.begin(); + compareCounter(it, 'a', 4, 0, __LINE__); + compareCounter(++it, 'b', 2, 0, __LINE__); + compareCounter(++it, 'c', 1, 0, __LINE__); + compareCounter(++it, 'd', 1, 0, __LINE__); +} + +// Test adding values, capacity exceeded +TEST(StreamSummaryTest, TestExceedCapacity) { + StreamSummary summary(3); + EXPECT_TRUE(summary.validate().ok()); + summary.offer('d'); + summary.offer('a'); + summary.offer('b'); + summary.offer('a'); + summary.offer('a'); + summary.offer('a'); + summary.offer('b'); + summary.offer('c'); // 'd' will be dropped + summary.offer('b'); + summary.offer('c'); + EXPECT_TRUE(summary.validate().ok()); + + { + auto top_k = summary.getTopK(); + auto it = top_k.begin(); + EXPECT_EQ(top_k.size(), 3); + compareCounter(it, 'a', 4, 0, __LINE__); + compareCounter(++it, 'b', 3, 0, __LINE__); + compareCounter(++it, 'c', 3, 1, __LINE__); + } + + // add item 'e', 'c' should be removed. value for 'c' will be added to error for 'e' + summary.offer('e'); + { + auto top_k = summary.getTopK(); + auto it = top_k.begin(); + EXPECT_EQ(top_k.size(), 3); + compareCounter(it, 'a', 4, 0, __LINE__); + compareCounter(++it, 'e', 4, 3, __LINE__); + compareCounter(++it, 'b', 3, 0, __LINE__); + } +} + +// Test inserting items in random order. topK should not depend on the insert order. +TEST(StreamSummaryTest, TestRandomInsertOrder) { + std::vector v{'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', + 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'e', 'e', 'f'}; + for (int i = 0; i < 5; ++i) { + // insert order should not matter if all items have a different count in input stream + std::shuffle(v.begin(), v.end(), std::default_random_engine()); + StreamSummary summary(10); + for (auto const c : v) { + summary.offer(c); + } + auto top_k = summary.getTopK(); + auto it = top_k.begin(); + compareCounter(it, 'a', 6, 0, __LINE__); + compareCounter(++it, 'b', 5, 0, __LINE__); + compareCounter(++it, 'c', 4, 0, __LINE__); + compareCounter(++it, 'd', 3, 0, __LINE__); + compareCounter(++it, 'e', 2, 0, __LINE__); + compareCounter(++it, 'f', 1, 0, __LINE__); + } +} + +// Test getTopK size parameter is handled as expected +TEST(StreamSummaryTest, TestGetTopKSize) { + std::vector v{'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', + 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'e', 'e', 'f'}; + std::shuffle(v.begin(), v.end(), std::default_random_engine()); + StreamSummary summary(20); + for (auto const c : v) { + summary.offer(c); + } + EXPECT_EQ(summary.getTopK().size(), 6); + EXPECT_EQ(summary.getTopK(1).size(), 1); + EXPECT_EQ(summary.getTopK(2).size(), 2); + EXPECT_EQ(summary.getTopK(3).size(), 3); + EXPECT_EQ(summary.getTopK(4).size(), 4); + EXPECT_EQ(summary.getTopK(5).size(), 5); + EXPECT_EQ(summary.getTopK(6).size(), 6); + EXPECT_EQ(summary.getTopK(7).size(), 6); +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id_test.cc b/test/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id_test.cc new file mode 100644 index 000000000000..17f9d47d6d38 --- /dev/null +++ b/test/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id_test.cc @@ -0,0 +1,31 @@ +#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/tenant_id.h" + +#include "absl/strings/str_cat.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace OpenTelemetry { + +// Test calculation using an empty string +TEST(TenantIdTest, TestEmpty) { EXPECT_EQ(absl::StrCat(calculateTenantId("")), "0"); } + +// Test calculation using strings with unexpected characters +TEST(TenantIdTest, TestUnexpected) { + EXPECT_EQ(absl::StrCat(calculateTenantId("abc 1234")), "182ccac"); + EXPECT_EQ(absl::StrCat(calculateTenantId(" ")), "b173ef2e"); + EXPECT_EQ(absl::StrCat(calculateTenantId("€someth")), "17bd71ec"); +} + +// Test calculation using some expected strings +TEST(TenantIdTest, TestValues) { + EXPECT_EQ(absl::StrCat(calculateTenantId("jmw13303")), "4d10bede"); + EXPECT_EQ(absl::StrCat(calculateTenantId("abc12345")), "5b3f9fed"); + EXPECT_EQ(absl::StrCat(calculateTenantId("?pfel")), "7712d29d"); +} + +} // namespace OpenTelemetry +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/opentelemetry/samplers/sampler_test.cc b/test/extensions/tracers/opentelemetry/samplers/sampler_test.cc index a8ff62c71d85..ee5a93679d4e 100644 --- a/test/extensions/tracers/opentelemetry/samplers/sampler_test.cc +++ b/test/extensions/tracers/opentelemetry/samplers/sampler_test.cc @@ -56,6 +56,12 @@ class SamplerFactoryTest : public testing::Test { NiceMock context; }; +// Test tracer category() +TEST_F(SamplerFactoryTest, TestGetName) { + TestSamplerFactory factory; + EXPECT_STREQ(factory.category().c_str(), "envoy.tracers.opentelemetry.samplers"); +} + // Test OTLP tracer without a sampler TEST_F(SamplerFactoryTest, TestWithoutSampler) { // using StrictMock, calls to SamplerFactory would cause a test failure @@ -132,13 +138,13 @@ TEST_F(SamplerFactoryTest, TestWithSampler) { auto driver = std::make_unique(opentelemetry_config, context); - // shouldSample returns a result without additional attributes and Decision::RECORD_AND_SAMPLE + // shouldSample returns a result without additional attributes and Decision::RecordAndSample EXPECT_CALL(*test_sampler, shouldSample(_, _, _, _, _, _)) .WillOnce([](const absl::optional, const std::string&, const std::string&, OTelSpanKind, OptRef, const std::vector&) { SamplingResult res; - res.decision = Decision::RECORD_AND_SAMPLE; + res.decision = Decision::RecordAndSample; res.tracestate = "this_is=tracesate"; return res; }); @@ -152,13 +158,13 @@ TEST_F(SamplerFactoryTest, TestWithSampler) { EXPECT_TRUE(span->sampled()); EXPECT_STREQ(span->tracestate().c_str(), "this_is=tracesate"); - // shouldSamples return a result containing additional attributes and Decision::DROP + // shouldSamples return a result containing additional attributes and Decision::Drop EXPECT_CALL(*test_sampler, shouldSample(_, _, _, _, _, _)) .WillOnce([](const absl::optional, const std::string&, const std::string&, OTelSpanKind, OptRef, const std::vector&) { SamplingResult res; - res.decision = Decision::DROP; + res.decision = Decision::Drop; std::map attributes; attributes["key"] = "value"; attributes["another_key"] = "another_value"; @@ -208,13 +214,13 @@ TEST_F(SamplerFactoryTest, TestInitialAttributes) { // Test sampling result decision TEST(SamplingResultTest, TestSamplingResult) { SamplingResult result; - result.decision = Decision::RECORD_AND_SAMPLE; + result.decision = Decision::RecordAndSample; EXPECT_TRUE(result.isRecording()); EXPECT_TRUE(result.isSampled()); - result.decision = Decision::RECORD_ONLY; + result.decision = Decision::RecordOnly; EXPECT_TRUE(result.isRecording()); EXPECT_FALSE(result.isSampled()); - result.decision = Decision::DROP; + result.decision = Decision::Drop; EXPECT_FALSE(result.isRecording()); EXPECT_FALSE(result.isSampled()); } diff --git a/test/extensions/transport_sockets/alts/alts_channel_pool_test.cc b/test/extensions/transport_sockets/alts/alts_channel_pool_test.cc index 86c76e0b4e2d..a84b13695e80 100644 --- a/test/extensions/transport_sockets/alts/alts_channel_pool_test.cc +++ b/test/extensions/transport_sockets/alts/alts_channel_pool_test.cc @@ -31,7 +31,6 @@ using ::grpc::gcp::HandshakerReq; using ::grpc::gcp::HandshakerResp; using ::grpc::gcp::HandshakerService; using ::testing::NotNull; -using ::testing::Test; class FakeHandshakerService final : public HandshakerService::Service { public: diff --git a/test/extensions/transport_sockets/alts/alts_integration_test.cc b/test/extensions/transport_sockets/alts/alts_integration_test.cc index 0b86fe77e5b0..22080ad3b0b2 100644 --- a/test/extensions/transport_sockets/alts/alts_integration_test.cc +++ b/test/extensions/transport_sockets/alts/alts_integration_test.cc @@ -127,12 +127,14 @@ class FakeHandshakerService : public HandshakerService::Service { grpc::gcp::HandshakerReq request; grpc::gcp::HandshakerResp response; while (stream->Read(&request)) { - status = ProcessRequest(&context, request, &response); - if (!status.ok()) - return WriteErrorResponse(stream, status); + status = processRequest(&context, request, &response); + if (!status.ok()) { + return writeErrorResponse(stream, status); + } stream->Write(response); - if (context.state == HandshakeState::COMPLETED) + if (context.state == HandshakeState::COMPLETED) { return grpc::Status::OK; + } request.Clear(); } return grpc::Status::OK; @@ -152,33 +154,31 @@ class FakeHandshakerService : public HandshakerService::Service { HandshakeState state = HandshakeState::INITIAL; }; - grpc::Status ProcessRequest(HandshakerContext* context, const grpc::gcp::HandshakerReq& request, + grpc::Status processRequest(HandshakerContext* context, const grpc::gcp::HandshakerReq& request, grpc::gcp::HandshakerResp* response) { response->Clear(); if (request.has_client_start()) { - return ProcessClientStart(context, request.client_start(), response); + return processClientStart(context, request.client_start(), response); } else if (request.has_server_start()) { - return ProcessServerStart(context, request.server_start(), response); + return processServerStart(context, request.server_start(), response); } else if (request.has_next()) { - return ProcessNext(context, request.next(), response); + return processNext(context, request.next(), response); } - return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Request is empty."); + return {grpc::StatusCode::INVALID_ARGUMENT, "Request is empty."}; } - grpc::Status ProcessClientStart(HandshakerContext* context, + grpc::Status processClientStart(HandshakerContext* context, const grpc::gcp::StartClientHandshakeReq& request, grpc::gcp::HandshakerResp* response) { // Checks request. if (context->state != HandshakeState::INITIAL) { - return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError); + return {grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError}; } if (request.application_protocols_size() == 0) { - return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, - "At least one application protocol needed."); + return {grpc::StatusCode::INVALID_ARGUMENT, "At least one application protocol needed."}; } if (request.record_protocols_size() == 0) { - return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, - "At least one record protocol needed."); + return {grpc::StatusCode::INVALID_ARGUMENT, "At least one record protocol needed."}; } // Sets response. response->set_out_frames(kClientInitFrame); @@ -190,20 +190,19 @@ class FakeHandshakerService : public HandshakerService::Service { return grpc::Status::OK; } - grpc::Status ProcessServerStart(HandshakerContext* context, + grpc::Status processServerStart(HandshakerContext* context, const grpc::gcp::StartServerHandshakeReq& request, grpc::gcp::HandshakerResp* response) { // Checks request. if (context->state != HandshakeState::INITIAL) { - return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError); + return {grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError}; } if (request.application_protocols_size() == 0) { - return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, - "At least one application protocol needed."); + return {grpc::StatusCode::INVALID_ARGUMENT, "At least one application protocol needed."}; } if (request.handshake_parameters().empty()) { - return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, - "At least one set of handshake parameters needed."); + return {grpc::StatusCode::INVALID_ARGUMENT, + "At least one set of handshake parameters needed."}; } // Sets response. if (request.in_bytes().empty()) { @@ -217,7 +216,7 @@ class FakeHandshakerService : public HandshakerService::Service { response->set_bytes_consumed(strlen(kClientInitFrame)); context->state = HandshakeState::SENT; } else { - return grpc::Status(grpc::StatusCode::UNKNOWN, kInvalidFrameError); + return {grpc::StatusCode::UNKNOWN, kInvalidFrameError}; } } response->mutable_status()->set_code(grpc::StatusCode::OK); @@ -225,16 +224,16 @@ class FakeHandshakerService : public HandshakerService::Service { return grpc::Status::OK; } - grpc::Status ProcessNext(HandshakerContext* context, + grpc::Status processNext(HandshakerContext* context, const grpc::gcp::NextHandshakeMessageReq& request, grpc::gcp::HandshakerResp* response) { if (context->is_client) { // Processes next request on client side. if (context->state != HandshakeState::SENT) { - return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError); + return {grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError}; } if (request.in_bytes() != kServerFrame) { - return grpc::Status(grpc::StatusCode::UNKNOWN, kInvalidFrameError); + return {grpc::StatusCode::UNKNOWN, kInvalidFrameError}; } response->set_out_frames(kClientFinishFrame); response->set_bytes_consumed(strlen(kServerFrame)); @@ -244,7 +243,7 @@ class FakeHandshakerService : public HandshakerService::Service { HandshakeState current_state = context->state; if (current_state == HandshakeState::STARTED) { if (request.in_bytes() != kClientInitFrame) { - return grpc::Status(grpc::StatusCode::UNKNOWN, kInvalidFrameError); + return {grpc::StatusCode::UNKNOWN, kInvalidFrameError}; } response->set_out_frames(kServerFrame); response->set_bytes_consumed(strlen(kClientInitFrame)); @@ -253,23 +252,23 @@ class FakeHandshakerService : public HandshakerService::Service { // Client finish frame may be sent along with the first payload from the // client, handshaker only consumes the client finish frame. if (request.in_bytes().substr(0, strlen(kClientFinishFrame)) != kClientFinishFrame) { - return grpc::Status(grpc::StatusCode::UNKNOWN, kInvalidFrameError); + return {grpc::StatusCode::UNKNOWN, kInvalidFrameError}; } response->set_bytes_consumed(strlen(kClientFinishFrame)); context->state = HandshakeState::COMPLETED; } else { - return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError); + return {grpc::StatusCode::FAILED_PRECONDITION, kWrongStateError}; } } // At this point, processing next request succeeded. response->mutable_status()->set_code(grpc::StatusCode::OK); if (context->state == HandshakeState::COMPLETED) { - *response->mutable_result() = GetHandshakerResult(); + *response->mutable_result() = getHandshakerResult(); } return grpc::Status::OK; } - grpc::Status WriteErrorResponse( + grpc::Status writeErrorResponse( grpc::ServerReaderWriter* stream, const grpc::Status& status) { EXPECT_TRUE(status.ok()); @@ -280,7 +279,7 @@ class FakeHandshakerService : public HandshakerService::Service { return status; } - grpc::gcp::HandshakerResult GetHandshakerResult() { + grpc::gcp::HandshakerResult getHandshakerResult() { grpc::gcp::HandshakerResult result; result.set_application_protocol("grpc"); result.set_record_protocol("ALTSRP_GCM_AES128_REKEY"); @@ -299,7 +298,7 @@ class FakeHandshakerService : public HandshakerService::Service { const std::string peer_identity_; }; -std::unique_ptr CreateFakeHandshakerService(const std::string& peer_identity) { +std::unique_ptr createFakeHandshakerService(const std::string& peer_identity) { return std::unique_ptr{new FakeHandshakerService(peer_identity)}; } @@ -347,7 +346,7 @@ class AltsIntegrationTestBase : public Event::TestUsingSimulatedTime, service = std::unique_ptr{capturing_handshaker_service_}; } else { capturing_handshaker_service_ = nullptr; - service = CreateFakeHandshakerService("peer_identity"); + service = createFakeHandshakerService("peer_identity"); } std::string server_address = Network::Test::getLoopbackAddressUrlString(version_) + ":0"; diff --git a/test/extensions/transport_sockets/alts/tsi_handshaker_test.cc b/test/extensions/transport_sockets/alts/tsi_handshaker_test.cc index 32476c23f426..977fb9ef5178 100644 --- a/test/extensions/transport_sockets/alts/tsi_handshaker_test.cc +++ b/test/extensions/transport_sockets/alts/tsi_handshaker_test.cc @@ -48,7 +48,6 @@ using ::grpc::gcp::HandshakerResult; using ::grpc::gcp::HandshakerService; using ::testing::IsNull; using ::testing::NotNull; -using ::testing::Test; constexpr absl::string_view ClientInit = "CLIENT_INIT"; constexpr absl::string_view ServerInit = "SERVER_INIT"; @@ -141,7 +140,7 @@ class ErrorHandshakerService final : public HandshakerService::Service { response.mutable_status()->set_details("Internal error."); EXPECT_TRUE(stream->Write(response)); } - return grpc::Status(grpc::StatusCode::INTERNAL, "DoHandshake internal error."); + return {grpc::StatusCode::INTERNAL, "DoHandshake internal error."}; } }; diff --git a/test/extensions/transport_sockets/alts/tsi_socket_test.cc b/test/extensions/transport_sockets/alts/tsi_socket_test.cc index a8b9b675b744..a0ca23e81e71 100644 --- a/test/extensions/transport_sockets/alts/tsi_socket_test.cc +++ b/test/extensions/transport_sockets/alts/tsi_socket_test.cc @@ -151,7 +151,7 @@ class ErrorHandshakerService final : public HandshakerService::Service { break; } } - return grpc::Status(grpc::StatusCode::INTERNAL, "DoHandshake internal error."); + return {grpc::StatusCode::INTERNAL, "DoHandshake internal error."}; } const bool keep_stream_alive_; diff --git a/test/extensions/transport_sockets/starttls/starttls_integration_test.cc b/test/extensions/transport_sockets/starttls/starttls_integration_test.cc index 719a0c34fcd7..cb2564e38286 100644 --- a/test/extensions/transport_sockets/starttls/starttls_integration_test.cc +++ b/test/extensions/transport_sockets/starttls/starttls_integration_test.cc @@ -71,7 +71,7 @@ Network::FilterStatus StartTlsSwitchFilter::onCommand(Buffer::Instance& buf, boo if (message == "switch") { buf.drain(buf.length()); buf.add("usetls"); - read_callbacks_->connection().addBytesSentCallback([=](uint64_t bytes) -> bool { + read_callbacks_->connection().addBytesSentCallback([=, this](uint64_t bytes) -> bool { // Wait until 6 bytes long "usetls" has been sent. if (bytes >= 6) { read_callbacks_->connection().startSecureTransport(); diff --git a/test/extensions/transport_sockets/tls/io_handle_bio_test.cc b/test/extensions/transport_sockets/tls/io_handle_bio_test.cc index 0f744ae48879..8c9600b7b71d 100644 --- a/test/extensions/transport_sockets/tls/io_handle_bio_test.cc +++ b/test/extensions/transport_sockets/tls/io_handle_bio_test.cc @@ -29,34 +29,20 @@ TEST_F(IoHandleBioTest, WriteError) { EXPECT_CALL(io_handle_, writev(_, 1)) .WillOnce( Return(testing::ByMove(Api::IoCallUint64Result(0, Network::IoSocketError::create(100))))); - EXPECT_EQ(-1, bio_->method->bwrite(bio_, nullptr, 10)); + EXPECT_EQ(-1, BIO_write(bio_, nullptr, 10)); const int err = ERR_get_error(); EXPECT_EQ(ERR_GET_LIB(err), ERR_LIB_SYS); EXPECT_EQ(ERR_GET_REASON(err), 100); } TEST_F(IoHandleBioTest, TestMiscApis) { - EXPECT_EQ(bio_->method->destroy(nullptr), 0); - EXPECT_EQ(bio_->method->bread(nullptr, nullptr, 0), 0); + EXPECT_EQ(BIO_read(bio_, nullptr, 0), 0); - EXPECT_DEATH(bio_->method->ctrl(bio_, BIO_C_GET_FD, 0, nullptr), "should not be called"); - EXPECT_DEATH(bio_->method->ctrl(bio_, BIO_C_SET_FD, 0, nullptr), "should not be called"); - - int ret = bio_->method->ctrl(bio_, BIO_CTRL_RESET, 0, nullptr); + int ret = BIO_reset(bio_); EXPECT_EQ(ret, 0); - ret = bio_->method->ctrl(bio_, BIO_CTRL_FLUSH, 0, nullptr); - EXPECT_EQ(ret, 1); - - ret = bio_->method->ctrl(bio_, BIO_CTRL_SET_CLOSE, 1, nullptr); + ret = BIO_flush(bio_); EXPECT_EQ(ret, 1); - - ret = bio_->method->ctrl(bio_, BIO_CTRL_GET_CLOSE, 0, nullptr); - EXPECT_EQ(ret, 1); - - EXPECT_CALL(io_handle_, close()) - .WillOnce(Return(testing::ByMove(Api::IoCallUint64Result{0, Api::IoError::none()}))); - bio_->init = 1; } } // namespace Tls diff --git a/test/fuzz/utility.h b/test/fuzz/utility.h index 681674debc4e..a450ac92e837 100644 --- a/test/fuzz/utility.h +++ b/test/fuzz/utility.h @@ -170,7 +170,9 @@ inline std::unique_ptr fromStreamInfo(const test::fuzz::StreamIn replaceInvalidHostCharacters( stream_info.address().envoy_internal_address().server_listener_name())); } else { - address = Envoy::Network::Address::resolveProtoAddress(stream_info.address()).value(); + auto address_or_error = Envoy::Network::Address::resolveProtoAddress(stream_info.address()); + THROW_IF_STATUS_NOT_OK(address_or_error, throw); + address = address_or_error.value(); } } else { address = Network::Utility::resolveUrl("tcp://10.0.0.1:443"); diff --git a/test/integration/base_integration_test.cc b/test/integration/base_integration_test.cc index bfae7ee7bbe9..23b216c0d2a6 100644 --- a/test/integration/base_integration_test.cc +++ b/test/integration/base_integration_test.cc @@ -74,6 +74,7 @@ BaseIntegrationTest::BaseIntegrationTest(const InstanceConstSharedPtrFn& upstrea })); ON_CALL(factory_context_.server_context_, api()).WillByDefault(ReturnRef(*api_)); ON_CALL(factory_context_, statsScope()).WillByDefault(ReturnRef(*stats_store_.rootScope())); + ON_CALL(factory_context_.server_context_, threadLocal()).WillByDefault(ReturnRef(thread_local_)); #ifndef ENVOY_ADMIN_FUNCTIONALITY config_helper_.addConfigModifier( diff --git a/test/integration/base_integration_test.h b/test/integration/base_integration_test.h index c6cf68fdcb11..33f1a755567d 100644 --- a/test/integration/base_integration_test.h +++ b/test/integration/base_integration_test.h @@ -523,6 +523,7 @@ class BaseIntegrationTest : protected Logger::Loggable { Network::DownstreamTransportSocketFactoryPtr createUpstreamTlsContext(const FakeUpstreamConfig& upstream_config); + testing::NiceMock thread_local_; testing::NiceMock factory_context_; Extensions::TransportSockets::Tls::ContextManagerImpl context_manager_{timeSystem()}; diff --git a/test/integration/buffer_accounting_integration_test.cc b/test/integration/buffer_accounting_integration_test.cc index 46d5194893d1..8ad89494b9ac 100644 --- a/test/integration/buffer_accounting_integration_test.cc +++ b/test/integration/buffer_accounting_integration_test.cc @@ -37,8 +37,6 @@ namespace { #define ASANITIZED /* Sanitized by GCC */ #endif -using testing::HasSubstr; - std::string protocolTestParamsAndBoolToString( const ::testing::TestParamInfo>& params) { return fmt::format("{}_{}", diff --git a/test/integration/cluster_filter_integration_test.cc b/test/integration/cluster_filter_integration_test.cc index f9450fc37592..a363d9f512c2 100644 --- a/test/integration/cluster_filter_integration_test.cc +++ b/test/integration/cluster_filter_integration_test.cc @@ -96,28 +96,10 @@ class PoliteFilterConfigFactory TestParent& test_parent_; }; -std::string ipInitializeUpstreamFiltersTestParamsToString( - const testing::TestParamInfo>& params) { - return fmt::format( - "{}_{}", - TestUtility::ipTestParamsToString( - testing::TestParamInfo(std::get<0>(params.param), 0)), - std::get<1>(params.param) ? "do_initialize_upstream_filters" - : "dont_initialize_upstream_filters"); -} - -class ClusterFilterIntegrationTestBase - : public testing::TestWithParam>, - public TestParent { +class ClusterFilterIntegrationTestBase : public testing::TestWithParam, + public TestParent { public: - ClusterFilterIntegrationTestBase() : factory_(*this), registration_(factory_) { - Runtime::maybeSetRuntimeGuard("envoy.reloadable_features.initialize_upstream_filters", - std::get<1>(GetParam())); - } - - // Get the test parameter whether upstream network filters are initialized right after the - // upstream connection has been established - bool upstreamFiltersInitializedWhenConnected() const { return std::get<1>(GetParam()); } + ClusterFilterIntegrationTestBase() : factory_(*this), registration_(factory_) {} void initialize() { on_new_connection_called_after_on_write_.store(absl::optional{}); } @@ -149,7 +131,7 @@ class ClusterFilterTcpIntegrationTest : public ClusterFilterIntegrationTestBase, public BaseIntegrationTest { public: ClusterFilterTcpIntegrationTest() - : BaseIntegrationTest(std::get<0>(GetParam()), ConfigHelper::tcpProxyConfig()) {} + : BaseIntegrationTest(GetParam(), ConfigHelper::tcpProxyConfig()) {} void initialize() override { enableHalfClose(true); @@ -166,10 +148,8 @@ class ClusterFilterTcpIntegrationTest : public ClusterFilterIntegrationTestBase, } }; -INSTANTIATE_TEST_SUITE_P( - IpVersionsInitializeUpstreamFilters, ClusterFilterTcpIntegrationTest, - testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), testing::Bool()), - ipInitializeUpstreamFiltersTestParamsToString); +INSTANTIATE_TEST_SUITE_P(IpVersionsInitializeUpstreamFilters, ClusterFilterTcpIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest())); TEST_P(ClusterFilterTcpIntegrationTest, TestClusterFilter) { initialize(); @@ -183,19 +163,12 @@ TEST_P(ClusterFilterTcpIntegrationTest, TestClusterFilter) { ASSERT_TRUE(fake_upstream_connection->waitForData(11, &observed_data)); EXPECT_EQ("please test", observed_data); - // Upstream read filters are expected to be initialized at this point after connection has been - // established but nothing has been read from the connection yet, but only if runtime feature - // flag 'initialize_upstream_filters' is true. - if (upstreamFiltersInitializedWhenConnected()) { - // Note that we need to have written on the connection and waited for the written data to be - // received so that we know the upstream connection has had chance to schedule the - // onNewConnection() callbacks. This test will be flaky if we expect onNewConnection() having - // been called before the waitForData() above. - ASSERT_TRUE(wasOnNewConnectionCalled()); - ASSERT_TRUE(wasOnNewConnectionCalledFirst()); - } else { - ASSERT_FALSE(wasOnNewConnectionCalled()); - } + // Note that we need to have written on the connection and waited for the written data to be + // received so that we know the upstream connection has had chance to schedule the + // onNewConnection() callbacks. This test will be flaky if we expect onNewConnection() having + // been called before the waitForData() above. + ASSERT_TRUE(wasOnNewConnectionCalled()); + ASSERT_TRUE(wasOnNewConnectionCalledFirst()); observed_data.clear(); ASSERT_TRUE(tcp_client->write(" everything")); @@ -206,12 +179,8 @@ TEST_P(ClusterFilterTcpIntegrationTest, TestClusterFilter) { tcp_client->waitForData("surely yes"); // Finally after reading from the upstream connection onNewConnection() has been called in all - // cases, but onWrite was called before it if runtime feature flag 'initialize_upstream_filters' - // is false. + // cases, but onWrite was called before it ASSERT_TRUE(wasOnNewConnectionCalled()); - if (!upstreamFiltersInitializedWhenConnected()) { - ASSERT_FALSE(wasOnNewConnectionCalledFirst()); - } ASSERT_TRUE(tcp_client->write("", true)); ASSERT_TRUE(fake_upstream_connection->waitForHalfClose()); @@ -223,8 +192,7 @@ TEST_P(ClusterFilterTcpIntegrationTest, TestClusterFilter) { class ClusterFilterHttpIntegrationTest : public ClusterFilterIntegrationTestBase, public HttpIntegrationTest { public: - ClusterFilterHttpIntegrationTest() - : HttpIntegrationTest(Http::CodecType::HTTP1, std::get<0>(GetParam())) {} + ClusterFilterHttpIntegrationTest() : HttpIntegrationTest(Http::CodecType::HTTP1, GetParam()) {} void initialize() override { config_helper_.addConfigModifier([](envoy::config::bootstrap::v3::Bootstrap& bootstrap) { @@ -240,10 +208,8 @@ class ClusterFilterHttpIntegrationTest : public ClusterFilterIntegrationTestBase } }; -INSTANTIATE_TEST_SUITE_P( - IpVersionsInitializeUpstreamFilters, ClusterFilterHttpIntegrationTest, - testing::Combine(testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), testing::Bool()), - ipInitializeUpstreamFiltersTestParamsToString); +INSTANTIATE_TEST_SUITE_P(IpVersionsInitializeUpstreamFilters, ClusterFilterHttpIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest())); TEST_P(ClusterFilterHttpIntegrationTest, TestClusterFilter) { initialize(); @@ -257,13 +223,9 @@ TEST_P(ClusterFilterHttpIntegrationTest, TestClusterFilter) { waitForNextUpstreamRequest(); // Upstream read filters are expected to be initialized at this point after only the request has - // been sent, but only if runtime feature flag 'initialize_upstream_filters' is true. - if (upstreamFiltersInitializedWhenConnected()) { - ASSERT_TRUE(wasOnNewConnectionCalled()); - ASSERT_TRUE(wasOnNewConnectionCalledFirst()); - } else { - ASSERT_FALSE(wasOnNewConnectionCalled()); - } + // been sent + ASSERT_TRUE(wasOnNewConnectionCalled()); + ASSERT_TRUE(wasOnNewConnectionCalledFirst()); EXPECT_TRUE(upstream_request_->complete()); EXPECT_EQ("hello!", upstream_request_->body().toString()); @@ -276,13 +238,9 @@ TEST_P(ClusterFilterHttpIntegrationTest, TestClusterFilter) { ASSERT_TRUE(response->complete()); // Finally after receiving the response onNewConnection() has been called in all cases, but - // onWrite was called before it if runtime feature flag 'initialize_upstream_filters' is false. + // onWrite was called before it ASSERT_TRUE(wasOnNewConnectionCalled()); - if (upstreamFiltersInitializedWhenConnected()) { - ASSERT_TRUE(wasOnNewConnectionCalledFirst()); - } else { - ASSERT_FALSE(wasOnNewConnectionCalledFirst()); - } + ASSERT_TRUE(wasOnNewConnectionCalledFirst()); EXPECT_EQ("200", response->headers().getStatusValue()); EXPECT_EQ("greetings", response->body()); diff --git a/test/integration/cx_limit_integration_test.cc b/test/integration/cx_limit_integration_test.cc index c998727d01b9..ccf2b19dc1c6 100644 --- a/test/integration/cx_limit_integration_test.cc +++ b/test/integration/cx_limit_integration_test.cc @@ -136,6 +136,18 @@ TEST_P(ConnectionLimitIntegrationTest, TestListenerLimit) { doTest(init_func, "downstream_cx_overflow"); } +TEST_P(ConnectionLimitIntegrationTest, TestDeprecationWarningForGlobalCxRuntimeLimit) { + std::function init_func = [this]() { + setGlobalLimit(4); + initialize(); + }; + const std::string log_line = + "Usage of the deprecated runtime key overload.global_downstream_max_connections, " + "consider switching to `envoy.resource_monitors.downstream_connections` instead." + "This runtime key will be removed in future."; + EXPECT_LOG_CONTAINS("warn", log_line, { init_func(); }); +} + // TODO (nezdolik) move this test to overload manager test suite, once runtime key is fully // deprecated. TEST_P(ConnectionLimitIntegrationTest, TestEmptyGlobalCxRuntimeLimit) { diff --git a/test/integration/filters/server_factory_context_filter.cc b/test/integration/filters/server_factory_context_filter.cc index cea3f7ee5457..610df7941993 100644 --- a/test/integration/filters/server_factory_context_filter.cc +++ b/test/integration/filters/server_factory_context_filter.cc @@ -29,8 +29,10 @@ class TestGrpcClient : public Grpc::AsyncStreamCallbacks public: TestGrpcClient(Server::Configuration::ServerFactoryContext& context, const envoy::config::core::v3::GrpcService& grpc_service) - : client_(context.clusterManager().grpcAsyncClientManager().getOrCreateRawAsyncClient( - grpc_service, context.scope(), true)), + : client_(context.clusterManager() + .grpcAsyncClientManager() + .getOrCreateRawAsyncClient(grpc_service, context.scope(), true) + .value()), method_descriptor_(helloworld::Greeter::descriptor()->FindMethodByName("SayHello")) {} // AsyncStreamCallbacks diff --git a/test/integration/filters/test_network_async_tcp_filter.cc b/test/integration/filters/test_network_async_tcp_filter.cc index 17f7d6fe4e75..6116b2d01dc1 100644 --- a/test/integration/filters/test_network_async_tcp_filter.cc +++ b/test/integration/filters/test_network_async_tcp_filter.cc @@ -50,6 +50,11 @@ class TestNetworkAsyncTcpFilter : public Network::ReadFilter { } Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override { + if (require_reconnect_ && !client_->connect()) { + ENVOY_LOG_MISC(debug, "Unable to reconnect to cluster"); + return Network::FilterStatus::StopIteration; + } + stats_.on_data_.inc(); ENVOY_LOG_MISC(debug, "Downstream onData: {}, length: {} sending to upstream", data.toString(), data.length()); @@ -76,6 +81,8 @@ class TestNetworkAsyncTcpFilter : public Network::ReadFilter { read_callbacks_->connection().addConnectionCallbacks(*downstream_callbacks_); } + bool require_reconnect_{false}; + private: struct DownstreamCallbacks : public Envoy::Network::ConnectionCallbacks { explicit DownstreamCallbacks(TestNetworkAsyncTcpFilter& parent) : parent_(parent) {} @@ -121,6 +128,12 @@ class TestNetworkAsyncTcpFilter : public Network::ReadFilter { void onEvent(Network::ConnectionEvent event) override { ENVOY_LOG_MISC(debug, "tcp client test filter upstream callback onEvent: {}", static_cast(event)); + + if (event == Network::ConnectionEvent::RemoteClose || + event == Network::ConnectionEvent::LocalClose) { + parent_.require_reconnect_ = true; + } + if (event != Network::ConnectionEvent::RemoteClose) { return; } diff --git a/test/integration/http_integration.cc b/test/integration/http_integration.cc index 32cd019ca2b5..e639caa7eeca 100644 --- a/test/integration/http_integration.cc +++ b/test/integration/http_integration.cc @@ -368,7 +368,7 @@ void HttpIntegrationTest::initialize() { // Needs to be instantiated before base class calls initialize() which starts a QUIC listener // according to the config. quic_transport_socket_factory_ = IntegrationUtil::createQuicUpstreamTransportSocketFactory( - *api_, stats_store_, context_manager_, san_to_match_); + *api_, stats_store_, context_manager_, thread_local_, san_to_match_); // Needed to config QUIC transport socket factory, and needs to be added before base class calls // initialize(). diff --git a/test/integration/integration_stream_decoder.h b/test/integration/integration_stream_decoder.h index 080b5cbbf915..0fd9343dc3ba 100644 --- a/test/integration/integration_stream_decoder.h +++ b/test/integration/integration_stream_decoder.h @@ -24,7 +24,7 @@ namespace Envoy { class IntegrationStreamDecoder : public Http::ResponseDecoder, public Http::StreamCallbacks { public: IntegrationStreamDecoder(Event::Dispatcher& dispatcher); - ~IntegrationStreamDecoder(); + ~IntegrationStreamDecoder() override; const std::string& body() { return body_; } bool complete() { return saw_end_stream_; } diff --git a/test/integration/load_stats_integration_test.cc b/test/integration/load_stats_integration_test.cc index 668cdb0fcf52..e98aa4b752d4 100644 --- a/test/integration/load_stats_integration_test.cc +++ b/test/integration/load_stats_integration_test.cc @@ -191,11 +191,11 @@ class LoadStatsIntegrationTest : public Grpc::GrpcClientIntegrationParamTest, cluster_stats->set_total_dropped_requests(cluster_stats->total_dropped_requests() + local_cluster_stats.total_dropped_requests()); - if (local_cluster_stats.dropped_requests().size() > 0) { + if (!local_cluster_stats.dropped_requests().empty()) { const uint64_t local_drop_count = local_cluster_stats.dropped_requests(0).dropped_count(); if (local_drop_count > 0) { envoy::config::endpoint::v3::ClusterStats::DroppedRequests* drop_request; - if (cluster_stats->dropped_requests().size() > 0) { + if (!cluster_stats->dropped_requests().empty()) { drop_request = cluster_stats->mutable_dropped_requests(0); drop_request->set_dropped_count(drop_request->dropped_count() + local_drop_count); } else { diff --git a/test/integration/multiplexed_integration_test.cc b/test/integration/multiplexed_integration_test.cc index 88b45501e6f2..1a45e8e551cd 100644 --- a/test/integration/multiplexed_integration_test.cc +++ b/test/integration/multiplexed_integration_test.cc @@ -1944,6 +1944,42 @@ class Http2FrameIntegrationTest : public testing::TestWithParam void { hcm.set_proxy_100_continue(true); }); + beginSession(); + FakeRawConnectionPtr fake_upstream_connection; + + // Start a request and wait for it to reach the upstream. + sendFrame(Http2Frame::makeRequest(1, "host", "/path/to/long/url")); + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + const Http2Frame settings_frame = Http2Frame::makeEmptySettingsFrame(); + ASSERT_TRUE(fake_upstream_connection->write(std::string(settings_frame))); + + test_server_->waitForGaugeEq("cluster.cluster_0.upstream_rq_active", 1); + + // A malformed frame is translated to 103 header with END_STREAM by the underlying codec. + // Typically we should get a protocol error, but this should not crash Envoy. + // PAYLOAD_LENGTH: \x05 + // FRAME_TYPE: \x01 + // FLAGS: \x32 + // STREAM_ID: \x01 + // ASCII: \x31, \x30, \x33 for 1, 0, 3 respectively + const std::vector header_frame = { + 0x00, 0x00, 0x05, 0x01, 0x32, 0x00, 0x00, 0x00, 0x01, 0x2d, 0xfe, 0xff, 0x01, 0x10, + 0x00, 0x00, 0x05, 0x09, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x09, 0x03, 0x31, 0x30, 0x33}; + const std::string header_frame_str(reinterpret_cast(header_frame.data()), + header_frame.size()); + ASSERT_TRUE(fake_upstream_connection->write(header_frame_str)); + + const Http2Frame response = readFrame(); + EXPECT_EQ(Http2Frame::Type::Headers, response.type()); + + tcp_client_->close(); + test_server_->waitForGaugeEq("http.config_test.downstream_rq_active", 0); +} + TEST_P(Http2FrameIntegrationTest, MaxConcurrentStreamsIsRespected) { const int kTotalRequests = 101; config_helper_.addConfigModifier( diff --git a/test/integration/overload_integration_test.cc b/test/integration/overload_integration_test.cc index d9060673cd3f..56d6df0ffdb9 100644 --- a/test/integration/overload_integration_test.cc +++ b/test/integration/overload_integration_test.cc @@ -19,12 +19,19 @@ using testing::HasSubstr; class OverloadIntegrationTest : public BaseOverloadIntegrationTest, public HttpProtocolIntegrationTest { protected: - void - initializeOverloadManager(const envoy::config::overload::v3::OverloadAction& overload_action) { + void initializeOverloadManager(const envoy::config::overload::v3::OverloadAction& overload_action, + absl::optional appendLocalOverloadHeader = absl::nullopt) { setupOverloadManagerConfig(overload_action); config_helper_.addConfigModifier([this](envoy::config::bootstrap::v3::Bootstrap& bootstrap) { *bootstrap.mutable_overload_manager() = this->overload_manager_config_; }); + + if (appendLocalOverloadHeader.has_value() && appendLocalOverloadHeader.value()) { + config_helper_.addConfigModifier( + [=](envoy::extensions::filters::network::http_connection_manager::v3:: + HttpConnectionManager& cm) -> void { cm.set_append_local_overload(true); }); + } + initialize(); updateResource(0); } @@ -62,6 +69,8 @@ TEST_P(OverloadIntegrationTest, CloseStreamsWhenOverloaded) { EXPECT_TRUE(response->complete()); EXPECT_EQ("503", response->headers().getStatusValue()); + // Verify that no local overload header is added by default + EXPECT_EQ(true, response->headers().get(Http::Headers::get().EnvoyLocalOverloaded).empty()); EXPECT_EQ("envoy overloaded", response->body()); codec_client_->close(); @@ -71,6 +80,7 @@ TEST_P(OverloadIntegrationTest, CloseStreamsWhenOverloaded) { EXPECT_TRUE(response->complete()); EXPECT_EQ("503", response->headers().getStatusValue()); + EXPECT_EQ(true, response->headers().get(Http::Headers::get().EnvoyLocalOverloaded).empty()); EXPECT_EQ("envoy overloaded", response->body()); codec_client_->close(); @@ -88,6 +98,56 @@ TEST_P(OverloadIntegrationTest, CloseStreamsWhenOverloaded) { EXPECT_EQ(0U, response->body().size()); } +TEST_P(OverloadIntegrationTest, AppendLocalOverloadHeader) { + initializeOverloadManager( + TestUtility::parseYaml(R"EOF( + name: "envoy.overload_actions.stop_accepting_requests" + triggers: + - name: "envoy.resource_monitors.testonly.fake_resource_monitor" + threshold: + value: 0.9 + )EOF"), + true); + + // Put envoy in overloaded state and check that it drops new requests and the local overload is + // correctly added. Test both header-only and header+body requests since the code paths are + // slightly different. + updateResource(0.9); + test_server_->waitForGaugeEq("overload.envoy.overload_actions.stop_accepting_requests.active", 1); + + Http::TestRequestHeaderMapImpl request_headers{{":method", "GET"}, + {":path", "/test/long/url"}, + {":scheme", "http"}, + {":authority", "sni.lyft.com"}}; + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + auto response = codec_client_->makeRequestWithBody(request_headers, 10); + ASSERT_TRUE(response->waitForEndStream()); + + EXPECT_TRUE(response->complete()); + EXPECT_EQ("503", response->headers().getStatusValue()); + EXPECT_EQ(Http::Headers::get().EnvoyOverloadedValues.True, + response->headers() + .get(Http::Headers::get().EnvoyLocalOverloaded)[0] + ->value() + .getStringView()); + EXPECT_EQ("envoy overloaded", response->body()); + codec_client_->close(); + + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + response = codec_client_->makeHeaderOnlyRequest(request_headers); + ASSERT_TRUE(response->waitForEndStream()); + + EXPECT_TRUE(response->complete()); + EXPECT_EQ("503", response->headers().getStatusValue()); + EXPECT_EQ(Http::Headers::get().EnvoyOverloadedValues.True, + response->headers() + .get(Http::Headers::get().EnvoyLocalOverloaded)[0] + ->value() + .getStringView()); + EXPECT_EQ("envoy overloaded", response->body()); + codec_client_->close(); +} + TEST_P(OverloadIntegrationTest, DisableKeepaliveWhenOverloaded) { if (downstreamProtocol() != Http::CodecType::HTTP1) { return; // only relevant for downstream HTTP1.x connections @@ -754,4 +814,39 @@ TEST_P(LoadShedPointIntegrationTest, Http2ServerDispatchSendsGoAwayCompletingPen "overload.envoy.load_shed_points.http2_server_go_away_on_dispatch.scale_percent", 0); } +TEST_P(LoadShedPointIntegrationTest, HttpConnectionMnagerCloseConnectionCreatingCodec) { + if (downstreamProtocol() == Http::CodecClient::Type::HTTP3) { + return; + } + autonomous_upstream_ = true; + initializeOverloadManager( + TestUtility::parseYaml(R"EOF( + name: "envoy.load_shed_points.hcm_ondata_creating_codec" + triggers: + - name: "envoy.resource_monitors.testonly.fake_resource_monitor" + threshold: + value: 0.90 + )EOF")); + + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + + updateResource(0.95); + test_server_->waitForGaugeEq( + "overload.envoy.load_shed_points.hcm_ondata_creating_codec.scale_percent", 100); + auto encoder_decoder = codec_client_->startRequest(default_request_headers_); + + test_server_->waitForCounterEq("http.config_test.downstream_rq_overload_close", 1); + ASSERT_TRUE(codec_client_->waitForDisconnect()); + + updateResource(0.80); + test_server_->waitForGaugeEq( + "overload.envoy.load_shed_points.hcm_ondata_creating_codec.scale_percent", 0); + + codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + test_server_->waitForCounterEq("http.config_test.downstream_rq_overload_close", 1); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_EQ(response->headers().getStatusValue(), "200"); +} + } // namespace Envoy diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index f4e305689202..e13e5a493b72 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -4451,6 +4451,52 @@ TEST_P(ProtocolIntegrationTest, HandleUpstreamSocketFail) { cleanupUpstreamAndDownstream(); } +// TODO(alyssawilk) fix windows build before flipping flag. +#ifndef WIN32 +// A singleton which will fail creation of the Nth socket +class AllowForceFail : public Api::OsSysCallsImpl { +public: + void startFailing() { + absl::MutexLock m(&mutex_); + fail_ = true; + } + Api::SysCallSocketResult socket(int domain, int type, int protocol) override { + absl::MutexLock m(&mutex_); + if (fail_) { + return {-1, 1}; + } + return Api::OsSysCallsImpl::socket(domain, type, protocol); + } + +private: + absl::Mutex mutex_; + bool fail_ = false; +}; + +TEST_P(ProtocolIntegrationTest, HandleUpstreamSocketCreationFail) { + config_helper_.addRuntimeOverride("envoy.restart_features.allow_client_socket_creation_failure", + "true"); + AllowForceFail fail_socket_n_; + TestThreadsafeSingletonInjector os_calls{&fail_socket_n_}; + + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + EXPECT_ENVOY_BUG( + { + fail_socket_n_.startFailing(); + auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + ASSERT_TRUE(response->waitForEndStream()); + EXPECT_EQ("503", response->headers().getStatusValue()); + }, + ""); + + test_server_.reset(); + cleanupUpstreamAndDownstream(); + fake_upstreams_.clear(); +} +#endif + TEST_P(ProtocolIntegrationTest, NoLocalInterfaceNameForUpstreamConnection) { config_helper_.prependFilter(R"EOF( name: stream-info-to-headers-filter diff --git a/test/integration/quic_http_integration_test.cc b/test/integration/quic_http_integration_test.cc index a4460d7f6add..80c5c117e4bb 100644 --- a/test/integration/quic_http_integration_test.cc +++ b/test/integration/quic_http_integration_test.cc @@ -300,6 +300,8 @@ class QuicHttpIntegrationTestBase : public HttpIntegrationTest { ON_CALL(context.server_context_, api()).WillByDefault(testing::ReturnRef(*api_)); ON_CALL(context, statsScope()).WillByDefault(testing::ReturnRef(stats_scope_)); ON_CALL(context, sslContextManager()).WillByDefault(testing::ReturnRef(context_manager_)); + ON_CALL(context.server_context_, threadLocal()) + .WillByDefault(testing::ReturnRef(thread_local_)); envoy::extensions::transport_sockets::quic::v3::QuicUpstreamTransport quic_transport_socket_config; auto* tls_context = quic_transport_socket_config.mutable_upstream_tls_context(); @@ -330,6 +332,60 @@ class QuicHttpIntegrationTestBase : public HttpIntegrationTest { } } + void testMultipleUpstreamQuicConnections() { + // As with testMultipleQuicConnections this function may be flaky when run with + // --runs_per_test=N where N > 1 but without --jobs=1. + setConcurrency(8); + + // Avoid having to figure out which requests land on which connections by + // having one request per upstream connection. + setUpstreamProtocol(Http::CodecType::HTTP3); + envoy::config::listener::v3::QuicProtocolOptions options; + options.mutable_quic_protocol_options()->mutable_max_concurrent_streams()->set_value(1); + mergeOptions(options); + + initialize(); + std::vector codec_clients; + std::vector responses; + std::vector upstream_requests; + std::vector upstream_connections; + + // Create |concurrency| clients + size_t num_requests = concurrency_ * 2; + for (size_t i = 1; i <= concurrency_; ++i) { + // See testMultipleQuicConnections for why this should result in connection spread. + designated_connection_ids_.push_back(quic::test::TestConnectionId(i << 32)); + codec_clients.push_back(makeHttpConnection(lookupPort("http"))); + } + + // Create |num_requests| requests and wait for them to be received upstream + for (size_t i = 0; i < num_requests; ++i) { + responses.push_back( + codec_clients[i % concurrency_]->makeHeaderOnlyRequest(default_request_headers_)); + waitForNextUpstreamRequest(); + ASSERT(upstream_request_ != nullptr); + upstream_connections.push_back(std::move(fake_upstream_connection_)); + upstream_requests.push_back(std::move(upstream_request_)); + } + + // Send |num_requests| responses as fast as possible to regression test + // against a prior credentials insert race. + for (size_t i = 0; i < num_requests; ++i) { + upstream_requests[i]->encodeHeaders(default_response_headers_, true); + } + + // Wait for |num_requests| responses to complete. + for (size_t i = 0; i < num_requests; ++i) { + ASSERT_TRUE(responses[i]->waitForEndStream()); + EXPECT_TRUE(responses[i]->complete()); + } + + // Close |concurrency| clients + for (size_t i = 0; i < concurrency_; ++i) { + codec_clients[i]->close(); + } + } + void testMultipleQuicConnections() { // Enabling SO_REUSEPORT with 8 workers. Unfortunately this setting makes the test rarely flaky // if it is configured to run with --runs_per_test=N where N > 1 but without --jobs=1. @@ -373,11 +429,8 @@ class QuicHttpIntegrationTestBase : public HttpIntegrationTest { for (size_t i = 0; i < concurrency_; ++i) { fake_upstream_connection_ = nullptr; upstream_request_ = nullptr; - auto encoder_decoder = - codec_clients[i]->startRequest(Http::TestRequestHeaderMapImpl{{":method", "GET"}, - {":path", "/test/long/url"}, - {":scheme", "http"}, - {":authority", "host"}}); + auto encoder_decoder = codec_clients[i]->startRequest(default_request_headers_); + auto& request_encoder = encoder_decoder.first; auto response = std::move(encoder_decoder.second); codec_clients[i]->sendData(request_encoder, 1000, true); @@ -693,7 +746,13 @@ TEST_P(QuicHttpIntegrationTest, EarlyDataDisabled) { codec_client_->close(); } -// Ensure multiple quic connections work, regardless of platform BPF support +// Not only test multiple quic connections, but disconnect and reconnect to +// trigger resumption. +TEST_P(QuicHttpIntegrationTest, MultipleUpstreamQuicConnections) { + setUpstreamProtocol(Http::CodecType::HTTP3); + testMultipleUpstreamQuicConnections(); +} + TEST_P(QuicHttpIntegrationTest, MultipleQuicConnectionsDefaultMode) { testMultipleQuicConnections(); } @@ -1804,38 +1863,39 @@ TEST_P(QuicInplaceLdsIntegrationTest, StatelessResetOldConnection) { TEST_P(QuicHttpIntegrationTest, UsesPreferredAddress) { autonomous_upstream_ = true; - config_helper_.addConfigModifier([=](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { - auto* listen_address = bootstrap.mutable_static_resources() - ->mutable_listeners(0) - ->mutable_address() - ->mutable_socket_address(); - // Change listening address to Any. - listen_address->set_address(version_ == Network::Address::IpVersion::v4 ? "0.0.0.0" : "::"); - auto* preferred_address_config = bootstrap.mutable_static_resources() - ->mutable_listeners(0) - ->mutable_udp_listener_config() - ->mutable_quic_options() - ->mutable_server_preferred_address_config(); - // Configure a loopback interface as the server's preferred address. - preferred_address_config->set_name("quic.server_preferred_address.fixed"); - envoy::extensions::quic::server_preferred_address::v3::FixedServerPreferredAddressConfig - server_preferred_address; - server_preferred_address.set_ipv4_address("127.0.0.2"); - server_preferred_address.set_ipv6_address("::2"); - preferred_address_config->mutable_typed_config()->PackFrom(server_preferred_address); - - // Configure a test listener filter which is incompatible with any server preferred addresses - // but with any matcher, which effectively disables the filter. - auto* listener_filter = - bootstrap.mutable_static_resources()->mutable_listeners(0)->add_listener_filters(); - listener_filter->set_name("dumb_filter"); - auto configuration = test::integration::filters::TestQuicListenerFilterConfig(); - configuration.set_added_value("foo"); - configuration.set_allow_server_migration(false); - configuration.set_allow_client_migration(false); - listener_filter->mutable_typed_config()->PackFrom(configuration); - listener_filter->mutable_filter_disabled()->set_any_match(true); - }); + config_helper_.addConfigModifier( + [=, this](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* listen_address = bootstrap.mutable_static_resources() + ->mutable_listeners(0) + ->mutable_address() + ->mutable_socket_address(); + // Change listening address to Any. + listen_address->set_address(version_ == Network::Address::IpVersion::v4 ? "0.0.0.0" : "::"); + auto* preferred_address_config = bootstrap.mutable_static_resources() + ->mutable_listeners(0) + ->mutable_udp_listener_config() + ->mutable_quic_options() + ->mutable_server_preferred_address_config(); + // Configure a loopback interface as the server's preferred address. + preferred_address_config->set_name("quic.server_preferred_address.fixed"); + envoy::extensions::quic::server_preferred_address::v3::FixedServerPreferredAddressConfig + server_preferred_address; + server_preferred_address.set_ipv4_address("127.0.0.2"); + server_preferred_address.set_ipv6_address("::2"); + preferred_address_config->mutable_typed_config()->PackFrom(server_preferred_address); + + // Configure a test listener filter which is incompatible with any server preferred + // addresses but with any matcher, which effectively disables the filter. + auto* listener_filter = + bootstrap.mutable_static_resources()->mutable_listeners(0)->add_listener_filters(); + listener_filter->set_name("dumb_filter"); + auto configuration = test::integration::filters::TestQuicListenerFilterConfig(); + configuration.set_added_value("foo"); + configuration.set_allow_server_migration(false); + configuration.set_allow_client_migration(false); + listener_filter->mutable_typed_config()->PackFrom(configuration); + listener_filter->mutable_filter_disabled()->set_any_match(true); + }); initialize(); codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); @@ -1872,38 +1932,39 @@ TEST_P(QuicHttpIntegrationTest, PreferredAddressRuntimeFlag) { autonomous_upstream_ = true; config_helper_.addRuntimeOverride( "envoy.reloadable_features.quic_send_server_preferred_address_to_all_clients", "false"); - config_helper_.addConfigModifier([=](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { - auto* listen_address = bootstrap.mutable_static_resources() - ->mutable_listeners(0) - ->mutable_address() - ->mutable_socket_address(); - // Change listening address to Any. - listen_address->set_address(version_ == Network::Address::IpVersion::v4 ? "0.0.0.0" : "::"); - auto* preferred_address_config = bootstrap.mutable_static_resources() - ->mutable_listeners(0) - ->mutable_udp_listener_config() - ->mutable_quic_options() - ->mutable_server_preferred_address_config(); - // Configure a loopback interface as the server's preferred address. - preferred_address_config->set_name("quic.server_preferred_address.fixed"); - envoy::extensions::quic::server_preferred_address::v3::FixedServerPreferredAddressConfig - server_preferred_address; - server_preferred_address.set_ipv4_address("127.0.0.2"); - server_preferred_address.set_ipv6_address("::2"); - preferred_address_config->mutable_typed_config()->PackFrom(server_preferred_address); - - // Configure a test listener filter which is incompatible with any server preferred addresses - // but with any matcher, which effectively disables the filter. - auto* listener_filter = - bootstrap.mutable_static_resources()->mutable_listeners(0)->add_listener_filters(); - listener_filter->set_name("dumb_filter"); - auto configuration = test::integration::filters::TestQuicListenerFilterConfig(); - configuration.set_added_value("foo"); - configuration.set_allow_server_migration(false); - configuration.set_allow_client_migration(false); - listener_filter->mutable_typed_config()->PackFrom(configuration); - listener_filter->mutable_filter_disabled()->set_any_match(true); - }); + config_helper_.addConfigModifier( + [=, this](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* listen_address = bootstrap.mutable_static_resources() + ->mutable_listeners(0) + ->mutable_address() + ->mutable_socket_address(); + // Change listening address to Any. + listen_address->set_address(version_ == Network::Address::IpVersion::v4 ? "0.0.0.0" : "::"); + auto* preferred_address_config = bootstrap.mutable_static_resources() + ->mutable_listeners(0) + ->mutable_udp_listener_config() + ->mutable_quic_options() + ->mutable_server_preferred_address_config(); + // Configure a loopback interface as the server's preferred address. + preferred_address_config->set_name("quic.server_preferred_address.fixed"); + envoy::extensions::quic::server_preferred_address::v3::FixedServerPreferredAddressConfig + server_preferred_address; + server_preferred_address.set_ipv4_address("127.0.0.2"); + server_preferred_address.set_ipv6_address("::2"); + preferred_address_config->mutable_typed_config()->PackFrom(server_preferred_address); + + // Configure a test listener filter which is incompatible with any server preferred + // addresses but with any matcher, which effectively disables the filter. + auto* listener_filter = + bootstrap.mutable_static_resources()->mutable_listeners(0)->add_listener_filters(); + listener_filter->set_name("dumb_filter"); + auto configuration = test::integration::filters::TestQuicListenerFilterConfig(); + configuration.set_added_value("foo"); + configuration.set_allow_server_migration(false); + configuration.set_allow_client_migration(false); + listener_filter->mutable_typed_config()->PackFrom(configuration); + listener_filter->mutable_filter_disabled()->set_any_match(true); + }); initialize(); codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); @@ -1992,36 +2053,38 @@ TEST_P(QuicHttpIntegrationTest, PreferredAddressDroppedByIncompatibleListenerFil autonomous_upstream_ = true; useAccessLog(fmt::format("%RESPONSE_CODE% %FILTER_STATE({})%", TestQuicListenerFilter::TestStringFilterState::key())); - config_helper_.addConfigModifier([=](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { - auto* listen_address = bootstrap.mutable_static_resources() - ->mutable_listeners(0) - ->mutable_address() - ->mutable_socket_address(); - // Change listening address to Any. - listen_address->set_address(version_ == Network::Address::IpVersion::v4 ? "0.0.0.0" : "::"); - auto* preferred_address_config = bootstrap.mutable_static_resources() - ->mutable_listeners(0) - ->mutable_udp_listener_config() - ->mutable_quic_options() - ->mutable_server_preferred_address_config(); - // Configure a loopback interface as the server's preferred address. - preferred_address_config->set_name("quic.server_preferred_address.fixed"); - envoy::extensions::quic::server_preferred_address::v3::FixedServerPreferredAddressConfig - server_preferred_address; - server_preferred_address.set_ipv4_address("127.0.0.2"); - server_preferred_address.set_ipv6_address("::2"); - preferred_address_config->mutable_typed_config()->PackFrom(server_preferred_address); - - // Configure a test listener filter which is incompatible with any server preferred addresses. - auto* listener_filter = - bootstrap.mutable_static_resources()->mutable_listeners(0)->add_listener_filters(); - listener_filter->set_name("dumb_filter"); - auto configuration = test::integration::filters::TestQuicListenerFilterConfig(); - configuration.set_added_value("foo"); - configuration.set_allow_server_migration(false); - configuration.set_allow_client_migration(false); - listener_filter->mutable_typed_config()->PackFrom(configuration); - }); + config_helper_.addConfigModifier( + [=, this](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void { + auto* listen_address = bootstrap.mutable_static_resources() + ->mutable_listeners(0) + ->mutable_address() + ->mutable_socket_address(); + // Change listening address to Any. + listen_address->set_address(version_ == Network::Address::IpVersion::v4 ? "0.0.0.0" : "::"); + auto* preferred_address_config = bootstrap.mutable_static_resources() + ->mutable_listeners(0) + ->mutable_udp_listener_config() + ->mutable_quic_options() + ->mutable_server_preferred_address_config(); + // Configure a loopback interface as the server's preferred address. + preferred_address_config->set_name("quic.server_preferred_address.fixed"); + envoy::extensions::quic::server_preferred_address::v3::FixedServerPreferredAddressConfig + server_preferred_address; + server_preferred_address.set_ipv4_address("127.0.0.2"); + server_preferred_address.set_ipv6_address("::2"); + preferred_address_config->mutable_typed_config()->PackFrom(server_preferred_address); + + // Configure a test listener filter which is incompatible with any server preferred + // addresses. + auto* listener_filter = + bootstrap.mutable_static_resources()->mutable_listeners(0)->add_listener_filters(); + listener_filter->set_name("dumb_filter"); + auto configuration = test::integration::filters::TestQuicListenerFilterConfig(); + configuration.set_added_value("foo"); + configuration.set_allow_server_migration(false); + configuration.set_allow_client_migration(false); + listener_filter->mutable_typed_config()->PackFrom(configuration); + }); initialize(); codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); diff --git a/test/integration/sds_generic_secret_integration_test.cc b/test/integration/sds_generic_secret_integration_test.cc index 2d1b3aed08a9..0bd26ff6c3d2 100644 --- a/test/integration/sds_generic_secret_integration_test.cc +++ b/test/integration/sds_generic_secret_integration_test.cc @@ -31,8 +31,9 @@ class SdsGenericSecretTestFilter : public Http::StreamDecoderFilter { // Http::StreamDecoderFilter Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, bool) override { - headers.addCopy(Http::LowerCaseString("secret"), - Config::DataSource::read(config_provider_->secret()->secret(), true, api_)); + headers.addCopy( + Http::LowerCaseString("secret"), + Config::DataSource::read(config_provider_->secret()->secret(), true, api_).value()); return Http::FilterHeadersStatus::Continue; } diff --git a/test/integration/tcp_async_client_integration_test.cc b/test/integration/tcp_async_client_integration_test.cc index cd31af091dd9..89c4e29c1771 100644 --- a/test/integration/tcp_async_client_integration_test.cc +++ b/test/integration/tcp_async_client_integration_test.cc @@ -111,6 +111,38 @@ TEST_P(TcpAsyncClientIntegrationTest, MultipleResponseFrames) { tcp_client->close(); } +TEST_P(TcpAsyncClientIntegrationTest, Reconnect) { + if (GetParam() == Network::Address::IpVersion::v6) { + return; + } + + enableHalfClose(true); + initialize(); + + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("listener_0")); + ASSERT_TRUE(tcp_client->write("hello1", false)); + test_server_->waitForCounterEq("cluster.cluster_0.upstream_cx_total", 1); + test_server_->waitForGaugeEq("cluster.cluster_0.upstream_cx_active", 1); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->waitForData( + [&](const std::string& data) -> bool { return data == "hello1"; })); + ASSERT_TRUE(fake_upstream_connection->close()); + test_server_->waitForGaugeEq("cluster.cluster_0.upstream_cx_active", 0); + + // We use the same tcp_client to ensure that a new upstream connection is created. + ASSERT_TRUE(tcp_client->write("hello2", false)); + test_server_->waitForCounterEq("cluster.cluster_0.upstream_cx_total", 2); + test_server_->waitForGaugeEq("cluster.cluster_0.upstream_cx_active", 1); + FakeRawConnectionPtr fake_upstream_connection2; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection2)); + ASSERT_TRUE(fake_upstream_connection2->waitForData( + [&](const std::string& data) -> bool { return data == "hello2"; })); + + tcp_client->close(); + test_server_->waitForGaugeEq("cluster.cluster_0.upstream_cx_active", 0); +} + #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) { diff --git a/test/integration/tcp_tunneling_integration_test.cc b/test/integration/tcp_tunneling_integration_test.cc index 5e0a5a37d664..023121aeef5f 100644 --- a/test/integration/tcp_tunneling_integration_test.cc +++ b/test/integration/tcp_tunneling_integration_test.cc @@ -1313,6 +1313,34 @@ TEST_P(TcpTunnelingIntegrationTest, CopyResponseTrailers) { EXPECT_THAT(waitForAccessLog(access_log_filename), testing::HasSubstr(trailer_value)); } +TEST_P(TcpTunnelingIntegrationTest, DownstreamFinOnUpstreamTrailers) { + if (upstreamProtocol() == Http::CodecType::HTTP1) { + return; + } + + initialize(); + + tcp_client_ = makeTcpConnection(lookupPort("tcp_proxy")); + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForHeadersComplete()); + + upstream_request_->encodeHeaders(default_response_headers_, false); + sendBidiData(fake_upstream_connection_); + + // Send trailers + const std::string trailer_value = "trailer-value"; + Http::TestResponseTrailerMapImpl response_trailers{{"test-trailer-name", trailer_value}}; + upstream_request_->encodeTrailers(response_trailers); + + // Upstream trailers should close the downstream connection for writing. + tcp_client_->waitForHalfClose(); + + // Close Connection + tcp_client_->close(); + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); +} + TEST_P(TcpTunnelingIntegrationTest, CloseUpstreamFirst) { initialize(); diff --git a/test/integration/udp_tunneling_integration_test.cc b/test/integration/udp_tunneling_integration_test.cc index 10aa40480d63..bca91a8f2d64 100644 --- a/test/integration/udp_tunneling_integration_test.cc +++ b/test/integration/udp_tunneling_integration_test.cc @@ -443,7 +443,7 @@ name: udp_proxy const std::string expectedCapsules(std::vector raw_datagrams) { std::string expected_capsules = ""; - for (std::string datagram : raw_datagrams) { + for (std::string& datagram : raw_datagrams) { expected_capsules += encapsulate(datagram); } diff --git a/test/integration/utility.cc b/test/integration/utility.cc index 1f7e3b75f73d..3d06c513d7fa 100644 --- a/test/integration/utility.cc +++ b/test/integration/utility.cc @@ -142,11 +142,13 @@ class TestConnectionCallbacks : public Network::ConnectionCallbacks { Network::UpstreamTransportSocketFactoryPtr IntegrationUtil::createQuicUpstreamTransportSocketFactory(Api::Api& api, Stats::Store& store, Ssl::ContextManager& context_manager, + ThreadLocal::Instance& threadlocal, const std::string& san_to_match) { NiceMock context; ON_CALL(context.server_context_, api()).WillByDefault(testing::ReturnRef(api)); ON_CALL(context, statsScope()).WillByDefault(testing::ReturnRef(*store.rootScope())); ON_CALL(context, sslContextManager()).WillByDefault(testing::ReturnRef(context_manager)); + ON_CALL(context.server_context_, threadLocal()).WillByDefault(testing::ReturnRef(threadlocal)); envoy::extensions::transport_sockets::quic::v3::QuicUpstreamTransport quic_transport_socket_config; auto* tls_context = quic_transport_socket_config.mutable_upstream_tls_context(); @@ -236,9 +238,10 @@ IntegrationUtil::makeSingleRequest(const Network::Address::InstanceConstSharedPt } #ifdef ENVOY_ENABLE_QUIC + testing::NiceMock threadlocal; Extensions::TransportSockets::Tls::ContextManagerImpl manager(time_system); Network::UpstreamTransportSocketFactoryPtr transport_socket_factory = - createQuicUpstreamTransportSocketFactory(api, mock_stats_store, manager, + createQuicUpstreamTransportSocketFactory(api, mock_stats_store, manager, threadlocal, "spiffe://lyft.com/backend-team"); auto& quic_transport_socket_factory = dynamic_cast(*transport_socket_factory); diff --git a/test/integration/utility.h b/test/integration/utility.h index 4bb330053a0e..64e4fbe63ab0 100644 --- a/test/integration/utility.h +++ b/test/integration/utility.h @@ -11,6 +11,7 @@ #include "envoy/http/header_map.h" #include "envoy/network/filter.h" #include "envoy/server/factory_context.h" +#include "envoy/thread_local/thread_local.h" #include "source/common/common/assert.h" #include "source/common/common/dump_state_utils.h" @@ -205,10 +206,9 @@ class IntegrationUtil { * Create transport socket factory for Quic upstream transport socket. * @return TransportSocketFactoryPtr the client transport socket factory. */ - static Network::UpstreamTransportSocketFactoryPtr - createQuicUpstreamTransportSocketFactory(Api::Api& api, Stats::Store& store, - Ssl::ContextManager& context_manager, - const std::string& san_to_match); + static Network::UpstreamTransportSocketFactoryPtr createQuicUpstreamTransportSocketFactory( + Api::Api& api, Stats::Store& store, Ssl::ContextManager& context_manager, + ThreadLocal::Instance& threadlocal, const std::string& san_to_match); static Http::HeaderValidatorFactoryPtr makeHeaderValidationFactory( const ::envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig& diff --git a/test/mocks/grpc/mocks.cc b/test/mocks/grpc/mocks.cc index 122563cf3340..c375a51226c7 100644 --- a/test/mocks/grpc/mocks.cc +++ b/test/mocks/grpc/mocks.cc @@ -39,6 +39,7 @@ MockAsyncClientFactory::MockAsyncClientFactory() { MockAsyncClientFactory::~MockAsyncClientFactory() = default; MockAsyncClientManager::MockAsyncClientManager() { + ON_CALL(*this, getOrCreateRawAsyncClient(_, _, _)).WillByDefault(Return(nullptr)); ON_CALL(*this, factoryForGrpcService(_, _, _)) .WillByDefault(Invoke([](const envoy::config::core::v3::GrpcService&, Stats::Scope&, bool) { return std::make_unique>(); diff --git a/test/mocks/grpc/mocks.h b/test/mocks/grpc/mocks.h index 920ccb7aa7d7..d0126823e671 100644 --- a/test/mocks/grpc/mocks.h +++ b/test/mocks/grpc/mocks.h @@ -111,15 +111,15 @@ class MockAsyncClientManager : public AsyncClientManager { MockAsyncClientManager(); ~MockAsyncClientManager() override; - MOCK_METHOD(AsyncClientFactoryPtr, factoryForGrpcService, + MOCK_METHOD(absl::StatusOr, factoryForGrpcService, (const envoy::config::core::v3::GrpcService& grpc_service, Stats::Scope& scope, bool skip_cluster_check)); - MOCK_METHOD(RawAsyncClientSharedPtr, getOrCreateRawAsyncClient, + MOCK_METHOD(absl::StatusOr, getOrCreateRawAsyncClient, (const envoy::config::core::v3::GrpcService& grpc_service, Stats::Scope& scope, bool skip_cluster_check)); - MOCK_METHOD(RawAsyncClientSharedPtr, getOrCreateRawAsyncClientWithHashKey, + MOCK_METHOD(absl::StatusOr, getOrCreateRawAsyncClientWithHashKey, (const GrpcServiceConfigWithHashKey& config_with_hash_key, Stats::Scope& scope, bool skip_cluster_check)); }; diff --git a/test/mocks/http/mocks.h b/test/mocks/http/mocks.h index 8b84f9f0e7e8..3ec3f7c5eb71 100644 --- a/test/mocks/http/mocks.h +++ b/test/mocks/http/mocks.h @@ -677,6 +677,7 @@ class MockConnectionManagerConfig : public ConnectionManagerConfig { MOCK_METHOD(uint64_t, maxRequestsPerConnection, (), (const)); MOCK_METHOD(const HttpConnectionManagerProto::ProxyStatusConfig*, proxyStatusConfig, (), (const)); MOCK_METHOD(ServerHeaderValidatorPtr, makeHeaderValidator, (Protocol protocol)); + MOCK_METHOD(bool, appendLocalOverload, (), (const)); MOCK_METHOD(bool, appendXForwardedPort, (), (const)); MOCK_METHOD(bool, addProxyProtocolConnectionState, (), (const)); diff --git a/test/mocks/server/factory_context.cc b/test/mocks/server/factory_context.cc index 945df5ef2fbd..98a28f435e21 100644 --- a/test/mocks/server/factory_context.cc +++ b/test/mocks/server/factory_context.cc @@ -11,7 +11,6 @@ namespace Envoy { namespace Server { namespace Configuration { -using ::testing::Return; using ::testing::ReturnRef; MockFactoryContext::MockFactoryContext() { diff --git a/test/mocks/stream_info/mocks.h b/test/mocks/stream_info/mocks.h index 0b166849e32a..c3c8518ac152 100644 --- a/test/mocks/stream_info/mocks.h +++ b/test/mocks/stream_info/mocks.h @@ -20,6 +20,10 @@ class Matcher : public internal::MatcherBase { public: explicit Matcher() = default; + + template ::type::is_gtest_matcher> + Matcher(M&& m) : internal::MatcherBase(std::forward(m)) {} + Matcher(Envoy::StreamInfo::ResponseFlag value) { *this = Eq(value); } Matcher(Envoy::StreamInfo::CoreResponseFlag value) { *this = Eq(Envoy::StreamInfo::ResponseFlag(value)); diff --git a/test/mocks/tcp/mocks.h b/test/mocks/tcp/mocks.h index 829e39152301..24e0ff38339f 100644 --- a/test/mocks/tcp/mocks.h +++ b/test/mocks/tcp/mocks.h @@ -99,6 +99,22 @@ class MockAsyncTcpClientCallbacks : public AsyncTcpClientCallbacks { MOCK_METHOD(void, onBelowWriteBufferLowWatermark, ()); }; +class MockAsyncTcpClient : public AsyncTcpClient { +public: + MockAsyncTcpClient() = default; + ~MockAsyncTcpClient() override = default; + + MOCK_METHOD(bool, connect, ()); + MOCK_METHOD(void, close, (Network::ConnectionCloseType type)); + MOCK_METHOD(Network::DetectedCloseType, detectedCloseType, (), (const)); + MOCK_METHOD(void, write, (Buffer::Instance & data, bool end_stream)); + MOCK_METHOD(void, readDisable, (bool disable)); + MOCK_METHOD(void, setAsyncTcpClientCallbacks, (AsyncTcpClientCallbacks & callbacks)); + MOCK_METHOD(Event::Dispatcher&, dispatcher, ()); + MOCK_METHOD(bool, connected, ()); + MOCK_METHOD(OptRef, getStreamInfo, ()); +}; + } // namespace AsyncClient } // namespace Tcp } // namespace Envoy diff --git a/test/mocks/thread_local/mocks.h b/test/mocks/thread_local/mocks.h index 36ccd578023b..09dff2377706 100644 --- a/test/mocks/thread_local/mocks.h +++ b/test/mocks/thread_local/mocks.h @@ -74,8 +74,7 @@ class MockInstance : public Instance { } void runOnAllThreads(const UpdateCb& cb, const std::function& main_callback) override { EXPECT_TRUE(was_set_); - parent_.runOnAllThreads([cb, this]() { cb(parent_.data_[index_]); }, - std::move(main_callback)); + parent_.runOnAllThreads([cb, this]() { cb(parent_.data_[index_]); }, main_callback); } bool isShutdown() const override { return parent_.shutdown_; } diff --git a/test/run_envoy_bazel_coverage.sh b/test/run_envoy_bazel_coverage.sh index 3261eeded5ab..feee13a07f11 100755 --- a/test/run_envoy_bazel_coverage.sh +++ b/test/run_envoy_bazel_coverage.sh @@ -3,8 +3,8 @@ set -e -o pipefail LLVM_VERSION=${LLVM_VERSION:-"14.0.0"} -CLANG_VERSION=$(clang --version | grep version | sed -e 's/\ *clang version \(.*\)\ */\1/') -LLVM_COV_VERSION=$(llvm-cov --version | grep version | sed -e 's/\ *LLVM version \(.*\)/\1/') +CLANG_VERSION=$(clang --version | grep version | sed -e 's/\ *clang version \([0-9.]*\).*/\1/') +LLVM_COV_VERSION=$(llvm-cov --version | grep version | sed -e 's/\ *LLVM version \([0-9.]*\).*/\1/') LLVM_PROFDATA_VERSION=$(llvm-profdata show --version | grep version | sed -e 's/\ *LLVM version \(.*\)/\1/') if [ "${CLANG_VERSION}" != "${LLVM_VERSION}" ] diff --git a/test/server/hot_restarting_child_test.cc b/test/server/hot_restarting_child_test.cc index da12147f5cf8..f2455034f054 100644 --- a/test/server/hot_restarting_child_test.cc +++ b/test/server/hot_restarting_child_test.cc @@ -15,10 +15,8 @@ #include "gtest/gtest.h" -using testing::AllOf; using testing::DoAll; using testing::Eq; -using testing::InSequence; using testing::Return; using testing::ReturnRef; using testing::SaveArg; diff --git a/test/server/server_corpus/rate_limit_nan b/test/server/server_corpus/rate_limit_nan new file mode 100644 index 000000000000..4c9b4bb59ec5 --- /dev/null +++ b/test/server/server_corpus/rate_limit_nan @@ -0,0 +1,44 @@ +node { + id: "\016\000\317@" + cluster: "@" +} +dynamic_resources { + ads_config { + api_type: DELTA_GRPC + grpc_services { + google_grpc { + target_uri: "7.0z1" + stat_prefix: "Ny" + } + } + rate_limit_settings { + max_tokens { + } + fill_rate { + value: nan + } + } + transport_api_version: V3 + } +} +layered_runtime { + layers { + name: "0" + rtds_layer { + name: "1=" + rtds_config { + ads { + } + initial_fetch_timeout { + seconds: 9472 + } + } + } + } + layers { + name: "q" + static_layer { + } + } +} +default_socket_interface: "#" diff --git a/test/server/server_test.cc b/test/server/server_test.cc index 5f088d5aba8f..3c67fcb4bf3d 100644 --- a/test/server/server_test.cc +++ b/test/server/server_test.cc @@ -668,7 +668,7 @@ class ServerInstanceImplWorkersTest : public ServerInstanceImplTest { EXPECT_CALL(restart_, drainParentListeners); } - ~ServerInstanceImplWorkersTest() { + ~ServerInstanceImplWorkersTest() override { server_->dispatcher().post([&] { server_->shutdown(); }); server_thread_->join(); } @@ -1345,10 +1345,10 @@ TEST_P(ServerInstanceImplTest, LogToFileError) { TEST_P(ServerInstanceImplTest, NoOptionsPassed) { thread_local_ = std::make_unique(); init_manager_ = std::make_unique("Server"); - server_.reset(new InstanceImpl( + server_ = std::make_unique( *init_manager_, options_, time_system_, hooks_, restart_, stats_store_, fakelock_, std::make_unique>(), *thread_local_, - Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(), nullptr)); + Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(), nullptr); EXPECT_THROW_WITH_MESSAGE( server_->initialize(std::make_shared("127.0.0.1"), component_factory_), diff --git a/test/test_common/wasm_base.h b/test/test_common/wasm_base.h index 5e3394bf5559..3e2b34393c06 100644 --- a/test/test_common/wasm_base.h +++ b/test/test_common/wasm_base.h @@ -114,7 +114,7 @@ template class WasmTestBase : public Base { NiceMock lifecycle_notifier_; envoy::config::core::v3::Metadata listener_metadata_; Context* root_context_ = nullptr; // Unowned. - Config::DataSource::RemoteAsyncDataProviderPtr remote_data_provider_; + RemoteAsyncDataProviderPtr remote_data_provider_; void setRootId(std::string root_id) { root_id_ = root_id; } void setVmConfiguration(std::string vm_configuration) { vm_configuration_ = vm_configuration; } diff --git a/tools/api_proto_plugin/plugin.bzl b/tools/api_proto_plugin/plugin.bzl index 9c2dd92a568b..014749a7d1a5 100644 --- a/tools/api_proto_plugin/plugin.bzl +++ b/tools/api_proto_plugin/plugin.bzl @@ -23,7 +23,7 @@ def _path_ignoring_repository(f): def _input_arg(i): return "%s=%s" % (i.basename, i.path) -def api_proto_plugin_impl(target, ctx, output_group, mnemonic, output_suffixes): +def api_proto_plugin_impl(target, ctx, output_group, mnemonic, output_suffixes, output_dir = ""): # Compute output files from the current proto_library node's dependencies. transitive_outputs = depset(transitive = [dep.output_groups[output_group] for dep in ctx.rule.attr.deps]) @@ -53,18 +53,26 @@ def api_proto_plugin_impl(target, ctx, output_group, mnemonic, output_suffixes): for f in target[ProtoInfo].transitive_sources.to_list(): import_paths.append("{}={}".format(_path_ignoring_repository(f), f.path)) - # The outputs live in the ctx.label's package root. We add some additional - # path information to match with protoc's notion of path relative locations. outputs = [] - for output_suffix in output_suffixes: - outputs += [ctx.actions.declare_file(ctx.label.name + "/" + _path_ignoring_repository(f) + - output_suffix) for f in proto_sources] + output_path = "" + + if output_suffixes: + # The outputs live in the ctx.label's package root. We add some additional + # path information to match with protoc's notion of path relative locations. + outputs = [] + for output_suffix in output_suffixes: + outputs += [ctx.actions.declare_file(ctx.label.name + "/" + _path_ignoring_repository(f) + + output_suffix) for f in proto_sources] + + ctx_path = ctx.label.package + "/" + ctx.label.name + output_path = outputs[0].root.path + "/" + outputs[0].owner.workspace_root + "/" + ctx_path + elif output_dir: + outputs.append(ctx.actions.declare_directory(output_dir)) + output_path = outputs[0].path # Create the protoc command-line args. inputs = [target[ProtoInfo].transitive_sources] - ctx_path = ctx.label.package + "/" + ctx.label.name - output_path = outputs[0].root.path + "/" + outputs[0].owner.workspace_root + "/" + ctx_path args = ctx.actions.args() args.add(ctx.label.workspace_root, format = "-I./%s") args.add_all(import_paths, format_each = "-I%s") diff --git a/tools/base/requirements.txt b/tools/base/requirements.txt index 268f131abcaf..26f39ac48a40 100644 --- a/tools/base/requirements.txt +++ b/tools/base/requirements.txt @@ -419,39 +419,39 @@ coloredlogs==15.0.1 \ crcmod==1.7 \ --hash=sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e # via gsutil -cryptography==42.0.2 \ - --hash=sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380 \ - --hash=sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589 \ - --hash=sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea \ - --hash=sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65 \ - --hash=sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a \ - --hash=sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3 \ - --hash=sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008 \ - --hash=sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1 \ - --hash=sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2 \ - --hash=sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635 \ - --hash=sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2 \ - --hash=sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90 \ - --hash=sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee \ - --hash=sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a \ - --hash=sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242 \ - --hash=sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12 \ - --hash=sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2 \ - --hash=sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d \ - --hash=sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be \ - --hash=sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee \ - --hash=sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6 \ - --hash=sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529 \ - --hash=sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929 \ - --hash=sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1 \ - --hash=sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6 \ - --hash=sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a \ - --hash=sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446 \ - --hash=sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9 \ - --hash=sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888 \ - --hash=sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4 \ - --hash=sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33 \ - --hash=sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f +cryptography==42.0.5 \ + --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \ + --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \ + --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \ + --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \ + --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \ + --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \ + --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \ + --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \ + --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \ + --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \ + --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \ + --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \ + --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \ + --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \ + --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \ + --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \ + --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \ + --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \ + --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \ + --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \ + --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \ + --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \ + --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \ + --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \ + --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \ + --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \ + --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \ + --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \ + --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \ + --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \ + --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \ + --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7 # via # -r requirements.in # aioquic @@ -689,9 +689,9 @@ gitdb==4.0.11 \ --hash=sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4 \ --hash=sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b # via gitpython -gitpython==3.1.41 \ - --hash=sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c \ - --hash=sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048 +gitpython==3.1.42 \ + --hash=sha256:1bf9cd7c9e7255f77778ea54359e54ac22a72a5b51288c457c881057b7bb9ecd \ + --hash=sha256:2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb # via -r requirements.in google-apitools==0.5.32 \ --hash=sha256:b78f74116558e0476e19501b5b4b2ac7c93261a69c5449c861ea95cbc853c688 \ @@ -700,7 +700,9 @@ google-apitools==0.5.32 \ google-auth[aiohttp]==2.27.0 \ --hash=sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245 \ --hash=sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821 - # via gsutil + # via + # google-auth + # gsutil google-reauth==0.1.1 \ --hash=sha256:cb39074488d74c8853074dde47368bbf8f739d4a4338b89aab696c895b6d8368 \ --hash=sha256:f9f6852a55c2c5453d581cd01f3d1278e86147c03d008409800390a834235892 @@ -919,57 +921,57 @@ oauth2client==4.1.3 \ # via # gcs-oauth2-boto-plugin # google-apitools -orjson==3.9.13 \ - --hash=sha256:031df1026c7ea8303332d78711f180231e3ae8b564271fb748a03926587c5546 \ - --hash=sha256:0d3ba9d88e20765335260d7b25547d7c571eee2b698200f97afa7d8c7cd668fc \ - --hash=sha256:0d691c44604941945b00e0a13b19a7d9c1a19511abadf0080f373e98fdeb6b31 \ - --hash=sha256:0fd9a2101d04e85086ea6198786a3f016e45475f800712e6833e14bf9ce2832f \ - --hash=sha256:16946d095212a3dec552572c5d9bca7afa40f3116ad49695a397be07d529f1fa \ - --hash=sha256:1ab9dbdec3f13f3ea6f937564ce21651844cfbf2725099f2f490426acf683c23 \ - --hash=sha256:23f21faf072ed3b60b5954686f98157e073f6a8068eaa58dbde83e87212eda84 \ - --hash=sha256:266e55c83f81248f63cc93d11c5e3a53df49a5d2598fa9e9db5f99837a802d5d \ - --hash=sha256:2cc03a35bfc71c8ebf96ce49b82c2a7be6af4b3cd3ac34166fdb42ac510bbfff \ - --hash=sha256:2f37f0cdd026ef777a4336e599d8194c8357fc14760c2a5ddcfdf1965d45504b \ - --hash=sha256:31372ba3a9fe8ad118e7d22fba46bbc18e89039e3bfa89db7bc8c18ee722dca8 \ - --hash=sha256:31fb66b41fb2c4c817d9610f0bc7d31345728d7b5295ac78b63603407432a2b2 \ - --hash=sha256:3869d65561f10071d3e7f35ae58fd377056f67d7aaed5222f318390c3ad30339 \ - --hash=sha256:3deadd8dc0e9ff844b5b656fa30a48dbee1c3b332d8278302dd9637f6b09f627 \ - --hash=sha256:43fd6036b16bb6742d03dae62f7bdf8214d06dea47e4353cde7e2bd1358d186f \ - --hash=sha256:446d9ad04204e79229ae19502daeea56479e55cbc32634655d886f5a39e91b44 \ - --hash=sha256:4584e8eb727bc431baaf1bf97e35a1d8a0109c924ec847395673dfd5f4ef6d6f \ - --hash=sha256:49b7e3fe861cb246361825d1a238f2584ed8ea21e714bf6bb17cebb86772e61c \ - --hash=sha256:5b98cd948372f0eb219bc309dee4633db1278687161e3280d9e693b6076951d2 \ - --hash=sha256:5ef58869f3399acbbe013518d8b374ee9558659eef14bca0984f67cb1fbd3c37 \ - --hash=sha256:60da7316131185d0110a1848e9ad15311e6c8938ee0b5be8cbd7261e1d80ee8f \ - --hash=sha256:62e9a99879c4d5a04926ac2518a992134bfa00d546ea5a4cae4b9be454d35a22 \ - --hash=sha256:63ef57a53bfc2091a7cd50a640d9ae866bd7d92a5225a1bab6baa60ef62583f2 \ - --hash=sha256:6e47153db080f5e87e8ba638f1a8b18995eede6b0abb93964d58cf11bcea362f \ - --hash=sha256:730385fdb99a21fce9bb84bb7fcbda72c88626facd74956bda712834b480729d \ - --hash=sha256:7ccd5bd222e5041069ad9d9868ab59e6dbc53ecde8d8c82b919954fbba43b46b \ - --hash=sha256:7e8e4a571d958910272af8d53a9cbe6599f9f5fd496a1bc51211183bb2072cbd \ - --hash=sha256:811ac076855e33e931549340288e0761873baf29276ad00f221709933c644330 \ - --hash=sha256:828c502bb261588f7de897e06cb23c4b122997cb039d2014cb78e7dabe92ef0c \ - --hash=sha256:838b898e8c1f26eb6b8d81b180981273f6f5110c76c22c384979aca854194f1b \ - --hash=sha256:860d0f5b42d0c0afd73fa4177709f6e1b966ba691fcd72175affa902052a81d6 \ - --hash=sha256:8a730bf07feacb0863974e67b206b7c503a62199de1cece2eb0d4c233ec29c11 \ - --hash=sha256:9156b96afa38db71344522f5517077eaedf62fcd2c9148392ff93d801128809c \ - --hash=sha256:9171e8e1a1f221953e38e84ae0abffe8759002fd8968106ee379febbb5358b33 \ - --hash=sha256:978117122ca4cc59b28af5322253017f6c5fc03dbdda78c7f4b94ae984c8dd43 \ - --hash=sha256:9b1b5adc5adf596c59dca57156b71ad301d73956f5bab4039b0e34dbf50b9fa0 \ - --hash=sha256:9bcf56efdb83244cde070e82a69c0f03c47c235f0a5cb6c81d9da23af7fbaae4 \ - --hash=sha256:a8c83718346de08d68b3cb1105c5d91e5fc39885d8610fdda16613d4e3941459 \ - --hash=sha256:ae77275a28667d9c82d4522b681504642055efa0368d73108511647c6499b31c \ - --hash=sha256:b57c0954a9fdd2b05b9cec0f5a12a0bdce5bf021a5b3b09323041613972481ab \ - --hash=sha256:b812417199eeb169c25f67815cfb66fd8de7ff098bf57d065e8c1943a7ba5c8f \ - --hash=sha256:cfad553a36548262e7da0f3a7464270e13900b898800fb571a5d4b298c3f8356 \ - --hash=sha256:d3222db9df629ef3c3673124f2e05fb72bc4a320c117e953fec0d69dde82e36d \ - --hash=sha256:d714595d81efab11b42bccd119977d94b25d12d3a806851ff6bfd286a4bce960 \ - --hash=sha256:d92a3e835a5100f1d5b566fff79217eab92223ca31900dba733902a182a35ab0 \ - --hash=sha256:ddc089315d030c54f0f03fb38286e2667c05009a78d659f108a8efcfbdf2e585 \ - --hash=sha256:e3b0c4da61f39899561e08e571f54472a09fa71717d9797928af558175ae5243 \ - --hash=sha256:eaaf80957c38e9d3f796f355a80fad945e72cd745e6b64c210e635b7043b673e \ - --hash=sha256:fa6b67f8bef277c2a4aadd548d58796854e7d760964126c3209b19bccc6a74f1 \ - --hash=sha256:fc6bc65b0cf524ee042e0bc2912b9206ef242edfba7426cf95763e4af01f527a +orjson==3.9.15 \ + --hash=sha256:001f4eb0ecd8e9ebd295722d0cbedf0748680fb9998d3993abaed2f40587257a \ + --hash=sha256:05a1f57fb601c426635fcae9ddbe90dfc1ed42245eb4c75e4960440cac667262 \ + --hash=sha256:10c57bc7b946cf2efa67ac55766e41764b66d40cbd9489041e637c1304400494 \ + --hash=sha256:12365576039b1a5a47df01aadb353b68223da413e2e7f98c02403061aad34bde \ + --hash=sha256:2973474811db7b35c30248d1129c64fd2bdf40d57d84beed2a9a379a6f57d0ab \ + --hash=sha256:2b5c0f532905e60cf22a511120e3719b85d9c25d0e1c2a8abb20c4dede3b05a5 \ + --hash=sha256:2c51378d4a8255b2e7c1e5cc430644f0939539deddfa77f6fac7b56a9784160a \ + --hash=sha256:2d99e3c4c13a7b0fb3792cc04c2829c9db07838fb6973e578b85c1745e7d0ce7 \ + --hash=sha256:2f256d03957075fcb5923410058982aea85455d035607486ccb847f095442bda \ + --hash=sha256:34cbcd216e7af5270f2ffa63a963346845eb71e174ea530867b7443892d77180 \ + --hash=sha256:4228aace81781cc9d05a3ec3a6d2673a1ad0d8725b4e915f1089803e9efd2b99 \ + --hash=sha256:4feeb41882e8aa17634b589533baafdceb387e01e117b1ec65534ec724023d04 \ + --hash=sha256:57d5d8cf9c27f7ef6bc56a5925c7fbc76b61288ab674eb352c26ac780caa5b10 \ + --hash=sha256:5bb399e1b49db120653a31463b4a7b27cf2fbfe60469546baf681d1b39f4edf2 \ + --hash=sha256:62482873e0289cf7313461009bf62ac8b2e54bc6f00c6fabcde785709231a5d7 \ + --hash=sha256:67384f588f7f8daf040114337d34a5188346e3fae6c38b6a19a2fe8c663a2f9b \ + --hash=sha256:6ae4e06be04dc00618247c4ae3f7c3e561d5bc19ab6941427f6d3722a0875ef7 \ + --hash=sha256:6f7b65bfaf69493c73423ce9db66cfe9138b2f9ef62897486417a8fcb0a92bfe \ + --hash=sha256:6fc2fe4647927070df3d93f561d7e588a38865ea0040027662e3e541d592811e \ + --hash=sha256:71c6b009d431b3839d7c14c3af86788b3cfac41e969e3e1c22f8a6ea13139404 \ + --hash=sha256:7413070a3e927e4207d00bd65f42d1b780fb0d32d7b1d951f6dc6ade318e1b5a \ + --hash=sha256:76bc6356d07c1d9f4b782813094d0caf1703b729d876ab6a676f3aaa9a47e37c \ + --hash=sha256:7f6cbd8e6e446fb7e4ed5bac4661a29e43f38aeecbf60c4b900b825a353276a1 \ + --hash=sha256:8055ec598605b0077e29652ccfe9372247474375e0e3f5775c91d9434e12d6b1 \ + --hash=sha256:809d653c155e2cc4fd39ad69c08fdff7f4016c355ae4b88905219d3579e31eb7 \ + --hash=sha256:82425dd5c7bd3adfe4e94c78e27e2fa02971750c2b7ffba648b0f5d5cc016a73 \ + --hash=sha256:87f1097acb569dde17f246faa268759a71a2cb8c96dd392cd25c668b104cad2f \ + --hash=sha256:920fa5a0c5175ab14b9c78f6f820b75804fb4984423ee4c4f1e6d748f8b22bc1 \ + --hash=sha256:92255879280ef9c3c0bcb327c5a1b8ed694c290d61a6a532458264f887f052cb \ + --hash=sha256:946c3a1ef25338e78107fba746f299f926db408d34553b4754e90a7de1d44068 \ + --hash=sha256:95cae920959d772f30ab36d3b25f83bb0f3be671e986c72ce22f8fa700dae061 \ + --hash=sha256:9cf1596680ac1f01839dba32d496136bdd5d8ffb858c280fa82bbfeb173bdd40 \ + --hash=sha256:9fe41b6f72f52d3da4db524c8653e46243c8c92df826ab5ffaece2dba9cccd58 \ + --hash=sha256:b17f0f14a9c0ba55ff6279a922d1932e24b13fc218a3e968ecdbf791b3682b25 \ + --hash=sha256:b3d336ed75d17c7b1af233a6561cf421dee41d9204aa3cfcc6c9c65cd5bb69a8 \ + --hash=sha256:b66bcc5670e8a6b78f0313bcb74774c8291f6f8aeef10fe70e910b8040f3ab75 \ + --hash=sha256:b725da33e6e58e4a5d27958568484aa766e825e93aa20c26c91168be58e08cbb \ + --hash=sha256:b72758f3ffc36ca566ba98a8e7f4f373b6c17c646ff8ad9b21ad10c29186f00d \ + --hash=sha256:bcef128f970bb63ecf9a65f7beafd9b55e3aaf0efc271a4154050fc15cdb386e \ + --hash=sha256:c8e8fe01e435005d4421f183038fc70ca85d2c1e490f51fb972db92af6e047c2 \ + --hash=sha256:d61f7ce4727a9fa7680cd6f3986b0e2c732639f46a5e0156e550e35258aa313a \ + --hash=sha256:d6768a327ea1ba44c9114dba5fdda4a214bdb70129065cd0807eb5f010bfcbb5 \ + --hash=sha256:e18668f1bd39e69b7fed19fa7cd1cd110a121ec25439328b5c89934e6d30d357 \ + --hash=sha256:e88b97ef13910e5f87bcbc4dd7979a7de9ba8702b54d3204ac587e83639c0c2b \ + --hash=sha256:ea0b183a5fe6b2b45f3b854b0d19c4e932d6f5934ae1f723b07cf9560edd4ec7 \ + --hash=sha256:ede0bde16cc6e9b96633df1631fbcd66491d1063667f260a4f2386a098393790 \ + --hash=sha256:f541587f5c558abd93cb0de491ce99a9ef8d1ae29dd6ab4dbb5a13281ae04cbd \ + --hash=sha256:fbbeb3c9b2edb5fd044b2a070f127a0ac456ffd079cb82746fc84af01ef021a4 \ + --hash=sha256:fdfa97090e2d6f73dced247a2f2d8004ac6449df6568f30e7fa1a045767c69a6 \ + --hash=sha256:ff0f9913d82e1d1fadbd976424c316fbc4d9c525c81d047bbdd16bd27dd98cfc # via # -r requirements.in # envoy-base-utils @@ -1002,18 +1004,18 @@ ply==3.11 \ --hash=sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3 \ --hash=sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce # via -r requirements.in -protobuf==4.25.2 \ - --hash=sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62 \ - --hash=sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d \ - --hash=sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61 \ - --hash=sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62 \ - --hash=sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3 \ - --hash=sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9 \ - --hash=sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830 \ - --hash=sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6 \ - --hash=sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0 \ - --hash=sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020 \ - --hash=sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e +protobuf==4.25.3 \ + --hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \ + --hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \ + --hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \ + --hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \ + --hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \ + --hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \ + --hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \ + --hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \ + --hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \ + --hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \ + --hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2 # via # -r requirements.in # envoy-base-utils @@ -1061,6 +1063,7 @@ pyjwt[crypto]==2.8.0 \ # via # gidgethub # pygithub + # pyjwt pylsqpack==0.3.18 \ --hash=sha256:005ddce84bdcbf5c3cf99f764504208e1aa0a91a8331bf47108f2708f2a315e6 \ --hash=sha256:06e1bbe47514b83cd03158e5558ef8cc44f578169c1820098be9f3cc4137f16a \ @@ -1217,9 +1220,9 @@ six==1.16.0 \ # pyu2f # sphinxcontrib-httpdomain # thrift -slack-sdk==3.26.2 \ - --hash=sha256:a10e8ee69ca17d274989d0c2bbecb875f19898da3052d8d57de0898a00b1ab52 \ - --hash=sha256:bcdac5e688fa50e9357ecd00b803b6a8bad766aa614d35d8dc0636f40adc48bf +slack-sdk==3.27.1 \ + --hash=sha256:85d86b34d807c26c8bb33c1569ec0985876f06ae4a2692afba765b7a5490d28c \ + --hash=sha256:c108e509160cf1324c5c8b1f47ca52fb5e287021b8caf9f4ec78ad737ab7b1d9 # via -r requirements.in smmap==5.0.1 \ --hash=sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62 \ @@ -1604,7 +1607,7 @@ zstandard==0.22.0 \ # via envoy-base-utils # The following packages are considered to be unsafe in a requirements file: -setuptools==69.1.0 \ - --hash=sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401 \ - --hash=sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6 +setuptools==69.1.1 \ + --hash=sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56 \ + --hash=sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8 # via -r requirements.in diff --git a/tools/code_format/check_format.py b/tools/code_format/check_format.py index 368478ac2c34..bae3ce814b77 100755 --- a/tools/code_format/check_format.py +++ b/tools/code_format/check_format.py @@ -257,7 +257,7 @@ def namespace_check_excluded_paths(self): @cached_property def namespace_re(self): - return re.compile("^\s*namespace\s+%s\s*{" % self.namespace_check, re.MULTILINE) + return re.compile(r"^\s*namespace\s+%s\s*{" % self.namespace_check, re.MULTILINE) # Map a line transformation function across each line of a file, # writing the result lines as requested. diff --git a/tools/code_format/config.yaml b/tools/code_format/config.yaml index 9cd42aba6c74..7da3e054be32 100644 --- a/tools/code_format/config.yaml +++ b/tools/code_format/config.yaml @@ -129,12 +129,10 @@ paths: - source/common/protobuf/message_validator_impl.cc - source/common/quic/quic_server_transport_socket_factory.cc - source/common/secret/secret_manager_impl.cc - - source/common/grpc/async_client_manager_impl.cc - source/common/grpc/google_grpc_utils.cc - source/common/tcp_proxy/tcp_proxy.cc - source/common/config/subscription_factory_impl.cc - source/common/config/xds_resource.cc - - source/common/config/datasource.cc - source/common/runtime/runtime_impl.cc - source/common/filter/config_discovery_impl.cc - source/common/json/json_internal.cc @@ -164,11 +162,15 @@ paths: - source/common/upstream/health_discovery_service.cc - source/common/secret/sds_api.h - source/common/secret/sds_api.cc + - source/common/secret/secret_provider_impl.cc - source/common/router/router.cc - source/common/config/config_provider_impl.h - source/common/common/logger_delegates.cc - source/common/upstream/health_checker_event_logger.h - source/common/upstream/outlier_detection_impl.h + - source/common/ssl/certificate_validation_context_config_impl.cc + - source/common/grpc/google_grpc_creds_impl.cc + - source/common/local_reply/local_reply.cc # Only one C++ file should instantiate grpc_init grpc_init: diff --git a/tools/code_format/envoy_build_fixer.py b/tools/code_format/envoy_build_fixer.py index 470d25f20b6a..87fcc8909559 100755 --- a/tools/code_format/envoy_build_fixer.py +++ b/tools/code_format/envoy_build_fixer.py @@ -33,18 +33,18 @@ ENVOY_RULE_REGEX = re.compile(r'envoy[_\w]+\(') # Match a load() statement for the envoy_package macros. -PACKAGE_LOAD_BLOCK_REGEX = re.compile('("envoy_package".*?\)\n)', re.DOTALL) -EXTENSION_PACKAGE_LOAD_BLOCK_REGEX = re.compile('("envoy_extension_package".*?\)\n)', re.DOTALL) -CONTRIB_PACKAGE_LOAD_BLOCK_REGEX = re.compile('("envoy_contrib_package".*?\)\n)', re.DOTALL) -MOBILE_PACKAGE_LOAD_BLOCK_REGEX = re.compile('("envoy_mobile_package".*?\)\n)', re.DOTALL) +PACKAGE_LOAD_BLOCK_REGEX = re.compile(r'("envoy_package".*?\)\n)', re.DOTALL) +EXTENSION_PACKAGE_LOAD_BLOCK_REGEX = re.compile(r'("envoy_extension_package".*?\)\n)', re.DOTALL) +CONTRIB_PACKAGE_LOAD_BLOCK_REGEX = re.compile(r'("envoy_contrib_package".*?\)\n)', re.DOTALL) +MOBILE_PACKAGE_LOAD_BLOCK_REGEX = re.compile(r'("envoy_mobile_package".*?\)\n)', re.DOTALL) # Match Buildozer 'print' output. Example of Buildozer print output: # cc_library json_transcoder_filter_lib [json_transcoder_filter.cc] (missing) (missing) BUILDOZER_PRINT_REGEX = re.compile( - '\s*([\w_]+)\s+([\w_]+)\s+[(\[](.*?)[)\]]\s+[(\[](.*?)[)\]]\s+[(\[](.*?)[)\]]') + r'\s*([\w_]+)\s+([\w_]+)\s+[(\[](.*?)[)\]]\s+[(\[](.*?)[)\]]\s+[(\[](.*?)[)\]]') # Match API header include in Envoy source file? -API_INCLUDE_REGEX = re.compile('#include "(contrib/envoy/.*|envoy/.*)/[^/]+\.pb\.(validate\.)?h"') +API_INCLUDE_REGEX = re.compile(r'#include "(contrib/envoy/.*|envoy/.*)/[^/]+\.pb\.(validate\.)?h"') class EnvoyBuildFixerError(Exception): diff --git a/tools/code_format/header_order.py b/tools/code_format/header_order.py index bd8ec81577f2..df1c8cb77f81 100755 --- a/tools/code_format/header_order.py +++ b/tools/code_format/header_order.py @@ -65,11 +65,11 @@ def regex_filter(regex): # Filters that define the #include blocks block_filters = [ file_header_filter(), - regex_filter('<.*\.h>'), - regex_filter('<.*>'), + regex_filter(r'<.*\.h>'), + regex_filter(r'<.*>'), ] for subdir in include_dir_order: - block_filters.append(regex_filter('"' + subdir + '/.*"')) + block_filters.append(regex_filter(r'"' + subdir + r'/.*"')) blocks = [] already_included = set([]) diff --git a/tools/gen_compilation_database.py b/tools/gen_compilation_database.py index 11932552f6f5..5e7fc75d3e13 100755 --- a/tools/gen_compilation_database.py +++ b/tools/gen_compilation_database.py @@ -100,8 +100,8 @@ def modify_compile_command(target, args): # depend on Envoy targets. if not target["file"].startswith("external/") or target["file"].startswith( "external/envoy"): - # *.h file is treated as C header by default while our headers files are all C++17. - options = "-x c++ -std=c++17 -fexceptions " + options + # *.h file is treated as C header by default while our headers files are all C++20. + options = "-x c++ -std=c++20 -fexceptions " + options target["command"] = " ".join([cc, options]) return target diff --git a/tools/protojsonschema/BUILD b/tools/protojsonschema/BUILD new file mode 100644 index 000000000000..6fed0c937a6c --- /dev/null +++ b/tools/protojsonschema/BUILD @@ -0,0 +1,22 @@ +load("@rules_proto_grpc//:defs.bzl", "proto_plugin") +load(":generate.bzl", "jsonschema_compile") + +licenses(["notice"]) # Apache 2 + +proto_plugin( + name = "protoc_gen_jsonschema_proto_plugin", + output_directory = True, + tool = "@com_github_chrusty_protoc_gen_jsonschema//cmd/protoc-gen-jsonschema", +) + +[ + jsonschema_compile( + # example: "@envoy_api//envoy/config/bootstrap/v3:pkg" => "envoy_config_bootstrap_v3" + name = proto.replace("@envoy_api//", "").replace("/", "_").replace(":pkg", ""), + protos = [proto], + ) + for proto in [ + "@envoy_api//envoy/config/bootstrap/v2:pkg", + "@envoy_api//envoy/config/bootstrap/v3:pkg", + ] +] diff --git a/tools/protojsonschema/generate.bzl b/tools/protojsonschema/generate.bzl new file mode 100644 index 000000000000..915945740768 --- /dev/null +++ b/tools/protojsonschema/generate.bzl @@ -0,0 +1,22 @@ +load( + "@rules_proto_grpc//:defs.bzl", + "ProtoPluginInfo", + "proto_compile_attrs", + "proto_compile_impl", +) + +# Create compile rule +jsonschema_compile = rule( + implementation = proto_compile_impl, + attrs = dict( + proto_compile_attrs, + _plugins = attr.label_list( + providers = [ProtoPluginInfo], + default = [ + Label(":protoc_gen_jsonschema_proto_plugin"), + ], + doc = "List of protoc plugins to apply", + ), + ), + toolchains = [str(Label("@rules_proto_grpc//protobuf:toolchain_type"))], +) diff --git a/tools/protojsonschema_with_aspects/BUILD b/tools/protojsonschema_with_aspects/BUILD new file mode 100644 index 000000000000..10cdeca6dd1c --- /dev/null +++ b/tools/protojsonschema_with_aspects/BUILD @@ -0,0 +1,12 @@ +load("//tools/protojsonschema_with_aspects:protojsonschema.bzl", "protojsonschema_rule") + +licenses(["notice"]) # Apache 2 + +protojsonschema_rule( + name = "api_protojsonschema", + visibility = ["//visibility:public"], + deps = [ + "@envoy_api//envoy/config/bootstrap/v2:pkg", + "@envoy_api//envoy/config/bootstrap/v3:pkg", + ], +) diff --git a/tools/protojsonschema_with_aspects/protojsonschema.bzl b/tools/protojsonschema_with_aspects/protojsonschema.bzl new file mode 100644 index 000000000000..a1a5e38742ce --- /dev/null +++ b/tools/protojsonschema_with_aspects/protojsonschema.bzl @@ -0,0 +1,39 @@ +load("@rules_proto//proto:defs.bzl", "ProtoInfo") +load("//tools/api_proto_plugin:plugin.bzl", "api_proto_plugin_aspect", "api_proto_plugin_impl") + +def _protojsonschema_impl(target, ctx): + return api_proto_plugin_impl( + target = target, + ctx = ctx, + output_group = "proto", + mnemonic = "protojsonschema", + output_suffixes = [], + output_dir = "jsonschema", + ) + +protojsonschema_aspect = api_proto_plugin_aspect( + "@com_github_chrusty_protoc_gen_jsonschema//cmd/protoc-gen-jsonschema", + _protojsonschema_impl, +) + +def _protojsonschema_rule_impl(ctx): + return [ + DefaultInfo( + files = depset( + transitive = [ + depset([ + path + for dep in ctx.attr.deps + for path in dep[OutputGroupInfo].proto.to_list() + ]), + ], + ), + ), + ] + +protojsonschema_rule = rule( + implementation = _protojsonschema_rule_impl, + attrs = { + "deps": attr.label_list(aspects = [protojsonschema_aspect]), + }, +) diff --git a/tools/repo/notify.py b/tools/repo/notify.py index d5a45ec2a37a..18a139f7e0c0 100644 --- a/tools/repo/notify.py +++ b/tools/repo/notify.py @@ -261,10 +261,11 @@ async def post_to_oncall(self): await self.send_message( channel='#envoy-maintainer-oncall', text=(f"*Stalled PRs* (PRs with review out-SLO, please address)\n{stalled}")) + num_issues = await self.track_open_issues() await self.send_message( channel='#envoy-maintainer-oncall', text=( - f"*Untriaged Issues* (please tag and cc area experts)\n<{ISSUE_LINK}|{ISSUE_LINK}>" + f"*{num_issues} Untriaged Issues* (please tag and cc area experts)\n<{ISSUE_LINK}|{ISSUE_LINK}>" )) except SlackApiError as e: self.log.error(f"Unexpected error {e.response['error']}") @@ -278,6 +279,11 @@ def pr_message(self, age, pull): f"<{pull['html_url']}|{html.escape(pull['title'])}> has been waiting " f"{markup}{days} days {hours} hours{markup}") + async def track_open_issues(self): + response = await self.session.get( + "https://api.github.com/repos/envoyproxy/envoy/issues?labels=triage") + return len(await response.json()) + async def run(self): if not self.github_token: self.log.error("Missing GITHUB_TOKEN: please check github workflow configuration") diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index c0016586ceeb..7f66087cef02 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -769,6 +769,8 @@ fixdate fixup flatbuffer flatc +fluentd +Fluentd fmt fmtlib fn @@ -965,6 +967,7 @@ moveable msec msg msghdr +msgpack multi multicast multikill @@ -1321,6 +1324,7 @@ suf superclass superroot superset +supportability svc symlink symlinked