From 47d445d680b6a6a2670b70dde74e9868caa35da5 Mon Sep 17 00:00:00 2001 From: Ashesh Vidyut <134911583+absolutelightning@users.noreply.github.com> Date: Fri, 21 Jul 2023 20:26:00 +0530 Subject: [PATCH] Envoy Integration Test Windows (#18007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [CONSUL-395] Update check_hostport and Usage (#40) * [CONSUL-397] Copy envoy binary from Image (#41) * [CONSUL-382] Support openssl in unique test dockerfile (#43) * [CONSUL-405] Add bats to single container (#44) * [CONSUL-414] Run Prometheus Test Cases and Validate Changes (#46) * [CONSUL-410] Run Jaeger in Single container (#45) * [CONSUL-412] Run test-sds-server in single container (#48) * [CONSUL-408] Clean containers (#47) * [CONSUL-384] Rebase and sync fork (#50) * [CONSUL-415] Create Scenarios Troubleshooting Docs (#49) * [CONSUL-417] Update Docs Single Container (#51) * [CONSUL-428] Add Socat to single container (#54) * [CONSUL-424] Replace pkill in kill_envoy function (#52) * [CONSUL-434] Modify Docker run functions in Helper script (#53) * [CONSUL-435] Replace docker run in set_ttl_check_state & wait_for_agent_service_register functions (#55) * [CONSUL-438] Add netcat (nc) in the Single container Dockerfile (#56) * [CONSUL-429] Replace Docker run with Docker exec (#57) * [CONSUL-436] Curl timeout and run tests (#58) * [CONSUL-443] Create dogstatsd Function (#59) * [CONSUL-431] Update Docs Netcat (#60) * [CONSUL-439] Parse nc Command in function (#61) * [CONSUL-463] Review curl Exec and get_ca_root Func (#63) * [CONSUL-453] Docker hostname in Helper functions (#64) * [CONSUL-461] Test wipe volumes without extra cont (#66) * [CONSUL-454] Check ports in the Server and Agent containers (#65) * [CONSUL-441] Update windows dockerfile with version (#62) * [CONSUL-466] Review case-grpc Failing Test (#67) * [CONSUL-494] Review case-cfg-resolver-svc-failover (#68) * [CONSUL-496] Replace docker_wget & docker_curl (#69) * [CONSUL-499] Cleanup Scripts - Remove nanoserver (#70) * [CONSUL-500] Update Troubleshooting Docs (#72) * [CONSUL-502] Pull & Tag Envoy Windows Image (#73) * [CONSUL-504] Replace docker run in docker_consul (#76) * [CONSUL-505] Change admin_bind * [CONSUL-399] Update envoy to 1.23.1 (#78) * [CONSUL-510] Support case-wanfed-gw on Windows (#79) * [CONSUL-506] Update troubleshooting Documentation (#80) * [CONSUL-512] Review debug_dump_volumes Function (#81) * [CONSUL-514] Add zipkin to Docker Image (#82) * [CONSUL-515] Update Documentation (#83) * [CONSUL-529] Support case-consul-exec (#86) * [CONSUL-530] Update Documentation (#87) * [CONSUL-530] Update default consul version 1.13.3 * [CONSUL-539] Cleanup (#91) * [CONSUL-546] Scripts Clean-up (#92) * [CONSUL-491] Support admin_access_log_path value for Windows (#71) * [CONSUL-519] Implement mkfifo Alternative (#84) * [CONSUL-542] Create OS Specific Files for Envoy Package (#88) * [CONSUL-543] Create exec_supported.go (#89) * [CONSUL-544] Test and Build Changes (#90) * Implement os.DevNull * using mmap instead of disk files * fix import in exec-unix * fix nmap open too many arguemtn * go fmt on file * changelog file * fix go mod * Update .changelog/17694.txt Co-authored-by: Dhia Ayachi * different mmap library * fix bootstrap json * some fixes * chocolatey version fix and image fix * using different library * fix Map funciton call * fix mmap call * fix tcp dump * fix tcp dump * windows tcp dump * Fix docker run * fix tests * fix go mod * fix version 16.0 * fix version * fix version dev * sleep to debug * fix sleep * fix permission issue * fix permission issue * fix permission issue * fix command * fix command * fix funciton * fix assert config entry status command not found * fix command not found assert_cert_has_cn * fix command not found assert_upstream_missing * fix command not found assert_upstream_missing_once * fix command not found get_upstream_endpoint * fix command not found get_envoy_public_listener_once * fix command not found * fix test cases * windows integration test workflow github * made code similar to unix using npipe * fix go.mod * fix dialing of npipe * dont wait * check size of written json * fix undefined n * running * fix dep * fix syntax error * fix workflow file * windows runner * fix runner * fix from json * fix runs on * merge connect envoy * fix cin path * build * fix file name * fix file name * fix dev build * remove unwanted code * fix upload * fix bin name * fix path * checkout current branch * fix path * fix tests * fix shell bash for windows sh files * fix permission of run-test.sh * removed docker dev * added shell bash for tests * fix tag * fix win=true * fix cd * added dev * fix variable undefined * removed failing tests * fix tcp dump image * fix curl * fix curl * tcp dump path * fix tcpdump path * fix curl * fix curl install * stop removing intermediate containers * fix tcpdump docker image * revert -rm * --rm=false * makeing docker image before * fix tcpdump * removed case consul exec * removed terminating gateway simple * comment case wasm * removed data dog * comment out upload coverage * uncomment case-consul-exec * comment case consul exec * if always * logs * using consul 1.17.0 * fix quotes * revert quotes * redirect to dev null * Revert version * revert consul connect * fix version * removed envoy connect * not using function * change log * docker logs * fix logs * restructure bad authz * rmeoved dev null * output * fix file descriptor * fix cacert * fix cacert * fix ca cert * cacert does not work in windows curl * fix func * removed docker logs * added sleep * fix tls * commented case-consul-exec * removed echo * retry docker consul * fix upload bin * uncomment consul exec * copying consul.exe to docker image * copy fix * fix paths * fix path * github workspace path * latest version * Revert "latest version" This reverts commit 5a7d7b82d9e7553bcb01b02557ec8969f9deba1d. * commented consul exec * added ssl revoke best effort * revert best effort * removed unused files * rename var name and change dir * windows runner * permission * needs setup fix * swtich to github runner * fix file path * fix path * fix path * fix path * fix path * fix path * fix build paths * fix tag * nightly runs * added matrix in github workflow, renamed files * fix job * fix matrix * removed brackes * from json * without using job matrix * fix quotes * revert job matrix * fix workflow * fix comment * added comment * nightly runs * removed datadog ci as it is already measured in linux one * running test * Revert "running test" This reverts commit 7013d15a23732179d18ec5d17336e16b26fab5d4. * pr comment fixes * running test now * running subset of test * running subset of test * job matrix * shell bash * removed bash shell * linux machine for job matrix * fix output * added cat to debug * using ubuntu latest * fix job matrix * fix win true * fix go test * revert job matrix --------- Co-authored-by: Jose Ignacio Lorenzo <74208929+joselo85@users.noreply.github.com> Co-authored-by: Franco Bruno Lavayen Co-authored-by: Ivan K Berlot Co-authored-by: Ezequiel Fernández Ponce <20102608+ezfepo@users.noreply.github.com> Co-authored-by: joselo85 Co-authored-by: Ezequiel Fernández Ponce Co-authored-by: Dhia Ayachi --- .changelog/18007.txt | 3 + .github/scripts/get_runner_classes_windows.sh | 26 + .../workflows/reusable-dev-build-windows.yml | 47 + .../workflows/test-integrations-windows.yml | 1210 +++++++++++++++++ .release/docker/docker-entrypoint-windows.sh | 82 ++ Dockerfile-windows | 51 + .../windows/Dockerfile-consul-dev-windows | 4 + .../windows/Dockerfile-consul-local-windows | 52 + .../windows/Dockerfile-openzipkin-windows | 12 + .../windows/build-consul-dev-image.sh | 14 + .../windows/build-consul-local-images.sh | 92 ++ .../windows/build-test-sds-server-image.sh | 5 + build-support/windows/windows-test.md | 119 ++ .../envoy/Dockerfile-consul-envoy-windows | 12 + .../connect/envoy/Dockerfile-tcpdump-windows | 7 + .../envoy/Dockerfile-test-sds-server-windows | 8 + .../integration/connect/envoy/WINDOWS-TEST.md | 40 + .../envoy/case-dogstatsd-udp/verify.bats | 9 +- .../case-gateways-local/secondary/setup.sh | 2 +- .../connect/envoy/case-grpc/service_s1.hcl | 2 +- .../connect/envoy/case-grpc/verify.bats | 2 +- .../connect/envoy/case-http-badauthz/setup.sh | 4 +- .../case-ingress-gateway-tls/verify.bats | 10 +- .../case-wanfed-gw/global-setup-windows.sh | 44 + .../connect/envoy/case-zipkin/verify.bats | 7 +- .../connect/envoy/docker-windows.md | 42 + .../connect/envoy/docs/img/linux-arch.png | Bin 0 -> 63964 bytes .../docs/img/windows-arch-singlecontainer.png | Bin 0 -> 114040 bytes .../envoy/docs/img/windows-linux-arch.png | Bin 0 -> 61475 bytes .../docs/windows-testing-architecture.md | 106 ++ .../connect/envoy/helpers.windows.bash | 1192 ++++++++++++++++ test/integration/connect/envoy/main_test.go | 100 +- .../connect/envoy/run-tests.windows.sh | 908 +++++++++++++ .../connect/envoy/windows-troubleshooting.md | 90 ++ 34 files changed, 4283 insertions(+), 19 deletions(-) create mode 100644 .changelog/18007.txt create mode 100755 .github/scripts/get_runner_classes_windows.sh create mode 100644 .github/workflows/reusable-dev-build-windows.yml create mode 100644 .github/workflows/test-integrations-windows.yml create mode 100644 .release/docker/docker-entrypoint-windows.sh create mode 100644 Dockerfile-windows create mode 100644 build-support/windows/Dockerfile-consul-dev-windows create mode 100644 build-support/windows/Dockerfile-consul-local-windows create mode 100644 build-support/windows/Dockerfile-openzipkin-windows create mode 100644 build-support/windows/build-consul-dev-image.sh create mode 100644 build-support/windows/build-consul-local-images.sh create mode 100644 build-support/windows/build-test-sds-server-image.sh create mode 100644 build-support/windows/windows-test.md create mode 100644 test/integration/connect/envoy/Dockerfile-consul-envoy-windows create mode 100644 test/integration/connect/envoy/Dockerfile-tcpdump-windows create mode 100644 test/integration/connect/envoy/Dockerfile-test-sds-server-windows create mode 100644 test/integration/connect/envoy/WINDOWS-TEST.md create mode 100644 test/integration/connect/envoy/case-wanfed-gw/global-setup-windows.sh create mode 100644 test/integration/connect/envoy/docker-windows.md create mode 100644 test/integration/connect/envoy/docs/img/linux-arch.png create mode 100644 test/integration/connect/envoy/docs/img/windows-arch-singlecontainer.png create mode 100644 test/integration/connect/envoy/docs/img/windows-linux-arch.png create mode 100644 test/integration/connect/envoy/docs/windows-testing-architecture.md create mode 100644 test/integration/connect/envoy/helpers.windows.bash create mode 100644 test/integration/connect/envoy/run-tests.windows.sh create mode 100644 test/integration/connect/envoy/windows-troubleshooting.md diff --git a/.changelog/18007.txt b/.changelog/18007.txt new file mode 100644 index 0000000000..b963d2f77f --- /dev/null +++ b/.changelog/18007.txt @@ -0,0 +1,3 @@ +```release-note:improvement +Windows: Integration tests for Consul Windows VMs +``` diff --git a/.github/scripts/get_runner_classes_windows.sh b/.github/scripts/get_runner_classes_windows.sh new file mode 100755 index 0000000000..c2e424d170 --- /dev/null +++ b/.github/scripts/get_runner_classes_windows.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# +# This script generates tag-sets that can be used as runs-on: values to select runners. + +set -euo pipefail + +case "$GITHUB_REPOSITORY" in + *-enterprise) + # shellcheck disable=SC2129 + echo "compute-small=['self-hosted', 'windows', 'small']" >> "$GITHUB_OUTPUT" + echo "compute-medium=['self-hosted', 'windows', 'medium']" >> "$GITHUB_OUTPUT" + echo "compute-large=['self-hosted', 'windows', 'large']" >> "$GITHUB_OUTPUT" + # m5d.8xlarge is equivalent to our xl custom runner in OSS + echo "compute-xl=['self-hosted', 'ondemand', 'windows', 'type=m5d.8xlarge']" >> "$GITHUB_OUTPUT" + ;; + *) + # shellcheck disable=SC2129 + echo "compute-small=['windows-2019']" >> "$GITHUB_OUTPUT" + echo "compute-medium=['windows-2019']" >> "$GITHUB_OUTPUT" + echo "compute-large=['windows-2019']" >> "$GITHUB_OUTPUT" + echo "compute-xl=['windows-2019']" >> "$GITHUB_OUTPUT" + ;; +esac diff --git a/.github/workflows/reusable-dev-build-windows.yml b/.github/workflows/reusable-dev-build-windows.yml new file mode 100644 index 0000000000..446fbb7136 --- /dev/null +++ b/.github/workflows/reusable-dev-build-windows.yml @@ -0,0 +1,47 @@ +name: reusable-dev-build-windows + +on: + workflow_call: + inputs: + uploaded-binary-name: + required: false + type: string + default: "consul.exe" + runs-on: + description: An expression indicating which kind of runners to use. + required: true + type: string + repository-name: + required: true + type: string + go-arch: + required: false + type: string + default: "" + secrets: + elevated-github-token: + required: true +jobs: + build: + runs-on: 'windows-2019' + steps: + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + # NOTE: This step is specifically needed for ENT. It allows us to access the required private HashiCorp repos. + - name: Setup Git + if: ${{ endsWith(inputs.repository-name, '-enterprise') }} + run: git config --global url."https://${{ secrets.elevated-github-token }}:@github.com".insteadOf "https://github.com" + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + with: + go-version-file: 'go.mod' + - name: Build + env: + GOARCH: ${{ inputs.goarch }} + run: go build . + # save dev build to pass to downstream jobs + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: ${{inputs.uploaded-binary-name}} + path: consul.exe + - name: Notify Slack + if: ${{ failure() }} + run: .github/scripts/notify_slack.sh diff --git a/.github/workflows/test-integrations-windows.yml b/.github/workflows/test-integrations-windows.yml new file mode 100644 index 0000000000..d71892c784 --- /dev/null +++ b/.github/workflows/test-integrations-windows.yml @@ -0,0 +1,1210 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: test-integrations-windows + +on: + schedule: + # * is a special character in YAML so you have to quote this string + # Run nightly at 12AM UTC/8PM EST/5PM PST. + - cron: '0 0 * * *' + +env: + TEST_RESULTS_DIR: /tmp/test-results + TEST_RESULTS_ARTIFACT_NAME: test-results + CONSUL_LICENSE: ${{ secrets.CONSUL_LICENSE }} + GOTAGS: ${{ endsWith(github.repository, '-enterprise') && 'consulent' || '' }} + GOTESTSUM_VERSION: "1.9.0" + CONSUL_BINARY_UPLOAD_NAME: consul.exe + # strip the hashicorp/ off the front of github.repository for consul + CONSUL_LATEST_IMAGE_NAME: ${{ endsWith(github.repository, '-enterprise') && github.repository || 'consul' }} + GOPRIVATE: github.com/hashicorp # Required for enterprise deps + +jobs: + setup: + runs-on: ubuntu-latest + name: Setup + outputs: + compute-small: ${{ steps.runners.outputs.compute-small }} + compute-medium: ${{ steps.runners.outputs.compute-medium }} + compute-large: ${{ steps.runners.outputs.compute-large }} + compute-xl: ${{ steps.runners.outputs.compute-xl }} + enterprise: ${{ steps.runners.outputs.enterprise }} + steps: + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - id: runners + run: .github/scripts/get_runner_classes_windows.sh + + dev-build: + uses: ./.github/workflows/reusable-dev-build-windows.yml + with: + runs-on: ${{ needs.setup.outputs.compute-xl }} + repository-name: ${{ github.repository }} + uploaded-binary-name: 'consul.exe' + secrets: + elevated-github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} + + # NOTE: Jobs needs to be added here manually. Jobs when run together on windows fails intermittently. + # So they are run independently of each other. + envoy-integration-test: + needs: + - setup + - dev-build + runs-on: ${{ fromJSON(needs.setup.outputs.compute-large) }} + permissions: + id-token: write # NOTE: this permission is explicitly required for Vault auth. + contents: read + strategy: + fail-fast: false + matrix: + envoy-version: [ "1.23.10", "1.24.8", "1.25.7", "1.26.2" ] + xds-target: [ "server", "client" ] + env: + ENVOY_VERSION: ${{ matrix.envoy-version }} + XDS_TARGET: ${{ matrix.xds-target }} + AWS_LAMBDA_REGION: us-west-2 + steps: + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + with: + go-version-file: 'go.mod' + + - name: Fetch binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: '${{ env.CONSUL_BINARY_UPLOAD_NAME }}' + path: ${{ github.workspace }} + + - name: Restore mode+x + run: chmod +x ${{ github.workspace }}\consul.exe + + - name: Setup TcpDump Docker Image + shell: bash + run: | + cd test/integration/connect/envoy + curl -sSL "https://asheshvidyut-bucket.s3.ap-southeast-2.amazonaws.com/tcpdump.exe" -o tcpdump.exe + docker build -t envoy-tcpdump -f Dockerfile-tcpdump-windows . + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 + + - name: Docker build consul + run: docker build -t windows/consul -f Dockerfile-windows . + + - name: Docker build consul local + shell: bash + run: cd build-support/windows && ./build-consul-local-images.sh + + - name: Docker build consul dev + shell: bash + run: cd build-support/windows && ./build-consul-dev-image.sh + + # https://hashicorp.atlassian.net/browse/NET-4973 + # ^ Ticket to figure out why grouping test case is failing on Windows Machine + + - name: Envoy Integration Tests for windows case-api-gateway-http-hostnames + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-api-gateway-http-hostnames" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-api-gateway-http-hostnames" -win=true + + - name: Envoy Integration Tests for windows case-api-gateway-http-simple + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-api-gateway-http-simple" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-api-gateway-http-simple" -win=true + + - name: Envoy Integration Tests for windows case-api-gateway-http-splitter-targets + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-api-gateway-http-splitter-targets" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-api-gateway-http-splitter-targets" -win=true + + - name: Envoy Integration Tests for windows case-api-gateway-http-tls-overlapping-hosts + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-api-gateway-http-tls-overlapping-hosts" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-api-gateway-http-tls-overlapping-hosts" -win=true + + - name: Envoy Integration Tests for windows case-api-gateway-tcp-conflicted + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-api-gateway-tcp-conflicted" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-api-gateway-tcp-conflicted" -win=true + + - name: Envoy Integration Tests for windows case-api-gateway-tcp-simple + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-api-gateway-tcp-simple" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-api-gateway-tcp-simple" -win=true + + - name: Envoy Integration Tests for windows case-api-gateway-tcp-tls-overlapping-hosts + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-api-gateway-tcp-tls-overlapping-hosts" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-api-gateway-tcp-tls-overlapping-hosts" -win=true + + - name: Envoy Integration Tests for windows case-badauthz + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-badauthz" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-badauthz" -win=true + + - name: Envoy Integration Tests for windows case-basic + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-basic" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-basic" -win=true + + - name: Envoy Integration Tests for windows case-centralconf + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-centralconf" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-centralconf" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-cluster-peering-failover + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-cluster-peering-failover" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-cluster-peering-failover" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-dc-failover-gateways-none + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-dc-failover-gateways-none" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-dc-failover-gateways-none" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-dc-failover-gateways-remote + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-dc-failover-gateways-remote" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-dc-failover-gateways-remote" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-defaultsubset + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-defaultsubset" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-defaultsubset" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-features + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-features" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-features" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-subset-onlypassing + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-subset-onlypassing" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-subset-onlypassing" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-subset-redirect + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-subset-redirect" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-subset-redirect" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-svc-failover + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-svc-failover" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-svc-failover" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-svc-redirect-http + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-svc-redirect-http" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-svc-redirect-http" -win=true + + - name: Envoy Integration Tests for windows case-cfg-resolver-svc-redirect-tcp + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-resolver-svc-redirect-tcp" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-resolver-svc-redirect-tcp" -win=true + + - name: Envoy Integration Tests for windows case-cfg-router-features + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-router-features" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-router-features" -win=true + + - name: Envoy Integration Tests for windows case-cfg-splitter-cluster-peering + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-splitter-cluster-peering" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-splitter-cluster-peering" -win=true + + - name: Envoy Integration Tests for windows case-cfg-splitter-features + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-splitter-features" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-splitter-features" -win=true + + - name: Envoy Integration Tests for windows case-cfg-splitter-peering-ingress-gateways + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cfg-splitter-peering-ingress-gateways" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cfg-splitter-peering-ingress-gateways" -win=true + + # This test runs fine on windows machine but fails on CI + # Task to be picked later on - https://hashicorp.atlassian.net/browse/NET-4972 + # - name: Envoy Integration Tests for windows case-consul-exec + # if: always() + # shell: bash + # env: + # GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + # GOTESTSUM_FORMAT: standard-verbose + # COMPOSE_INTERACTIVE_NO_CLI: 1 + # LAMBDA_TESTS_ENABLED: "true" + # # tput complains if this isn't set to something. + # TERM: ansi + # run: | + # #shellcheck disable=SC2001 + # echo "Running Integration Test case-consul-exec" + # # shellcheck disable=SC2001 + # go test -v -timeout=30m -tags integration \ + # ./test/integration/connect/envoy -run="TestEnvoy/case-consul-exec" -win=true + + - name: Envoy Integration Tests for windows case-cross-peer-control-plane-mgw + if: always() + shell: bash + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cross-peer-control-plane-mgw" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cross-peer-control-plane-mgw" -win=true + + - name: Envoy Integration Tests for windows case-cross-peers + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cross-peers" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cross-peers" -win=true + + - name: Envoy Integration Tests for windows case-cross-peers-http + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cross-peers-http" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cross-peers-http" -win=true + + - name: Envoy Integration Tests for windows case-cross-peers-http-router + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cross-peers-http-router" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cross-peers-http-router" -win=true + + - name: Envoy Integration Tests for windows case-cross-peers-resolver-redirect-tcp + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-cross-peers-resolver-redirect-tcp" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-cross-peers-resolver-redirect-tcp" -win=true + + - name: Envoy Integration Tests for windows case-dogstatsd-udp + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-dogstatsd-udp" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-dogstatsd-udp" -win=true + + - name: Envoy Integration Tests for windows case-envoyext-ratelimit + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-envoyext-ratelimit" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-envoyext-ratelimit" -win=true + + - name: Envoy Integration Tests for windows case-expose-checks + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-expose-checks" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-expose-checks" -win=true + + - name: Envoy Integration Tests for windows case-gateway-without-services + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-gateway-without-services" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-gateway-without-services" -win=true + + - name: Envoy Integration Tests for windows case-gateways-local + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-gateways-local" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-gateways-local" -win=true + + - name: Envoy Integration Tests for windows case-gateways-remote + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-gateways-remote" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-gateways-remote" -win=true + + - name: Envoy Integration Tests for windows case-grpc + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-grpc" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-grpc" -win=true + + - name: Envoy Integration Tests for windows case-http + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-http" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-http" -win=true + + - name: Envoy Integration Tests for windows case-http-badauthz + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-http-badauthz" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-http-badauthz" -win=true + + - name: Envoy Integration Tests for windows case-ingress-gateway-grpc + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-ingress-gateway-grpc" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-gateway-grpc" -win=true + + - name: Envoy Integration Tests for windows case-ingress-gateway-http + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-ingress-gateway-http" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-gateway-http" -win=true + + - name: Envoy Integration Tests for windows case-ingress-gateway-multiple-services + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-ingress-gateway-multiple-services" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-gateway-multiple-services" -win=true + + - name: Envoy Integration Tests for windows case-ingress-gateway-peering-failover + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-ingress-gateway-peering-failover" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-gateway-peering-failover" -win=true + + - name: Envoy Integration Tests for windows case-ingress-gateway-simple + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-ingress-gateway-simple" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-gateway-simple" -win=true + + - name: Envoy Integration Tests for windows case-ingress-mesh-gateways-resolver + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-ingress-mesh-gateways-resolver" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-mesh-gateways-resolver" -win=true + + - name: Envoy Integration Tests for windows case-l7-intentions + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-l7-intentions" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-l7-intentions" -win=true + + - name: Envoy Integration Tests for windows case-multidc-rsa-ca + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-multidc-rsa-ca" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-multidc-rsa-ca" -win=true + + - name: Envoy Integration Tests for windows case-prometheus + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-prometheus" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-prometheus" -win=true + + - name: Envoy Integration Tests for windows case-property-override + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-property-override" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-property-override" -win=true + + - name: Envoy Integration Tests for windows case-stats-proxy + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-stats-proxy" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-stats-proxy" -win=true + + - name: Envoy Integration Tests for windows case-statsd-udp + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-statsd-udp" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-statsd-udp" -win=true + + - name: Envoy Integration Tests for windows case-terminating-gateway-hostnames + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-terminating-gateway-hostnames" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-terminating-gateway-hostnames" -win=true + + - name: Envoy Integration Tests for windows case-terminating-gateway-simple + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-terminating-gateway-simple" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-terminating-gateway-simple" -win=true + + - name: Envoy Integration Tests for windows case-terminating-gateway-without-services + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-terminating-gateway-without-services" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-terminating-gateway-without-services" -win=true + + - name: Envoy Integration Tests for windows case-upstream-config + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-upstream-config" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-upstream-config" -win=true + + - name: Envoy Integration Tests for windows case-wanfed-gw + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-wanfed-gw" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-wanfed-gw" -win=true + + - name: Envoy Integration Tests for windows case-ingress-gateway-sds + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-ingress-gateway-sds" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-gateway-sds" -win=true + + - name: Envoy Integration Tests for windows case-lua + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-lua" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-lua" -win=true + + - name: Envoy Integration Tests for windows case-terminating-gateway-subsets + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-terminating-gateway-subsets" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-terminating-gateway-subsets" -win=true + + # Skipping this because - https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/wasm_filter + # - name: Envoy Integration Tests for windows case-wasm + # shell: bash + # env: + # GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + # GOTESTSUM_FORMAT: standard-verbose + # COMPOSE_INTERACTIVE_NO_CLI: 1 + # LAMBDA_TESTS_ENABLED: "true" + # # tput complains if this isn't set to something. + # TERM: ansi + # run: | + # # shellcheck disable=SC2001 + # echo "Running Integration Test case-wasm" + # # shellcheck disable=SC2001 + # go test -v -timeout=30m -tags integration \ + # ./test/integration/connect/envoy -run="TestEnvoy/case-wasm" -win=true + + # Skipping because of - cacert is not available in curl windows + # https://www.phillipsj.net/posts/windows-curl-and-self-signed-certs/ + # - name: Envoy Integration Tests for windows case-ingress-gateway-tls + # shell: bash + # if: always() + # env: + # GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + # GOTESTSUM_FORMAT: standard-verbose + # COMPOSE_INTERACTIVE_NO_CLI: 1 + # LAMBDA_TESTS_ENABLED: "true" + # # tput complains if this isn't set to something. + # TERM: ansi + # run: | + # # shellcheck disable=SC2001 + # echo "Running Integration Test case-ingress-gateway-tls" + # # shellcheck disable=SC2001 + # go test -v -timeout=30m -tags integration \ + # ./test/integration/connect/envoy -run="TestEnvoy/case-ingress-gateway-tls" -win=true + + - name: Envoy Integration Tests for windows case-mesh-to-lambda + shell: bash + if: always() + env: + GOTESTSUM_JUNITFILE: ${{ env.TEST_RESULTS_DIR }}/results.xml + GOTESTSUM_FORMAT: standard-verbose + COMPOSE_INTERACTIVE_NO_CLI: 1 + LAMBDA_TESTS_ENABLED: "true" + # tput complains if this isn't set to something. + TERM: ansi + run: | + # shellcheck disable=SC2001 + echo "Running Integration Test case-mesh-to-lambda" + # shellcheck disable=SC2001 + go test -v -timeout=30m -tags integration \ + ./test/integration/connect/envoy -run="TestEnvoy/case-mesh-to-lambda" -win=true + + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Authenticate to Vault + if: ${{ endsWith(github.repository, '-enterprise') }} + id: vault-auth + run: vault-auth + + # NOTE: ENT specific step as we store secrets in Vault. + - name: Fetch Secrets + if: ${{ endsWith(github.repository, '-enterprise') }} + id: secrets + uses: hashicorp/vault-action@v2.5.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/datadog apikey | DATADOG_API_KEY; + + - name: Prepare datadog-ci + shell: bash + if: ${{ !endsWith(github.repository, '-enterprise') }} + run: | + curl -L --fail "https://github.com/DataDog/datadog-ci/releases/download/v2.17.2/datadog-ci_win-x64.exe" --output "C:/datadog-ci" + chmod +x C:/datadog-ci + + - name: Upload coverage + # do not run on forks + if: github.event.pull_request.head.repo.full_name == github.repository + env: + DATADOG_API_KEY: "${{ endsWith(github.repository, '-enterprise') && env.DATADOG_API_KEY || secrets.DATADOG_API_KEY }}" + DD_ENV: ci + run: C:/datadog-ci junit upload --service "$GITHUB_REPOSITORY" $TEST_RESULTS_DIR/results.xml + + test-integrations-success: + needs: + - envoy-integration-test + - upgrade-integration-test + runs-on: 'ubuntu-latest' + if: ${{ always() }} + steps: + - name: evaluate upstream job results + run: | + # exit 1 if failure or cancelled result for any upstream job + if printf '${{ toJSON(needs) }}' | grep -E -i '\"result\": \"(failure|cancelled)\"'; then + printf "Tests failed or workflow cancelled:\n\n${{ toJSON(needs) }}" + exit 1 + fi \ No newline at end of file diff --git a/.release/docker/docker-entrypoint-windows.sh b/.release/docker/docker-entrypoint-windows.sh new file mode 100644 index 0000000000..776b8113ce --- /dev/null +++ b/.release/docker/docker-entrypoint-windows.sh @@ -0,0 +1,82 @@ +#!/usr/bin/dumb-init /bin/sh +set -e + +# Note above that we run dumb-init as PID 1 in order to reap zombie processes +# as well as forward signals to all processes in its session. Normally, sh +# wouldn't do either of these functions so we'd leak zombies as well as do +# unclean termination of all our sub-processes. +# As of docker 1.13, using docker run --init achieves the same outcome. + +# You can set CONSUL_BIND_INTERFACE to the name of the interface you'd like to +# bind to and this will look up the IP and pass the proper -bind= option along +# to Consul. +CONSUL_BIND= +if [ -n "$CONSUL_BIND_INTERFACE" ]; then + CONSUL_BIND_ADDRESS=$(ip -o -4 addr list $CONSUL_BIND_INTERFACE | head -n1 | awk '{print $4}' | cut -d/ -f1) + if [ -z "$CONSUL_BIND_ADDRESS" ]; then + echo "Could not find IP for interface '$CONSUL_BIND_INTERFACE', exiting" + exit 1 + fi + + CONSUL_BIND="-bind=$CONSUL_BIND_ADDRESS" + echo "==> Found address '$CONSUL_BIND_ADDRESS' for interface '$CONSUL_BIND_INTERFACE', setting bind option..." +fi + +# You can set CONSUL_CLIENT_INTERFACE to the name of the interface you'd like to +# bind client intefaces (HTTP, DNS, and RPC) to and this will look up the IP and +# pass the proper -client= option along to Consul. +CONSUL_CLIENT= +if [ -n "$CONSUL_CLIENT_INTERFACE" ]; then + CONSUL_CLIENT_ADDRESS=$(ip -o -4 addr list $CONSUL_CLIENT_INTERFACE | head -n1 | awk '{print $4}' | cut -d/ -f1) + if [ -z "$CONSUL_CLIENT_ADDRESS" ]; then + echo "Could not find IP for interface '$CONSUL_CLIENT_INTERFACE', exiting" + exit 1 + fi + + CONSUL_CLIENT="-client=$CONSUL_CLIENT_ADDRESS" + echo "==> Found address '$CONSUL_CLIENT_ADDRESS' for interface '$CONSUL_CLIENT_INTERFACE', setting client option..." +fi + +# CONSUL_DATA_DIR is exposed as a volume for possible persistent storage. The +# CONSUL_CONFIG_DIR isn't exposed as a volume but you can compose additional +# config files in there if you use this image as a base, or use CONSUL_LOCAL_CONFIG +# below. +CONSUL_DATA_DIR=C:\\consul\\data +CONSUL_CONFIG_DIR=C:\\consul\\config + +# You can also set the CONSUL_LOCAL_CONFIG environemnt variable to pass some +# Consul configuration JSON without having to bind any volumes. +if [ -n "$CONSUL_LOCAL_CONFIG" ]; then + echo "$CONSUL_LOCAL_CONFIG" > "$CONSUL_CONFIG_DIR/local.json" +fi + +# If the user is trying to run Consul directly with some arguments, then +# pass them to Consul. +if [ "${1:0:1}" = '-' ]; then + set -- consul "$@" +fi + +# Look for Consul subcommands. +if [ "$1" = 'agent' ]; then + shift + set -- consul agent \ + -data-dir="$CONSUL_DATA_DIR" \ + -config-dir="$CONSUL_CONFIG_DIR" \ + $CONSUL_BIND \ + $CONSUL_CLIENT \ + "$@" +elif [ "$1" = 'version' ]; then + # This needs a special case because there's no help output. + set -- consul "$@" +elif consul --help "$1" 2>&1 | grep -q "consul $1"; then + # We can't use the return code to check for the existence of a subcommand, so + # we have to use grep to look for a pattern in the help output. + set -- consul "$@" +fi + +# NOTE: Unlike in the regular Consul Docker image, we don't have code here +# for changing data-dir directory ownership or using su-exec because OpenShift +# won't run this container as root and so we can't change data dir ownership, +# and there's no need to use su-exec. + +exec "$@" \ No newline at end of file diff --git a/Dockerfile-windows b/Dockerfile-windows new file mode 100644 index 0000000000..14582908db --- /dev/null +++ b/Dockerfile-windows @@ -0,0 +1,51 @@ +FROM mcr.microsoft.com/windows/servercore:ltsc2019 +ARG VERSION=1.16.0 + +ENV chocolateyVersion=1.4.0 + +LABEL org.opencontainers.image.authors="Consul Team " \ + org.opencontainers.image.url="https://www.consul.io/" \ + org.opencontainers.image.documentation="https://www.consul.io/docs" \ + org.opencontainers.image.source="https://github.com/hashicorp/consul" \ + org.opencontainers.image.version=$VERSION \ + org.opencontainers.image.vendor="HashiCorp" \ + org.opencontainers.image.title="consul" \ + org.opencontainers.image.description="Consul is a datacenter runtime that provides service discovery, configuration, and orchestration." \ + version=${VERSION} + +RUN ["powershell", "Set-ExecutionPolicy", "Bypass", "-Scope", "Process", "-Force;"] +RUN ["powershell", "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))"] + +RUN choco install git.install -yf +RUN SETX /M path "%PATH%;C:\Program Files\Git\bin" + +RUN mkdir C:\\consul +RUN mkdir C:\\consul\\data +RUN mkdir C:\\consul\\config + +# Server RPC is used for communication between Consul clients and servers for internal +# request forwarding. +EXPOSE 8300 + +# Serf LAN and WAN (WAN is used only by Consul servers) are used for gossip between +# Consul agents. LAN is within the datacenter and WAN is between just the Consul +# servers in all datacenters. +EXPOSE 8301 8301/udp 8302 8302/udp + +# HTTP and DNS (both TCP and UDP) are the primary interfaces that applications +# use to interact with Consul. +EXPOSE 8500 8600 8600/udp + +#ENV CONSUL_URL=https://releases.hashicorp.com/consul/${VERSION}/consul_${VERSION}_windows_amd64.zip +#RUN curl %CONSUL_URL% -L -o consul.zip +#RUN tar -xf consul.zip -C consul + +COPY consul.exe C:\\consul + +COPY .release/docker/docker-entrypoint-windows.sh C:\\docker-entrypoint-windows.sh +ENTRYPOINT ["bash.exe", "docker-entrypoint-windows.sh"] + +# By default you'll get an insecure single-node development server that stores +# everything in RAM, exposes a web UI and HTTP endpoints, and bootstraps itself. +# Don't use this configuration for production. +CMD ["agent", "-dev", "-client", "0.0.0.0"] diff --git a/build-support/windows/Dockerfile-consul-dev-windows b/build-support/windows/Dockerfile-consul-dev-windows new file mode 100644 index 0000000000..4e35ccb6e5 --- /dev/null +++ b/build-support/windows/Dockerfile-consul-dev-windows @@ -0,0 +1,4 @@ +ARG VERSION=1.16.0 + +FROM windows/consul:${VERSION}-local +COPY dist/ C:\\consul diff --git a/build-support/windows/Dockerfile-consul-local-windows b/build-support/windows/Dockerfile-consul-local-windows new file mode 100644 index 0000000000..992c48c286 --- /dev/null +++ b/build-support/windows/Dockerfile-consul-local-windows @@ -0,0 +1,52 @@ +ARG VERSION=1.13.3 + +FROM windows/test-sds-server as test-sds-server +FROM docker.mirror.hashicorp.services/windows/openzipkin as openzipkin +FROM windows/consul:${VERSION} + +# Fortio binary downloaded +RUN mkdir fortio +ENV FORTIO_URL=https://github.com/fortio/fortio/releases/download/v1.33.0/fortio_win_1.33.0.zip +RUN curl %FORTIO_URL% -L -o fortio.zip +RUN tar -xf fortio.zip -C fortio + +RUN choco install openssl -yf +RUN choco install jq -yf +RUN choco install netcat -yf +RUN choco install openjdk -yf + +# Install Bats +ENV BATS_URL=https://github.com/bats-core/bats-core/archive/refs/tags/v1.7.0.zip +RUN curl %BATS_URL% -L -o bats.zip +RUN mkdir bats-core +RUN tar -xf bats.zip -C bats-core --strip-components=1 +RUN cd "C:\\Program Files\\Git\\bin" && bash.exe -c "/c/bats-core/install.sh /c/bats" + +# Install Jaeger +ENV JAEGER_URL=https://github.com/jaegertracing/jaeger/releases/download/v1.11.0/jaeger-1.11.0-windows-amd64.tar.gz +RUN curl %JAEGER_URL% -L -o jaeger.tar.gz +RUN mkdir jaeger +RUN tar -xf jaeger.tar.gz -C jaeger --strip-components=1 + +# Install Socat +ENV SOCAT_URL=https://github.com/tech128/socat-1.7.3.0-windows/archive/refs/heads/master.zip +RUN curl %SOCAT_URL% -L -o socat.zip +RUN mkdir socat +RUN tar -xf socat.zip -C socat --strip-components=1 + +# Copy test-sds-server binary and certs +COPY --from=test-sds-server ["C:/go/src/", "C:/test-sds-server/"] + +# Copy openzipkin .jar file +COPY --from=openzipkin ["C:/zipkin", "C:/zipkin"] + +EXPOSE 8300 +EXPOSE 8301 8301/udp 8302 8302/udp +EXPOSE 8500 8600 8600/udp +EXPOSE 8502 + +EXPOSE 19000 19001 19002 19003 19004 +EXPOSE 21000 21001 21002 21003 21004 +EXPOSE 5000 1234 2345 + +RUN SETX /M path "%PATH%;C:\consul;C:\fortio;C:\jaeger;C:\Program Files\Git\bin;C:\Program Files\Git\usr\bin;C:\Program Files\OpenSSL-Win64\bin;C:\bats\bin\;C:\ProgramData\chocolatey\lib\jq\tools;C:\socat" diff --git a/build-support/windows/Dockerfile-openzipkin-windows b/build-support/windows/Dockerfile-openzipkin-windows new file mode 100644 index 0000000000..b23867f0b2 --- /dev/null +++ b/build-support/windows/Dockerfile-openzipkin-windows @@ -0,0 +1,12 @@ +FROM docker.mirror.hashicorp.services/windows/openjdk:1809 + +RUN mkdir zipkin +RUN curl.exe -sSL 'https://search.maven.org/remote_content?g=io.zipkin&a=zipkin-server&v=LATEST&c=exec' -o zipkin/zipkin.jar + +EXPOSE 9410/tcp + +EXPOSE 9411/tcp + +WORKDIR /zipkin + +ENTRYPOINT ["java", "-jar", "zipkin.jar"] \ No newline at end of file diff --git a/build-support/windows/build-consul-dev-image.sh b/build-support/windows/build-consul-dev-image.sh new file mode 100644 index 0000000000..4c03f2f9b0 --- /dev/null +++ b/build-support/windows/build-consul-dev-image.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +cd ../../ +rm -rf dist + +export GOOS=windows GOARCH=amd64 +VERSION=1.16.0 +CONSUL_BUILDDATE=$(date +"%Y-%m-%dT%H:%M:%SZ") +GIT_IMPORT=github.com/hashicorp/consul/version +GOLDFLAGS=" -X $GIT_IMPORT.Version=$VERSION -X $GIT_IMPORT.VersionPrerelease=dev -X $GIT_IMPORT.BuildDate=$CONSUL_BUILDDATE " + +go build -ldflags "$GOLDFLAGS" -o ./dist/ . + +docker build -t windows/consul:${VERSION}-dev -f build-support/windows/Dockerfile-consul-dev-windows . --build-arg VERSION=${VERSION} diff --git a/build-support/windows/build-consul-local-images.sh b/build-support/windows/build-consul-local-images.sh new file mode 100644 index 0000000000..eaa7cc1056 --- /dev/null +++ b/build-support/windows/build-consul-local-images.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +readonly HASHICORP_DOCKER_PROXY="docker.mirror.hashicorp.services" + +# Build Consul Version 1.13.3 / 1.12.6 / 1.11.11 +VERSION=${VERSION:-"1.16.0"} +export VERSION + +# Build Windows Envoy Version 1.23.1 / 1.21.5 / 1.20.7 +ENVOY_VERSION=${ENVOY_VERSION:-"1.23.1"} +export ENVOY_VERSION + +echo "Building Images" + + +# Pull Windows Servercore image +echo " " +echo "Pull Windows Servercore image" +docker pull mcr.microsoft.com/windows/servercore:1809 +# Tag Windows Servercore image +echo " " +echo "Tag Windows Servercore image" +docker tag mcr.microsoft.com/windows/servercore:1809 "${HASHICORP_DOCKER_PROXY}/windows/servercore:1809" + + +# Pull Windows Nanoserver image +echo " " +echo "Pull Windows Nanoserver image" +docker pull mcr.microsoft.com/windows/nanoserver:1809 +# Tag Windows Nanoserver image +echo " " +echo "Tag Windows Nanoserver image" +docker tag mcr.microsoft.com/windows/nanoserver:1809 "${HASHICORP_DOCKER_PROXY}/windows/nanoserver:1809" + + +# Pull Windows OpenJDK image +echo " " +echo "Pull Windows OpenJDK image" +docker pull openjdk:windowsservercore-1809 +# Tag Windows OpenJDK image +echo " " +echo "Tag Windows OpenJDK image" +docker tag openjdk:windowsservercore-1809 "${HASHICORP_DOCKER_PROXY}/windows/openjdk:1809" + +# Pull Windows Golang image +echo " " +echo "Pull Windows Golang image" +docker pull golang:1.18.1-nanoserver-1809 +# Tag Windows Golang image +echo " " +echo "Tag Windows Golang image" +docker tag golang:1.18.1-nanoserver-1809 "${HASHICORP_DOCKER_PROXY}/windows/golang:1809" + + +# Pull Kubernetes/pause image +echo " " +echo "Pull Kubernetes/pause image" +docker pull mcr.microsoft.com/oss/kubernetes/pause:3.6 +# Tag Kubernetes/pause image +echo " " +echo "Tag Kubernetes/pause image" +docker tag mcr.microsoft.com/oss/kubernetes/pause:3.6 "${HASHICORP_DOCKER_PROXY}/windows/kubernetes/pause" + +# Pull envoy-windows image +echo " " +echo "Pull envoyproxy/envoy-windows image" +docker pull envoyproxy/envoy-windows:v${ENVOY_VERSION} +# Tag envoy-windows image +echo " " +echo "Tag envoyproxy/envoy-windows image" +docker tag envoyproxy/envoy-windows:v${ENVOY_VERSION} "${HASHICORP_DOCKER_PROXY}/windows/envoy-windows:v${ENVOY_VERSION}" + +# Build Windows Openzipkin Image +docker build -t "${HASHICORP_DOCKER_PROXY}/windows/openzipkin" -f Dockerfile-openzipkin-windows . + + +# Build Windows Test sds server Image +./build-test-sds-server-image.sh + + +# Build windows/consul:${VERSION} Image +echo " " +echo "Build windows/consul:${VERSION} Image" +docker build -t "windows/consul:${VERSION}" -f ../../Dockerfile-windows ../../ --build-arg VERSION=${VERSION} + + +# Build windows/consul:${VERSION}-local Image +echo " " +echo "Build windows/consul:${VERSION}-local Image" +docker build -t windows/consul:${VERSION}-local -f ./Dockerfile-consul-local-windows . --build-arg VERSION=${VERSION} + +echo "Building Complete!" diff --git a/build-support/windows/build-test-sds-server-image.sh b/build-support/windows/build-test-sds-server-image.sh new file mode 100644 index 0000000000..25de3dadbe --- /dev/null +++ b/build-support/windows/build-test-sds-server-image.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +cd ../../test/integration/connect/envoy + +docker build -t windows/test-sds-server -f ./Dockerfile-test-sds-server-windows test-sds-server diff --git a/build-support/windows/windows-test.md b/build-support/windows/windows-test.md new file mode 100644 index 0000000000..5295e40757 --- /dev/null +++ b/build-support/windows/windows-test.md @@ -0,0 +1,119 @@ +# Dockerfiles for Windows Integration Tests + +## Index + +- [About](#about-this-file) +- [Consul Windows](#consul-windows) +- [Consul Windows Local](#consul-windows-local) +- [Consul Windows Dev](#consul-windows-dev) +- [Dockerfile-openzipkin-windows](#dockerfile-openzipkin-windows) + +## About this File + +In this file you will find which Docker images that need to be pre-built to run the Envoy integration tests on Windows, as well as information on how to run each of these files individually for testing purposes. + +## Consul Windows + +The Windows/Consul:_{VERSION}_ image is built from the "Dockerfile-windows" file located at the root of the project. +To do this, the official [windows/servercore image](https://hub.docker.com/_/microsoft-windows-servercore) is used as base image. +To build the image, use the following command: + +```shell +docker build -t windows/consul -f Dockerfile-windows . --build-arg VERSION=${VERSION} +``` + +You can test the built file by running the following command: + +```shell +docker run --rm -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8500:8500 -p 8600:8600 --name consul --hostname "consul-primary-server" --network-alias "consul-primary-server" windows/consul agent -dev -datacenter "primary" -grpc-port -1 -client "0.0.0.0" -bind "0.0.0.0" +``` + +If everything works properly you should openning the browser and check the Consul UI running on: `http://localhost:8500` + +## Consul Windows Local + +The Windows/Consul:_{VERSION}_-local custom image deployed in the "Dockerfile-consul-local-windows" DockerFile is built from the selected by the shell script _build-consul-local-images.sh_. +When executing it, all the tools required to run the Windows Connect Envoy Integration Tests will be added to the image. +It is necessary that the _"windows/consul"_ image has been built first. This script also takes care of that. + +To build this image you need to run the following command on your terminal: + +```shell +./build-consul-local-images.sh +``` + +> [!NOTE] +> Shell script execution may vary depending on your terminal, we recommend using **Git Bash** for Windows. + +```shell +docker run --rm -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8500:8500 -p 8600:8600 --name consul-local --hostname "consul-primary-server" --network-alias "consul-primary-server" windows/consul:_{VERSION}_-local agent -dev -datacenter "primary" -grpc-port -1 -client "0.0.0.0" -bind "0.0.0.0" +``` + +If everything works properly you can use your browser and check the Consul UI running on: `http://localhost:8500` + +## Consul Windows Dev + +The Windows/Consul:_{VERSION}_-dev custom image deployed in the "Dockerfile-consul-dev-windows" DockerFile is generated by the shell script named _build-consul-dev-image.sh_. +When executing it, the compilation of Consul is carried out and it is saved in the _"dist"_ directory, this file is then copied to the _"windows/consul:_{VERSION}_-dev"_ image. +It is necessary that the _"windows/consul_{VERSION}_-local"_ image has been built first. + +To build this image you need to run the following command on your terminal: + +```shell +./build-consul-dev-image.sh +``` + +> [!NOTE] +> Shell script execution may vary depending on your terminal, we recommend using **Git Bash** for Windows. + +You can test the built file by running the following command: + +```shell +docker run --rm -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8500:8500 -p 8600:8600 --name consul-local --hostname "consul-primary-server" --network-alias "consul-primary-server" windows/consul:_{VERSION}_-dev agent -dev -datacenter "primary" -grpc-port -1 -client "0.0.0.0" -bind "0.0.0.0" +``` + +If everything works properly you can use your browser and check the Consul UI running on: `http://localhost:8500` + +## Dockerfile-openzipkin-windows + +Due to the unavailability of an official Openzipkin Docker image for Windows, the [openjdk Windows image](https://hub.docker.com/layers/openjdk/library/openjdk/jdk-windowsservercore-1809/images/sha256-b0cc238d2ec5fb58109a0006ff9e1bcaf66a5301f49bcb8dece9599ac5be6331) was used, where the latest self-contained executable Openzipkin .jar file is downloaded. + +To build this image you need to run the following command on your terminal: + +```shell +docker build -t openzipkin -f Dockerfile-openzipkin-windows . +``` + +You can test the built file by running the following command: + +```shell +docker run --rm --name openzipkin +``` + +If everything works as it should, you will see the zipkin logo being displayed, along with the current version and port configuration: + +```shell +:: version 2.23.18 :: commit 4b71677 :: + +20XX-XX-XX XX:XX:XX.XXX INFO [/] 1252 --- [oss-http-*:9411] c.l.a.s.Server : Serving HTTP at /[0:0:0:0:0:0:0:0]:9411 - http://127.0.0.1:9411/ +``` + +# Testing + +During development, it may be more convenient to check your work-in-progress by running only the tests which you expect to be affected by your changes, as the full test suite can take several minutes to execute. [Go's built-in test tool](https://golang.org/pkg/cmd/go/internal/test/) allows specifying a list of packages to test and the `-run` option to only include test names matching a regular expression. +The `go test -short` flag can also be used to skip slower tests. + +Examples (run from the repository root): + +- `go test -v ./connect` will run all tests in the connect package (see `./connect` folder) +- `go test -v -run TestRetryJoin ./command/agent` will run all tests in the agent package (see `./command/agent` folder) with name substring `TestRetryJoin` + +When a pull request is opened CI will run all tests and lint to verify the change. + +If you want to run the tests on Windows images you must attach the win=true flag. + +Example: + +```shell +go test -v -timeout=30m -tags integration ./test/integration/connect/envoy -run="TestEnvoy/case-badauthz" -win=true +``` diff --git a/test/integration/connect/envoy/Dockerfile-consul-envoy-windows b/test/integration/connect/envoy/Dockerfile-consul-envoy-windows new file mode 100644 index 0000000000..b760fd5754 --- /dev/null +++ b/test/integration/connect/envoy/Dockerfile-consul-envoy-windows @@ -0,0 +1,12 @@ +# From Consul Version 1.13.3 / 1.12.6 / 1.11.11 +ARG VERSION=1.16.0-dev +# From Envoy version 1.23.1 / 1.21.5 / 1.20.7 +ARG ENVOY_VERSION + +FROM docker.mirror.hashicorp.services/windows/envoy-windows:v${ENVOY_VERSION} as envoy +FROM windows/consul:${VERSION} + +# Copy envoy.exe from FROM windows/envoy-windows:${ENVOY_VERSION} +COPY --from=envoy ["C:/Program Files/envoy/", "C:/envoy/"] + +RUN SETX /M path "%PATH%;C:\envoy;" \ No newline at end of file diff --git a/test/integration/connect/envoy/Dockerfile-tcpdump-windows b/test/integration/connect/envoy/Dockerfile-tcpdump-windows new file mode 100644 index 0000000000..cbf5041630 --- /dev/null +++ b/test/integration/connect/envoy/Dockerfile-tcpdump-windows @@ -0,0 +1,7 @@ +FROM mcr.microsoft.com/windows/servercore:ltsc2019 + +COPY ["tcpdump.exe", "C:/Program Files/"] + +ENTRYPOINT ["C:/Program Files/tcpdump.exe"] + +# docker.exe build -t envoy-tcpdump -f Dockerfile-tcpdump-windows . diff --git a/test/integration/connect/envoy/Dockerfile-test-sds-server-windows b/test/integration/connect/envoy/Dockerfile-test-sds-server-windows new file mode 100644 index 0000000000..fc5e45b88d --- /dev/null +++ b/test/integration/connect/envoy/Dockerfile-test-sds-server-windows @@ -0,0 +1,8 @@ +FROM docker.mirror.hashicorp.services/windows/golang:1809 + +WORKDIR /go/src +COPY ./ . + +RUN go build -v -o test-sds-server.exe sds.go + +CMD ["test-sds-server.exe"] diff --git a/test/integration/connect/envoy/WINDOWS-TEST.md b/test/integration/connect/envoy/WINDOWS-TEST.md new file mode 100644 index 0000000000..d9217f7a38 --- /dev/null +++ b/test/integration/connect/envoy/WINDOWS-TEST.md @@ -0,0 +1,40 @@ +# Envoy Integration Tests on Windows + +## Index + +- [About](#about) +- [Pre-built core images](#pre-built-core-images) +- [Test images](#integration-test-images) +- [Run Tests](#run-tests) + +## About + +This file is the entrypoint to understand how to execute Envoy integration tests on Windows as well as to understand the differences between Linux tests and Windows tests. Below you can find a list of relevant documentation that has been written while working on supporting the Envoy integration tests on Windows. + +- [Windows Testing Architecture](test/integration/connect/envoy/docs/windows-testing-architecture.md): On this file you will find why the testing architecture on Windows differs from Linux's. +- [Build Images](build-support-windows/BUILD-IMAGES.md): Here you will find how to build the images required for executing the tests. +- [Windows Troubleshooting](test/integration/connect/envoy/WindowsTroubleshooting.md): This file lists, among other things everything we needed to change/adapt for the existing tests to run in Windows containers. + +## Pre-built core images + +Before running the integration tests, you must pre-build the core images that the tests require to be ran on the Windows environment. Make sure to check out the `BUILD-IMAGES` file [here](build-support-windows/BUILD-IMAGES.md) for this purpose. + +## Integration test images + +During the execution of the integration tests, several images are built based-on the pre-built core images. To get more information about these and how to run them independently, please check out the `docker.windows` file [here](test/integration/connect/envoy/docker.windows.md). + +## Run tests + +To run all the integration tests, you need to execute next command + +```shell +go test -v -timeout=30s -tags integration ./test/integration/connect/envoy -run="TestEnvoy" -win=true +``` + +To run a single test case, the name should be specified. For instance, to run the `case-badauthz` test, you need to execute next command + +```shell +go test -v -timeout=30m -tags integration ./test/integration/connect/envoy -run="TestEnvoy/case-badauthz" -win=true +``` + +> :warning: Note that the flag `-win=true` must be specified as shown in the above commands. This flag is very important because the same allows to indicate that the tests will be executed on the Windows environment. When executing the Envoy integration tests the **End of Line Sequence** of every related file and or script will be automatically changed from **LF to CRLF**. diff --git a/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats b/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats index 55b0ad7684..dfc238ad6d 100644 --- a/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats +++ b/test/integration/connect/envoy/case-dogstatsd-udp/verify.bats @@ -24,14 +24,11 @@ load helpers } @test "s1 proxy should be sending metrics to statsd" { - run retry_default cat /workdir/primary/statsd/statsd.log + run retry_default must_match_in_statsd_logs '^envoy\.' primary - echo "METRICS:" - echo "$output" - echo "COUNT: $(echo "$output" | grep -Ec '^envoy\.')" + echo "METRICS: $output" - [ "$status" == 0 ] - [ $(echo $output | grep -Ec '^envoy\.') -gt "0" ] + [ "$status" == 0 ] } @test "s1 proxy should be sending dogstatsd tagged metrics" { diff --git a/test/integration/connect/envoy/case-gateways-local/secondary/setup.sh b/test/integration/connect/envoy/case-gateways-local/secondary/setup.sh index 938135c9f4..68fd765ad0 100644 --- a/test/integration/connect/envoy/case-gateways-local/secondary/setup.sh +++ b/test/integration/connect/envoy/case-gateways-local/secondary/setup.sh @@ -9,4 +9,4 @@ register_services secondary gen_envoy_bootstrap s2 19001 secondary gen_envoy_bootstrap mesh-gateway 19003 secondary true -retry_default docker_consul secondary curl -s "http://localhost:8500/v1/catalog/service/consul?dc=primary" >/dev/null +retry_default docker_consul secondary curl -s "http://localhost:8500/v1/catalog/service/consul?dc=primary" > /dev/null diff --git a/test/integration/connect/envoy/case-grpc/service_s1.hcl b/test/integration/connect/envoy/case-grpc/service_s1.hcl index b22ba221fa..1a72954240 100644 --- a/test/integration/connect/envoy/case-grpc/service_s1.hcl +++ b/test/integration/connect/envoy/case-grpc/service_s1.hcl @@ -20,7 +20,7 @@ services { protocol = "grpc" envoy_dogstatsd_url = "udp://127.0.0.1:8125" envoy_stats_tags = ["foo=bar"] - envoy_stats_flush_interval = "1s" + envoy_stats_flush_interval = "5s" } } } diff --git a/test/integration/connect/envoy/case-grpc/verify.bats b/test/integration/connect/envoy/case-grpc/verify.bats index 422258a0c0..fc7ca15b5b 100644 --- a/test/integration/connect/envoy/case-grpc/verify.bats +++ b/test/integration/connect/envoy/case-grpc/verify.bats @@ -43,7 +43,7 @@ load helpers metrics_query='envoy.cluster.grpc.PingServer.total.*[#,]local_cluster:s1(,|$)' fi - run retry_default must_match_in_statsd_logs "${metrics_query}" + run retry_long must_match_in_statsd_logs "${metrics_query}" echo "OUTPUT: $output" [ "$status" == 0 ] diff --git a/test/integration/connect/envoy/case-http-badauthz/setup.sh b/test/integration/connect/envoy/case-http-badauthz/setup.sh index 6bd91b1f4e..66a5874129 100644 --- a/test/integration/connect/envoy/case-http-badauthz/setup.sh +++ b/test/integration/connect/envoy/case-http-badauthz/setup.sh @@ -5,10 +5,10 @@ set -eEuo pipefail +register_services primary + # Setup deny intention setup_upsert_l4_intention s1 s2 deny -register_services primary - gen_envoy_bootstrap s1 19000 primary gen_envoy_bootstrap s2 19001 primary diff --git a/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats b/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats index 61eaaf97cc..92a158e51b 100644 --- a/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats +++ b/test/integration/connect/envoy/case-ingress-gateway-tls/verify.bats @@ -19,7 +19,7 @@ load helpers } @test "ingress-gateway should have healthy endpoints for s1" { - assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s1 HEALTHY 1 + assert_upstream_has_endpoints_in_status 127.0.0.1:20000 s1 HEALTHY 1 } @test "should be able to connect to s1 through the TLS-enabled ingress port" { @@ -29,8 +29,8 @@ load helpers run retry_default curl --cacert <(get_ca_root) -s -f -d hello \ --resolve s1.ingress.consul:9998:127.0.0.1 \ https://s1.ingress.consul:9998 - [ "$status" -eq 0 ] - [[ "$output" == *"hello"* ]] + [ "$status" -eq 0 ] + [[ "$output" == *"hello"* ]] } @test "should be able to connect to s1 through the TLS-enabled ingress port using the custom host" { @@ -38,6 +38,6 @@ load helpers run retry_default curl --cacert <(get_ca_root) -s -f -d hello \ --resolve test.example.com:9999:127.0.0.1 \ https://test.example.com:9999 - [ "$status" -eq 0 ] - [[ "$output" == *"hello"* ]] + [ "$status" -eq 0 ] + [[ "$output" == *"hello"* ]] } diff --git a/test/integration/connect/envoy/case-wanfed-gw/global-setup-windows.sh b/test/integration/connect/envoy/case-wanfed-gw/global-setup-windows.sh new file mode 100644 index 0000000000..c63b12a12f --- /dev/null +++ b/test/integration/connect/envoy/case-wanfed-gw/global-setup-windows.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# initialize the outputs for each dc +for dc in primary secondary; do + rm -rf "workdir/${dc}/tls" + mkdir -p "workdir/${dc}/tls" +done + +container="consul-envoy-integ-tls-init--${CASE_NAME}" + +scriptlet=" +mkdir /out ; +cd /out ; +consul tls ca create ; +consul tls cert create -dc=primary -server -node=pri ; +consul tls cert create -dc=secondary -server -node=sec ; +" + +docker.exe rm -f "$container" &>/dev/null || true +docker.exe run -i --net=none --name="$container" windows/consul:local bash -c "${scriptlet}" + +# primary +for f in \ + consul-agent-ca.pem \ + primary-server-consul-0-key.pem \ + primary-server-consul-0.pem \ + ; do + docker.exe cp "${container}:C:\\Program Files\\Git\\out\\$f" workdir/primary/tls +done + +# secondary +for f in \ + consul-agent-ca.pem \ + secondary-server-consul-0-key.pem \ + secondary-server-consul-0.pem \ + ; do + docker.exe cp "${container}:C:\\Program Files\\Git\\out\\$f" workdir/secondary/tls +done + +# Private keys have 600 perms but tests are run as another user +chmod 666 workdir/primary/tls/primary-server-consul-0-key.pem +chmod 666 workdir/secondary/tls/secondary-server-consul-0-key.pem + +docker.exe rm -f "$container" >/dev/null || true \ No newline at end of file diff --git a/test/integration/connect/envoy/case-zipkin/verify.bats b/test/integration/connect/envoy/case-zipkin/verify.bats index d771d52363..5093456890 100644 --- a/test/integration/connect/envoy/case-zipkin/verify.bats +++ b/test/integration/connect/envoy/case-zipkin/verify.bats @@ -35,14 +35,17 @@ load helpers # Send traced request through upstream. Debug echoes headers back which we can # use to get the traceID generated (no way to force one I can find with Envoy # currently?) - run curl -s -f -H 'x-client-trace-id:test-sentinel' localhost:5000/Debug + # Fixed from /Debug -> /debug. Reason: /Debug return null + run curl -s -f -H 'x-client-trace-id:test-sentinel' localhost:5000/debug -m 5 echo "OUTPUT $output" [ "$status" == "0" ] # Get the traceID from the output - TRACEID=$(echo $output | grep 'X-B3-Traceid:' | cut -c 15-) + # Replaced grep by jq to filter the TraceId. + # Reason: Grep did not filter and return the entire raw string and the test was failing + TRACEID=$(echo $output | jq -rR 'split("X-B3-Traceid: ") | last' | cut -c -16) # Get the trace from Jaeger. Won't bother parsing it just seeing it show up # there is enough to know that the tracing config worked. diff --git a/test/integration/connect/envoy/docker-windows.md b/test/integration/connect/envoy/docker-windows.md new file mode 100644 index 0000000000..a9f2bbcaca --- /dev/null +++ b/test/integration/connect/envoy/docker-windows.md @@ -0,0 +1,42 @@ +# Docker Files for Windows Integration Tests + +## Index + +- [About](#about-this-file) +- [Pre-requisites](#pre-requisites) +- [Dockerfile-test-sds-server-windows](#dockerfile-test-sds-server-windows) + +## About this File + +In this file you will find which Dockerfiles are needed to run the Envoy integration tests on Windows, as well as information on how to run each of these files individually for testing purposes. + +## Pre-requisites + +After building and running the images and containers, you need to have pre-built the base images used by these Dockerfiles. See [pre-built images required in Windows](../../../../build-support-windows/BUILD-IMAGES.md) + +## Dockerfile-test-sds-server-windows + +This file sole purpose is to build the test-sds-server executable using Go. To do so, we use an official [golang image](https://hub.docker.com/_/golang/) provided in docker hub with Windows nano server. +To build this image you need to run the following command on your terminal: + +```shell +docker build -t test-sds-server -f Dockerfile-test-sds-server-windows test-sds-server +``` + +This is the same command used in run-tests.sh + +You can test the built file by running the following command: + +```shell +docker run --rm -p 1234:1234 --name test-sds-server test-sds-server +``` + +If everything works properly you should get the following output: + +```shell +20XX-XX-XXTXX:XX:XX.XXX-XXX [INFO] Loaded cert from file: name=ca-root +20XX-XX-XXTXX:XX:XX.XXX-XXX [INFO] Loaded cert from file: name=foo.example.com +20XX-XX-XXTXX:XX:XX.XXX-XXX [INFO] Loaded cert from file: name=wildcard.ingress.consul +20XX-XX-XXTXX:XX:XX.XXX-XXX [INFO] Loaded cert from file: name=www.example.com +20XX-XX-XXTXX:XX:XX.XXX-XXX [INFO] ==> SDS listening: addr=0.0.0.0:1234 +``` diff --git a/test/integration/connect/envoy/docs/img/linux-arch.png b/test/integration/connect/envoy/docs/img/linux-arch.png new file mode 100644 index 0000000000000000000000000000000000000000..710b83b24570baad3e673b71d2c59c8e8018edd5 GIT binary patch literal 63964 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 #@kZ!sf*w33Y#gk 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�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 literal 0 HcmV?d00001 diff --git a/test/integration/connect/envoy/docs/img/windows-linux-arch.png b/test/integration/connect/envoy/docs/img/windows-linux-arch.png new file mode 100644 index 0000000000000000000000000000000000000000..d1c05533e51f21a971153bbcfff5ae81714bbae9 GIT binary patch literal 61475 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 to work) + # 1 - is not truthy + + local val=$(tr '[:upper:]' '[:lower:]' <<<"$1") + case $val in + 1 | t | true | y | yes) + return 0 + ;; + *) + return 1 + ;; + esac +} + +function get_cert { + local HOSTPORT=$1 + local SERVER_NAME=$2 + local CA_FILE=$3 + local SNI_FLAG="" + if [ -n "$SERVER_NAME" ]; then + SNI_FLAG="-servername $SERVER_NAME" + fi + CERT=$(openssl s_client -connect $HOSTPORT $SNI_FLAG -showcerts /dev/null) + + echo "WANT CN: ${CN} (SNI: ${SERVER_NAME})" + echo "GOT CERT:" + echo "$CERT" + + echo "$CERT" | grep "CN = ${CN}" +} + +function get_upstream_endpoint { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + run curl -s -f "http://${HOSTPORT}/clusters?format=json" + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output " +.cluster_statuses[] +| select(.name|startswith(\"${CLUSTER_NAME}\"))" +} + +function assert_upstream_missing_once { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + + run get_upstream_endpoint $HOSTPORT $CLUSTER_NAME + [ "$status" -eq 0 ] + echo "$output" + [ "" == "$output" ] +} + +function assert_upstream_missing { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + run retry_long assert_upstream_missing_once $HOSTPORT $CLUSTER_NAME + echo "OUTPUT: $output $status" + + [ "$status" -eq 0 ] +} + +function assert_envoy_version { + local ADMINPORT=$1 + run retry_default curl -f -s localhost:$ADMINPORT/server_info + [ "$status" -eq 0 ] + # Envoy 1.8.0 returns a plain text line like + # envoy 5d25f466c3410c0dfa735d7d4358beb76b2da507/1.8.0/Clean/DEBUG live 3 3 0 + # Later versions return JSON. + if (echo $output | grep '^envoy'); then + VERSION=$(echo $output | cut -d ' ' -f 2) + else + VERSION=$(echo $output | jq -r '.version') + fi + echo "Status=$status" + echo "Output=$output" + echo "---" + echo "Got version=$VERSION" + echo "Want version=$ENVOY_VERSION" + + # 1.20.2, 1.19.3 and 1.18.6 are special snowflakes in that the version for + # the release is reported with a '-dev' suffix (eg 1.20.2-dev). + if [ "$ENVOY_VERSION" = "1.20.2" ]; then + ENVOY_VERSION="1.20.2-dev" + elif [ "$ENVOY_VERSION" = "1.19.3" ]; then + ENVOY_VERSION="1.19.3-dev" + elif [ "$ENVOY_VERSION" = "1.18.6" ]; then + ENVOY_VERSION="1.18.6-dev" + fi + + echo $VERSION | grep "/$ENVOY_VERSION/" +} + +function assert_envoy_expose_checks_listener_count { + local HOSTPORT=$1 + local EXPECT_PATH=$2 + + # scrape this once + BODY=$(get_envoy_expose_checks_listener_once $HOSTPORT) + echo "BODY = $BODY" + + CHAINS=$(echo "$BODY" | jq '.active_state.listener.filter_chains | length') + echo "CHAINS = $CHAINS (expect 1)" + [ "${CHAINS:-0}" -eq 1 ] + + RANGES=$(echo "$BODY" | jq '.active_state.listener.filter_chains[0].filter_chain_match.source_prefix_ranges | length') + echo "RANGES = $RANGES (expect 3)" + # note: if IPv6 is not supported in the kernel per + # agent/xds:kernelSupportsIPv6() then this will only be 2 + [ "${RANGES:-0}" -eq 3 ] + + HCM=$(echo "$BODY" | jq '.active_state.listener.filter_chains[0].filters[0]') + HCM_NAME=$(echo "$HCM" | jq -r '.name') + HCM_PATH=$(echo "$HCM" | jq -r '.typed_config.route_config.virtual_hosts[0].routes[0].match.path') + echo "HCM = $HCM" + [ "${HCM_NAME:-}" == "envoy.filters.network.http_connection_manager" ] + [ "${HCM_PATH:-}" == "${EXPECT_PATH}" ] +} + +function get_envoy_expose_checks_listener_once { + local HOSTPORT=$1 + run curl -m 5 -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output '.configs[] | select(.["@type"] == "type.googleapis.com/envoy.admin.v3.ListenersConfigDump") | .dynamic_listeners[] | select(.name | startswith("exposed_path_"))' +} + +function get_envoy_public_listener_once { + local HOSTPORT=$1 + run curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output '.configs[] | select(.["@type"] == "type.googleapis.com/envoy.admin.v3.ListenersConfigDump") | .dynamic_listeners[] | select(.name | startswith("public_listener:"))' +} + +function assert_envoy_http_rbac_policy_count { + local HOSTPORT=$1 + local EXPECT_COUNT=$2 + + GOT_COUNT=$(get_envoy_http_rbac_once $HOSTPORT | jq '.rules.policies | length') + echo "GOT_COUNT = $GOT_COUNT" + [ "${GOT_COUNT:-0}" -eq $EXPECT_COUNT ] +} + +function get_envoy_http_rbac_once { + local HOSTPORT=$1 + run curl -m 5 -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output '.configs[2].dynamic_listeners[].active_state.listener.filter_chains[0].filters[0].typed_config.http_filters[] | select(.name == "envoy.filters.http.rbac") | .typed_config' +} + +function assert_envoy_network_rbac_policy_count { + local HOSTPORT=$1 + local EXPECT_COUNT=$2 + + GOT_COUNT=$(get_envoy_network_rbac_once $HOSTPORT | jq '.rules.policies | length') + echo "GOT_COUNT = $GOT_COUNT" + [ "${GOT_COUNT:-0}" -eq $EXPECT_COUNT ] +} + +function get_envoy_network_rbac_once { + local HOSTPORT=$1 + run curl -m 5 -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output '.configs[2].dynamic_listeners[].active_state.listener.filter_chains[0].filters[] | select(.name == "envoy.filters.network.rbac") | .typed_config' +} + +function get_envoy_listener_filters { + local HOSTPORT=$1 + run retry_default curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output '.configs[2].dynamic_listeners[].active_state.listener | "\(.name) \( .filter_chains[0].filters | map(.name) | join(","))"' +} + +function get_envoy_http_filter { + local HOSTPORT=$1 + local FILTER_NAME=$2 + run retry_default curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output ".configs[2].dynamic_listeners[] | .active_state.listener.filter_chains[].filters[] | select(.name == \"envoy.filters.network.http_connection_manager\") | .typed_config.http_filters[] | select(.name == \"${FILTER_NAME}\")" +} + +function get_envoy_http_filters { + local HOSTPORT=$1 + run retry_default curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output '.configs[2].dynamic_listeners[].active_state.listener | "\(.name) \( .filter_chains[0].filters[] | select(.name == "envoy.filters.network.http_connection_manager") | .typed_config.http_filters | map(.name) | join(","))"' +} + +function get_envoy_dynamic_cluster_once { + local HOSTPORT=$1 + local NAME_PREFIX=$2 + run curl -m 5 -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output ".configs[] | select (.[\"@type\"] == \"type.googleapis.com/envoy.admin.v3.ClustersConfigDump\") | .dynamic_active_clusters[] | select(.cluster.name | startswith(\"${NAME_PREFIX}\"))" +} + +function assert_envoy_dynamic_cluster_exists_once { + local HOSTPORT=$1 + local NAME_PREFIX=$2 + local EXPECT_SNI=$3 + BODY="$(get_envoy_dynamic_cluster_once $HOSTPORT $NAME_PREFIX)" + [ -n "$BODY" ] + + SNI="$(echo "$BODY" | jq --raw-output ".cluster.transport_socket.typed_config.sni | select(. | startswith(\"${EXPECT_SNI}\"))")" + [ -n "$SNI" ] +} + +function assert_envoy_dynamic_cluster_exists { + local HOSTPORT=$1 + local NAME_PREFIX=$2 + local EXPECT_SNI=$3 + run retry_long assert_envoy_dynamic_cluster_exists_once $HOSTPORT $NAME_PREFIX $EXPECT_SNI + [ "$status" -eq 0 ] +} + +function get_envoy_cluster_config { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + run retry_default curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output " + .configs[1].dynamic_active_clusters[] + | select(.cluster.name|startswith(\"${CLUSTER_NAME}\")) + | .cluster + " +} + +function get_envoy_stats_flush_interval { + local HOSTPORT=$1 + run retry_default curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + #echo "$output" > /workdir/s1_envoy_dump.json + echo "$output" | jq --raw-output '.configs[0].bootstrap.stats_flush_interval' +} + +# snapshot_envoy_admin is meant to be used from a teardown scriptlet from the host. +function snapshot_envoy_admin { + local HOSTPORT=$1 + local ENVOY_NAME=$2 + local DC=${3:-primary} + local OUTDIR="${LOG_DIR}/envoy-snapshots/${DC}/${ENVOY_NAME}" + + mkdir -p "${OUTDIR}" + docker_consul_exec "$DC" bash -c "curl -s http://${HOSTPORT}/config_dump" > "${OUTDIR}/config_dump.json" + docker_consul_exec "$DC" bash -c "curl -s http://${HOSTPORT}/clusters?format=json" > "${OUTDIR}/clusters.json" + docker_consul_exec "$DC" bash -c "curl -s http://${HOSTPORT}/stats" > "${OUTDIR}/stats.txt" + docker_consul_exec "$DC" bash -c "curl -s http://${HOSTPORT}/stats/prometheus" > "${OUTDIR}/stats_prometheus.txt" +} + +function reset_envoy_metrics { + local HOSTPORT=$1 + curl -m 5 -s -f -XPOST $HOSTPORT/reset_counters + return $? +} + +function get_all_envoy_metrics { + local HOSTPORT=$1 + curl -m 5 -s -f $HOSTPORT/stats + return $? +} + +function get_envoy_metrics { + local HOSTPORT=$1 + local METRICS=$2 + + get_all_envoy_metrics $HOSTPORT | grep "$METRICS" +} + +function assert_upstream_has_endpoint_port { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local PORT_VALUE=$3 + + run retry_long assert_upstream_has_endpoint_port_once $HOSTPORT $CLUSTER_NAME $PORT_VALUE + [ "$status" -eq 0 ] +} + +function get_upstream_endpoint_in_status_count { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local HEALTH_STATUS=$3 + run curl -m 5 -s -f "http://${HOSTPORT}/clusters?format=json" + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output " +.cluster_statuses[] +| select(.name|startswith(\"${CLUSTER_NAME}\")) +| [.host_statuses[].health_status.eds_health_status] +| [select(.[] == \"${HEALTH_STATUS}\")] +| length" +} + +function assert_upstream_has_endpoints_in_status_once { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local HEALTH_STATUS=$3 + local EXPECT_COUNT=$4 + + GOT_COUNT=$(get_upstream_endpoint_in_status_count $HOSTPORT $CLUSTER_NAME $HEALTH_STATUS) + + [ "$GOT_COUNT" -eq $EXPECT_COUNT ] +} + +function assert_upstream_has_endpoints_in_status { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local HEALTH_STATUS=$3 + local EXPECT_COUNT=$4 + run retry_long assert_upstream_has_endpoints_in_status_once $HOSTPORT $CLUSTER_NAME $HEALTH_STATUS $EXPECT_COUNT + [ "$status" -eq 0 ] +} + +function assert_envoy_metric { + set -eEuo pipefail + local HOSTPORT=$1 + local METRIC=$2 + local EXPECT_COUNT=$3 + + METRICS=$(get_envoy_metrics $HOSTPORT "$METRIC") + + if [ -z "${METRICS}" ]; then + echo "Metric not found" 1>&2 + return 1 + fi + + GOT_COUNT=$(awk -F: '{print $2}' <<<"$METRICS" | head -n 1 | tr -d ' ') + + if [ -z "$GOT_COUNT" ]; then + echo "Couldn't parse metric count" 1>&2 + return 1 + fi + + if [ $EXPECT_COUNT -ne $GOT_COUNT ]; then + echo "$METRIC - expected count: $EXPECT_COUNT, actual count: $GOT_COUNT" 1>&2 + return 1 + fi +} + +function assert_envoy_metric_at_least { + set -eEuo pipefail + local HOSTPORT=$1 + local METRIC=$2 + local EXPECT_COUNT=$3 + + METRICS=$(get_envoy_metrics $HOSTPORT "$METRIC") + + if [ -z "${METRICS}" ]; then + echo "Metric not found" 1>&2 + return 1 + fi + + GOT_COUNT=$(awk -F: '{print $2}' <<<"$METRICS" | head -n 1 | tr -d ' ') + + if [ -z "$GOT_COUNT" ]; then + echo "Couldn't parse metric count" 1>&2 + return 1 + fi + + if [ $EXPECT_COUNT -gt $GOT_COUNT ]; then + echo "$METRIC - expected >= count: $EXPECT_COUNT, actual count: $GOT_COUNT" 1>&2 + return 1 + fi +} + +function assert_envoy_aggregate_metric_at_least { + set -eEuo pipefail + local HOSTPORT=$1 + local METRIC=$2 + local EXPECT_COUNT=$3 + + METRICS=$(get_envoy_metrics $HOSTPORT "$METRIC") + + if [ -z "${METRICS}" ]; then + echo "Metric not found" 1>&2 + return 1 + fi + + GOT_COUNT=$(awk '{ sum += $2 } END { print sum }' <<<"$METRICS") + + if [ -z "$GOT_COUNT" ]; then + echo "Couldn't parse metric count" 1>&2 + return 1 + fi + + if [ $EXPECT_COUNT -gt $GOT_COUNT ]; then + echo "$METRIC - expected >= count: $EXPECT_COUNT, actual count: $GOT_COUNT" 1>&2 + return 1 + fi +} + +function get_healthy_service_count { + local SERVICE_NAME=$1 + local DC=$2 + local NS=$3 + local AP=$4 + local PEER_NAME=$5 + + run curl -m 5 -s -f ${HEADERS} "consul-${DC}-client:8500/v1/health/connect/${SERVICE_NAME}?passing&ns=${NS}&partition=${AP}&peer=${PEER_NAME}" + + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output '. | length' +} + +function assert_alive_wan_member_count { + local DC=$1 + local EXPECT_COUNT=$2 + run retry_long assert_alive_wan_member_count_once $DC $EXPECT_COUNT + [ "$status" -eq 0 ] +} + +function assert_alive_wan_member_count_once { + local DC=$1 + local EXPECT_COUNT=$2 + + GOT_COUNT=$(get_alive_wan_member_count $DC) + + [ "$GOT_COUNT" -eq "$EXPECT_COUNT" ] +} + +function get_alive_wan_member_count { + local DC=$1 + run retry_default curl -sL -f "consul-${DC}-server:8500/v1/agent/members?wan=1" + [ "$status" -eq 0 ] + # echo "$output" >&3 + echo "$output" | jq '.[] | select(.Status == 1) | .Name' | wc -l +} + +function assert_service_has_healthy_instances_once { + local SERVICE_NAME=$1 + local EXPECT_COUNT=$2 + local DC=${3:-primary} + local NS=${4:-} + local AP=${5:-} + local PEER_NAME=${6:-} + + GOT_COUNT=$(get_healthy_service_count "$SERVICE_NAME" "$DC" "$NS" "$AP" "$PEER_NAME") + + [ "$GOT_COUNT" -eq $EXPECT_COUNT ] +} + +function assert_service_has_healthy_instances { + local SERVICE_NAME=$1 + local EXPECT_COUNT=$2 + local DC=${3:-primary} + local NS=${4:-} + local AP=${5:-} + local PEER_NAME=${6:-} + + run retry_long assert_service_has_healthy_instances_once "$SERVICE_NAME" "$EXPECT_COUNT" "$DC" "$NS" "$AP" "$PEER_NAME" + [ "$status" -eq 0 ] +} + +function check_intention { + local SOURCE=$1 + local DESTINATION=$2 + get_consul_hostname primary + + curl -m 5 -s -f "${CONSUL_HOSTNAME}:8500/v1/connect/intentions/check?source=${SOURCE}&destination=${DESTINATION}" | jq ".Allowed" +} + +function assert_intention_allowed { + local SOURCE=$1 + local DESTINATION=$2 + + run check_intention "${SOURCE}" "${DESTINATION}" + [ "$status" -eq 0 ] + [ "$output" = "true" ] +} + +function assert_intention_denied { + local SOURCE=$1 + local DESTINATION=$2 + + run check_intention "${SOURCE}" "${DESTINATION}" + [ "$status" -eq 0 ] + [ "$output" = "false" ] +} + +function docker_consul { + local DC=$1 + shift 1 + retry_default docker_exec envoy_consul-${DC}_1 "$@" +} + +function docker_consul_for_proxy_bootstrap { + local DC=$1 + shift 1 + + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"$DC"_1 + + docker.exe exec -i $CONTAINER_NAME bash.exe -c "$@" +} + +function docker_exec { + if ! docker.exe exec -i "$@"; then + echo "Failed to execute: docker exec -i $@" 1>&2 + return 1 + fi +} + +function docker_consul_exec { + local DC=$1 + shift 1 + docker_exec envoy_consul-${DC}_1 "$@" +} + +function kill_envoy { + local BOOTSTRAP_NAME=$1 + local DC=${2:-primary} + + PORT=$( cat /c/workdir/$DC/envoy/${BOOTSTRAP_NAME}-bootstrap.json | jq .admin.address.socket_address.port_value ) + PID=$( netstat -qo | grep "127.0.0.1:$PORT" | sed -r "s/.* //g" ) + tskill $PID +} + +function must_match_in_statsd_logs { + local DC=${2:-primary} + local FILE="/c/workdir/${DC}/statsd/statsd.log" + + COUNT=$( grep -Ec $1 $FILE ) + echo "COUNT of '$1' matches: $COUNT" + + [ "$COUNT" -gt "0" ] +} + +function must_match_in_prometheus_response { + run curl -m 5 -f -s $1/metrics + COUNT=$( echo "$output" | grep -Ec $2 ) + + echo "OUTPUT head -n 10" + echo "$output" | head -n 10 + echo "COUNT of '$2' matches: $COUNT" + + [ "$status" == 0 ] + [ "$COUNT" -gt "0" ] +} + +function must_match_in_stats_proxy_response { + run curl -m 5 -f -s $1/$2 + COUNT=$( echo "$output" | grep -Ec $3 ) + + echo "OUTPUT head -n 10" + echo "$output" | head -n 10 + echo "COUNT of '$3' matches: $COUNT" + + [ "$status" == 0 ] + [ "$COUNT" -gt "0" ] +} + +# must_fail_tcp_connection checks that a request made through an upstream fails, +# probably due to authz being denied if all other tests passed already. Although +# we are using curl, this only works as expected for TCP upstreams as we are +# checking TCP-level errors. HTTP upstreams will return a valid 503 generated by +# Envoy rather than a connection-level error. +function must_fail_tcp_connection { + # Attempt to curl through upstream + run curl -m 5 --no-keepalive -s -v -f -d hello $1 + + echo "OUTPUT $output" + + # Should fail during handshake and return "got nothing" error + [ "$status" == "52" ] + + # Verbose output should enclude empty reply + echo "$output" | grep 'Empty reply from server' +} + +function must_pass_tcp_connection { + run curl -m 5 --no-keepalive -s -f -d hello $1 + + echo "OUTPUT $output" + + [ "$status" == "0" ] + [ "$output" = "hello" ] +} + +# must_fail_http_connection see must_fail_tcp_connection but this expects Envoy +# to generate a 503 response since the upstreams have refused connection. +function must_fail_http_connection { + # Attempt to curl through upstream + run curl -m 5 --no-keepalive -s -i -d hello "$1" + + echo "OUTPUT $output" + + [ "$status" == "0" ] + + local expect_response="${2:-403 Forbidden}" + # Should fail request with 503 + echo "$output" | grep "${expect_response}" +} + +# must_pass_http_request allows you to craft a specific http request to assert +# that envoy will NOT reject the request. Primarily of use for testing L7 +# intentions. +function must_pass_http_request { + local METHOD=$1 + local URL=$2 + local DEBUG_HEADER_VALUE="${3:-""}" + + local extra_args + if [[ -n "${DEBUG_HEADER_VALUE}" ]]; then + extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" + fi + case "$METHOD" in + GET) ;; + + DELETE) + extra_args="$extra_args -X${METHOD}" + ;; + PUT | POST) + extra_args="$extra_args -d'{}' -X${METHOD}" + ;; + *) + return 1 + ;; + esac + + run curl -m 5 --no-keepalive -v -s -f $extra_args "$URL" + [ "$status" == 0 ] +} + +# must_fail_http_request allows you to craft a specific http request to assert +# that envoy will reject the request. Primarily of use for testing L7 +# intentions. +function must_fail_http_request { + local METHOD=$1 + local URL=$2 + local DEBUG_HEADER_VALUE="${3:-""}" + + local extra_args + if [[ -n "${DEBUG_HEADER_VALUE}" ]]; then + extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" + fi + case "$METHOD" in + HEAD) + extra_args="$extra_args -I" + ;; + GET) ;; + + DELETE) + extra_args="$extra_args -X${METHOD}" + ;; + PUT | POST) + extra_args="$extra_args -d'{}' -X${METHOD}" + ;; + *) + return 1 + ;; + esac + + # Attempt to curl through upstream + run curl -m 5 --no-keepalive -s -i $extra_args "$URL" + + echo "OUTPUT $output" + + echo "$output" | grep "403 Forbidden" +} + +function upsert_config_entry { + local DC="$1" + local BODY="$2" + + echo "$BODY" | docker_consul "$DC" consul config write - +} + +function gen_envoy_bootstrap { + SERVICE=$1 + ADMIN_PORT=$2 + DC=${3:-primary} + IS_GW=${4:-0} + EXTRA_ENVOY_BS_ARGS="${5-}" + ADMIN_HOST="0.0.0.0" + + PROXY_ID="$SERVICE" + if ! is_set "$IS_GW"; then + PROXY_ID="$SERVICE-sidecar-proxy" + ADMIN_HOST="127.0.0.1" + fi + + if output=$(docker_consul_for_proxy_bootstrap $DC "consul connect envoy -bootstrap \ + -proxy-id $PROXY_ID \ + -envoy-version "$ENVOY_VERSION" \ + -http-addr envoy_consul-${DC}_1:8500 \ + -grpc-addr envoy_consul-${DC}_1:8502 \ + -admin-access-log-path="C:/envoy/envoy.log" \ + -admin-bind $ADMIN_HOST:$ADMIN_PORT ${EXTRA_ENVOY_BS_ARGS} \ + > /c/workdir/${DC}/envoy/${SERVICE}-bootstrap.json"); then + + # All OK, write config to file + echo $output + #echo "$output" > /c/workdir/${DC}/envoy/$SERVICE-bootstrap.json + else + status=$? + # Command failed, instead of swallowing error (printed on stdout by docker + # it seems) by writing it to file, echo it + echo "$output" + #return $status + fi + + +} + +function read_config_entry { + local KIND=$1 + local NAME=$2 + local DC=${3:-primary} + get_consul_hostname $DC + docker_consul_exec "$DC" bash -c "consul config read -kind $KIND -name $NAME -http-addr=\"$CONSUL_HOSTNAME:8500\"" +} + +function wait_for_namespace { + local NS="${1}" + local DC=${2:-primary} + get_consul_hostname $DC + retry_default docker_consul_exec "$DC" bash -c "curl -sLf http://${CONSUL_HOSTNAME}:8500/v1/namespace/${NS} >/dev/null" +} + +function wait_for_config_entry { + retry_default read_config_entry "$@" +} + +function assert_config_entry_status { + local TYPE="$1" + local STATUS="$2" + local REASON="$3" + local DC="$4" + local KIND="$5" + local NAME="$6" + local NS=${7:-} + local AP=${8:-} + local PEER=${9:-} + + status=$(curl -s -f "consul-${DC}-client:8500/v1/config/${KIND}/${NAME}?passing&ns=${NS}&partition=${AP}&peer=${PEER}" | jq ".Status.Conditions[] | select(.Type == \"$TYPE\" and .Status == \"$STATUS\" and .Reason == \"$REASON\")") + [ -n "$status" ] +} + +function delete_config_entry { + local KIND=$1 + local NAME=$2 + get_consul_hostname primary + retry_default curl -sL -XDELETE "http://${CONSUL_HOSTNAME}:8500/v1/config/${KIND}/${NAME}" +} + +function register_services { + local DC=${1:-primary} + wait_for_leader "$DC" + docker_consul_exec ${DC} bash -c "consul services register workdir/${DC}/register/service_*.hcl" +} + +# wait_for_leader waits until a leader is elected. +# Its first argument must be the datacenter name. +function wait_for_leader { + get_consul_hostname primary + retry_default docker_consul_exec "$1" bash -c "[[ $(curl --fail -sS http://${CONSUL_HOSTNAME}:8500/v1/status/leader) ]]" +} + +function setup_upsert_l4_intention { + local SOURCE=$1 + local DESTINATION=$2 + local ACTION=$3 + get_consul_hostname primary + retry_default docker_consul_exec primary bash -c "curl -sL -X PUT -d '{\"Action\": \"${ACTION}\"}' 'http://${CONSUL_HOSTNAME}:8500/v1/connect/intentions/exact?source=${SOURCE}&destination=${DESTINATION}'" +} + +function upsert_l4_intention { + local SOURCE=$1 + local DESTINATION=$2 + local ACTION=$3 + get_consul_hostname primary + retry_default curl -sL -XPUT "http://${CONSUL_HOSTNAME}:8500/v1/connect/intentions/exact?source=${SOURCE}&destination=${DESTINATION}" \ + -d"{\"Action\": \"${ACTION}\"}" >/dev/null +} + +function get_ca_root { + get_consul_hostname primary + curl -s -f "http://${CONSUL_HOSTNAME}:8500/v1/connect/ca/roots" | jq -r ".Roots[0].RootCert" +} + +function wait_for_agent_service_register { + local SERVICE_ID=$1 + local DC=${2:-primary} + get_consul_hostname $DC + retry_default docker_consul_exec "$DC" bash -c "curl -sLf 'http://${CONSUL_HOSTNAME}:8500/v1/agent/service/${SERVICE_ID}' >/dev/null" +} + +function set_ttl_check_state { + local CHECK_ID=$1 + local CHECK_STATE=$2 + local DC=${3:-primary} + get_consul_hostname $DC + + case "$CHECK_STATE" in + pass) ;; + + warn) ;; + + fail) ;; + + *) + echo "invalid ttl check state '${CHECK_STATE}'" >&2 + return 1 + ;; + esac + + retry_default docker_consul_exec "$DC" bash -c "curl -sL -XPUT 'http://${CONSUL_HOSTNAME}:8500/v1/agent/check/warn/${CHECK_ID}' >/dev/null" +} + +function get_upstream_fortio_name { + local HOST=$1 + local PORT=$2 + local PREFIX=$3 + local DEBUG_HEADER_VALUE="${4:-""}" + local extra_args + if [[ -n "${DEBUG_HEADER_VALUE}" ]]; then + extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" + fi + # split proto if https:// is at the front of the host since the --resolve + # string needs just a bare host. + local PROTO="" + local CA_FILE="" + if [ "${HOST:0:8}" = "https://" ]; then + HOST="${HOST:8}" + PROTO="https://" + # Fix in the CA_FILE parameter: for Windows environments, the root path starts with "/c" + extra_args="${extra_args} --cacert /c/workdir/test-sds-server/certs/ca-root.crt" + fi + # We use --resolve instead of setting a Host header since we need the right + # name to be sent for SNI in some cases too. + run retry_default curl --ssl-revoke-best-effort -v -s -f --resolve "${HOST}:${PORT}:127.0.0.1" $extra_args \ + "${PROTO}${HOST}:${PORT}${PREFIX}/debug?env=dump" + + # Useful Debugging but breaks the expectation that the value output is just + # the grep output when things don't fail + if [ "$status" != 0 ]; then + echo "GOT FORTIO OUTPUT: $output" + fi + [ "$status" == 0 ] + echo "$output" | grep -E "^FORTIO_NAME=" +} + +function get_upstream_endpoint_port { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local PORT_VALUE=$3 + run curl -s -f "http://${HOSTPORT}/clusters?format=json" + [ "$status" -eq 0 ] + echo "$output" | jq --raw-output " +.cluster_statuses[] +| select(.name|startswith(\"${CLUSTER_NAME}\")) +| [.host_statuses[].address.socket_address.port_value] +| [select(.[] == ${PORT_VALUE})] +| length" +} + +function assert_upstream_has_endpoint_port_once { + local HOSTPORT=$1 + local CLUSTER_NAME=$2 + local PORT_VALUE=$3 + + GOT_COUNT=$(get_upstream_endpoint_port $HOSTPORT $CLUSTER_NAME $PORT_VALUE) + + [ "$GOT_COUNT" -eq 1 ] +} + +function assert_expected_fortio_name { + local EXPECT_NAME=$1 + local HOST=${2:-"localhost"} + local PORT=${3:-5000} + local URL_PREFIX=${4:-""} + local DEBUG_HEADER_VALUE="${5:-""}" + + run get_upstream_fortio_name ${HOST} ${PORT} "${URL_PREFIX}" "${DEBUG_HEADER_VALUE}" + + echo "GOT: $output" + + [ "$status" == 0 ] + [ "$output" == "FORTIO_NAME=${EXPECT_NAME}" ] +} + +function assert_expected_fortio_name_pattern { + local EXPECT_NAME_PATTERN=$1 + local HOST=${2:-"localhost"} + local PORT=${3:-5000} + local URL_PREFIX=${4:-""} + local DEBUG_HEADER_VALUE="${5:-""}" + + GOT=$(get_upstream_fortio_name ${HOST} ${PORT} "${URL_PREFIX}" "${DEBUG_HEADER_VALUE}") + + if [[ "$GOT" =~ $EXPECT_NAME_PATTERN ]]; then + : + else + echo "expected name pattern: $EXPECT_NAME_PATTERN, actual name: $GOT" 1>&2 + return 1 + fi +} + +function get_upstream_fortio_host_header { + local HOST=$1 + local PORT=$2 + local PREFIX=$3 + local DEBUG_HEADER_VALUE="${4:-""}" + local extra_args + if [[ -n "${DEBUG_HEADER_VALUE}" ]]; then + extra_args="-H x-test-debug:${DEBUG_HEADER_VALUE}" + fi + run retry_default curl -v -s -f -H"Host: ${HOST}" $extra_args \ + "localhost:${PORT}${PREFIX}/debug" + [ "$status" == 0 ] + echo "$output" | grep -E "^Host: " +} + +function assert_expected_fortio_host_header { + local EXPECT_HOST=$1 + local HOST=${2:-"localhost"} + local PORT=${3:-5000} + local URL_PREFIX=${4:-""} + local DEBUG_HEADER_VALUE="${5:-""}" + + GOT=$(get_upstream_fortio_host_header ${HOST} ${PORT} "${URL_PREFIX}" "${DEBUG_HEADER_VALUE}") + + if [ "$GOT" != "Host: ${EXPECT_HOST}" ]; then + echo "expected Host header: $EXPECT_HOST, actual Host header: $GOT" 1>&2 + return 1 + fi +} + +function create_peering { + local GENERATE_PEER=$1 + local ESTABLISH_PEER=$2 + run curl -m 5 -sL -XPOST "http://consul-${GENERATE_PEER}-client:8500/v1/peering/token" -d"{ \"PeerName\" : \"${GENERATE_PEER}-to-${ESTABLISH_PEER}\" }" + # echo "$output" >&3 + [ "$status" == 0 ] + + local token + token="$(echo "$output" | jq -r .PeeringToken)" + [ -n "$token" ] + + run curl -m 5 -sLv -XPOST "http://consul-${ESTABLISH_PEER}-client:8500/v1/peering/establish" -d"{ \"PeerName\" : \"${ESTABLISH_PEER}-to-${GENERATE_PEER}\", \"PeeringToken\" : \"${token}\" }" + # echo "$output" >&3 + [ "$status" == 0 ] +} + +function assert_service_has_imported { + local DC=${1:-primary} + local SERVICE_NAME=$2 + local PEER_NAME=$3 + + run curl -s -f "http://consul-${DC}-client:8500/v1/peering/${PEER_NAME}" + [ "$status" == 0 ] + + echo "$output" | jq --raw-output '.StreamStatus.ImportedServices' | grep -e "${SERVICE_NAME}" + if [ $? -ne 0 ]; then + echo "Error finding service: ${SERVICE_NAME}" + return 1 + fi +} + +function get_lambda_envoy_http_filter { + local HOSTPORT=$1 + local NAME_PREFIX=$2 + run retry_default curl -s -f $HOSTPORT/config_dump + [ "$status" -eq 0 ] + # get the full http filter object so the individual fields can be validated. + echo "$output" | jq --raw-output ".configs[2].dynamic_listeners[] | .active_state.listener.filter_chains[].filters[] | select(.name == \"envoy.filters.network.http_connection_manager\") | .typed_config.http_filters[] | select(.name == \"envoy.filters.http.aws_lambda\") | .typed_config" +} + +function register_lambdas { + local DC=${1:-primary} + # register lambdas to the catalog + for f in $(find workdir/${DC}/register -type f -name 'lambda_*.json'); do + retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/catalog/register" >/dev/null && \ + echo "Registered Lambda: $(jq -r .Service.Service $f)" + done + # write service-defaults config entries for lambdas + for f in $(find workdir/${DC}/register -type f -name 'service_defaults_*.json'); do + varsub ${f} AWS_LAMBDA_REGION AWS_LAMBDA_ARN + retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/config" >/dev/null && \ + echo "Wrote config: $(jq -r '.Kind + " / " + .Name' $f)" + done +} + +function assert_lambda_envoy_dynamic_cluster_exists { + local HOSTPORT=$1 + local NAME_PREFIX=$2 + + local BODY=$(get_envoy_dynamic_cluster_once $HOSTPORT $NAME_PREFIX) + [ -n "$BODY" ] + + [ "$(echo $BODY | jq -r '.cluster.transport_socket.typed_config.sni')" == '*.amazonaws.com' ] +} + +function assert_lambda_envoy_dynamic_http_filter_exists { + local HOSTPORT=$1 + local NAME_PREFIX=$2 + local ARN=$3 + + local FILTER=$(get_lambda_envoy_http_filter $HOSTPORT $NAME_PREFIX) + [ -n "$FILTER" ] + + [ "$(echo $FILTER | jq -r '.arn')" == "$ARN" ] +} + +function varsub { + local file=$1 + shift + for v in "$@"; do + sed -i "s/\${$v}/${!v}/g" $file + done +} + +function get_url_header { + local URL=$1 + local HEADER=$2 + run curl -s -f -X GET -I "${URL}" + [ "$status" == 0 ] + RESP=$(echo "$output" | tr -d '\r') + RESP=$(echo "$RESP" | grep -E "^${HEADER}: ") + RESP=$(echo "$RESP" | sed "s/^${HEADER}: //g") + echo "$RESP" +} + +function assert_url_header { + local URL=$1 + local HEADER=$2 + local VALUE=$3 + run get_url_header "$URL" "$HEADER" + [ "$status" == 0 ] + [ "$VALUE" = "$output" ] +} + +# assert_upstream_message asserts both the returned code +# and message from upstream service +function assert_upstream_message { + local HOSTPORT=$1 + run curl -s -d hello localhost:$HOSTPORT + + if [ "$status" -ne 0 ]; then + echo "Command failed" + return 1 + fi + + if (echo $output | grep 'hello'); then + return 0 + fi + + echo "expected message not found in $output" + return 1 +} \ No newline at end of file diff --git a/test/integration/connect/envoy/main_test.go b/test/integration/connect/envoy/main_test.go index b81a72e37d..a035280553 100644 --- a/test/integration/connect/envoy/main_test.go +++ b/test/integration/connect/envoy/main_test.go @@ -7,6 +7,9 @@ package envoy import ( + "flag" + "io/ioutil" + "log" "os" "os/exec" "sort" @@ -16,11 +19,23 @@ import ( "github.com/stretchr/testify/require" ) +var ( + flagWin = flag.Bool("win", false, "Execute tests on windows") +) + func TestEnvoy(t *testing.T) { + flag.Parse() + + if *flagWin == true { + dir := "../../../" + check_dir_files(dir) + } + testcases, err := discoverCases() require.NoError(t, err) runCmd(t, "suite_setup") + defer runCmd(t, "suite_teardown") for _, tc := range testcases { @@ -40,7 +55,8 @@ func TestEnvoy(t *testing.T) { } } -func runCmd(t *testing.T, c string, env ...string) { + +func runCmdLinux(t *testing.T, c string, env ...string) { t.Helper() cmd := exec.Command("./run-tests.sh", c) @@ -52,6 +68,34 @@ func runCmd(t *testing.T, c string, env ...string) { } } +func runCmdWindows(t *testing.T, c string, env ...string) { + t.Helper() + + param_5 := "false" + if env != nil { + param_5 = strings.Join(env, " ") + } + + cmd := exec.Command("cmd", "/C", "bash run-tests.windows.sh", c, param_5) + cmd.Env = append(os.Environ(), env...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + t.Fatalf("command failed: %v", err) + } +} + +func runCmd(t *testing.T, c string, env ...string) { + t.Helper() + + if *flagWin == true { + runCmdWindows(t, c, env...) + + } else { + runCmdLinux(t, c, env...) + } +} + // Discover the cases so we pick up both oss and ent copies. func discoverCases() ([]string, error) { cwd, err := os.Getwd() @@ -74,3 +118,57 @@ func discoverCases() ([]string, error) { sort.Strings(out) return out, nil } + +// CRLF convert functions +// Recursively iterates through the directory passed by parameter looking for the sh and bash files. +// Upon finding them, it calls crlf_file_check. +func check_dir_files(path string) { + files, err := ioutil.ReadDir(path) + if err != nil { + log.Fatal(err) + } + for _, fil := range files { + + v := strings.Split(fil.Name(), ".") + file_extension := v[len(v)-1] + + file_path := path + "/" + fil.Name() + + if fil.IsDir() == true { + check_dir_files(file_path) + } + + if file_extension == "sh" || file_extension == "bash" { + crlf_file_check(file_path) + } + } +} + +// Check if a file contains CRLF line endings if so call crlf_normalize +func crlf_file_check(file_name string) { + + file, err := ioutil.ReadFile(file_name) + text := string(file) + + if edit := crlf_verify(text); edit != -1 { + crlf_normalize(file_name, text) + } + + if err != nil { + log.Fatal(err) + } +} + +// Checks for the existence of CRLF line endings. +func crlf_verify(text string) int { + position := strings.Index(text, "\r\n") + return position +} + +// Replace CRLF line endings with LF. +func crlf_normalize(filename, text string) { + text = strings.Replace(text, "\r\n", "\n", -1) + data := []byte(text) + + ioutil.WriteFile(filename, data, 0644) +} diff --git a/test/integration/connect/envoy/run-tests.windows.sh b/test/integration/connect/envoy/run-tests.windows.sh new file mode 100644 index 0000000000..2388bcd5b6 --- /dev/null +++ b/test/integration/connect/envoy/run-tests.windows.sh @@ -0,0 +1,908 @@ +#!/usr/bin/env bash + +if [ $2 != "false" ] +then + export $2 +fi + +readonly self_name="$0" + +readonly HASHICORP_DOCKER_PROXY="docker.mirror.hashicorp.services" + +readonly SINGLE_CONTAINER_BASE_NAME=envoy_consul + +# DEBUG=1 enables set -x for this script so echos every command run +DEBUG=${DEBUG:-} + +XDS_TARGET=${XDS_TARGET:-server} + +# ENVOY_VERSION to run each test against +ENVOY_VERSION=${ENVOY_VERSION:-"1.23.1"} +export ENVOY_VERSION + +export DOCKER_BUILDKIT=0 + +if [ ! -z "$DEBUG" ] ; then + set -x +fi + +source helpers.windows.bash + +function command_error { + echo "ERR: command exited with status $1" 1>&2 + echo " command: $2" 1>&2 + echo " line: $3" 1>&2 + echo " function: $4" 1>&2 + echo " called at: $5" 1>&2 + # printf '%s\n' "${FUNCNAME[@]}" + # printf '%s\n' "${BASH_SOURCE[@]}" + # printf '%s\n' "${BASH_LINENO[@]}" +} + +trap 'command_error $? "${BASH_COMMAND}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_SOURCE[0]}:${BASH_LINENO[0]}"' ERR + +readonly WORKDIR_SNIPPET="-v envoy_workdir:C:\workdir" + +function network_snippet { + local DC="$1" + echo "--net=envoy-tests" +} + +function aws_snippet { + LAMBDA_TESTS_ENABLED=${LAMBDA_TESTS_ENABLED:-false} + if [ "$LAMBDA_TESTS_ENABLED" != false ]; then + local snippet="" + + # The Lambda integration cases assume that a Lambda function exists in $AWS_REGION with an ARN of $AWS_LAMBDA_ARN. + # The AWS credentials must have permission to invoke the Lambda function. + [ -n "$(set | grep '^AWS_ACCESS_KEY_ID=')" ] && snippet="${snippet} -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" + [ -n "$(set | grep '^AWS_SECRET_ACCESS_KEY=')" ] && snippet="${snippet} -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" + [ -n "$(set | grep '^AWS_SESSION_TOKEN=')" ] && snippet="${snippet} -e AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN" + [ -n "$(set | grep '^AWS_LAMBDA_REGION=')" ] && snippet="${snippet} -e AWS_LAMBDA_REGION=$AWS_LAMBDA_REGION" + [ -n "$(set | grep '^AWS_LAMBDA_ARN=')" ] && snippet="${snippet} -e AWS_LAMBDA_ARN=$AWS_LAMBDA_ARN" + + echo "$snippet" + fi +} + +function init_workdir { + local CLUSTER="$1" + + if test -z "$CLUSTER" + then + CLUSTER=primary + fi + + # Note, we use explicit set of dirs so we don't delete .gitignore. Also, + # don't wipe logs between runs as they are already split and we need them to + # upload as artifacts later. + rm -rf workdir/${CLUSTER} + rm -rf workdir/logs + mkdir -p workdir/${CLUSTER}/{consul,consul-server,register,envoy,bats,statsd,data} + + # Reload consul config from defaults + cp consul-base-cfg/*.hcl workdir/${CLUSTER}/consul/ + + # Add any overrides if there are any (no op if not) + find ${CASE_DIR} -maxdepth 1 -name '*.hcl' -type f -exec cp -f {} workdir/${CLUSTER}/consul \; + + # Copy all the test files + find ${CASE_DIR} -maxdepth 1 -name '*.bats' -type f -exec cp -f {} workdir/${CLUSTER}/bats \; + # Copy CLUSTER specific bats + cp helpers.windows.bash workdir/${CLUSTER}/bats/helpers.bash + + # Add any CLUSTER overrides + if test -d "${CASE_DIR}/${CLUSTER}" + then + find ${CASE_DIR}/${CLUSTER} -type f -name '*.hcl' -exec cp -f {} workdir/${CLUSTER}/consul \; + find ${CASE_DIR}/${CLUSTER} -type f -name '*.bats' -exec cp -f {} workdir/${CLUSTER}/bats \; + fi + + # move all of the registration files OUT of the consul config dir now + find workdir/${CLUSTER}/consul -type f -name 'service_*.hcl' -exec mv -f {} workdir/${CLUSTER}/register \; + + # move the server.hcl out of the consul dir so that it doesn't get picked up + # by the client agent (if we're running with XDS_TARGET=client). + if test -f "workdir/${CLUSTER}/consul/server.hcl" + then + mv workdir/${CLUSTER}/consul/server.hcl workdir/${CLUSTER}/consul-server/server.hcl + fi + + # copy the ca-certs for SDS so we can verify the right ones are served + mkdir -p workdir/test-sds-server/certs + cp test-sds-server/certs/ca-root.crt workdir/test-sds-server/certs/ca-root.crt + + if test -d "${CASE_DIR}/data" + then + cp -r ${CASE_DIR}/data/* workdir/${CLUSTER}/data + fi + + return 0 +} + +function docker_kill_rm { + local name + local todo=() + for name in "$@"; do + name="envoy_${name}_1" + if docker.exe container inspect $name &>/dev/null; then + if [[ "$name" == envoy_tcpdump-* ]]; then + echo -n "Gracefully stopping $name..." + docker.exe stop $name &> /dev/null + echo "done" + fi + todo+=($name) + fi + done + + if [[ ${#todo[@]} -eq 0 ]]; then + return 0 + fi + + echo -n "Killing and removing: ${todo[@]}..." + docker.exe rm -v -f ${todo[@]} &> /dev/null + echo "done" +} + +function start_consul { + local DC=${1:-primary} + + # 8500/8502 are for consul + # 9411 is for zipkin which shares the network with consul + # 16686 is for jaeger ui which also shares the network with consul + ports=( + '-p=8500:8500' + '-p=8502:8502' + '-p=9411:9411' + '-p=16686:16686' + ) + case "$DC" in + secondary) + ports=( + '-p=9500:8500' + '-p=9502:8502' + ) + ;; + alpha) + ports=( + '-p=9510:8500' + '-p=9512:8502' + ) + ;; + esac + + license="${CONSUL_LICENSE:-}" + # load the consul license so we can pass it into the consul + # containers as an env var in the case that this is a consul + # enterprise test + if test -z "$license" -a -n "${CONSUL_LICENSE_PATH:-}" + then + license=$(cat $CONSUL_LICENSE_PATH) + fi + + # We currently run these integration tests in two modes: one in which Envoy's + # xDS sessions are served directly by a Consul server, and another in which it + # goes through a client agent. + # + # This is necessary because servers and clients source configuration data in + # different ways (client agents use an RPC-backed cache and servers use their + # own local data) and we want to catch regressions in both. + # + # In the future we should also expand these tests to register services to the + # catalog directly (agentless) rather than relying on the server also being + # an agent. + # + # When XDS_TARGET=client we'll start a Consul server with its gRPC port + # disabled (but only if REQUIRE_PEERS is not set), and a client agent with + # its gRPC port enabled. + # + # When XDS_TARGET=server (or anything else) we'll run a single Consul server + # with its gRPC port enabled. + # + # In either case, the hostname `consul-${DC}-server` should be used as a + # server address (e.g. for WAN joining) and `consul-${DC}-client` should be + # used as a client address (e.g. for interacting with the HTTP API). + # + # Both hostnames work in both modes because we set network aliases on the + # containers such that both hostnames will resolve to the same container when + # XDS_TARGET=server. + # + # We also join containers to the network `container:consul-${DC}_1` in many + # places (see: network_snippet) so that we can curl localhost etc. In both + # modes, you can assume that this name refers to the client's container. + # + # Any .hcl files in the case/cluster directory will be given to both clients + # and servers (via the -config-dir flag) *except for* server.hcl which will + # only be applied to the server (and service registrations which will be made + # against the client). + if [[ "$XDS_TARGET" == "client" ]] + then + docker_kill_rm consul-${DC}-server + docker_kill_rm consul-${DC} + + server_grpc_port="-1" + if is_set $REQUIRE_PEERS; then + server_grpc_port="8502" + fi + + docker.exe run -d --name envoy_consul-${DC}-server_1 \ + --net=envoy-tests \ + $WORKDIR_SNIPPET \ + --hostname "consul-${DC}-server" \ + --network-alias "consul-${DC}-server" \ + -e "CONSUL_LICENSE=$license" \ + windows/consul:local \ + agent -dev -datacenter "${DC}" \ + -config-dir "C:\\workdir\\${DC}\\consul" \ + -config-dir "C:\\workdir\\${DC}\\consul-server" \ + -grpc-port $server_grpc_port \ + -client "0.0.0.0" \ + -bind "0.0.0.0" >/dev/null + + docker.exe run -d --name envoy_consul-${DC}_1 \ + --net=envoy-tests \ + $WORKDIR_SNIPPET \ + --hostname "consul-${DC}-client" \ + --network-alias "consul-${DC}-client" \ + -e "CONSUL_LICENSE=$license" \ + ${ports[@]} \ + windows/consul:local \ + agent -datacenter "${DC}" \ + -config-dir "C:\\workdir\\${DC}\\consul" \ + -data-dir "/tmp/consul" \ + -client "0.0.0.0" \ + -grpc-port 8502 \ + -datacenter "${DC}" \ + -retry-join "consul-${DC}-server" >/dev/null + else + docker_kill_rm consul-${DC} + + docker.exe run -d --name envoy_consul-${DC}_1 \ + --net=envoy-tests \ + $WORKDIR_SNIPPET \ + --memory 4096m \ + --cpus 2 \ + --hostname "consul-${DC}" \ + --network-alias "consul-${DC}-client" \ + --network-alias "consul-${DC}-server" \ + -e "CONSUL_LICENSE=$license" \ + ${ports[@]} \ + windows/consul:local \ + agent -dev -datacenter "${DC}" \ + -config-dir "C:\\workdir\\${DC}\\consul" \ + -config-dir "C:\\workdir\\${DC}\\consul-server" \ + -client "0.0.0.0" >/dev/null + fi +} + +function start_partitioned_client { + local PARTITION=${1:-ap1} + + # Start consul now as setup script needs it up + docker_kill_rm consul-${PARTITION} + + license="${CONSUL_LICENSE:-}" + # load the consul license so we can pass it into the consul + # containers as an env var in the case that this is a consul + # enterprise test + if test -z "$license" -a -n "${CONSUL_LICENSE_PATH:-}" + then + license=$(cat $CONSUL_LICENSE_PATH) + fi + + sh -c "rm -rf /workdir/${PARTITION}/data" + + # Run consul and expose some ports to the host to make debugging locally a + # bit easier. + # + docker.exe run -d --name envoy_consul-${PARTITION}_1 \ + --net=envoy-tests \ + $WORKDIR_SNIPPET \ + --hostname "consul-${PARTITION}-client" \ + --network-alias "consul-${PARTITION}-client" \ + -e "CONSUL_LICENSE=$license" \ + windows/consul:local agent \ + -datacenter "primary" \ + -retry-join "consul-primary-server" \ + -grpc-port 8502 \ + -data-dir "/tmp/consul" \ + -config-dir "C:\\workdir\\${PARTITION}/consul" \ + -client "0.0.0.0" >/dev/null +} + +function pre_service_setup { + local CLUSTER=${1:-primary} + + # Run test case setup (e.g. generating Envoy bootstrap, starting containers) + if [ -f "${CASE_DIR}/${CLUSTER}/setup.sh" ] + then + source ${CASE_DIR}/${CLUSTER}/setup.sh + else + source ${CASE_DIR}/setup.sh + fi +} + +function start_services { + # Start containers required + if [ ! -z "$REQUIRED_SERVICES" ] ; then + docker_kill_rm $REQUIRED_SERVICES + run_containers $REQUIRED_SERVICES + fi + + return 0 +} + +function verify { + local CLUSTER="$1" + if test -z "$CLUSTER"; then + CLUSTER="primary" + fi + + # Execute tests + res=0 + + # Nuke any previous case's verify container. + docker_kill_rm verify-${CLUSTER} + + echo "Running ${CLUSTER} verification step for ${CASE_DIR}..." + + # need to tell the PID 1 inside of the container that it won't be actual PID + # 1 because we're using --pid=host so we use TINI_SUBREAPER + if docker.exe exec -i ${SINGLE_CONTAINER_BASE_NAME}-${CLUSTER}_1 bash \ + -c "TINI_SUBREAPER=1 \ + ENVOY_VERSION=${ENVOY_VERSION} \ + XDS_TARGET=${XDS_TARGET} \ + /c/bats/bin/bats \ + --pretty /c/workdir/${CLUSTER}/bats" ; then + echo "✓ PASS" + else + echo "⨯ FAIL" + res=1 + fi + + return $res +} + +function capture_logs { + local LOG_DIR="workdir/logs/${CASE_DIR}/${ENVOY_VERSION}" + + init_vars + + echo "Capturing Logs" + mkdir -p "$LOG_DIR" + + services="$REQUIRED_SERVICES consul-primary" + if [[ "$XDS_TARGET" == "client" ]] + then + services="$services consul-primary-server" + fi + + if is_set $REQUIRE_SECONDARY + then + services="$services consul-secondary" + + if [[ "$XDS_TARGET" == "client" ]] + then + services="$services consul-secondary-server" + fi + fi + + if is_set $REQUIRE_PARTITIONS + then + services="$services consul-ap1" + fi + if is_set $REQUIRE_PEERS + then + services="$services consul-alpha" + + if [[ "$XDS_TARGET" == "client" ]] + then + services="$services consul-alpha-server" + fi + fi + + if [ -f "${CASE_DIR}/capture.sh" ] + then + echo "Executing ${CASE_DIR}/capture.sh" + source ${CASE_DIR}/capture.sh || true + fi + + for cont in $services; do + echo "Capturing log for $cont" + docker.exe logs "envoy_${cont}_1" &> "${LOG_DIR}/${cont}.log" || { + echo "EXIT CODE $?" > "${LOG_DIR}/${cont}.log" + } + done +} + +function stop_services { + # Teardown + docker_kill_rm $REQUIRED_SERVICES + + docker_kill_rm consul-primary consul-primary-server consul-secondary consul-secondary-server consul-ap1 consul-alpha consul-alpha-server +} + +function init_vars { + source "defaults.sh" + if [ -f "${CASE_DIR}/vars.sh" ] ; then + source "${CASE_DIR}/vars.sh" + fi +} + +function global_setup { + if [ -f "${CASE_DIR}/global-setup-windows.sh" ] ; then + source "${CASE_DIR}/global-setup-windows.sh" + fi +} + +function wipe_volumes { + docker.exe exec -w "C:\workdir" envoy_workdir_1 cmd /c "rd /s /q . 2>nul" +} + +# Windows containers does not allow cp command while running. +function stop_and_copy_files { + # Create CMD file to execute within the container + echo "icacls C:\workdir /grant:r Everyone:(OI)(CI)F /T" > copy.cmd + echo "XCOPY C:\workdir_bak C:\workdir /e /h /c /i /y" > copy.cmd + # Stop dummy container to copy local workdir to container's workdir_bak + docker.exe stop envoy_workdir_1 > /dev/null + docker.exe cp workdir/. envoy_workdir_1:/workdir_bak + # Copy CMD file into container + docker.exe cp copy.cmd envoy_workdir_1:/ + # Start dummy container and execute the CMD file + docker.exe start envoy_workdir_1 > /dev/null + docker.exe exec envoy_workdir_1 copy.cmd + # Delete local CMD file after execution + rm copy.cmd +} + +function run_tests { + CASE_DIR="${CASE_DIR?CASE_DIR must be set to the path of the test case}" + CASE_NAME=$( basename $CASE_DIR | cut -c6- ) + export CASE_NAME + export SKIP_CASE="" + + init_vars + + # Initialize the workdir + init_workdir primary + + if is_set $REQUIRE_SECONDARY + then + init_workdir secondary + fi + if is_set $REQUIRE_PARTITIONS + then + init_workdir ap1 + fi + if is_set $REQUIRE_PEERS + then + init_workdir alpha + fi + + global_setup + + # Allow vars.sh to set a reason to skip this test case based on the ENV + if [ "$SKIP_CASE" != "" ] ; then + echo "SKIPPING CASE: $SKIP_CASE" + return 0 + fi + + # Wipe state + wipe_volumes + + # Copying base files to shared volume + stop_and_copy_files + + # Starting Consul primary cluster + start_consul primary + + if is_set $REQUIRE_SECONDARY; then + start_consul secondary + fi + if is_set $REQUIRE_PARTITIONS; then + docker_consul "primary" consul partition create -name ap1 > /dev/null + start_partitioned_client ap1 + fi + if is_set $REQUIRE_PEERS; then + start_consul alpha + fi + + echo "Setting up the primary datacenter" + pre_service_setup primary + + if is_set $REQUIRE_SECONDARY; then + echo "Setting up the secondary datacenter" + pre_service_setup secondary + fi + if is_set $REQUIRE_PARTITIONS; then + echo "Setting up the non-default partition" + pre_service_setup ap1 + fi + if is_set $REQUIRE_PEERS; then + echo "Setting up the alpha peer" + pre_service_setup alpha + fi + + echo "Starting services" + start_services + + # Run the verify container and report on the output + echo "Verifying the primary datacenter" + verify primary + + if is_set $REQUIRE_SECONDARY; then + echo "Verifying the secondary datacenter" + verify secondary + fi + if is_set $REQUIRE_PEERS; then + echo "Verifying the alpha peer" + verify alpha + fi +} + +function test_teardown { + init_vars + + stop_services +} + +function workdir_cleanup { + docker_kill_rm workdir + docker.exe volume rm -f envoy_workdir &>/dev/null || true +} + + +function suite_setup { + # Cleanup from any previous unclean runs. + suite_teardown + + docker.exe network create -d "nat" envoy-tests &>/dev/null + + # Start the volume container + # + # This is a dummy container that we use to create volume and keep it + # accessible while other containers are down. + docker.exe volume create envoy_workdir &>/dev/null + docker.exe run -d --name envoy_workdir_1 \ + $WORKDIR_SNIPPET \ + --user ContainerAdministrator \ + --net=none \ + "${HASHICORP_DOCKER_PROXY}/windows/kubernetes/pause" &>/dev/null + + # pre-build the consul+envoy container + echo "Rebuilding 'windows/consul:local' image with envoy $ENVOY_VERSION..." + retry_default docker.exe build -t windows/consul:local \ + --build-arg ENVOY_VERSION=${ENVOY_VERSION} \ + -f Dockerfile-consul-envoy-windows . + + + local CONSUL_VERSION=$(docker image inspect --format='{{.ContainerConfig.Labels.version}}' \ + windows/consul:local) + echo "Running Tests with Consul=$CONSUL_VERSION - Envoy=$ENVOY_VERSION - XDS_TARGET=$XDS_TARGET" +} + +function suite_teardown { + docker_kill_rm verify-primary verify-secondary verify-alpha + + # this is some hilarious magic + docker_kill_rm $(grep "^function run_container_" $self_name | \ + sed 's/^function run_container_\(.*\) {/\1/g') + + docker_kill_rm consul-primary consul-primary-server consul-secondary consul-secondary-server consul-ap1 consul-alpha consul-alpha-server + + if docker.exe network inspect envoy-tests &>/dev/null ; then + echo -n "Deleting network 'envoy-tests'..." + docker.exe network rm envoy-tests + echo "done" + fi + + workdir_cleanup +} + +function run_containers { + for name in $@ ; do + run_container $name + done +} + +function run_container { + docker_kill_rm "$1" + "run_container_$1" +} + +function common_run_container_service { + local service="$1" + local CLUSTER="$2" + local httpPort="$3" + local grpcPort="$4" + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"$CLUSTER"_1 + + docker.exe exec -d $CONTAINER_NAME bash \ + -c "FORTIO_NAME=${service} \ + fortio.exe server \ + -http-port ":$httpPort" \ + -grpc-port ":$grpcPort" \ + -redirect-port disabled" +} + +function run_container_s1 { + common_run_container_service s1 primary 8080 8079 +} + +function run_container_s1-ap1 { + common_run_container_service s1 ap1 8080 8079 +} + +function run_container_s2 { + common_run_container_service s2 primary 8181 8179 +} +function run_container_s2-v1 { + common_run_container_service s2-v1 primary 8182 8178 +} +function run_container_s2-v2 { + common_run_container_service s2-v2 primary 8183 8177 +} + +function run_container_s3 { + common_run_container_service s3 primary 8282 8279 +} +function run_container_s3-v1 { + common_run_container_service s3-v1 primary 8283 8278 +} +function run_container_s3-v2 { + common_run_container_service s3-v2 primary 8284 8277 +} +function run_container_s3-alt { + common_run_container_service s3-alt primary 8286 8280 +} + +function run_container_s4 { + common_run_container_service s4 primary 8382 8281 +} + +function run_container_s1-secondary { + common_run_container_service s1-secondary secondary 8080 8079 +} + +function run_container_s2-secondary { + common_run_container_service s2-secondary secondary 8181 8179 +} + +function run_container_s2-ap1 { + common_run_container_service s2 ap1 8480 8479 +} + +function run_container_s3-ap1 { + common_run_container_service s3 ap1 8580 8579 +} + +function run_container_s1-alpha { + common_run_container_service s1-alpha alpha 8080 8079 +} + +function run_container_s2-alpha { + common_run_container_service s2-alpha alpha 8181 8179 +} + +function run_container_s3-alpha { + common_run_container_service s3-alpha alpha 8282 8279 +} + +function common_run_container_sidecar_proxy { + local service="$1" + local CLUSTER="$2" + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"$CLUSTER"_1 + + # Hot restart breaks since both envoys seem to interact with each other + # despite separate containers that don't share IPC namespace. Not quite + # sure how this happens but may be due to unix socket being in some shared + # location? + docker.exe exec -d $CONTAINER_NAME bash \ + -c "envoy.exe \ + -c /c/workdir/${CLUSTER}/envoy/${service}-bootstrap.json \ + -l trace \ + --disable-hot-restart \ + --drain-time-s 1 >/dev/null" +} + +function run_container_s1-sidecar-proxy { + common_run_container_sidecar_proxy s1 primary +} + +function run_container_s1-ap1-sidecar-proxy { + common_run_container_sidecar_proxy s1 ap1 +} + +function run_container_s1-sidecar-proxy-consul-exec { + local CLUSTER="primary" + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"$CLUSTER"_1 + local ADMIN_HOST="127.0.0.1" + local ADMIN_PORT="19000" + + docker.exe exec -d $CONTAINER_NAME bash \ + -c "consul connect envoy -sidecar-for s1 \ + -http-addr $CONTAINER_NAME:8500 \ + -grpc-addr $CONTAINER_NAME:8502 \ + -admin-bind $ADMIN_HOST:$ADMIN_PORT \ + -envoy-version ${ENVOY_VERSION} \ + -- \ + -l trace >/dev/null" +} + +function run_container_s2-sidecar-proxy { + common_run_container_sidecar_proxy s2 primary +} +function run_container_s2-v1-sidecar-proxy { + common_run_container_sidecar_proxy s2-v1 primary +} +function run_container_s2-v2-sidecar-proxy { + common_run_container_sidecar_proxy s2-v2 primary +} + +function run_container_s3-sidecar-proxy { + common_run_container_sidecar_proxy s3 primary +} +function run_container_s3-v1-sidecar-proxy { + common_run_container_sidecar_proxy s3-v1 primary +} +function run_container_s3-v2-sidecar-proxy { + common_run_container_sidecar_proxy s3-v2 primary +} + +function run_container_s3-alt-sidecar-proxy { + common_run_container_sidecar_proxy s3-alt primary +} + +function run_container_s1-sidecar-proxy-secondary { + common_run_container_sidecar_proxy s1 secondary +} +function run_container_s2-sidecar-proxy-secondary { + common_run_container_sidecar_proxy s2 secondary +} + +function run_container_s2-ap1-sidecar-proxy { + common_run_container_sidecar_proxy s2 ap1 +} + +function run_container_s3-ap1-sidecar-proxy { + common_run_container_sidecar_proxy s3 ap1 +} + +function run_container_s1-sidecar-proxy-alpha { + common_run_container_sidecar_proxy s1 alpha +} +function run_container_s2-sidecar-proxy-alpha { + common_run_container_sidecar_proxy s2 alpha +} +function run_container_s3-sidecar-proxy-alpha { + common_run_container_sidecar_proxy s3 alpha +} + +function common_run_container_gateway { + local name="$1" + local DC="$2" + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"$DC"_1 + + # Hot restart breaks since both envoys seem to interact with each other + # despite separate containers that don't share IPC namespace. Not quite + # sure how this happens but may be due to unix socket being in some shared + # location? + docker.exe exec -d $CONTAINER_NAME bash \ + -c "envoy.exe \ + -c /c/workdir/${DC}/envoy/${name}-bootstrap.json \ + -l trace \ + --disable-hot-restart \ + --drain-time-s 1 >/dev/null" +} + +function run_container_gateway-primary { + common_run_container_gateway mesh-gateway primary +} +function run_container_gateway-secondary { + common_run_container_gateway mesh-gateway secondary +} +function run_container_gateway-alpha { + common_run_container_gateway mesh-gateway alpha +} + +function run_container_ingress-gateway-primary { + common_run_container_gateway ingress-gateway primary +} + +function run_container_api-gateway-primary { + common_run_container_gateway api-gateway primary +} + +function run_container_terminating-gateway-primary { + common_run_container_gateway terminating-gateway primary +} + +function run_container_fake-statsd { + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"primary"_1 + # This magic SYSTEM incantation is needed since Envoy doesn't add newlines and so + # we need each packet to be passed to echo to add a new line before + # appending. But it does not work on Windows. + docker.exe exec -d $CONTAINER_NAME bash -c "socat -u UDP-RECVFROM:8125,fork,reuseaddr OPEN:/workdir/primary/statsd/statsd.log,create,append" +} + +function run_container_zipkin { + docker.exe run -d --name $(container_name) \ + $WORKDIR_SNIPPET \ + $(network_snippet primary) \ + "${HASHICORP_DOCKER_PROXY}/windows/openzipkin" +} + +function run_container_jaeger { + echo "Starting Jaeger service..." + + local DC=${1:-primary} + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"$DC"_1 + + docker.exe exec -d $CONTAINER_NAME bash -c "jaeger-all-in-one.exe \ + --collector.zipkin.http-port=9411" +} + +function run_container_test-sds-server { + echo "Starting test-sds-server" + + local DC=${1:-primary} + local CONTAINER_NAME="$SINGLE_CONTAINER_BASE_NAME"-"$DC"_1 + + docker.exe exec -d $CONTAINER_NAME bash -c "cd /c/test-sds-server && + ./test-sds-server.exe" +} + +function container_name { + echo "envoy_${FUNCNAME[1]/#run_container_/}_1" +} +function container_name_prev { + echo "envoy_${FUNCNAME[2]/#run_container_/}_1" +} + +# This is a debugging tool. Run via 'bash run-tests.sh debug_dump_volumes' on Powershell +function debug_dump_volumes { + local LINUX_PATH=$(pwd) + local WIN_PATH=$( echo "$LINUX_PATH" | sed 's/^\/mnt//' | sed -e 's/^\///' -e 's/\//\\/g' -e 's/^./\0:/' ) + docker.exe run -it \ + $WORKDIR_SNIPPET \ + -v "$WIN_PATH":"C:\\cwd" \ + --net=none \ + "${HASHICORP_DOCKER_PROXY}/windows/nanoserver:1809" \ + cmd /c "xcopy \workdir \cwd\workdir /E /H /C /I /Y" +} + +function run_container_tcpdump-primary { + # To use add "tcpdump-primary" to REQUIRED_SERVICES + common_run_container_tcpdump primary +} +function run_container_tcpdump-secondary { + # To use add "tcpdump-secondary" to REQUIRED_SERVICES + common_run_container_tcpdump secondary +} +function run_container_tcpdump-alpha { + # To use add "tcpdump-alpha" to REQUIRED_SERVICES + common_run_container_tcpdump alpha +} + +function common_run_container_tcpdump { + local DC="$1" + + # we cant run this in circle but its only here to temporarily enable. + +# docker.exe build --rm=false -t envoy-tcpdump -f Dockerfile-tcpdump-windows . + + docker.exe run -d --name $(container_name_prev) \ + $(network_snippet $DC) \ + envoy-tcpdump \ + -v -i any \ + -w "/data/${DC}.pcap" +} + +case "${1-}" in + "") + echo "command required" + exit 1 ;; + *) + "$@" ;; +esac diff --git a/test/integration/connect/envoy/windows-troubleshooting.md b/test/integration/connect/envoy/windows-troubleshooting.md new file mode 100644 index 0000000000..a3a83e0888 --- /dev/null +++ b/test/integration/connect/envoy/windows-troubleshooting.md @@ -0,0 +1,90 @@ +# Envoy Integration Tests on Windows + +## Index + +- [About this Guide](#about-this-guide) +- [Prerequisites](#prerequisites) +- [Running the Tests](#running-the-tests) +- [Troubleshooting](#troubleshooting) + - [About Envoy Integration Tests on Windows](#about-envoy-integration-tests-on-windows) + - [Common Errors](#common-errors) +- [Windows Scripts Changes](#windows-scripts-changes) +- [Volume Issues](#volume-issues) + +## About this Guide + +On this guide you will find all the information required to run the Envoy integration tests on Windows. + +## Prerequisites + +To run the integration tests yo will need to have the following installed on your System: + +- GO v1.18(or later). +- Gotestsum library [installation](https://pkg.go.dev/gotest.tools/gotestsum). +- Docker. + +Before running the tests, you will need to build the required Docker images, to do so, you can use the script provided [here](../../../../build-support-windows/build-images.sh): + +- Build Images Script Execution + - From a Bash console (GitBash or WSL) execute: `./build-images.sh` + +## Running the Tests + +To execute the tests you need to run the following command depending on the shell you are using: +**On Powershell**: +`go test -v -timeout=30m -tags integration ./test/integration/connect/envoy -run="TestEnvoy/" -win=true` +Where **TEST CASE** is the individual test case we want to execute (e.g. case-badauthz). + +**On Git Bash**: +`ENVOY_VERSION= go test -v -timeout=30m -tags integration ./test/integration/connect/envoy -run="TestEnvoy/" -win=true` +Where **TEST CASE** is the individual test case we want to execute (e.g. case-badauthz), and **ENVOY VERSION** is the version which you are currently testing. + +> [!TIP] +> When executing the integration tests using **Powershell** you may need to set the ENVOY_VERSION value manually in line 20 of the [run-tests.windows.sh](run-tests.windows.sh) file. + +> [!WARNING] +> When executing the integration tests for Windows environments, the **End of Line Sequence** of every related file and/or script will be changed from **LF** to **CRLF**. + +### About Envoy Integration Tests on Windows + +Integration tests on Linux run a multi-container architecture that take advantage of the Host Network Docker feature, using this feature means that the container's network stack is not isolated from the Docker host (the container shares the host’s networking namespace), and the container does not get its own IP-address allocated (read more about this [here](https://docs.docker.com/network/host/)). This feature is only available for Linux, which made migrating the tests to Windows challenging, since replicating the same architecture created more issues, that's why a **single container** architecture was chosen to run the Envoy integration tests. +Using a single container architecture meant that we could use the same tests as on linux, moreover we were able to speed-up their execution by replacing *docker run* commands which started utility containers, for *docker exec* commands. + +### Common errors + +If the tests are executed without docker running, the following error will be seen: + +```powershell +error during connect: This error may indicate that the docker daemon is not running.: Post "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/build?buildargs=%7B%7D&cachefrom=%5B%5D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile-bats-windows&labels=%7B%7D&memory=0&memswap=0&networkmode=default&rm=1&shmsize=0&t=bats-verify&target=&ulimits=null&version=1": open //./pipe/docker_engine: The system cannot find the file specified. +``` + +If any of the docker images does not exist or is mistagged, an error similar to the following will be displayed: + +```powershell +Error response from daemon: No such container: envoy_workdir_1 +``` + +If you run the Windows tests from WSL you will get the following error message: + +```bash +main_test.go:34: command failed: exec: "cmd": executable file not found in $PATH +``` + +## Windows Scripts Changes + +- The "http-addr", "grpc-addr" and "admin-access-log-path" flags were added to the creation of the Envoy Bootstrap files. +- To execute commands sh was replaced by bash on our Windows container. +- All paths were updated to use Windows format. +- Created *stop_and_copy_files* function to copy files into the shared volume (see [volume issues](#volume-issues)). +- Changed the *-admin-bind* value from `0.0.0.0` to `127.0.0.1` when generating the Envoy Bootstrap files. +- Removed the *&&* from the *common_run_container_service's* docker exec command and replaced it with *\*. +- Removed *docker_wget* and *docker_curl* functions from [helpers.windows.bash](helpers.windows.bash) file and replaced them with **docker_consul_exec**, this way we avoid starting intermediate containers when capturing logs. +- The function *wipe_volumes* uses a `docker exec` command instead of the original `docker run`, this way we speed up test execution by avoiding to start a new container just to delete volume content before each test run. +- For **case-grpc** we increased the `envoy_stats_flush_interval` value from 1s to 5s, on Windows, the original value caused the test to pass or fail randomly. +- For **case-wanfed-gw** a new script was created: **global-setup-windows.sh**, this file replaces global-setup.sh when running this test in Windows. The new script uses the windows/consul:local Docker image to generate the required TLS files and copies them into host's workdir directory. +- To use the **debug_dump_volumes** function, you need to use it via Powershell and execute the following command: `bash run-tests.windows.sh debug_dump_volumes` Make sure to be positioned with your terminal in the correct directory. +- For **case-consul-exec** this case can only be run when using the consul-dev Docker image on this repository, since it relies on features implemented only here. These features are: Windows valid default value for "-admin-access-log-path" and `consul connect envoy` command starts Envoy. This features have also been submitted in [PR#15114](https://github.com/hashicorp/consul/pull/15114). + +## Volume Issues + +Another difference that arose when migrating the tests from Linux to Windows, is that file system operations can't be executed while Windows containers are running. Currently, when running the tests a **named volume** is created and all of the required files are copied into that volume. Because of the constraint mentioned before, the workaround we implemented was creating a function (**stop_and_copy_files**) that stops the *kubernetes/pause* container and executes a script to copy the required files and finally starts the container again.