From eca8b0277d7ed3cbaabefc5185ccb350ca3dcdbc Mon Sep 17 00:00:00 2001 From: Dan Bond Date: Tue, 21 Mar 2023 10:37:32 -0700 Subject: [PATCH 01/17] [NET-3029] Migrate build-distros to GHA (#16669) * migrate build distros to GHA Signed-off-by: Dan Bond * build-arm Signed-off-by: Dan Bond * don't use matrix Signed-off-by: Dan Bond * check-go-mod Signed-off-by: Dan Bond * add notify slack script Signed-off-by: Dan Bond * notify slack if failure Signed-off-by: Dan Bond * rm notify slack script Signed-off-by: Dan Bond * fix check-go-mod job Signed-off-by: Dan Bond --------- Signed-off-by: Dan Bond --- .github/workflows/build-distros.yml | 75 +++++++++++++++++++++++++++++ .github/workflows/build.yml | 46 +++++++++--------- 2 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/build-distros.yml diff --git a/.github/workflows/build-distros.yml b/.github/workflows/build-distros.yml new file mode 100644 index 000000000000..87d6f9605442 --- /dev/null +++ b/.github/workflows/build-distros.yml @@ -0,0 +1,75 @@ +# NOTE: this workflow builds Consul binaries on multiple architectures for PRs. +# It is aimed at checking new commits don't introduce any breaking build changes. +name: build-distros + +on: [pull_request] + +permissions: + contents: read + +jobs: + check-go-mod: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: go mod tidy + - run: | + if [[ -n $(git status -s) ]]; then + echo "Git directory has changes" + git status -s + exit 1 + fi + + build-386: + needs: check-go-mod + env: + XC_OS: "freebsd linux windows" + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - name: Build + run: | + for os in $XC_OS; do + GOOS="$os" GOARCH=386 CGO_ENABLED=0 go build + done + + build-amd64: + needs: check-go-mod + env: + XC_OS: "darwin freebsd linux solaris windows" + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - name: Build + run: | + for os in $XC_OS; do + GOOS="$os" GOARCH=amd64 CGO_ENABLED=0 go build + done + + build-arm: + needs: check-go-mod + runs-on: ubuntu-22.04 + env: + CGO_ENABLED: 1 + GOOS: linux + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v3.5.0 + with: + go-version-file: 'go.mod' + - run: | + sudo rm -fv /etc/apt/sources.list.d/github_git-lfs.list # workaround for https://github.com/actions/runner-images/issues/1983 + sudo apt-get update --allow-releaseinfo-change-suite --allow-releaseinfo-change-version && sudo apt-get install -y gcc-arm-linux-gnueabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu + + - run: CC=arm-linux-gnueabi-gcc GOARCH=arm GOARM=5 go build + - run: CC=arm-linux-gnueabihf-gcc GOARCH=arm GOARM=6 go build + - run: CC=aarch64-linux-gnu-gcc GOARCH=arm64 go build diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b0c1dbbd82da..b6ec5c03cfdf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: pre-version: ${{ steps.set-product-version.outputs.prerelease-product-version }} shared-ldflags: ${{ steps.shared-ldflags.outputs.shared-ldflags }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: set product version id: set-product-version uses: hashicorp/actions-set-product-version@v1 @@ -60,7 +60,7 @@ jobs: filepath: ${{ steps.generate-metadata-file.outputs.filepath }} steps: - name: 'Checkout directory' - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Generate metadata file id: generate-metadata-file uses: hashicorp/actions-generate-metadata@v1 @@ -68,7 +68,7 @@ jobs: version: ${{ needs.set-product-version.outputs.product-version }} product: ${{ env.PKG_NAME }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@3.1.2 with: name: metadata.json path: ${{ steps.generate-metadata-file.outputs.filepath }} @@ -92,10 +92,10 @@ jobs: name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Setup with node and yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # pin@v3.6.0 with: node-version: '14' cache: 'yarn' @@ -157,13 +157,13 @@ jobs: echo "RPM_PACKAGE=$(basename out/*.rpm)" >> $GITHUB_ENV echo "DEB_PACKAGE=$(basename out/*.deb)" >> $GITHUB_ENV - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@3.1.2 if: ${{ matrix.goos == 'linux' }} with: name: ${{ env.RPM_PACKAGE }} path: out/${{ env.RPM_PACKAGE }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # pin@3.1.2 if: ${{ matrix.goos == 'linux' }} with: name: ${{ env.DEB_PACKAGE }} @@ -181,10 +181,10 @@ jobs: name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Setup with node and yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # pin@v3.6.0 with: node-version: '14' cache: 'yarn' @@ -232,7 +232,7 @@ jobs: version: ${{needs.set-product-version.outputs.product-version}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 # Strip everything but MAJOR.MINOR from the version string and add a `-dev` suffix # This naming convention will be used ONLY for per-commit dev images @@ -266,7 +266,7 @@ jobs: version: ${{needs.set-product-version.outputs.product-version}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - uses: hashicorp/actions-docker-build@v1 with: version: ${{env.version}} @@ -286,7 +286,7 @@ jobs: version: ${{needs.set-product-version.outputs.product-version}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 # Strip everything but MAJOR.MINOR from the version string and add a `-dev` suffix # This naming convention will be used ONLY for per-commit dev images @@ -323,15 +323,15 @@ jobs: name: Verify ${{ matrix.arch }} linux binary steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Download ${{ matrix.arch }} zip - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.zip_name }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # pin@v2.1.0 if: ${{ matrix.arch == 'arm' || matrix.arch == 'arm64' }} with: # this should be a comma-separated string as opposed to an array @@ -353,10 +353,10 @@ jobs: name: Verify amd64 darwin binary steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Download amd64 darwin zip - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.zip_name }} @@ -380,7 +380,7 @@ jobs: name: Verify ${{ matrix.arch }} debian package steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Set package version run: | @@ -391,12 +391,12 @@ jobs: echo "pkg_name=consul_${{ env.pkg_version }}-1_${{ matrix.arch }}.deb" >> $GITHUB_ENV - name: Download workflow artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.pkg_name }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # pin@v2.1.0 with: platforms: all @@ -417,7 +417,7 @@ jobs: name: Verify ${{ matrix.arch }} rpm steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Set package version run: | @@ -428,12 +428,12 @@ jobs: echo "pkg_name=consul-${{ env.pkg_version }}-1.${{ matrix.arch }}.rpm" >> $GITHUB_ENV - name: Download workflow artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # pin@v3.0.2 with: name: ${{ env.pkg_name }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # pin@v2.1.0 with: platforms: all From 93a3a76de70d290924ef5bfa7d794c65e4c5242e Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Tue, 21 Mar 2023 10:44:02 -0700 Subject: [PATCH 02/17] Update envoy extension docs, service-defaults, add multi-config example for lua (#16710) --- .../config-entries/service-defaults.mdx | 38 +++++++++- .../proxies/envoy-extensions/usage/lua.mdx | 69 +++++++++++++++---- 2 files changed, 92 insertions(+), 15 deletions(-) diff --git a/website/content/docs/connect/config-entries/service-defaults.mdx b/website/content/docs/connect/config-entries/service-defaults.mdx index f14b0c63e643..e1e15cf7acb2 100644 --- a/website/content/docs/connect/config-entries/service-defaults.mdx +++ b/website/content/docs/connect/config-entries/service-defaults.mdx @@ -57,6 +57,10 @@ The following outline shows how to format the service splitter configuration ent - [`TransparentProxy`](#transparentproxy): map | no default - [`OutboundListenerPort`](#transparentproxy): integer | `15001` - [`DialedDirectly`](#transparentproxy ): boolean | `false` +- [`EnvoyExtensions`](#envoyextensions): list | no default + - [`Name`](#envoyextensions): string | `""` + - [`Required`](#envoyextensions): string | `""` + - [`Arguments`](#envoyextensions): map | `nil` - [`Destination`](#destination): map | no default - [`Addresses`](#destination): list | no default - [`Port`](#destination): integer | `0` @@ -120,6 +124,10 @@ The following outline shows how to format the service splitter configuration ent - [`transparentProxy`](#transparentproxy): map | no default - [`outboundListenerPort`](#transparentproxy): integer | `15001` - [`dialedDirectly`](#transparentproxy): boolean | `false` + - [`envoyExtensions`](#envoyextensions): list | no default + - [`name`](#envoyextensions): string | `""` + - [`required`](#envoyextensions): string | `""` + - [`arguments`](#envoyextensions): map | `nil` - [`destination`](#destination): map | no default - [`addresses`](#destination): list | no default - [`port`](#destination): integer | `0` @@ -128,7 +136,7 @@ The following outline shows how to format the service splitter configuration ent - [`localRequestTiimeoutMs`](#localrequesttimeoutms): integer | `0` - [`meshGateway`](#meshgateway): map | no default - [`mode`](#meshgateway): string | no default - - [`externalSNI`](#externalsni): string | no defaiult + - [`externalSNI`](#externalsni): string | no default - [`expose`](#expose): map | no default - [`checks`](#expose-checks): boolean | `false` - [`paths`](#expose-paths): list | no default @@ -666,7 +674,7 @@ Map that specifies a set of rules that enable Consul to remove hosts from the up ### `TransparentProxy` -Controls configurations specific to proxies in transparent mode. Refer to [Transparent Proxy](/consul/docs/connect/transparent-proxy) for additional information. +Controls configurations specific to proxies in transparent mode. Refer to [Transparent Proxy](/consul/docs/connect/transparent-proxy) for additional information. You can configure the following parameters in the `TransparentProxy` block: @@ -675,6 +683,18 @@ You can configure the following parameters in the `TransparentProxy` block: | `OutboundListenerPort` | Specifies the port that the proxy listens on for outbound traffic. This must be the same port number where outbound application traffic is redirected. | integer | `15001` | | `DialedDirectly` | Enables transparent proxies to dial the proxy instance's IP address directly when set to `true`. Transparent proxies commonly dial upstreams at the `"virtual"` tagged address, which load balances across instances. Dialing individual instances can be helpful for stateful services, such as a database cluster with a leader. | boolean | `false` | +### `EnvoyExtensions` + +List of extensions to modify Envoy proxy configuration. Refer to [Envoy Extensions](/consul/docs/connect/proxies/envoy-extensions) for additional information. + +You can configure the following parameters in the `EnvoyExtensions` block: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `Name` | Name of the extension. | string | `""` | +| `Required` | When Required is true and the extension does not update any Envoy resources, an error is returned. Use this parameter to ensure that extensions required for secure communication are not unintentionally bypassed. | string | `""` | +| `Arguments` | Arguments to pass to the extension executable. | map | `nil` | + ### `Destination[]` Configures the destination for service traffic through terminating gateways. Refer to [Terminating Gateway](/consul/docs/connect/terminating-gateway) for additional information. @@ -1046,6 +1066,20 @@ You can configure the following parameters in the `TransparentProxy` block: | `outboundListenerPort` | Specifies the port that the proxy listens on for outbound traffic. This must be the same port number where outbound application traffic is redirected. | integer | `15001` | | `dialedDirectly` | Enables transparent proxies to dial the proxy instance's IP address directly when set to `true`. Transparent proxies commonly dial upstreams at the `"virtual"` tagged address, which load balances across instances. Dialing individual instances can be helpful for stateful services, such as a database cluster with a leader. | boolean | `false` | +### `spec.envoyExtensions` + +List of extensions to modify Envoy proxy configuration. Refer to [Envoy Extensions](/consul/docs/connect/proxies/envoy-extensions) for additional information. + +#### Values + +You can configure the following parameters in the `EnvoyExtensions` block: + +| Parameter | Description | Data type | Default | +| --- | --- | --- | --- | +| `name` | Name of the extension. | string | `""` | +| `required` | When Required is true and the extension does not update any Envoy resources, an error is returned. Use this parameter to ensure that extensions required for secure communication are not unintentionally bypassed. | string | `""` | +| `arguments` | Arguments to pass to the extension executable. | map | `nil` | + ### `spec.destination` Map of configurations that specify one or more destinations for service traffic routed through terminating gateways. Refer to [Terminating Gateway](/consul/docs/connect/terminating-gateway) for additional information. diff --git a/website/content/docs/connect/proxies/envoy-extensions/usage/lua.mdx b/website/content/docs/connect/proxies/envoy-extensions/usage/lua.mdx index a68e7a822518..496b7d5fa58f 100644 --- a/website/content/docs/connect/proxies/envoy-extensions/usage/lua.mdx +++ b/website/content/docs/connect/proxies/envoy-extensions/usage/lua.mdx @@ -164,22 +164,65 @@ In the following example, the `service-defaults` configure the Lua Envoy extensi ```hcl Kind = "service-defaults" Name = "myservice" -EnvoyExtensions { - Name = "builtin/lua" - - Arguments = { - ProxyType = "connect-proxy" - Listener = "inbound" - Script = < Alternatively, you can apply the same extension configuration to [`proxy-defaults`](/consul/docs/connect/config-entries/proxy-defaults#envoyextensions) configuration entries. + +You can also specify multiple Lua filters through the Envoy extensions. They will not override each other. + + + +```hcl +Kind = "service-defaults" +Name = "myservice" +EnvoyExtensions = [ + { + Name = "builtin/lua", + Arguments = { + ProxyType = "connect-proxy" + Listener = "inbound" + Script = <<-EOF +function envoy_on_request(request_handle) + meta = request_handle:streamInfo():dynamicMetadata() + m = meta:get("consul") + request_handle:headers():add("x-consul-datacenter", m["datacenter1"]) +end + EOF + } + }, + { + Name = "builtin/lua", + Arguments = { + ProxyType = "connect-proxy" + Listener = "inbound" + Script = <<-EOF +function envoy_on_request(request_handle) + meta = request_handle:streamInfo():dynamicMetadata() + m = meta:get("consul") + request_handle:headers():add("x-consul-datacenter", m["datacenter2"]) +end + EOF + } + } +] +``` + + \ No newline at end of file From 036ee5669e59c53507c583b585a04c62e2fd02b8 Mon Sep 17 00:00:00 2001 From: Dan Bond Date: Tue, 21 Mar 2023 11:16:37 -0700 Subject: [PATCH 03/17] fix build workflow (#16719) Signed-off-by: Dan Bond --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6ec5c03cfdf..8c49acbdd8d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,7 +60,7 @@ jobs: filepath: ${{ steps.generate-metadata-file.outputs.filepath }} steps: - name: 'Checkout directory' - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # pin@v3.3.0 - name: Generate metadata file id: generate-metadata-file uses: hashicorp/actions-generate-metadata@v1 From 8f7e4d4a7cbb70463860a5c9f5eaf30af745414c Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 21 Mar 2023 11:26:40 -0700 Subject: [PATCH 04/17] Helm docs without developer.hashicorp.com prefix (#16711) This was causing linter errors --- website/content/docs/k8s/helm.mdx | 72 +++++++++++++++---------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/website/content/docs/k8s/helm.mdx b/website/content/docs/k8s/helm.mdx index ea45c2c1f525..ac6d802c12d5 100644 --- a/website/content/docs/k8s/helm.mdx +++ b/website/content/docs/k8s/helm.mdx @@ -58,7 +58,7 @@ Use these links to navigate to a particular top-level stanza. the prefix will be `-consul`. - `domain` ((#v-global-domain)) (`string: consul`) - The domain Consul will answer DNS queries for - (Refer to [`-domain`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_domain)) and the domain services synced from + (Refer to [`-domain`](/consul/docs/agent/config/cli-flags#_domain)) and the domain services synced from Consul into Kubernetes will have, e.g. `service-name.service.consul`. - `peering` ((#v-global-peering)) - Configures the Cluster Peering feature. Requires Consul v1.14+ and Consul-K8s v1.0.0+. @@ -119,7 +119,7 @@ Use these links to navigate to a particular top-level stanza. - `secretsBackend` ((#v-global-secretsbackend)) - secretsBackend is used to configure Vault as the secrets backend for the Consul on Kubernetes installation. The Vault cluster needs to have the Kubernetes Auth Method, KV2 and PKI secrets engines enabled and have necessary secrets, policies and roles created prior to installing Consul. - Refer to [Vault as the Secrets Backend](https://developer.hashicorp.com/consul/docs/k8s/deployment-configurations/vault) + Refer to [Vault as the Secrets Backend](/consul/docs/k8s/deployment-configurations/vault) documentation for full instructions. The Vault cluster _must_ not have the Consul cluster installed by this Helm chart as its storage backend @@ -210,7 +210,7 @@ Use these links to navigate to a particular top-level stanza. The provider will be configured to use the Vault Kubernetes auth method and therefore requires the role provided by `global.secretsBackend.vault.consulServerRole` to have permissions to the root and intermediate PKI paths. - Please refer to [Vault ACL policies](https://developer.hashicorp.com/consul/docs/connect/ca/vault#vault-acl-policies) + Please refer to [Vault ACL policies](/consul/docs/connect/ca/vault#vault-acl-policies) documentation for information on how to configure the Vault policies. - `address` ((#v-global-secretsbackend-vault-connectca-address)) (`string: ""`) - The address of the Vault server. @@ -218,13 +218,13 @@ Use these links to navigate to a particular top-level stanza. - `authMethodPath` ((#v-global-secretsbackend-vault-connectca-authmethodpath)) (`string: kubernetes`) - The mount path of the Kubernetes auth method in Vault. - `rootPKIPath` ((#v-global-secretsbackend-vault-connectca-rootpkipath)) (`string: ""`) - The path to a PKI secrets engine for the root certificate. - For more details, please refer to [Vault Connect CA configuration](https://developer.hashicorp.com/consul/docs/connect/ca/vault#rootpkipath). + For more details, please refer to [Vault Connect CA configuration](/consul/docs/connect/ca/vault#rootpkipath). - `intermediatePKIPath` ((#v-global-secretsbackend-vault-connectca-intermediatepkipath)) (`string: ""`) - The path to a PKI secrets engine for the generated intermediate certificate. - For more details, please refer to [Vault Connect CA configuration](https://developer.hashicorp.com/consul/docs/connect/ca/vault#intermediatepkipath). + For more details, please refer to [Vault Connect CA configuration](/consul/docs/connect/ca/vault#intermediatepkipath). - `additionalConfig` ((#v-global-secretsbackend-vault-connectca-additionalconfig)) (`string: {}`) - Additional Connect CA configuration in JSON format. - Please refer to [Vault Connect CA configuration](https://developer.hashicorp.com/consul/docs/connect/ca/vault#configuration) + Please refer to [Vault Connect CA configuration](/consul/docs/connect/ca/vault#configuration) for all configuration options available for that provider. Example: @@ -258,7 +258,7 @@ Use these links to navigate to a particular top-level stanza. inject webhooks. - `gossipEncryption` ((#v-global-gossipencryption)) - Configures Consul's gossip encryption key. - (Refer to [`-encrypt`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_encrypt)). + (Refer to [`-encrypt`](/consul/docs/agent/config/cli-flags#_encrypt)). By default, gossip encryption is not enabled. The gossip encryption key may be set automatically or manually. The recommended method is to automatically generate the key. To automatically generate and set a gossip encryption key, set autoGenerate to true. @@ -289,17 +289,17 @@ Use these links to navigate to a particular top-level stanza. - `recursors` ((#v-global-recursors)) (`array: []`) - A list of addresses of upstream DNS servers that are used to recursively resolve DNS queries. These values are given as `-recursor` flags to Consul servers and clients. - Refer to [`-recursor`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_recursor) for more details. + Refer to [`-recursor`](/consul/docs/agent/config/cli-flags#_recursor) for more details. If this is an empty array (the default), then Consul DNS will only resolve queries for the Consul top level domain (by default `.consul`). - - `tls` ((#v-global-tls)) - Enables [TLS](https://developer.hashicorp.com/consul/tutorials/security/tls-encryption-secure) + - `tls` ((#v-global-tls)) - Enables [TLS](/consul/tutorials/security/tls-encryption-secure) across the cluster to verify authenticity of the Consul servers and clients. Requires Consul v1.4.1+. - `enabled` ((#v-global-tls-enabled)) (`boolean: false`) - If true, the Helm chart will enable TLS for Consul servers and clients and all consul-k8s-control-plane components, as well as generate certificate authority (optional) and server and client certificates. - This setting is required for [Cluster Peering](https://developer.hashicorp.com/consul/docs/connect/cluster-peering/k8s). + This setting is required for [Cluster Peering](/consul/docs/connect/cluster-peering/k8s). - `enableAutoEncrypt` ((#v-global-tls-enableautoencrypt)) (`boolean: false`) - If true, turns on the auto-encrypt feature on clients and servers. It also switches consul-k8s-control-plane components to retrieve the CA from the servers @@ -316,7 +316,7 @@ Use these links to navigate to a particular top-level stanza. - `verify` ((#v-global-tls-verify)) (`boolean: true`) - If true, `verify_outgoing`, `verify_server_hostname`, and `verify_incoming` for internal RPC communication will be set to `true` for Consul servers and clients. Set this to false to incrementally roll out TLS on an existing Consul cluster. - Please refer to [TLS on existing clusters](https://developer.hashicorp.com/consul/docs/k8s/operations/tls-on-existing-cluster) + Please refer to [TLS on existing clusters](/consul/docs/k8s/operations/tls-on-existing-cluster) for more details. - `httpsOnly` ((#v-global-tls-httpsonly)) (`boolean: true`) - If true, the Helm chart will configure Consul to disable the HTTP port on @@ -469,7 +469,7 @@ Use these links to navigate to a particular top-level stanza. This address must be reachable from the Consul servers in the primary datacenter. This auth method will be used to provision ACL tokens for Consul components and is different from the one used by the Consul Service Mesh. - Please refer to the [Kubernetes Auth Method documentation](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods/kubernetes). + Please refer to the [Kubernetes Auth Method documentation](/consul/docs/security/acl/auth-methods/kubernetes). You can retrieve this value from your `kubeconfig` by running: @@ -580,7 +580,7 @@ Use these links to navigate to a particular top-level stanza. Consul server agents. - `replicas` ((#v-server-replicas)) (`integer: 1`) - The number of server agents to run. This determines the fault tolerance of - the cluster. Please refer to the [deployment table](https://developer.hashicorp.com/consul/docs/architecture/consensus#deployment-table) + the cluster. Please refer to the [deployment table](/consul/docs/architecture/consensus#deployment-table) for more information. - `bootstrapExpect` ((#v-server-bootstrapexpect)) (`int: null`) - The number of servers that are expected to be running. @@ -619,7 +619,7 @@ Use these links to navigate to a particular top-level stanza. Vault Secrets backend: If you are using Vault as a secrets backend, a Vault Policy must be created which allows `["create", "update"]` capabilities on the PKI issuing endpoint, which is usually of the form `pki/issue/consul-server`. - Complete [this tutorial](https://developer.hashicorp.com/consul/tutorials/vault-secure/vault-pki-consul-secure-tls) + Complete [this tutorial](/consul/tutorials/vault-secure/vault-pki-consul-secure-tls) to learn how to generate a compatible certificate. Note: when using TLS, both the `server.serverCert` and `global.tls.caCert` which points to the CA endpoint of this PKI engine must be provided. @@ -659,15 +659,15 @@ Use these links to navigate to a particular top-level stanza. storage classes, the PersistentVolumeClaims would need to be manually created. A `null` value will use the Kubernetes cluster's default StorageClass. If a default StorageClass does not exist, you will need to create one. - Refer to the [Read/Write Tuning](https://developer.hashicorp.com/consul/docs/install/performance#read-write-tuning) + Refer to the [Read/Write Tuning](/consul/docs/install/performance#read-write-tuning) section of the Server Performance Requirements documentation for considerations around choosing a performant storage class. - ~> **Note:** The [Reference Architecture](https://developer.hashicorp.com/consul/tutorials/production-deploy/reference-architecture#hardware-sizing-for-consul-servers) + ~> **Note:** The [Reference Architecture](/consul/tutorials/production-deploy/reference-architecture#hardware-sizing-for-consul-servers) contains best practices and recommendations for selecting suitable hardware sizes for your Consul servers. - - `connect` ((#v-server-connect)) (`boolean: true`) - This will enable/disable [Connect](https://developer.hashicorp.com/consul/docs/connect). Setting this to true + - `connect` ((#v-server-connect)) (`boolean: true`) - This will enable/disable [Connect](/consul/docs/connect). Setting this to true _will not_ automatically secure pod communication, this setting will only enable usage of the feature. Consul will automatically initialize a new CA and set of certificates. Additional Connect settings can be configured @@ -719,7 +719,7 @@ Use these links to navigate to a particular top-level stanza. control a rolling update of Consul server agents. This value specifies the [partition](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#partitions) for performing a rolling update. Please read the linked Kubernetes - and [Upgrade Consul](https://developer.hashicorp.com/consul/docs/k8s/upgrade#upgrading-consul-servers) + and [Upgrade Consul](/consul/docs/k8s/upgrade#upgrading-consul-servers) documentation for more information. - `disruptionBudget` ((#v-server-disruptionbudget)) - This configures the [`PodDisruptionBudget`](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) @@ -735,7 +735,7 @@ Use these links to navigate to a particular top-level stanza. --set 'server.disruptionBudget.maxUnavailable=0'` flag to the helm chart installation command because of a limitation in the Helm templating language. - - `extraConfig` ((#v-server-extraconfig)) (`string: {}`) - A raw string of extra [JSON configuration](https://developer.hashicorp.com/consul/docs/agent/config/config-files) for Consul + - `extraConfig` ((#v-server-extraconfig)) (`string: {}`) - A raw string of extra [JSON configuration](/consul/docs/agent/config/config-files) for Consul servers. This will be saved as-is into a ConfigMap that is read by the Consul server agents. This can be used to add additional configuration that isn't directly exposed by the chart. @@ -912,18 +912,18 @@ Use these links to navigate to a particular top-level stanza. it could be used to configure custom consul parameters. - `snapshotAgent` ((#v-server-snapshotagent)) - Values for setting up and running - [snapshot agents](https://developer.hashicorp.com/consul/commands/snapshot/agent) + [snapshot agents](/consul/commands/snapshot/agent) within the Consul clusters. They run as a sidecar with Consul servers. - `enabled` ((#v-server-snapshotagent-enabled)) (`boolean: false`) - If true, the chart will install resources necessary to run the snapshot agent. - `interval` ((#v-server-snapshotagent-interval)) (`string: 1h`) - Interval at which to perform snapshots. - Refer to [`interval`](https://developer.hashicorp.com/consul/commands/snapshot/agent#interval) + Refer to [`interval`](/consul/commands/snapshot/agent#interval) - `configSecret` ((#v-server-snapshotagent-configsecret)) - A Kubernetes or Vault secret that should be manually created to contain the entire config to be used on the snapshot agent. This is the preferred method of configuration since there are usually storage - credentials present. Please refer to the [Snapshot agent config](https://developer.hashicorp.com/consul/commands/snapshot/agent#config-file-options) + credentials present. Please refer to the [Snapshot agent config](/consul/commands/snapshot/agent#config-file-options) for details. - `secretName` ((#v-server-snapshotagent-configsecret-secretname)) (`string: null`) - The name of the Kubernetes secret or Vault secret path that holds the snapshot agent config. @@ -981,7 +981,7 @@ Use these links to navigate to a particular top-level stanza. - `k8sAuthMethodHost` ((#v-externalservers-k8sauthmethodhost)) (`string: null`) - If you are setting `global.acls.manageSystemACLs` and `connectInject.enabled` to true, set `k8sAuthMethodHost` to the address of the Kubernetes API server. This address must be reachable from the Consul servers. - Please refer to the [Kubernetes Auth Method documentation](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods/kubernetes). + Please refer to the [Kubernetes Auth Method documentation](/consul/docs/security/acl/auth-methods/kubernetes). You could retrieve this value from your `kubeconfig` by running: @@ -1004,7 +1004,7 @@ Use these links to navigate to a particular top-level stanza. - `image` ((#v-client-image)) (`string: null`) - The name of the Docker image (including any tag) for the containers running Consul client agents. - - `join` ((#v-client-join)) (`array: null`) - A list of valid [`-retry-join` values](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_retry_join). + - `join` ((#v-client-join)) (`array: null`) - A list of valid [`-retry-join` values](/consul/docs/agent/config/cli-flags#_retry_join). If this is `null` (default), then the clients will attempt to automatically join the server cluster running within Kubernetes. This means that with `server.enabled` set to true, clients will automatically @@ -1025,7 +1025,7 @@ Use these links to navigate to a particular top-level stanza. required for Connect. - `nodeMeta` ((#v-client-nodemeta)) - nodeMeta specifies an arbitrary metadata key/value pair to associate with the node - (refer to [`-node-meta`](https://developer.hashicorp.com/consul/docs/agent/config/cli-flags#_node_meta)) + (refer to [`-node-meta`](/consul/docs/agent/config/cli-flags#_node_meta)) - `pod-name` ((#v-client-nodemeta-pod-name)) (`string: ${HOSTNAME}`) @@ -1069,7 +1069,7 @@ Use these links to navigate to a particular top-level stanza. - `tlsInit` ((#v-client-containersecuritycontext-tlsinit)) (`map`) - The tls-init initContainer - - `extraConfig` ((#v-client-extraconfig)) (`string: {}`) - A raw string of extra [JSON configuration](https://developer.hashicorp.com/consul/docs/agent/config/config-files) for Consul + - `extraConfig` ((#v-client-extraconfig)) (`string: {}`) - A raw string of extra [JSON configuration](/consul/docs/agent/config/config-files) for Consul clients. This will be saved as-is into a ConfigMap that is read by the Consul client agents. This can be used to add additional configuration that isn't directly exposed by the chart. @@ -1335,16 +1335,16 @@ Use these links to navigate to a particular top-level stanza. will inherit from `global.metrics.enabled` value. - `provider` ((#v-ui-metrics-provider)) (`string: prometheus`) - Provider for metrics. Refer to - [`metrics_provider`](https://developer.hashicorp.com/consul/docs/agent/config/config-files#ui_config_metrics_provider) + [`metrics_provider`](/consul/docs/agent/config/config-files#ui_config_metrics_provider) This value is only used if `ui.enabled` is set to true. - `baseURL` ((#v-ui-metrics-baseurl)) (`string: http://prometheus-server`) - baseURL is the URL of the prometheus server, usually the service URL. This value is only used if `ui.enabled` is set to true. - - `dashboardURLTemplates` ((#v-ui-dashboardurltemplates)) - Corresponds to [`dashboard_url_templates`](https://developer.hashicorp.com/consul/docs/agent/config/config-files#ui_config_dashboard_url_templates) + - `dashboardURLTemplates` ((#v-ui-dashboardurltemplates)) - Corresponds to [`dashboard_url_templates`](/consul/docs/agent/config/config-files#ui_config_dashboard_url_templates) configuration. - - `service` ((#v-ui-dashboardurltemplates-service)) (`string: ""`) - Sets [`dashboardURLTemplates.service`](https://developer.hashicorp.com/consul/docs/agent/config/config-files#ui_config_dashboard_url_templates_service). + - `service` ((#v-ui-dashboardurltemplates-service)) (`string: ""`) - Sets [`dashboardURLTemplates.service`](/consul/docs/agent/config/config-files#ui_config_dashboard_url_templates_service). ### syncCatalog ((#h-synccatalog)) @@ -1364,7 +1364,7 @@ Use these links to navigate to a particular top-level stanza. to run the sync program. - `default` ((#v-synccatalog-default)) (`boolean: true`) - If true, all valid services in K8S are - synced by default. If false, the service must be [annotated](https://developer.hashicorp.com/consul/docs/k8s/service-sync#enable-and-disable-sync) + synced by default. If false, the service must be [annotated](/consul/docs/k8s/service-sync#enable-and-disable-sync) properly to sync. In either case an annotation can override the default. @@ -1544,7 +1544,7 @@ Use these links to navigate to a particular top-level stanza. - `default` ((#v-connectinject-default)) (`boolean: false`) - If true, the injector will inject the Connect sidecar into all pods by default. Otherwise, pods must specify the - [injection annotation](https://developer.hashicorp.com/consul/docs/k8s/connect#consul-hashicorp-com-connect-inject) + [injection annotation](/consul/docs/k8s/connect#consul-hashicorp-com-connect-inject) to opt-in to Connect injection. If this is true, pods can use the same annotation to explicitly opt-out of injection. @@ -1834,8 +1834,8 @@ Use these links to navigate to a particular top-level stanza. If set to an empty string all service accounts can log in. This only has effect if ACLs are enabled. - Refer to Auth methods [Binding rules](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods#binding-rules) - and [Trusted identiy attributes](https://developer.hashicorp.com/consul/docs/security/acl/auth-methods/kubernetes#trusted-identity-attributes) + Refer to Auth methods [Binding rules](/consul/docs/security/acl/auth-methods#binding-rules) + and [Trusted identiy attributes](/consul/docs/security/acl/auth-methods/kubernetes#trusted-identity-attributes) for more details. Requires Consul >= v1.5. @@ -1907,11 +1907,11 @@ Use these links to navigate to a particular top-level stanza. ### meshGateway ((#h-meshgateway)) -- `meshGateway` ((#v-meshgateway)) - [Mesh Gateways](https://developer.hashicorp.com/consul/docs/connect/gateways/mesh-gateway) enable Consul Connect to work across Consul datacenters. +- `meshGateway` ((#v-meshgateway)) - [Mesh Gateways](/consul/docs/connect/gateways/mesh-gateway) enable Consul Connect to work across Consul datacenters. - - `enabled` ((#v-meshgateway-enabled)) (`boolean: false`) - If [mesh gateways](https://developer.hashicorp.com/consul/docs/connect/gateways/mesh-gateway) are enabled, a Deployment will be created that runs + - `enabled` ((#v-meshgateway-enabled)) (`boolean: false`) - If [mesh gateways](/consul/docs/connect/gateways/mesh-gateway) are enabled, a Deployment will be created that runs gateways and Consul Connect will be configured to use gateways. - This setting is required for [Cluster Peering](https://developer.hashicorp.com/consul/docs/connect/cluster-peering/k8s). + This setting is required for [Cluster Peering](/consul/docs/connect/cluster-peering/k8s). Requirements: consul 1.6.0+ if using `global.acls.manageSystemACLs``. - `replicas` ((#v-meshgateway-replicas)) (`integer: 1`) - Number of replicas for the Deployment. From 769d9505a8bdefb938128adea370b4384feb18f6 Mon Sep 17 00:00:00 2001 From: Dhia Ayachi Date: Tue, 21 Mar 2023 14:27:00 -0400 Subject: [PATCH 05/17] add extra resiliency to snapshot restore test (#16712) --- .../test/snapshot/snapshot_restore_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/integration/consul-container/test/snapshot/snapshot_restore_test.go b/test/integration/consul-container/test/snapshot/snapshot_restore_test.go index 1d82b1cfb10c..35621ab99b4b 100644 --- a/test/integration/consul-container/test/snapshot/snapshot_restore_test.go +++ b/test/integration/consul-container/test/snapshot/snapshot_restore_test.go @@ -3,6 +3,7 @@ package snapshot import ( "fmt" "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster" libtopology "github.com/hashicorp/consul/test/integration/consul-container/libs/topology" "github.com/hashicorp/consul/test/integration/consul-container/libs/utils" @@ -79,6 +80,9 @@ func testSnapShotRestoreForLogStore(t *testing.T, logStore libcluster.LogStore) libcluster.WaitForLeader(t, cluster2, client2) + leader, err := cluster2.Leader() + require.NoError(t, err) + followers, err := cluster2.Followers() require.NoError(t, err) require.Len(t, followers, 2) @@ -86,6 +90,17 @@ func testSnapShotRestoreForLogStore(t *testing.T, logStore libcluster.LogStore) // use a follower api client and set `AllowStale` to true // to test the follower snapshot install code path as well. fc := followers[0].GetClient() + lc := leader.GetClient() + + retry.Run(t, func(r *retry.R) { + self, err := lc.Agent().Self() + require.NoError(r, err) + LeaderLogIndex := self["Stats"]["raft"].(map[string]interface{})["last_log_index"].(string) + self, err = fc.Agent().Self() + require.NoError(r, err) + followerLogIndex := self["Stats"]["raft"].(map[string]interface{})["last_log_index"].(string) + require.Equal(r, LeaderLogIndex, followerLogIndex) + }) for i := 0; i < 100; i++ { kv, _, err := fc.KV().Get(fmt.Sprintf("key-%d", i), &api.QueryOptions{AllowStale: true}) From 7f6f6891f7812f060dadfb9aaacffe353de9b9d0 Mon Sep 17 00:00:00 2001 From: cskh Date: Tue, 21 Mar 2023 22:29:21 -0400 Subject: [PATCH 06/17] fix: gracefully fail on invalid port number (#16721) --- agent/config/builder.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/agent/config/builder.go b/agent/config/builder.go index d072429e1d25..af59e9b5b4ec 100644 --- a/agent/config/builder.go +++ b/agent/config/builder.go @@ -455,6 +455,14 @@ func (b *builder) build() (rt RuntimeConfig, err error) { sidecarMaxPort := b.portVal("ports.sidecar_max_port", c.Ports.SidecarMaxPort) exposeMinPort := b.portVal("ports.expose_min_port", c.Ports.ExposeMinPort) exposeMaxPort := b.portVal("ports.expose_max_port", c.Ports.ExposeMaxPort) + if serverPort <= 0 { + return RuntimeConfig{}, fmt.Errorf( + "server-port must be greater than zero") + } + if serfPortLAN <= 0 { + return RuntimeConfig{}, fmt.Errorf( + "serf-lan-port must be greater than zero") + } if proxyMaxPort < proxyMinPort { return RuntimeConfig{}, fmt.Errorf( "proxy_min_port must be less than proxy_max_port. To disable, set both to zero.") From e818fdead0feed54ec460ae95762767610936d8c Mon Sep 17 00:00:00 2001 From: Ronald Date: Wed, 22 Mar 2023 14:17:19 +0100 Subject: [PATCH 07/17] Copyright headers for config files git + circleci (#16703) * Copyright headers for config files git + circleci * Release folder copyright headers --- .circleci/bash_env.sh | 3 +++ .circleci/config.yml | 3 +++ .circleci/scripts/rerun-fails-report.sh | 3 +++ .circleci/terraform/load-test/main.tf | 3 +++ .circleci/terraform/load-test/variables.tf | 3 +++ .github/ISSUE_TEMPLATE/config.yml | 3 +++ .github/dependabot.yml | 3 +++ .github/pr-labeler.yml | 3 +++ .github/scripts/metrics_checker.sh | 3 +++ .github/scripts/verify_artifact.sh | 3 +++ .github/scripts/verify_bin.sh | 3 +++ .github/scripts/verify_deb.sh | 3 +++ .github/scripts/verify_docker.sh | 3 +++ .github/scripts/verify_rpm.sh | 3 +++ .github/workflows/backport-assistant.yml | 3 +++ .github/workflows/backport-checker.yml | 3 +++ .github/workflows/backport-reminder.yml | 3 +++ .github/workflows/bot-auto-approve.yaml | 3 +++ .github/workflows/broken-link-check.yml | 3 +++ .github/workflows/build.yml | 3 +++ .github/workflows/changelog-checker.yml | 3 +++ .github/workflows/check-legacy-links-format.yml | 3 +++ .github/workflows/embedded-asset-checker.yml | 3 +++ .github/workflows/issue-comment-created.yml | 3 +++ .github/workflows/jira-issues.yaml | 3 +++ .github/workflows/jira-pr.yaml | 3 +++ .github/workflows/load-test.yml | 3 +++ .github/workflows/nightly-test-1.12.x.yaml | 3 +++ .github/workflows/nightly-test-1.13.x.yaml | 3 +++ .github/workflows/nightly-test-1.14.x.yaml | 3 +++ .github/workflows/nightly-test-1.15.x.yaml | 3 +++ .github/workflows/nightly-test-main.yaml | 3 +++ .github/workflows/oss-merge-trigger.yml | 3 +++ .github/workflows/pr-labeler.yml | 3 +++ .github/workflows/pr-metrics-test-checker.yml | 3 +++ .github/workflows/stale.yml | 3 +++ .release/ci.hcl | 3 +++ .release/docker/docker-entrypoint-ubi.sh | 3 +++ .release/docker/docker-entrypoint.sh | 3 +++ .release/linux/package/etc/consul.d/consul.hcl | 3 +++ .release/release-metadata.hcl | 3 +++ .release/security-scan.hcl | 3 +++ 42 files changed, 126 insertions(+) diff --git a/.circleci/bash_env.sh b/.circleci/bash_env.sh index 38bcfd5bd367..63c3daa6caf4 100644 --- a/.circleci/bash_env.sh +++ b/.circleci/bash_env.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + export GIT_COMMIT=$(git rev-parse --short HEAD) export GIT_COMMIT_YEAR=$(git show -s --format=%cd --date=format:%Y HEAD) diff --git a/.circleci/config.yml b/.circleci/config.yml index 34738285e5f1..469223d7d355 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- version: 2.1 diff --git a/.circleci/scripts/rerun-fails-report.sh b/.circleci/scripts/rerun-fails-report.sh index 959f0708e685..7f81ef9044f8 100755 --- a/.circleci/scripts/rerun-fails-report.sh +++ b/.circleci/scripts/rerun-fails-report.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # # Add a comment on the github PR if there were any rerun tests. # diff --git a/.circleci/terraform/load-test/main.tf b/.circleci/terraform/load-test/main.tf index 1a8865c065d9..614f76b21971 100644 --- a/.circleci/terraform/load-test/main.tf +++ b/.circleci/terraform/load-test/main.tf @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + terraform { backend "s3" { } diff --git a/.circleci/terraform/load-test/variables.tf b/.circleci/terraform/load-test/variables.tf index 414cfa84e7fe..0231ca0440bf 100644 --- a/.circleci/terraform/load-test/variables.tf +++ b/.circleci/terraform/load-test/variables.tf @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + variable "vpc_name" { description = "Name of the VPC" } diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2efc5faff9b7..36f9456693ff 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + blank_issues_enabled: false contact_links: - name: Consul Community Support diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c60f2e869672..05387a7c9b80 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + version: 2 updates: - package-ecosystem: gomod diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml index 1e371d5f9013..d873b9258ecc 100644 --- a/.github/pr-labeler.yml +++ b/.github/pr-labeler.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + pr/dependencies: - vendor/**/* - go.* diff --git a/.github/scripts/metrics_checker.sh b/.github/scripts/metrics_checker.sh index f68c85ed1af2..a34cdf12fbec 100755 --- a/.github/scripts/metrics_checker.sh +++ b/.github/scripts/metrics_checker.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -uo pipefail ### This script checks if any metric behavior has been modified. diff --git a/.github/scripts/verify_artifact.sh b/.github/scripts/verify_artifact.sh index d1998785662a..48bfede1cb33 100755 --- a/.github/scripts/verify_artifact.sh +++ b/.github/scripts/verify_artifact.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -euo pipefail diff --git a/.github/scripts/verify_bin.sh b/.github/scripts/verify_bin.sh index 6f7017271748..ff572d87fae9 100755 --- a/.github/scripts/verify_bin.sh +++ b/.github/scripts/verify_bin.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -euo pipefail diff --git a/.github/scripts/verify_deb.sh b/.github/scripts/verify_deb.sh index e4a22a26191d..84a9a10c8563 100755 --- a/.github/scripts/verify_deb.sh +++ b/.github/scripts/verify_deb.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -euo pipefail diff --git a/.github/scripts/verify_docker.sh b/.github/scripts/verify_docker.sh index 725bf92b9f56..fbbeb7dff464 100755 --- a/.github/scripts/verify_docker.sh +++ b/.github/scripts/verify_docker.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -euo pipefail diff --git a/.github/scripts/verify_rpm.sh b/.github/scripts/verify_rpm.sh index 75a63bcbc91b..17709a1d90e1 100755 --- a/.github/scripts/verify_rpm.sh +++ b/.github/scripts/verify_rpm.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -euo pipefail diff --git a/.github/workflows/backport-assistant.yml b/.github/workflows/backport-assistant.yml index 95fc03c10bb1..d4e2b2d4c762 100644 --- a/.github/workflows/backport-assistant.yml +++ b/.github/workflows/backport-assistant.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This action creates downstream PRs for PRs with backport labels defined. # See docs here: https://github.com/hashicorp/backport-assistant diff --git a/.github/workflows/backport-checker.yml b/.github/workflows/backport-checker.yml index c9af23ea9717..0e7cb0396ae5 100644 --- a/.github/workflows/backport-checker.yml +++ b/.github/workflows/backport-checker.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This workflow checks that there is either a 'pr/no-backport' label applied to a PR # or there is a backport/* label indicating a backport has been set diff --git a/.github/workflows/backport-reminder.yml b/.github/workflows/backport-reminder.yml index 359451269d7a..b358122dbf0c 100644 --- a/.github/workflows/backport-reminder.yml +++ b/.github/workflows/backport-reminder.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This workflow sends a reminder comment to PRs that have labels starting with # `backport/` to check that the backport has run successfully. diff --git a/.github/workflows/bot-auto-approve.yaml b/.github/workflows/bot-auto-approve.yaml index 7731e4553ce8..2b652388999c 100644 --- a/.github/workflows/bot-auto-approve.yaml +++ b/.github/workflows/bot-auto-approve.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Bot Auto Approve on: pull_request_target diff --git a/.github/workflows/broken-link-check.yml b/.github/workflows/broken-link-check.yml index bbfcd73c6b60..0674b526beab 100644 --- a/.github/workflows/broken-link-check.yml +++ b/.github/workflows/broken-link-check.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Broken Link Check on: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8c49acbdd8d3..e67a3a55ae37 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: build on: diff --git a/.github/workflows/changelog-checker.yml b/.github/workflows/changelog-checker.yml index bb13255d297e..18b63ce8ef35 100644 --- a/.github/workflows/changelog-checker.yml +++ b/.github/workflows/changelog-checker.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This workflow checks that there is either a 'pr/no-changelog' label applied to a PR # or there is a .changelog/.txt file associated with a PR for a changelog entry diff --git a/.github/workflows/check-legacy-links-format.yml b/.github/workflows/check-legacy-links-format.yml index f067bd231a49..85dbb0e70f2e 100644 --- a/.github/workflows/check-legacy-links-format.yml +++ b/.github/workflows/check-legacy-links-format.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Legacy Link Format Checker on: diff --git a/.github/workflows/embedded-asset-checker.yml b/.github/workflows/embedded-asset-checker.yml index 8eb60d70d08d..4bb07771bd68 100644 --- a/.github/workflows/embedded-asset-checker.yml +++ b/.github/workflows/embedded-asset-checker.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This workflow detects if there is a diff in the `agent/uiserver/dist` directory # which is used by Consul to serve its embedded UI. # `agent/uiserver/dist` should not be manually updated. diff --git a/.github/workflows/issue-comment-created.yml b/.github/workflows/issue-comment-created.yml index 47056a66bc22..01e7e13f8bc4 100644 --- a/.github/workflows/issue-comment-created.yml +++ b/.github/workflows/issue-comment-created.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Issue Comment Created on: diff --git a/.github/workflows/jira-issues.yaml b/.github/workflows/jira-issues.yaml index 93e8710afa62..f71727bf62d1 100644 --- a/.github/workflows/jira-issues.yaml +++ b/.github/workflows/jira-issues.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + on: issues: types: [opened, closed, deleted, reopened] diff --git a/.github/workflows/jira-pr.yaml b/.github/workflows/jira-pr.yaml index 7537c773126f..4b872b6aaf88 100644 --- a/.github/workflows/jira-pr.yaml +++ b/.github/workflows/jira-pr.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + on: pull_request_target: types: [opened, closed, reopened] diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index ab7d793e7945..61d23cde71d3 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Load Test on: diff --git a/.github/workflows/nightly-test-1.12.x.yaml b/.github/workflows/nightly-test-1.12.x.yaml index 906f2ba8fb35..f757f877e2ef 100644 --- a/.github/workflows/nightly-test-1.12.x.yaml +++ b/.github/workflows/nightly-test-1.12.x.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Nightly Test 1.12.x on: schedule: diff --git a/.github/workflows/nightly-test-1.13.x.yaml b/.github/workflows/nightly-test-1.13.x.yaml index 2df70ff68807..f2ae90dfbd2d 100644 --- a/.github/workflows/nightly-test-1.13.x.yaml +++ b/.github/workflows/nightly-test-1.13.x.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Nightly Test 1.13.x on: schedule: diff --git a/.github/workflows/nightly-test-1.14.x.yaml b/.github/workflows/nightly-test-1.14.x.yaml index 745ad7608ee8..6b8ac4f45e80 100644 --- a/.github/workflows/nightly-test-1.14.x.yaml +++ b/.github/workflows/nightly-test-1.14.x.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Nightly Test 1.14.x on: schedule: diff --git a/.github/workflows/nightly-test-1.15.x.yaml b/.github/workflows/nightly-test-1.15.x.yaml index 1b8f20787f82..075ad1bf7450 100644 --- a/.github/workflows/nightly-test-1.15.x.yaml +++ b/.github/workflows/nightly-test-1.15.x.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Nightly Test 1.15.x on: schedule: diff --git a/.github/workflows/nightly-test-main.yaml b/.github/workflows/nightly-test-main.yaml index e823bac7b562..4a2050d59b75 100644 --- a/.github/workflows/nightly-test-main.yaml +++ b/.github/workflows/nightly-test-main.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Nightly Test Main on: schedule: diff --git a/.github/workflows/oss-merge-trigger.yml b/.github/workflows/oss-merge-trigger.yml index 4d08442d90fb..4a4fdaa208e3 100644 --- a/.github/workflows/oss-merge-trigger.yml +++ b/.github/workflows/oss-merge-trigger.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: Trigger OSS to Enterprise Merge on: pull_request_target: diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 64d728084b54..a29cadcb685b 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: "Pull Request Labeler" on: pull_request_target: diff --git a/.github/workflows/pr-metrics-test-checker.yml b/.github/workflows/pr-metrics-test-checker.yml index 7c42da595bdc..a73f4fbb3ff5 100644 --- a/.github/workflows/pr-metrics-test-checker.yml +++ b/.github/workflows/pr-metrics-test-checker.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: "Check for metrics tests" on: pull_request: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index a0646a559d69..f3da6d422b6b 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + name: stale on: schedule: diff --git a/.release/ci.hcl b/.release/ci.hcl index 25f64e4c6b78..062a925102d3 100644 --- a/.release/ci.hcl +++ b/.release/ci.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + schema = "1" project "consul" { diff --git a/.release/docker/docker-entrypoint-ubi.sh b/.release/docker/docker-entrypoint-ubi.sh index 6ce389b27422..a932ad7286e2 100755 --- a/.release/docker/docker-entrypoint-ubi.sh +++ b/.release/docker/docker-entrypoint-ubi.sh @@ -1,4 +1,7 @@ #!/usr/bin/dumb-init /bin/sh +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -e # Note above that we run dumb-init as PID 1 in order to reap zombie processes diff --git a/.release/docker/docker-entrypoint.sh b/.release/docker/docker-entrypoint.sh index fe91711c6eb0..c169576b6cf8 100755 --- a/.release/docker/docker-entrypoint.sh +++ b/.release/docker/docker-entrypoint.sh @@ -1,4 +1,7 @@ #!/usr/bin/dumb-init /bin/sh +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + set -e # Note above that we run dumb-init as PID 1 in order to reap zombie processes diff --git a/.release/linux/package/etc/consul.d/consul.hcl b/.release/linux/package/etc/consul.d/consul.hcl index a064e95af770..b54644b2f9cc 100644 --- a/.release/linux/package/etc/consul.d/consul.hcl +++ b/.release/linux/package/etc/consul.d/consul.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # Full configuration options can be found at https://www.consul.io/docs/agent/config # datacenter diff --git a/.release/release-metadata.hcl b/.release/release-metadata.hcl index fedd5c53f9f3..8de2623fdee4 100644 --- a/.release/release-metadata.hcl +++ b/.release/release-metadata.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + url_docker_registry_dockerhub = "https://hub.docker.com/r/hashicorp/consul" url_docker_registry_ecr = "https://gallery.ecr.aws/hashicorp/consul" url_license = "https://github.com/hashicorp/consul/blob/main/LICENSE" diff --git a/.release/security-scan.hcl b/.release/security-scan.hcl index 490ddd274635..3352890686ae 100644 --- a/.release/security-scan.hcl +++ b/.release/security-scan.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + container { dependencies = true alpine_secdb = false From 3c5c53aa8099cab679633fb2bf90e89632c13986 Mon Sep 17 00:00:00 2001 From: Eric Haberkorn Date: Wed, 22 Mar 2023 09:24:13 -0400 Subject: [PATCH 08/17] fix bug where pqs that failover to a cluster peer dont un-fail over (#16729) --- .changelog/16729.txt | 3 ++ agent/consul/prepared_query_endpoint.go | 6 +-- agent/consul/prepared_query_endpoint_test.go | 41 ++++++++++++++++---- 3 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 .changelog/16729.txt diff --git a/.changelog/16729.txt b/.changelog/16729.txt new file mode 100644 index 000000000000..36c6e1aeabb2 --- /dev/null +++ b/.changelog/16729.txt @@ -0,0 +1,3 @@ +```release-note:bug +peering: Fix issue resulting in prepared query failover to cluster peers never un-failing over. +``` diff --git a/agent/consul/prepared_query_endpoint.go b/agent/consul/prepared_query_endpoint.go index ffa4b5e50915..54ef82bafdd1 100644 --- a/agent/consul/prepared_query_endpoint.go +++ b/agent/consul/prepared_query_endpoint.go @@ -468,7 +468,7 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest, // by the query setup. if len(reply.Nodes) == 0 { wrapper := &queryServerWrapper{srv: p.srv, executeRemote: p.ExecuteRemote} - if err := queryFailover(wrapper, query, args, reply); err != nil { + if err := queryFailover(wrapper, *query, args, reply); err != nil { return err } } @@ -707,7 +707,7 @@ func (q *queryServerWrapper) GetOtherDatacentersByDistance() ([]string, error) { // queryFailover runs an algorithm to determine which DCs to try and then calls // them to try to locate alternative services. -func queryFailover(q queryServer, query *structs.PreparedQuery, +func queryFailover(q queryServer, query structs.PreparedQuery, args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { @@ -789,7 +789,7 @@ func queryFailover(q queryServer, query *structs.PreparedQuery, // the remote query as well. remote := &structs.PreparedQueryExecuteRemoteRequest{ Datacenter: dc, - Query: *query, + Query: query, Limit: args.Limit, QueryOptions: args.QueryOptions, Connect: args.Connect, diff --git a/agent/consul/prepared_query_endpoint_test.go b/agent/consul/prepared_query_endpoint_test.go index d883c8bf4d38..ca1ad0c664fb 100644 --- a/agent/consul/prepared_query_endpoint_test.go +++ b/agent/consul/prepared_query_endpoint_test.go @@ -2092,16 +2092,16 @@ func TestPreparedQuery_Execute(t *testing.T) { require.NoError(t, msgpackrpc.CallWithCodec(codec1, "PreparedQuery.Apply", &query, &query.Query.ID)) // Update the health of a node to mark it critical. - setHealth := func(t *testing.T, codec rpc.ClientCodec, dc string, node string, health string) { + setHealth := func(t *testing.T, codec rpc.ClientCodec, dc string, i int, health string) { t.Helper() req := structs.RegisterRequest{ Datacenter: dc, - Node: node, + Node: fmt.Sprintf("node%d", i), Address: "127.0.0.1", Service: &structs.NodeService{ Service: "foo", Port: 8000, - Tags: []string{"dc1", "tag1"}, + Tags: []string{dc, fmt.Sprintf("tag%d", i)}, }, Check: &structs.HealthCheck{ Name: "failing", @@ -2113,7 +2113,7 @@ func TestPreparedQuery_Execute(t *testing.T) { var reply struct{} require.NoError(t, msgpackrpc.CallWithCodec(codec, "Catalog.Register", &req, &reply)) } - setHealth(t, codec1, "dc1", "node1", api.HealthCritical) + setHealth(t, codec1, "dc1", 1, api.HealthCritical) // The failing node should be filtered. t.Run("failing node filtered", func(t *testing.T) { @@ -2133,7 +2133,7 @@ func TestPreparedQuery_Execute(t *testing.T) { }) // Upgrade it to a warning and re-query, should be 10 nodes again. - setHealth(t, codec1, "dc1", "node1", api.HealthWarning) + setHealth(t, codec1, "dc1", 1, api.HealthWarning) t.Run("warning nodes are included", func(t *testing.T) { req := structs.PreparedQueryExecuteRequest{ Datacenter: "dc1", @@ -2303,7 +2303,7 @@ func TestPreparedQuery_Execute(t *testing.T) { // Now fail everything in dc1 and we should get an empty list back. for i := 0; i < 10; i++ { - setHealth(t, codec1, "dc1", fmt.Sprintf("node%d", i+1), api.HealthCritical) + setHealth(t, codec1, "dc1", i+1, api.HealthCritical) } t.Run("everything is failing so should get empty list", func(t *testing.T) { req := structs.PreparedQueryExecuteRequest{ @@ -2474,7 +2474,7 @@ func TestPreparedQuery_Execute(t *testing.T) { // Set all checks in dc2 as critical for i := 0; i < 10; i++ { - setHealth(t, codec2, "dc2", fmt.Sprintf("node%d", i+1), api.HealthCritical) + setHealth(t, codec2, "dc2", i+1, api.HealthCritical) } // Now we should see 9 nodes from dc3 (we have the tag filter still) @@ -2493,6 +2493,31 @@ func TestPreparedQuery_Execute(t *testing.T) { } expectFailoverPeerNodes(t, &query, &reply, 9) }) + + // Set all checks in dc1 as passing + for i := 0; i < 10; i++ { + setHealth(t, codec1, "dc1", i+1, api.HealthPassing) + } + + // Nothing is healthy so nothing is returned + t.Run("un-failing over", func(t *testing.T) { + retry.Run(t, func(r *retry.R) { + req := structs.PreparedQueryExecuteRequest{ + Datacenter: "dc1", + QueryIDOrName: query.Query.ID, + QueryOptions: structs.QueryOptions{Token: execToken}, + } + + var reply structs.PreparedQueryExecuteResponse + require.NoError(t, msgpackrpc.CallWithCodec(codec1, "PreparedQuery.Execute", &req, &reply)) + + for _, node := range reply.Nodes { + assert.NotEqual(t, "node3", node.Node.Node) + } + + expectNodes(t, &query, &reply, 9) + }) + }) } func TestPreparedQuery_Execute_ForwardLeader(t *testing.T) { @@ -2982,7 +3007,7 @@ func (m *mockQueryServer) ExecuteRemote(args *structs.PreparedQueryExecuteRemote func TestPreparedQuery_queryFailover(t *testing.T) { t.Parallel() - query := &structs.PreparedQuery{ + query := structs.PreparedQuery{ Name: "test", Service: structs.ServiceQuery{ Failover: structs.QueryFailoverOptions{ From 495ad4c7efc206948b35920074d2dbe8fe061f11 Mon Sep 17 00:00:00 2001 From: Eric Haberkorn Date: Wed, 22 Mar 2023 14:56:18 -0400 Subject: [PATCH 09/17] add enterprise xds tests (#16738) --- agent/agent_endpoint_test.go | 4 +- agent/proxycfg/manager_test.go | 2 +- agent/proxycfg/testing.go | 14 +- agent/proxycfg/testing_api_gateway.go | 2 +- agent/proxycfg/testing_connect_proxy.go | 14 +- agent/proxycfg/testing_ingress_gateway.go | 2 +- agent/proxycfg/testing_upstreams.go | 243 +++++++++++------- agent/proxycfg_test.go | 2 +- agent/sidecar_service_test.go | 4 +- agent/structs/discovery_chain.go | 6 +- agent/structs/testing_connect_proxy_config.go | 57 ++-- agent/xds/clusters_test.go | 209 ++++++++------- agent/xds/delta_envoy_extender_oss_test.go | 14 +- agent/xds/endpoints_test.go | 119 +++++---- .../runtime_config_oss_test.go | 6 +- agent/xds/listeners_test.go | 232 +++++++++-------- agent/xds/resources_test.go | 18 +- agent/xds/routes_test.go | 49 ++-- ...and-redirect-to-cluster-peer.latest.golden | 66 ++--- ...and-failover-to-cluster-peer.latest.golden | 136 +++++----- ...and-redirect-to-cluster-peer.latest.golden | 136 +++++----- .../validateupstream_test.go | 18 +- agent/xds/xds_protocol_helpers_test.go | 2 +- command/services/config_test.go | 8 +- 24 files changed, 738 insertions(+), 625 deletions(-) diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index c9cfbee45cb8..2c5ee9f3727a 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -186,7 +186,7 @@ func TestAgent_Services_ExternalConnectProxy(t *testing.T) { Port: 5000, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "db", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, } a.State.AddServiceWithChecks(srv1, nil, "", false) @@ -226,7 +226,7 @@ func TestAgent_Services_Sidecar(t *testing.T) { LocallyRegisteredAsSidecar: true, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "db", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), Mode: structs.ProxyModeTransparent, TransparentProxy: structs.TransparentProxyConfig{ OutboundListenerPort: 10101, diff --git a/agent/proxycfg/manager_test.go b/agent/proxycfg/manager_test.go index b478489a61e2..bf2b8db9a92b 100644 --- a/agent/proxycfg/manager_test.go +++ b/agent/proxycfg/manager_test.go @@ -95,7 +95,7 @@ func TestManager_BasicLifecycle(t *testing.T) { }) } - upstreams := structs.TestUpstreams(t) + upstreams := structs.TestUpstreams(t, false) for i := range upstreams { upstreams[i].DestinationNamespace = structs.IntentionDefaultNamespace upstreams[i].DestinationPartition = api.PartitionDefaultName diff --git a/agent/proxycfg/testing.go b/agent/proxycfg/testing.go index 412688d51d1c..a0b71c66e11b 100644 --- a/agent/proxycfg/testing.go +++ b/agent/proxycfg/testing.go @@ -552,7 +552,7 @@ func TestGatewayServiceGroupBarDC1(t testing.T) structs.CheckServiceNodes { }, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "bar", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, }, @@ -573,7 +573,7 @@ func TestGatewayServiceGroupBarDC1(t testing.T) structs.CheckServiceNodes { }, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "bar", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, }, @@ -594,7 +594,7 @@ func TestGatewayServiceGroupBarDC1(t testing.T) structs.CheckServiceNodes { }, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "bar", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, }, @@ -620,7 +620,7 @@ func TestGatewayServiceGroupFooDC1(t testing.T) structs.CheckServiceNodes { }, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "foo", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, }, @@ -641,7 +641,7 @@ func TestGatewayServiceGroupFooDC1(t testing.T) structs.CheckServiceNodes { }, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "foo", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, }, @@ -662,7 +662,7 @@ func TestGatewayServiceGroupFooDC1(t testing.T) structs.CheckServiceNodes { }, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "foo", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, }, @@ -683,7 +683,7 @@ func TestGatewayServiceGroupFooDC1(t testing.T) structs.CheckServiceNodes { }, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "foo", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, Checks: structs.HealthChecks{ diff --git a/agent/proxycfg/testing_api_gateway.go b/agent/proxycfg/testing_api_gateway.go index dd55f2eec5c2..b63c624e05a9 100644 --- a/agent/proxycfg/testing_api_gateway.go +++ b/agent/proxycfg/testing_api_gateway.go @@ -105,7 +105,7 @@ func TestConfigSnapshotAPIGateway( }) } - upstreams := structs.TestUpstreams(t) + upstreams := structs.TestUpstreams(t, false) baseEvents = testSpliceEvents(baseEvents, setupTestVariationConfigEntriesAndSnapshot( t, variation, upstreams, additionalEntries..., diff --git a/agent/proxycfg/testing_connect_proxy.go b/agent/proxycfg/testing_connect_proxy.go index 394687a44bcc..332c8ef2d8f3 100644 --- a/agent/proxycfg/testing_connect_proxy.go +++ b/agent/proxycfg/testing_connect_proxy.go @@ -7,6 +7,7 @@ import ( "github.com/mitchellh/go-testing-interface" "github.com/stretchr/testify/assert" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul/discoverychain" "github.com/hashicorp/consul/agent/structs" @@ -23,7 +24,7 @@ func TestConfigSnapshot(t testing.T, nsFn func(ns *structs.NodeService), extraUp assert.True(t, dbChain.Default) var ( - upstreams = structs.TestUpstreams(t) + upstreams = structs.TestUpstreams(t, false) dbUpstream = upstreams[0] geoUpstream = upstreams[1] @@ -93,19 +94,25 @@ func TestConfigSnapshot(t testing.T, nsFn func(ns *structs.NodeService), extraUp func TestConfigSnapshotDiscoveryChain( t testing.T, variation string, + enterprise bool, nsFn func(ns *structs.NodeService), extraUpdates []UpdateEvent, additionalEntries ...structs.ConfigEntry, ) *ConfigSnapshot { roots, leaf := TestCerts(t) + var entMeta acl.EnterpriseMeta + if enterprise { + entMeta = acl.NewEnterpriseMetaWithPartition("ap1", "ns1") + } + var ( - upstreams = structs.TestUpstreams(t) + upstreams = structs.TestUpstreams(t, enterprise) geoUpstream = upstreams[1] geoUID = NewUpstreamID(&geoUpstream) - webSN = structs.ServiceIDString("web", nil) + webSN = structs.ServiceIDString("web", &entMeta) ) baseEvents := testSpliceEvents([]UpdateEvent{ @@ -157,6 +164,7 @@ func TestConfigSnapshotDiscoveryChain( }, Meta: nil, TaggedAddresses: nil, + EnterpriseMeta: entMeta, }, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates)) } diff --git a/agent/proxycfg/testing_ingress_gateway.go b/agent/proxycfg/testing_ingress_gateway.go index bca283f18505..274f9931b75e 100644 --- a/agent/proxycfg/testing_ingress_gateway.go +++ b/agent/proxycfg/testing_ingress_gateway.go @@ -84,7 +84,7 @@ func TestConfigSnapshotIngressGateway( }, }}) - upstreams := structs.TestUpstreams(t) + upstreams := structs.TestUpstreams(t, false) upstreams = structs.Upstreams{upstreams[0]} // just keep 'db' baseEvents = testSpliceEvents(baseEvents, setupTestVariationConfigEntriesAndSnapshot( diff --git a/agent/proxycfg/testing_upstreams.go b/agent/proxycfg/testing_upstreams.go index 15e591edf427..5e88d6e18adc 100644 --- a/agent/proxycfg/testing_upstreams.go +++ b/agent/proxycfg/testing_upstreams.go @@ -5,6 +5,7 @@ import ( "github.com/mitchellh/go-testing-interface" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul/discoverychain" "github.com/hashicorp/consul/agent/structs" @@ -23,7 +24,7 @@ func setupTestVariationConfigEntriesAndSnapshot( dbUID = NewUpstreamID(&dbUpstream) ) - dbChain := setupTestVariationDiscoveryChain(t, variation, additionalEntries...) + dbChain := setupTestVariationDiscoveryChain(t, variation, dbUID.EnterpriseMeta, additionalEntries...) nodes := TestUpstreamNodes(t, "db") if variation == "register-to-terminating-gateway" { @@ -46,29 +47,42 @@ func setupTestVariationConfigEntriesAndSnapshot( }, } + dbOpts := structs.DiscoveryTargetOpts{ + Service: dbUID.Name, + Namespace: dbUID.NamespaceOrDefault(), + Partition: dbUID.PartitionOrDefault(), + Datacenter: "dc1", + } + dbChainID := structs.ChainID(dbOpts) + makeChainID := func(opts structs.DiscoveryTargetOpts) string { + return structs.ChainID(structs.MergeDiscoveryTargetOpts(dbOpts, opts)) + } + switch variation { case "default": case "simple-with-overrides": case "simple": case "external-sni": case "failover": + chainID := makeChainID(structs.DiscoveryTargetOpts{Service: "fail"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:fail.default.default.dc1:" + dbUID.String(), + CorrelationID: "upstream-target:" + chainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesAlternate(t), }, }) case "failover-through-remote-gateway-triggered": events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc1:" + dbUID.String(), + CorrelationID: "upstream-target:" + dbChainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesInStatus(t, "critical"), }, }) fallthrough case "failover-through-remote-gateway": + chainID := makeChainID(structs.DiscoveryTargetOpts{Datacenter: "dc2"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc2:" + dbUID.String(), + CorrelationID: "upstream-target:" + chainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesDC2(t), }, @@ -91,8 +105,13 @@ func setupTestVariationConfigEntriesAndSnapshot( }, }, }) + uid := UpstreamID{ + Name: "db", + Peer: "cluster-01", + EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(dbUID.PartitionOrDefault(), ""), + } events = append(events, UpdateEvent{ - CorrelationID: "upstream-peer:db?peer=cluster-01", + CorrelationID: "upstream-peer:" + uid.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: structs.CheckServiceNodes{structs.TestCheckNodeServiceWithNameInPeer(t, "db", "dc1", "cluster-01", "10.40.1.1", false)}, }, @@ -109,83 +128,93 @@ func setupTestVariationConfigEntriesAndSnapshot( }, }, }) + uid := UpstreamID{ + Name: "db", + Peer: "cluster-01", + EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(dbUID.PartitionOrDefault(), ""), + } events = append(events, UpdateEvent{ - CorrelationID: "upstream-peer:db?peer=cluster-01", + CorrelationID: "upstream-peer:" + uid.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: structs.CheckServiceNodes{structs.TestCheckNodeServiceWithNameInPeer(t, "db", "dc2", "cluster-01", "10.40.1.1", false)}, }, }) case "failover-through-double-remote-gateway-triggered": + chainID := makeChainID(structs.DiscoveryTargetOpts{Datacenter: "dc2"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc1:" + dbUID.String(), + CorrelationID: "upstream-target:" + dbChainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesInStatus(t, "critical"), }, - }) - events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc2:" + dbUID.String(), - Result: &structs.IndexedCheckServiceNodes{ - Nodes: TestUpstreamNodesInStatusDC2(t, "critical"), - }, - }) + }, + UpdateEvent{ + CorrelationID: "upstream-target:" + chainID + ":" + dbUID.String(), + Result: &structs.IndexedCheckServiceNodes{ + Nodes: TestUpstreamNodesInStatusDC2(t, "critical"), + }, + }) fallthrough case "failover-through-double-remote-gateway": + chainID := makeChainID(structs.DiscoveryTargetOpts{Datacenter: "dc3"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc3:" + dbUID.String(), + CorrelationID: "upstream-target:" + chainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesDC2(t), }, - }) - events = append(events, UpdateEvent{ - CorrelationID: "mesh-gateway:dc2:" + dbUID.String(), - Result: &structs.IndexedCheckServiceNodes{ - Nodes: TestGatewayNodesDC2(t), - }, - }) - events = append(events, UpdateEvent{ - CorrelationID: "mesh-gateway:dc3:" + dbUID.String(), - Result: &structs.IndexedCheckServiceNodes{ - Nodes: TestGatewayNodesDC3(t), + }, + UpdateEvent{ + CorrelationID: "mesh-gateway:dc2:" + dbUID.String(), + Result: &structs.IndexedCheckServiceNodes{ + Nodes: TestGatewayNodesDC2(t), + }, }, - }) + UpdateEvent{ + CorrelationID: "mesh-gateway:dc3:" + dbUID.String(), + Result: &structs.IndexedCheckServiceNodes{ + Nodes: TestGatewayNodesDC3(t), + }, + }) case "failover-through-local-gateway-triggered": events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc1:" + dbUID.String(), + CorrelationID: "upstream-target:" + dbChainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesInStatus(t, "critical"), }, }) fallthrough case "failover-through-local-gateway": + chainID := makeChainID(structs.DiscoveryTargetOpts{Datacenter: "dc2"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc2:" + dbUID.String(), + CorrelationID: "upstream-target:" + chainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesDC2(t), }, - }) - events = append(events, UpdateEvent{ - CorrelationID: "mesh-gateway:dc1:" + dbUID.String(), - Result: &structs.IndexedCheckServiceNodes{ - Nodes: TestGatewayNodesDC1(t), - }, - }) + }, + UpdateEvent{ + CorrelationID: "mesh-gateway:dc1:" + dbUID.String(), + Result: &structs.IndexedCheckServiceNodes{ + Nodes: TestGatewayNodesDC1(t), + }, + }) case "failover-through-double-local-gateway-triggered": + db2ChainID := makeChainID(structs.DiscoveryTargetOpts{Datacenter: "dc2"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc1:" + dbUID.String(), + CorrelationID: "upstream-target:" + dbChainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesInStatus(t, "critical"), }, - }) - events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc2:" + dbUID.String(), - Result: &structs.IndexedCheckServiceNodes{ - Nodes: TestUpstreamNodesInStatusDC2(t, "critical"), - }, - }) + }, + UpdateEvent{ + CorrelationID: "upstream-target:" + db2ChainID + ":" + dbUID.String(), + Result: &structs.IndexedCheckServiceNodes{ + Nodes: TestUpstreamNodesInStatusDC2(t, "critical"), + }, + }) fallthrough case "failover-through-double-local-gateway": + db3ChainID := makeChainID(structs.DiscoveryTargetOpts{Datacenter: "dc3"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:db.default.default.dc3:" + dbUID.String(), + CorrelationID: "upstream-target:" + db3ChainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesDC2(t), }, @@ -197,14 +226,16 @@ func setupTestVariationConfigEntriesAndSnapshot( }, }) case "splitter-with-resolver-redirect-multidc": + v1ChainID := makeChainID(structs.DiscoveryTargetOpts{ServiceSubset: "v1"}) + v2ChainID := makeChainID(structs.DiscoveryTargetOpts{ServiceSubset: "v2", Datacenter: "dc2"}) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:v1.db.default.default.dc1:" + dbUID.String(), + CorrelationID: "upstream-target:" + v1ChainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodes(t, "db"), }, }) events = append(events, UpdateEvent{ - CorrelationID: "upstream-target:v2.db.default.default.dc2:" + dbUID.String(), + CorrelationID: "upstream-target:" + v2ChainID + ":" + dbUID.String(), Result: &structs.IndexedCheckServiceNodes{ Nodes: TestUpstreamNodesDC2(t), }, @@ -225,6 +256,7 @@ func setupTestVariationConfigEntriesAndSnapshot( func setupTestVariationDiscoveryChain( t testing.T, variation string, + entMeta acl.EnterpriseMeta, additionalEntries ...structs.ConfigEntry, ) *structs.CompiledDiscoveryChain { // Compile a chain. @@ -249,6 +281,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, }, @@ -256,13 +289,15 @@ func setupTestVariationDiscoveryChain( case "external-sni": entries = append(entries, &structs.ServiceConfigEntry{ - Kind: structs.ServiceDefaults, - Name: "db", - ExternalSNI: "db.some.other.service.mesh", + Kind: structs.ServiceDefaults, + Name: "db", + EnterpriseMeta: entMeta, + ExternalSNI: "db.some.other.service.mesh", }, &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, }, @@ -272,6 +307,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, Failover: map[string]structs.ServiceResolverFailover{ @@ -286,8 +322,9 @@ func setupTestVariationDiscoveryChain( case "failover-through-remote-gateway": entries = append(entries, &structs.ServiceConfigEntry{ - Kind: structs.ServiceDefaults, - Name: "db", + Kind: structs.ServiceDefaults, + Name: "db", + EnterpriseMeta: entMeta, MeshGateway: structs.MeshGatewayConfig{ Mode: structs.MeshGatewayModeRemote, }, @@ -295,6 +332,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, Failover: map[string]structs.ServiceResolverFailover{ @@ -309,6 +347,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, Failover: map[string]structs.ServiceResolverFailover{ @@ -325,6 +364,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, Redirect: &structs.ServiceResolverRedirect{ @@ -337,8 +377,9 @@ func setupTestVariationDiscoveryChain( case "failover-through-double-remote-gateway": entries = append(entries, &structs.ServiceConfigEntry{ - Kind: structs.ServiceDefaults, - Name: "db", + Kind: structs.ServiceDefaults, + Name: "db", + EnterpriseMeta: entMeta, MeshGateway: structs.MeshGatewayConfig{ Mode: structs.MeshGatewayModeRemote, }, @@ -346,6 +387,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, Failover: map[string]structs.ServiceResolverFailover{ @@ -360,8 +402,9 @@ func setupTestVariationDiscoveryChain( case "failover-through-local-gateway": entries = append(entries, &structs.ServiceConfigEntry{ - Kind: structs.ServiceDefaults, - Name: "db", + Kind: structs.ServiceDefaults, + Name: "db", + EnterpriseMeta: entMeta, MeshGateway: structs.MeshGatewayConfig{ Mode: structs.MeshGatewayModeLocal, }, @@ -369,6 +412,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, Failover: map[string]structs.ServiceResolverFailover{ @@ -383,8 +427,9 @@ func setupTestVariationDiscoveryChain( case "failover-through-double-local-gateway": entries = append(entries, &structs.ServiceConfigEntry{ - Kind: structs.ServiceDefaults, - Name: "db", + Kind: structs.ServiceDefaults, + Name: "db", + EnterpriseMeta: entMeta, MeshGateway: structs.MeshGatewayConfig{ Mode: structs.MeshGatewayModeLocal, }, @@ -392,6 +437,7 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, Failover: map[string]structs.ServiceResolverFailover{ @@ -402,25 +448,29 @@ func setupTestVariationDiscoveryChain( }, ) case "splitter-with-resolver-redirect-multidc": + em := acl.NewEnterpriseMetaWithPartition(entMeta.PartitionOrDefault(), acl.NamespaceOrDefault("")) entries = append(entries, &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + EnterpriseMeta: em, Config: map[string]interface{}{ "protocol": "http", }, }, &structs.ServiceSplitterConfigEntry{ - Kind: structs.ServiceResolver, - Name: "db", + Kind: structs.ServiceResolver, + Name: "db", + EnterpriseMeta: entMeta, Splits: []structs.ServiceSplit{ {Weight: 50, Service: "db-dc1"}, {Weight: 50, Service: "db-dc2"}, }, }, &structs.ServiceResolverConfigEntry{ - Kind: structs.ServiceResolver, - Name: "db-dc1", + Kind: structs.ServiceResolver, + Name: "db-dc1", + EnterpriseMeta: entMeta, Redirect: &structs.ServiceResolverRedirect{ Service: "db", ServiceSubset: "v1", @@ -428,8 +478,9 @@ func setupTestVariationDiscoveryChain( }, }, &structs.ServiceResolverConfigEntry{ - Kind: structs.ServiceResolver, - Name: "db-dc2", + Kind: structs.ServiceResolver, + Name: "db-dc2", + EnterpriseMeta: entMeta, Redirect: &structs.ServiceResolverRedirect{ Service: "db", ServiceSubset: "v2", @@ -437,8 +488,9 @@ func setupTestVariationDiscoveryChain( }, }, &structs.ServiceResolverConfigEntry{ - Kind: structs.ServiceResolver, - Name: "db", + Kind: structs.ServiceResolver, + Name: "db", + EnterpriseMeta: entMeta, Subsets: map[string]structs.ServiceResolverSubset{ "v1": { Filter: "Service.Meta.version == v1", @@ -454,19 +506,22 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, }, &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + EnterpriseMeta: entMeta, Config: map[string]interface{}{ "protocol": "http", }, }, &structs.ServiceSplitterConfigEntry{ - Kind: structs.ServiceSplitter, - Name: "db", + Kind: structs.ServiceSplitter, + Name: "db", + EnterpriseMeta: entMeta, Splits: []structs.ServiceSplit{ { Weight: 95.5, @@ -506,19 +561,22 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, }, &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + EnterpriseMeta: entMeta, Config: map[string]interface{}{ "protocol": "grpc", }, }, &structs.ServiceRouterConfigEntry{ - Kind: structs.ServiceRouter, - Name: "db", + Kind: structs.ServiceRouter, + Name: "db", + EnterpriseMeta: entMeta, Routes: []structs.ServiceRoute{ { Match: &structs.ServiceRouteMatch{ @@ -538,19 +596,22 @@ func setupTestVariationDiscoveryChain( &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "db", + EnterpriseMeta: entMeta, ConnectTimeout: 33 * time.Second, RequestTimeout: 33 * time.Second, }, &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + EnterpriseMeta: entMeta, Config: map[string]interface{}{ "protocol": "http", }, }, &structs.ServiceSplitterConfigEntry{ - Kind: structs.ServiceSplitter, - Name: "split-3-ways", + Kind: structs.ServiceSplitter, + Name: "split-3-ways", + EnterpriseMeta: entMeta, Splits: []structs.ServiceSplit{ {Weight: 95.5, Service: "big-side"}, {Weight: 4, Service: "goldilocks-side"}, @@ -558,8 +619,9 @@ func setupTestVariationDiscoveryChain( }, }, &structs.ServiceRouterConfigEntry{ - Kind: structs.ServiceRouter, - Name: "db", + Kind: structs.ServiceRouter, + Name: "db", + EnterpriseMeta: entMeta, Routes: []structs.ServiceRoute{ { Match: httpMatch(&structs.ServiceRouteHTTPMatch{ @@ -790,23 +852,26 @@ func setupTestVariationDiscoveryChain( case "lb-resolver": entries = append(entries, &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + EnterpriseMeta: entMeta, Config: map[string]interface{}{ "protocol": "http", }, }, &structs.ServiceSplitterConfigEntry{ - Kind: structs.ServiceSplitter, - Name: "db", + Kind: structs.ServiceSplitter, + Name: "db", + EnterpriseMeta: entMeta, Splits: []structs.ServiceSplit{ {Weight: 95.5, Service: "something-else"}, {Weight: 4.5, Service: "db"}, }, }, &structs.ServiceResolverConfigEntry{ - Kind: structs.ServiceResolver, - Name: "db", + Kind: structs.ServiceResolver, + Name: "db", + EnterpriseMeta: entMeta, LoadBalancer: &structs.LoadBalancer{ Policy: "ring_hash", RingHashConfig: &structs.RingHashConfig{ @@ -845,7 +910,7 @@ func setupTestVariationDiscoveryChain( entries = append(entries, additionalEntries...) } - return discoverychain.TestCompileConfigEntries(t, "db", "default", "default", "dc1", connect.TestClusterID+".consul", compileSetup, entries...) + return discoverychain.TestCompileConfigEntries(t, "db", entMeta.NamespaceOrDefault(), entMeta.PartitionOrDefault(), "dc1", connect.TestClusterID+".consul", compileSetup, entries...) } func httpMatch(http *structs.ServiceRouteHTTPMatch) *structs.ServiceRouteMatch { diff --git a/agent/proxycfg_test.go b/agent/proxycfg_test.go index 18a5c586245c..11f9b8fe7955 100644 --- a/agent/proxycfg_test.go +++ b/agent/proxycfg_test.go @@ -41,7 +41,7 @@ func TestAgent_local_proxycfg(t *testing.T) { LocallyRegisteredAsSidecar: true, Proxy: structs.ConnectProxyConfig{ DestinationServiceName: "db", - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(), } diff --git a/agent/sidecar_service_test.go b/agent/sidecar_service_test.go index 3b4a018a52d7..37854298e62e 100644 --- a/agent/sidecar_service_test.go +++ b/agent/sidecar_service_test.go @@ -93,7 +93,7 @@ func TestAgent_sidecarServiceFromNodeService(t *testing.T) { LocalServiceAddress: "127.0.127.0", LocalServicePort: 9999, Config: map[string]interface{}{"baz": "qux"}, - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), }, }, }, @@ -118,7 +118,7 @@ func TestAgent_sidecarServiceFromNodeService(t *testing.T) { LocalServiceAddress: "127.0.127.0", LocalServicePort: 9999, Config: map[string]interface{}{"baz": "qux"}, - Upstreams: structs.TestAddDefaultsToUpstreams(t, structs.TestUpstreams(t), + Upstreams: structs.TestAddDefaultsToUpstreams(t, structs.TestUpstreams(t, false), *structs.DefaultEnterpriseMetaInDefaultPartition()), }, }, diff --git a/agent/structs/discovery_chain.go b/agent/structs/discovery_chain.go index fd2900b8faad..9473e533fba0 100644 --- a/agent/structs/discovery_chain.go +++ b/agent/structs/discovery_chain.go @@ -59,7 +59,7 @@ type CompiledDiscoveryChain struct { // ID returns an ID that encodes the service, namespace, partition, and datacenter. // This ID allows us to compare a discovery chain target to the chain upstream itself. func (c *CompiledDiscoveryChain) ID() string { - return chainID(DiscoveryTargetOpts{ + return ChainID(DiscoveryTargetOpts{ Service: c.ServiceName, Namespace: c.Namespace, Partition: c.Partition, @@ -314,7 +314,7 @@ func (t *DiscoveryTarget) ToDiscoveryTargetOpts() DiscoveryTargetOpts { } } -func chainID(opts DiscoveryTargetOpts) string { +func ChainID(opts DiscoveryTargetOpts) string { // NOTE: this format is similar to the SNI syntax for simplicity if opts.Peer != "" { return fmt.Sprintf("%s.%s.default.external.%s", opts.Service, opts.Namespace, opts.Peer) @@ -326,7 +326,7 @@ func chainID(opts DiscoveryTargetOpts) string { } func (t *DiscoveryTarget) setID() { - t.ID = chainID(t.ToDiscoveryTargetOpts()) + t.ID = ChainID(t.ToDiscoveryTargetOpts()) } func (t *DiscoveryTarget) String() string { diff --git a/agent/structs/testing_connect_proxy_config.go b/agent/structs/testing_connect_proxy_config.go index fdee3f6937db..0021612e9e84 100644 --- a/agent/structs/testing_connect_proxy_config.go +++ b/agent/structs/testing_connect_proxy_config.go @@ -11,37 +11,46 @@ import ( func TestConnectProxyConfig(t testing.T) ConnectProxyConfig { return ConnectProxyConfig{ DestinationServiceName: "web", - Upstreams: TestUpstreams(t), + Upstreams: TestUpstreams(t, false), } } // TestUpstreams returns a set of upstreams to be used in tests exercising most // important configuration patterns. -func TestUpstreams(t testing.T) Upstreams { - return Upstreams{ - { - // We rely on this one having default type in a few tests... - DestinationName: "db", - LocalBindPort: 9191, - Config: map[string]interface{}{ - // Float because this is how it is decoded by JSON decoder so this - // enables the value returned to be compared directly to a decoded JSON - // response without spurious type loss. - "connect_timeout_ms": float64(1000), - }, - }, - { - DestinationType: UpstreamDestTypePreparedQuery, - DestinationName: "geo-cache", - LocalBindPort: 8181, - LocalBindAddress: "127.10.10.10", - }, - { - DestinationName: "upstream_socket", - LocalBindSocketPath: "/tmp/upstream.sock", - LocalBindSocketMode: "0700", +func TestUpstreams(t testing.T, enterprise bool) Upstreams { + db := Upstream{ + // We rely on this one having default type in a few tests... + DestinationName: "db", + LocalBindPort: 9191, + Config: map[string]interface{}{ + // Float because this is how it is decoded by JSON decoder so this + // enables the value returned to be compared directly to a decoded JSON + // response without spurious type loss. + "connect_timeout_ms": float64(1000), }, } + + geoCache := Upstream{ + DestinationType: UpstreamDestTypePreparedQuery, + DestinationName: "geo-cache", + LocalBindPort: 8181, + LocalBindAddress: "127.10.10.10", + } + + if enterprise { + db.DestinationNamespace = "foo" + db.DestinationPartition = "bar" + + geoCache.DestinationNamespace = "baz" + geoCache.DestinationPartition = "qux" + } + + return Upstreams{db, geoCache, { + DestinationName: "upstream_socket", + LocalBindSocketPath: "/tmp/upstream.sock", + LocalBindSocketMode: "0700", + }, + } } // TestAddDefaultsToUpstreams takes an array of upstreams (such as that from diff --git a/agent/xds/clusters_test.go b/agent/xds/clusters_test.go index e2269dc7ffa1..094b9ceb182d 100644 --- a/agent/xds/clusters_test.go +++ b/agent/xds/clusters_test.go @@ -21,6 +21,112 @@ import ( "github.com/hashicorp/consul/types" ) +type clusterTestCase struct { + name string + create func(t testinf.T) *proxycfg.ConfigSnapshot + overrideGoldenName string +} + +func makeClusterDiscoChainTests(enterprise bool) []clusterTestCase { + return []clusterTestCase{ + { + name: "custom-upstream-default-chain", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", enterprise, func(ns *structs.NodeService) { + ns.Proxy.Upstreams[0].Config["envoy_cluster_json"] = + customAppClusterJSON(t, customClusterJSONOptions{ + Name: "myservice", + }) + }, nil) + }, + }, + { + name: "connect-proxy-with-chain", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-chain-external-sni", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-chain-and-overrides", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-chain-and-failover", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway-triggered", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway-triggered", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway-triggered", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway-triggered", enterprise, nil, nil) + }, + }, + { + name: "splitter-with-resolver-redirect", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-lb-in-resolver", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "lb-resolver", enterprise, nil, nil) + }, + }, + } +} + func TestClustersFromSnapshot(t *testing.T) { // TODO: we should move all of these to TestAllResourcesFromSnapshot // eventually to test all of the xDS types at once with the same input, @@ -29,11 +135,7 @@ func TestClustersFromSnapshot(t *testing.T) { t.Skip("too slow for testing.Short") } - tests := []struct { - name string - create func(t testinf.T) *proxycfg.ConfigSnapshot - overrideGoldenName string - }{ + tests := []clusterTestCase{ { name: "connect-proxy-with-tls-outgoing-min-version-auto", create: func(t testinf.T) *proxycfg.ConfigSnapshot { @@ -135,17 +237,6 @@ func TestClustersFromSnapshot(t *testing.T) { }, nil) }, }, - { - name: "custom-upstream-default-chain", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", func(ns *structs.NodeService) { - ns.Proxy.Upstreams[0].Config["envoy_cluster_json"] = - customAppClusterJSON(t, customClusterJSONOptions{ - Name: "myservice", - }) - }, nil) - }, - }, { name: "custom-upstream-ignores-tls", overrideGoldenName: "custom-upstream", // should be the same @@ -245,90 +336,6 @@ func TestClustersFromSnapshot(t *testing.T) { }, nil) }, }, - { - name: "connect-proxy-with-chain", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil) - }, - }, - { - name: "connect-proxy-with-chain-external-sni", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", nil, nil) - }, - }, - { - name: "connect-proxy-with-chain-and-overrides", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", nil, nil) - }, - }, - { - name: "connect-proxy-with-chain-and-failover", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway-triggered", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway-triggered", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway-triggered", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway-triggered", nil, nil) - }, - }, - { - name: "splitter-with-resolver-redirect", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", nil, nil) - }, - }, - { - name: "connect-proxy-lb-in-resolver", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "lb-resolver", nil, nil) - }, - }, { name: "expose-paths-local-app-paths", create: func(t testinf.T) *proxycfg.ConfigSnapshot { @@ -767,6 +774,8 @@ func TestClustersFromSnapshot(t *testing.T) { }, } + tests = append(tests, makeClusterDiscoChainTests(false)...) + latestEnvoyVersion := xdscommon.EnvoyVersions[0] for _, envoyVersion := range xdscommon.EnvoyVersions { sf, err := xdscommon.DetermineSupportedProxyFeaturesFromString(envoyVersion) diff --git a/agent/xds/delta_envoy_extender_oss_test.go b/agent/xds/delta_envoy_extender_oss_test.go index f6791ba65435..48b7589ada1c 100644 --- a/agent/xds/delta_envoy_extender_oss_test.go +++ b/agent/xds/delta_envoy_extender_oss_test.go @@ -92,7 +92,7 @@ end`, { name: "lambda-connect-proxy", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, makeLambdaServiceDefaults(false)) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, makeLambdaServiceDefaults(false)) }, }, { @@ -107,13 +107,13 @@ end`, { name: "lambda-connect-proxy-with-terminating-gateway-upstream", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", nil, nil, makeLambdaServiceDefaults(false)) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", false, nil, nil, makeLambdaServiceDefaults(false)) }, }, { name: "lambda-connect-proxy-opposite-meta", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, makeLambdaServiceDefaults(true)) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, makeLambdaServiceDefaults(true)) }, }, { @@ -129,13 +129,13 @@ end`, { name: "lua-outbound-applies-to-upstreams", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, makeLuaServiceDefaults(false)) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, makeLuaServiceDefaults(false)) }, }, { name: "lua-inbound-doesnt-applies-to-upstreams", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, makeLuaServiceDefaults(true)) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, makeLuaServiceDefaults(true)) }, }, { @@ -183,7 +183,7 @@ end`, { name: "lua-connect-proxy-with-terminating-gateway-upstream", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", nil, nil, makeLambdaServiceDefaults(false)) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", false, nil, nil, makeLambdaServiceDefaults(false)) }, }, { @@ -205,7 +205,7 @@ end`, }, } } - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nsFunc, nil, makeLambdaServiceDefaults(true)) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nsFunc, nil, makeLambdaServiceDefaults(true)) }, }, { diff --git a/agent/xds/endpoints_test.go b/agent/xds/endpoints_test.go index e43865495a7c..31215adba93d 100644 --- a/agent/xds/endpoints_test.go +++ b/agent/xds/endpoints_test.go @@ -217,136 +217,143 @@ func Test_makeLoadAssignment(t *testing.T) { } } -func TestEndpointsFromSnapshot(t *testing.T) { - // TODO: we should move all of these to TestAllResourcesFromSnapshot - // eventually to test all of the xDS types at once with the same input, - // just as it would be triggered by our xDS server. - if testing.Short() { - t.Skip("too slow for testing.Short") - } +type endpointTestCase struct { + name string + create func(t testinf.T) *proxycfg.ConfigSnapshot + overrideGoldenName string +} - tests := []struct { - name string - create func(t testinf.T) *proxycfg.ConfigSnapshot - overrideGoldenName string - }{ +func makeEndpointDiscoChainTests(enterprise bool) []endpointTestCase { + return []endpointTestCase{ { - name: "mesh-gateway", + name: "connect-proxy-with-chain", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotMeshGateway(t, "default", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", enterprise, nil, nil) }, }, { - name: "mesh-gateway-using-federation-states", + name: "connect-proxy-with-chain-external-sni", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotMeshGateway(t, "federation-states", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", enterprise, nil, nil) }, }, { - name: "mesh-gateway-newer-information-in-federation-states", + name: "connect-proxy-with-chain-and-overrides", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotMeshGateway(t, "newer-info-in-federation-states", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", enterprise, nil, nil) }, }, { - name: "mesh-gateway-older-information-in-federation-states", + name: "connect-proxy-with-chain-and-failover", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotMeshGateway(t, "older-info-in-federation-states", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", enterprise, nil, nil) }, }, { - name: "mesh-gateway-no-services", + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotMeshGateway(t, "no-services", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-chain", + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway-triggered", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-chain-external-sni", + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-chain-and-overrides", + name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway-triggered", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-chain-and-failover", + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway-triggered", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway-triggered", + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway-triggered", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway", + name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway-triggered", enterprise, nil, nil) }, }, { - name: "connect-proxy-with-tcp-chain-double-failover-through-remote-gateway-triggered", + name: "connect-proxy-with-default-chain-and-custom-cluster", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-remote-gateway-triggered", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", enterprise, func(ns *structs.NodeService) { + ns.Proxy.Upstreams[0].Config["envoy_cluster_json"] = + customAppClusterJSON(t, customClusterJSONOptions{ + Name: "myservice", + }) + }, nil) }, }, { - name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", + name: "splitter-with-resolver-redirect", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", enterprise, nil, nil) }, }, + } +} + +func TestEndpointsFromSnapshot(t *testing.T) { + // TODO: we should move all of these to TestAllResourcesFromSnapshot + // eventually to test all of the xDS types at once with the same input, + // just as it would be triggered by our xDS server. + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + tests := []endpointTestCase{ { - name: "connect-proxy-with-tcp-chain-failover-through-local-gateway-triggered", + name: "mesh-gateway", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway-triggered", nil, nil) + return proxycfg.TestConfigSnapshotMeshGateway(t, "default", nil, nil) }, }, { - name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway", + name: "mesh-gateway-using-federation-states", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway", nil, nil) + return proxycfg.TestConfigSnapshotMeshGateway(t, "federation-states", nil, nil) }, }, { - name: "connect-proxy-with-tcp-chain-double-failover-through-local-gateway-triggered", + name: "mesh-gateway-newer-information-in-federation-states", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-double-local-gateway-triggered", nil, nil) + return proxycfg.TestConfigSnapshotMeshGateway(t, "newer-info-in-federation-states", nil, nil) }, }, { - name: "connect-proxy-with-default-chain-and-custom-cluster", + name: "mesh-gateway-older-information-in-federation-states", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", func(ns *structs.NodeService) { - ns.Proxy.Upstreams[0].Config["envoy_cluster_json"] = - customAppClusterJSON(t, customClusterJSONOptions{ - Name: "myservice", - }) - }, nil) + return proxycfg.TestConfigSnapshotMeshGateway(t, "older-info-in-federation-states", nil, nil) }, }, { - name: "splitter-with-resolver-redirect", + name: "mesh-gateway-no-services", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", nil, nil) + return proxycfg.TestConfigSnapshotMeshGateway(t, "no-services", nil, nil) }, }, { @@ -498,6 +505,8 @@ func TestEndpointsFromSnapshot(t *testing.T) { }, } + tests = append(tests, makeEndpointDiscoChainTests(false)...) + latestEnvoyVersion := xdscommon.EnvoyVersions[0] for _, envoyVersion := range xdscommon.EnvoyVersions { sf, err := xdscommon.DetermineSupportedProxyFeaturesFromString(envoyVersion) diff --git a/agent/xds/extensionruntime/runtime_config_oss_test.go b/agent/xds/extensionruntime/runtime_config_oss_test.go index 62ce5f812c18..cc004c788de8 100644 --- a/agent/xds/extensionruntime/runtime_config_oss_test.go +++ b/agent/xds/extensionruntime/runtime_config_oss_test.go @@ -130,11 +130,11 @@ func TestGetRuntimeConfigurations_ConnectProxy(t *testing.T) { } // Setup a snapshot where the db upstream is on a connect proxy. - snapConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, serviceDefaults) + snapConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, serviceDefaults) // Setup a snapshot where the db upstream is on a terminating gateway. - snapTermGw := proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", nil, nil, serviceDefaults) + snapTermGw := proxycfg.TestConfigSnapshotDiscoveryChain(t, "register-to-terminating-gateway", false, nil, nil, serviceDefaults) // Setup a snapshot with the local service web has extensions. - snapWebConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", func(ns *structs.NodeService) { + snapWebConnect := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, func(ns *structs.NodeService) { ns.Proxy.EnvoyExtensions = envoyExtensions }, nil) diff --git a/agent/xds/listeners_test.go b/agent/xds/listeners_test.go index 6d0d64407bbf..a69a74a2b1c5 100644 --- a/agent/xds/listeners_test.go +++ b/agent/xds/listeners_test.go @@ -21,6 +21,121 @@ import ( "github.com/hashicorp/consul/types" ) +type listenerTestCase struct { + name string + create func(t testinf.T) *proxycfg.ConfigSnapshot + // Setup is called before the test starts. It is passed the snapshot from + // TestConfigSnapshot and is allowed to modify it in any way to setup the + // test input. + overrideGoldenName string + generatorSetup func(*ResourceGenerator) +} + +func makeListenerDiscoChainTests(enterprise bool) []listenerTestCase { + return []listenerTestCase{ + { + name: "custom-upstream-ignored-with-disco-chain", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", enterprise, func(ns *structs.NodeService) { + for i := range ns.Proxy.Upstreams { + if ns.Proxy.Upstreams[i].DestinationName != "db" { + continue // only tweak the db upstream + } + if ns.Proxy.Upstreams[i].Config == nil { + ns.Proxy.Upstreams[i].Config = map[string]interface{}{} + } + + uid := proxycfg.NewUpstreamID(&ns.Proxy.Upstreams[i]) + + ns.Proxy.Upstreams[i].Config["envoy_listener_json"] = + customListenerJSON(t, customListenerJSONOptions{ + Name: uid.EnvoyID() + ":custom-upstream", + }) + } + }, nil) + }, + }, + { + name: "splitter-with-resolver-redirect", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-http-chain", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", enterprise, nil, nil, + &structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + Config: map[string]interface{}{ + "protocol": "http", + }, + }, + ) + }, + }, + { + name: "connect-proxy-with-http2-chain", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", enterprise, nil, nil, + &structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + Config: map[string]interface{}{ + "protocol": "http2", + }, + }, + ) + }, + }, + { + name: "connect-proxy-with-grpc-chain", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", enterprise, nil, nil, + &structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + Config: map[string]interface{}{ + "protocol": "grpc", + }, + }, + ) + }, + }, + { + name: "connect-proxy-with-chain-external-sni", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-chain-and-overrides", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway", enterprise, nil, nil) + }, + }, + { + name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", + create: func(t testinf.T) *proxycfg.ConfigSnapshot { + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway", enterprise, nil, nil) + }, + }, + } +} + func TestListenersFromSnapshot(t *testing.T) { // TODO: we should move all of these to TestAllResourcesFromSnapshot // eventually to test all of the xDS types at once with the same input, @@ -29,16 +144,7 @@ func TestListenersFromSnapshot(t *testing.T) { t.Skip("too slow for testing.Short") } - tests := []struct { - name string - create func(t testinf.T) *proxycfg.ConfigSnapshot - // Setup is called before the test starts. It is passed the snapshot from - // TestConfigSnapshot and is allowed to modify it in any way to setup the - // test input. - setup func(snap *proxycfg.ConfigSnapshot) - overrideGoldenName string - generatorSetup func(*ResourceGenerator) - }{ + tests := []listenerTestCase{ { name: "connect-proxy-with-tls-outgoing-min-version-auto", create: func(t testinf.T) *proxycfg.ConfigSnapshot { @@ -326,106 +432,6 @@ func TestListenersFromSnapshot(t *testing.T) { }, nil) }, }, - { - name: "custom-upstream-ignored-with-disco-chain", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", func(ns *structs.NodeService) { - for i := range ns.Proxy.Upstreams { - if ns.Proxy.Upstreams[i].DestinationName != "db" { - continue // only tweak the db upstream - } - if ns.Proxy.Upstreams[i].Config == nil { - ns.Proxy.Upstreams[i].Config = map[string]interface{}{} - } - - uid := proxycfg.NewUpstreamID(&ns.Proxy.Upstreams[i]) - - ns.Proxy.Upstreams[i].Config["envoy_listener_json"] = - customListenerJSON(t, customListenerJSONOptions{ - Name: uid.EnvoyID() + ":custom-upstream", - }) - } - }, nil) - }, - }, - { - name: "splitter-with-resolver-redirect", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil) - }, - }, - { - name: "connect-proxy-with-http-chain", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil, - &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, - Config: map[string]interface{}{ - "protocol": "http", - }, - }, - ) - }, - }, - { - name: "connect-proxy-with-http2-chain", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil, - &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, - Config: map[string]interface{}{ - "protocol": "http2", - }, - }, - ) - }, - }, - { - name: "connect-proxy-with-grpc-chain", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil, - &structs.ProxyConfigEntry{ - Kind: structs.ProxyDefaults, - Name: structs.ProxyConfigGlobal, - Config: map[string]interface{}{ - "protocol": "grpc", - }, - }, - ) - }, - }, - { - name: "connect-proxy-with-chain-external-sni", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", nil, nil) - }, - }, - { - name: "connect-proxy-with-chain-and-overrides", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-failover-through-remote-gateway", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-remote-gateway", nil, nil) - }, - }, - { - name: "connect-proxy-with-tcp-chain-failover-through-local-gateway", - create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-through-local-gateway", nil, nil) - }, - }, { name: "connect-proxy-upstream-defaults", create: func(t testinf.T) *proxycfg.ConfigSnapshot { @@ -1092,6 +1098,8 @@ func TestListenersFromSnapshot(t *testing.T) { }, } + tests = append(tests, makeListenerDiscoChainTests(false)...) + latestEnvoyVersion := xdscommon.EnvoyVersions[0] for _, envoyVersion := range xdscommon.EnvoyVersions { sf, err := xdscommon.DetermineSupportedProxyFeaturesFromString(envoyVersion) @@ -1110,10 +1118,6 @@ func TestListenersFromSnapshot(t *testing.T) { // golder files for every test case and so not be any use! testcommon.SetupTLSRootsAndLeaf(t, snap) - if tt.setup != nil { - tt.setup(snap) - } - // Need server just for logger dependency g := NewResourceGenerator(testutil.Logger(t), nil, false) g.ProxyFeatures = sf diff --git a/agent/xds/resources_test.go b/agent/xds/resources_test.go index 24bee7660615..1f9b99274bdd 100644 --- a/agent/xds/resources_test.go +++ b/agent/xds/resources_test.go @@ -175,7 +175,7 @@ func TestAllResourcesFromSnapshot(t *testing.T) { } tests = append(tests, getConnectProxyTransparentProxyGoldenTestCases()...) tests = append(tests, getMeshGatewayPeeringGoldenTestCases()...) - tests = append(tests, getTrafficControlPeeringGoldenTestCases()...) + tests = append(tests, getTrafficControlPeeringGoldenTestCases(false)...) tests = append(tests, getEnterpriseGoldenTestCases()...) tests = append(tests, getAPIGatewayGoldenTestCases(t)...) @@ -253,21 +253,29 @@ func getMeshGatewayPeeringGoldenTestCases() []goldenTestCase { } } -func getTrafficControlPeeringGoldenTestCases() []goldenTestCase { - return []goldenTestCase{ +func getTrafficControlPeeringGoldenTestCases(enterprise bool) []goldenTestCase { + cases := []goldenTestCase{ { name: "connect-proxy-with-chain-and-failover-to-cluster-peer", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-to-cluster-peer", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-to-cluster-peer", enterprise, nil, nil) }, }, { name: "connect-proxy-with-chain-and-redirect-to-cluster-peer", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "redirect-to-cluster-peer", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "redirect-to-cluster-peer", enterprise, nil, nil) }, }, } + + if enterprise { + for i := range cases { + cases[i].name = "enterprise-" + cases[i].name + } + } + + return cases } const ( diff --git a/agent/xds/routes_test.go b/agent/xds/routes_test.go index cec0f650c7a5..c68e54c6d0a7 100644 --- a/agent/xds/routes_test.go +++ b/agent/xds/routes_test.go @@ -19,67 +19,74 @@ import ( "github.com/hashicorp/consul/sdk/testutil" ) -func TestRoutesFromSnapshot(t *testing.T) { - // TODO: we should move all of these to TestAllResourcesFromSnapshot - // eventually to test all of the xDS types at once with the same input, - // just as it would be triggered by our xDS server. - if testing.Short() { - t.Skip("too slow for testing.Short") - } +type routeTestCase struct { + name string + create func(t testinf.T) *proxycfg.ConfigSnapshot + overrideGoldenName string +} - tests := []struct { - name string - create func(t testinf.T) *proxycfg.ConfigSnapshot - overrideGoldenName string - }{ +func makeRouteDiscoChainTests(enterprise bool) []routeTestCase { + return []routeTestCase{ { name: "connect-proxy-with-chain", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple", enterprise, nil, nil) }, }, { name: "connect-proxy-with-chain-external-sni", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "external-sni", enterprise, nil, nil) }, }, { name: "connect-proxy-with-chain-and-overrides", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "simple-with-overrides", enterprise, nil, nil) }, }, { name: "splitter-with-resolver-redirect", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "splitter-with-resolver-redirect-multidc", enterprise, nil, nil) }, }, { name: "connect-proxy-with-chain-and-splitter", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "chain-and-splitter", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "chain-and-splitter", enterprise, nil, nil) }, }, { name: "connect-proxy-with-grpc-router", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "grpc-router", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "grpc-router", enterprise, nil, nil) }, }, { name: "connect-proxy-with-chain-and-router", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "chain-and-router", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "chain-and-router", enterprise, nil, nil) }, }, { name: "connect-proxy-lb-in-resolver", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "lb-resolver", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "lb-resolver", enterprise, nil, nil) }, }, + } +} + +func TestRoutesFromSnapshot(t *testing.T) { + // TODO: we should move all of these to TestAllResourcesFromSnapshot + // eventually to test all of the xDS types at once with the same input, + // just as it would be triggered by our xDS server. + if testing.Short() { + t.Skip("too slow for testing.Short") + } + + tests := []routeTestCase{ // TODO(rb): test match stanza skipped for grpc // Start ingress gateway test cases { @@ -188,6 +195,8 @@ func TestRoutesFromSnapshot(t *testing.T) { }, } + tests = append(tests, makeRouteDiscoChainTests(false)...) + latestEnvoyVersion := xdscommon.EnvoyVersions[0] for _, envoyVersion := range xdscommon.EnvoyVersions { sf, err := xdscommon.DetermineSupportedProxyFeaturesFromString(envoyVersion) diff --git a/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden b/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden index 8cb6ce20a06d..e55cdc39f7a1 100644 --- a/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden +++ b/agent/xds/testdata/endpoints/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden @@ -1,63 +1,63 @@ { - "versionInfo": "00000001", - "resources": [ + "versionInfo": "00000001", + "resources": [ { - "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", - "clusterName": "db.default.cluster-01.external.peer1.domain", - "endpoints": [ + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "db.default.cluster-01.external.peer1.domain", + "endpoints": [ { - "lbEndpoints": [ + "lbEndpoints": [ { - "endpoint": { - "address": { - "socketAddress": { - "address": "10.40.1.1", - "portValue": 8080 + "endpoint": { + "address": { + "socketAddress": { + "address": "10.40.1.1", + "portValue": 8080 } } }, - "healthStatus": "HEALTHY", - "loadBalancingWeight": 1 + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 } ] } ] }, { - "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", - "clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", - "endpoints": [ + "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "clusterName": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul", + "endpoints": [ { - "lbEndpoints": [ + "lbEndpoints": [ { - "endpoint": { - "address": { - "socketAddress": { - "address": "10.10.1.1", - "portValue": 8080 + "endpoint": { + "address": { + "socketAddress": { + "address": "10.10.1.1", + "portValue": 8080 } } }, - "healthStatus": "HEALTHY", - "loadBalancingWeight": 1 + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 }, { - "endpoint": { - "address": { - "socketAddress": { - "address": "10.20.1.2", - "portValue": 8080 + "endpoint": { + "address": { + "socketAddress": { + "address": "10.20.1.2", + "portValue": 8080 } } }, - "healthStatus": "HEALTHY", - "loadBalancingWeight": 1 + "healthStatus": "HEALTHY", + "loadBalancingWeight": 1 } ] } ] } ], - "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", - "nonce": "00000001" + "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", + "nonce": "00000001" } \ No newline at end of file diff --git a/agent/xds/testdata/listeners/connect-proxy-with-chain-and-failover-to-cluster-peer.latest.golden b/agent/xds/testdata/listeners/connect-proxy-with-chain-and-failover-to-cluster-peer.latest.golden index 57d50f71c367..5fdd2e351c0e 100644 --- a/agent/xds/testdata/listeners/connect-proxy-with-chain-and-failover-to-cluster-peer.latest.golden +++ b/agent/xds/testdata/listeners/connect-proxy-with-chain-and-failover-to-cluster-peer.latest.golden @@ -1,119 +1,115 @@ { - "versionInfo": "00000001", - "resources": [ + "versionInfo": "00000001", + "resources": [ { - "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", - "name": "db:127.0.0.1:9191", - "address": { - "socketAddress": { - "address": "127.0.0.1", - "portValue": 9191 + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "db:127.0.0.1:9191", + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 9191 } }, - "filterChains": [ + "filterChains": [ { - "filters": [ + "filters": [ { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "upstream.db.default.default.dc1", - "cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.db.default.default.dc1", + "cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" } } ] } ], - "trafficDirection": "OUTBOUND" + "trafficDirection": "OUTBOUND" }, { - "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", - "name": "prepared_query:geo-cache:127.10.10.10:8181", - "address": { - "socketAddress": { - "address": "127.10.10.10", - "portValue": 8181 + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 } }, - "filterChains": [ + "filterChains": [ { - "filters": [ + "filters": [ { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "upstream.prepared_query_geo-cache", - "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.prepared_query_geo-cache", + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" } } ] } ], - "trafficDirection": "OUTBOUND" + "trafficDirection": "OUTBOUND" }, { - "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", - "name": "public_listener:0.0.0.0:9999", - "address": { - "socketAddress": { - "address": "0.0.0.0", - "portValue": 9999 + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 } }, - "filterChains": [ + "filterChains": [ { - "filters": [ + "filters": [ { - "name": "envoy.filters.network.rbac", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC", - "rules": { - - }, - "statPrefix": "connect_authz" + "name": "envoy.filters.network.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC", + "rules": {}, + "statPrefix": "connect_authz" } }, { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "public_listener", - "cluster": "local_app" + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "public_listener", + "cluster": "local_app" } } ], - "transportSocket": { - "name": "tls", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", - "commonTlsContext": { - "tlsParams": { - - }, - "tlsCertificates": [ + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ { - "certificateChain": { - "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" }, - "privateKey": { - "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" } } ], - "validationContext": { - "trustedCa": { - "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" } } }, - "requireClientCertificate": true + "requireClientCertificate": true } } } ], - "trafficDirection": "INBOUND" + "trafficDirection": "INBOUND" } ], - "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", - "nonce": "00000001" + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" } \ No newline at end of file diff --git a/agent/xds/testdata/listeners/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden b/agent/xds/testdata/listeners/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden index e061148c0088..02d749a2c5c2 100644 --- a/agent/xds/testdata/listeners/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden +++ b/agent/xds/testdata/listeners/connect-proxy-with-chain-and-redirect-to-cluster-peer.latest.golden @@ -1,119 +1,115 @@ { - "versionInfo": "00000001", - "resources": [ + "versionInfo": "00000001", + "resources": [ { - "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", - "name": "db:127.0.0.1:9191", - "address": { - "socketAddress": { - "address": "127.0.0.1", - "portValue": 9191 + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "db:127.0.0.1:9191", + "address": { + "socketAddress": { + "address": "127.0.0.1", + "portValue": 9191 } }, - "filterChains": [ + "filterChains": [ { - "filters": [ + "filters": [ { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "upstream.db.default.default.dc1", - "cluster": "db.default.cluster-01.external.peer1.domain" + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.db.default.default.dc1", + "cluster": "db.default.cluster-01.external.peer1.domain" } } ] } ], - "trafficDirection": "OUTBOUND" + "trafficDirection": "OUTBOUND" }, { - "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", - "name": "prepared_query:geo-cache:127.10.10.10:8181", - "address": { - "socketAddress": { - "address": "127.10.10.10", - "portValue": 8181 + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "prepared_query:geo-cache:127.10.10.10:8181", + "address": { + "socketAddress": { + "address": "127.10.10.10", + "portValue": 8181 } }, - "filterChains": [ + "filterChains": [ { - "filters": [ + "filters": [ { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "upstream.prepared_query_geo-cache", - "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "upstream.prepared_query_geo-cache", + "cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul" } } ] } ], - "trafficDirection": "OUTBOUND" + "trafficDirection": "OUTBOUND" }, { - "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", - "name": "public_listener:0.0.0.0:9999", - "address": { - "socketAddress": { - "address": "0.0.0.0", - "portValue": 9999 + "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", + "name": "public_listener:0.0.0.0:9999", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 9999 } }, - "filterChains": [ + "filterChains": [ { - "filters": [ + "filters": [ { - "name": "envoy.filters.network.rbac", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC", - "rules": { - - }, - "statPrefix": "connect_authz" + "name": "envoy.filters.network.rbac", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC", + "rules": {}, + "statPrefix": "connect_authz" } }, { - "name": "envoy.filters.network.tcp_proxy", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", - "statPrefix": "public_listener", - "cluster": "local_app" + "name": "envoy.filters.network.tcp_proxy", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy", + "statPrefix": "public_listener", + "cluster": "local_app" } } ], - "transportSocket": { - "name": "tls", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", - "commonTlsContext": { - "tlsParams": { - - }, - "tlsCertificates": [ + "transportSocket": { + "name": "tls", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext", + "commonTlsContext": { + "tlsParams": {}, + "tlsCertificates": [ { - "certificateChain": { - "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" + "certificateChain": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n" }, - "privateKey": { - "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" + "privateKey": { + "inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n" } } ], - "validationContext": { - "trustedCa": { - "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" + "validationContext": { + "trustedCa": { + "inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n" } } }, - "requireClientCertificate": true + "requireClientCertificate": true } } } ], - "trafficDirection": "INBOUND" + "trafficDirection": "INBOUND" } ], - "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", - "nonce": "00000001" + "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", + "nonce": "00000001" } \ No newline at end of file diff --git a/agent/xds/validateupstream-test/validateupstream_test.go b/agent/xds/validateupstream-test/validateupstream_test.go index 250b6acdec3b..4e41ba398bd6 100644 --- a/agent/xds/validateupstream-test/validateupstream_test.go +++ b/agent/xds/validateupstream-test/validateupstream_test.go @@ -43,13 +43,13 @@ func TestValidateUpstreams(t *testing.T) { { name: "tcp-success", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil) }, }, { name: "tcp-missing-listener", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil) }, patcher: func(ir *xdscommon.IndexedResources) *xdscommon.IndexedResources { delete(ir.Index[xdscommon.ListenerType], listenerName) @@ -60,7 +60,7 @@ func TestValidateUpstreams(t *testing.T) { { name: "tcp-missing-cluster", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil) }, patcher: func(ir *xdscommon.IndexedResources) *xdscommon.IndexedResources { delete(ir.Index[xdscommon.ClusterType], sni) @@ -71,7 +71,7 @@ func TestValidateUpstreams(t *testing.T) { { name: "http-success", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, httpServiceDefaults) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, httpServiceDefaults) }, }, { @@ -79,7 +79,7 @@ func TestValidateUpstreams(t *testing.T) { // RDS, Envoy's Route Discovery Service, is only used for HTTP services with a customized discovery chain, so we // need to use the test snapshot and add L7 config entries. create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, []proxycfg.UpdateEvent{ + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, []proxycfg.UpdateEvent{ // The events ensure there are endpoints for the v1 and v2 subsets. { CorrelationID: "upstream-target:v1.db.default.default.dc1:" + dbUID.String(), @@ -104,7 +104,7 @@ func TestValidateUpstreams(t *testing.T) { // RDS, Envoy's Route Discovery Service, is only used for HTTP services with a customized discovery chain, so we // need to use the test snapshot and add L7 config entries. create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, []proxycfg.UpdateEvent{ + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, []proxycfg.UpdateEvent{ // The events ensure there are endpoints for the v1 and v2 subsets. { CorrelationID: "upstream-target:v1.db.default.default.dc1:" + dbUID.String(), @@ -129,19 +129,19 @@ func TestValidateUpstreams(t *testing.T) { { name: "redirect", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "redirect-to-cluster-peer", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "redirect-to-cluster-peer", false, nil, nil) }, }, { name: "failover", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover", false, nil, nil) }, }, { name: "failover-to-cluster-peer", create: func(t testinf.T) *proxycfg.ConfigSnapshot { - return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-to-cluster-peer", nil, nil) + return proxycfg.TestConfigSnapshotDiscoveryChain(t, "failover-to-cluster-peer", false, nil, nil) }, }, { diff --git a/agent/xds/xds_protocol_helpers_test.go b/agent/xds/xds_protocol_helpers_test.go index 2edd05b9fb20..b71c8282e8f1 100644 --- a/agent/xds/xds_protocol_helpers_test.go +++ b/agent/xds/xds_protocol_helpers_test.go @@ -47,7 +47,7 @@ func newTestSnapshot( dbServiceProtocol string, additionalEntries ...structs.ConfigEntry, ) *proxycfg.ConfigSnapshot { - snap := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, additionalEntries...) + snap := proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", false, nil, nil, additionalEntries...) snap.ConnectProxy.PreparedQueryEndpoints = map[proxycfg.UpstreamID]structs.CheckServiceNodes{ UID("prepared_query:geo-cache"): proxycfg.TestPreparedQueryNodes(t, "geo-cache"), } diff --git a/command/services/config_test.go b/command/services/config_test.go index 1647b9293425..b54a793aa474 100644 --- a/command/services/config_test.go +++ b/command/services/config_test.go @@ -137,7 +137,7 @@ func TestStructsToAgentService(t *testing.T) { DestinationServiceName: "web", LocalServiceAddress: "127.0.0.1", LocalServicePort: 8181, - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), Mode: structs.ProxyModeTransparent, Config: map[string]interface{}{ "foo": "bar", @@ -154,7 +154,7 @@ func TestStructsToAgentService(t *testing.T) { DestinationServiceName: "web", LocalServiceAddress: "127.0.0.1", LocalServicePort: 8181, - Upstreams: structs.TestUpstreams(t).ToAPI(), + Upstreams: structs.TestUpstreams(t, false).ToAPI(), Mode: api.ProxyModeTransparent, Config: map[string]interface{}{ "foo": "bar", @@ -174,7 +174,7 @@ func TestStructsToAgentService(t *testing.T) { DestinationServiceName: "web", LocalServiceAddress: "127.0.0.1", LocalServicePort: 8181, - Upstreams: structs.TestUpstreams(t), + Upstreams: structs.TestUpstreams(t, false), Mode: structs.ProxyModeTransparent, TransparentProxy: structs.TransparentProxyConfig{ OutboundListenerPort: 808, @@ -201,7 +201,7 @@ func TestStructsToAgentService(t *testing.T) { DestinationServiceName: "web", LocalServiceAddress: "127.0.0.1", LocalServicePort: 8181, - Upstreams: structs.TestUpstreams(t).ToAPI(), + Upstreams: structs.TestUpstreams(t, false).ToAPI(), Mode: api.ProxyModeTransparent, TransparentProxy: &api.TransparentProxyConfig{ OutboundListenerPort: 808, From 3ba0eb507469fc578386c979f0912d91bc4b55e7 Mon Sep 17 00:00:00 2001 From: Dhia Ayachi Date: Wed, 22 Mar 2023 15:19:54 -0400 Subject: [PATCH 10/17] delete config when nil (#16690) * delete config when nil * fix mock interface implementation * fix handler test to use the right assertion * extract DeleteConfig as a separate API. * fix mock limiter implementation to satisfy the new interface * fix failing tests * add test comments --- agent/consul/multilimiter/mock_RateLimiter.go | 7 +- agent/consul/multilimiter/multilimiter.go | 52 +++-- .../consul/multilimiter/multilimiter_test.go | 190 ++++++++++++++---- agent/consul/rate/handler.go | 2 +- agent/consul/rate/handler_test.go | 3 + 5 files changed, 201 insertions(+), 53 deletions(-) diff --git a/agent/consul/multilimiter/mock_RateLimiter.go b/agent/consul/multilimiter/mock_RateLimiter.go index d36c2e161ef9..0c33f92bfa83 100644 --- a/agent/consul/multilimiter/mock_RateLimiter.go +++ b/agent/consul/multilimiter/mock_RateLimiter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.20.0. DO NOT EDIT. package multilimiter @@ -27,6 +27,11 @@ func (_m *MockRateLimiter) Allow(entity LimitedEntity) bool { return r0 } +// DeleteConfig provides a mock function with given fields: prefix +func (_m *MockRateLimiter) DeleteConfig(prefix []byte) { + _m.Called(prefix) +} + // Run provides a mock function with given fields: ctx func (_m *MockRateLimiter) Run(ctx context.Context) { _m.Called(ctx) diff --git a/agent/consul/multilimiter/multilimiter.go b/agent/consul/multilimiter/multilimiter.go index 21839d3fe060..13e01f8ebaa5 100644 --- a/agent/consul/multilimiter/multilimiter.go +++ b/agent/consul/multilimiter/multilimiter.go @@ -26,6 +26,7 @@ type RateLimiter interface { Run(ctx context.Context) Allow(entity LimitedEntity) bool UpdateConfig(c LimiterConfig, prefix []byte) + DeleteConfig(prefix []byte) } type limiterWithKey struct { @@ -67,7 +68,6 @@ type LimiterConfig struct { // Config is a MultiLimiter configuration type Config struct { - LimiterConfig ReconcileCheckLimit time.Duration ReconcileCheckInterval time.Duration } @@ -75,14 +75,13 @@ type Config struct { // UpdateConfig will update the MultiLimiter Config // which will cascade to all the Limiter(s) LimiterConfig func (m *MultiLimiter) UpdateConfig(c LimiterConfig, prefix []byte) { - m.configsLock.Lock() - defer m.configsLock.Unlock() - if prefix == nil { - prefix = []byte("") - } - configs := m.limitersConfigs.Load() - newConfigs, _, _ := configs.Insert(prefix, &c) - m.limitersConfigs.Store(newConfigs) + m.updateConfig(&c, prefix) +} + +// DeleteConfig will delete the MultiLimiter Config +// which will cascade to all the Limiter(s) LimiterConfig +func (m *MultiLimiter) DeleteConfig(prefix []byte) { + m.updateConfig(nil, prefix) } // NewMultiLimiter create a new MultiLimiter @@ -143,14 +142,16 @@ func (m *MultiLimiter) Allow(e LimitedEntity) bool { } configs := m.limitersConfigs.Load() - config := &m.defaultConfig.Load().LimiterConfig + p, _, ok := configs.Root().LongestPrefix(e.Key()) - if ok { - c, ok := configs.Get(p) - if ok && c != nil { - config = c.(*LimiterConfig) - } + if !ok { + return true + } + var config *LimiterConfig + c, ok := configs.Get(p) + if ok && c != nil { + config = c.(*LimiterConfig) } limiter := &Limiter{limiter: rate.NewLimiter(config.Rate, config.Burst)} @@ -159,6 +160,24 @@ func (m *MultiLimiter) Allow(e LimitedEntity) bool { return limiter.limiter.Allow() } +// UpdateConfig will update the MultiLimiter Config +// which will cascade to all the Limiter(s) LimiterConfig +func (m *MultiLimiter) updateConfig(c *LimiterConfig, prefix []byte) { + m.configsLock.Lock() + defer m.configsLock.Unlock() + if prefix == nil { + prefix = []byte("") + } + configs := m.limitersConfigs.Load() + var newConfigs *radix.Tree + if c == nil { + newConfigs, _, _ = configs.Delete(prefix) + } else { + newConfigs, _, _ = configs.Insert(prefix, c) + } + m.limitersConfigs.Store(newConfigs) +} + type ticker interface { Ticker() <-chan time.Time } @@ -211,7 +230,10 @@ func (m *MultiLimiter) reconcileConfig(txn *radix.Txn) { // find the prefix for the leaf and check if the defaultConfig is up-to-date // it's possible that the prefix is equal to the key p, _, ok := m.limitersConfigs.Load().Root().LongestPrefix(k) + + // no corresponding config found, need to delete it if !ok { + txn.Delete(k) continue } v, ok := m.limitersConfigs.Load().Get(p) diff --git a/agent/consul/multilimiter/multilimiter_test.go b/agent/consul/multilimiter/multilimiter_test.go index 2b04f29eef8e..c34440ff4072 100644 --- a/agent/consul/multilimiter/multilimiter_test.go +++ b/agent/consul/multilimiter/multilimiter_test.go @@ -5,14 +5,15 @@ import ( "context" "encoding/binary" "fmt" - "github.com/hashicorp/consul/sdk/testutil/retry" - radix "github.com/hashicorp/go-immutable-radix" - "github.com/stretchr/testify/require" - "golang.org/x/time/rate" "math/rand" "sync" "testing" "time" + + "github.com/hashicorp/consul/sdk/testutil/retry" + radix "github.com/hashicorp/go-immutable-radix" + "github.com/stretchr/testify/require" + "golang.org/x/time/rate" ) type Limited struct { @@ -24,17 +25,19 @@ func (l Limited) Key() []byte { } func TestNewMultiLimiter(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}} + c := Config{} m := NewMultiLimiter(c) require.NotNil(t, m) require.NotNil(t, m.limiters) } func TestRateLimiterUpdate(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 1 * time.Hour, ReconcileCheckInterval: 10 * time.Millisecond} + c := Config{ReconcileCheckLimit: 1 * time.Hour, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) key := Key([]byte("test")) + c1 := LimiterConfig{Rate: 10} + m.UpdateConfig(c1, key) //Allow a key m.Allow(Limited{key: key}) storeLimiter(m) @@ -71,21 +74,22 @@ func TestRateLimiterUpdate(t *testing.T) { func TestRateLimiterCleanup(t *testing.T) { // Create a limiter and Allow a key, check the key exists - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 1 * time.Second, ReconcileCheckInterval: 10 * time.Millisecond} + c := Config{ReconcileCheckLimit: 1 * time.Second, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) limiters := m.limiters.Load() ctx, cancel := context.WithCancel(context.Background()) defer cancel() m.Run(ctx) key := Key([]byte("test")) + m.UpdateConfig(LimiterConfig{Rate: 0.1}, key) m.Allow(Limited{key: key}) - retry.RunWith(&retry.Timer{Wait: 100 * time.Millisecond, Timeout: 2 * time.Second}, t, func(r *retry.R) { + retry.RunWith(&retry.Timer{Wait: 100 * time.Millisecond, Timeout: 10 * time.Second}, t, func(r *retry.R) { l := m.limiters.Load() require.NotEqual(r, limiters, l) limiters = l }) - retry.RunWith(&retry.Timer{Wait: 100 * time.Millisecond, Timeout: 2 * time.Second}, t, func(r *retry.R) { + retry.RunWith(&retry.Timer{Wait: 100 * time.Millisecond, Timeout: 10 * time.Second}, t, func(r *retry.R) { v, ok := limiters.Get(key) require.True(r, ok) require.NotNil(t, v) @@ -120,79 +124,104 @@ func reconcile(m *MultiLimiter) { ctx := context.Background() reconcileCheckLimit := m.defaultConfig.Load().ReconcileCheckLimit mockTicker.tickerCh <- time.Now() - m.reconcile(ctx, &mockTicker, txn, reconcileCheckLimit) + txn = m.reconcile(ctx, &mockTicker, txn, reconcileCheckLimit) + m.limiters.Store(txn.Commit()) } func TestRateLimiterStore(t *testing.T) { // Create a MultiLimiter m with a defaultConfig c and check the defaultConfig is applied t.Run("Store multiple transactions", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) ipNoPrefix1 := Key([]byte(""), []byte("127.0.0.1")) + c1 := LimiterConfig{Rate: 1} ipNoPrefix2 := Key([]byte(""), []byte("127.0.0.2")) + c2 := LimiterConfig{Rate: 2} + { + // Update config for ipNoPrefix1 and check it's applied + m.UpdateConfig(c1, ipNoPrefix1) m.Allow(ipLimited{key: ipNoPrefix1}) storeLimiter(m) l, ok := m.limiters.Load().Get(ipNoPrefix1) require.True(t, ok) require.NotNil(t, l) limiter := l.(*Limiter) - require.True(t, c.isApplied(limiter.limiter)) + require.True(t, c1.isApplied(limiter.limiter)) } + { + // Update config for ipNoPrefix2 and check it's applied + m.UpdateConfig(c2, ipNoPrefix2) m.Allow(ipLimited{key: ipNoPrefix2}) storeLimiter(m) l, ok := m.limiters.Load().Get(ipNoPrefix2) require.True(t, ok) require.NotNil(t, l) limiter := l.(*Limiter) - require.True(t, c.isApplied(limiter.limiter)) + require.True(t, c2.isApplied(limiter.limiter)) + + //Check that ipNoPrefix1 is unchanged l, ok = m.limiters.Load().Get(ipNoPrefix1) require.True(t, ok) require.NotNil(t, l) limiter = l.(*Limiter) - require.True(t, c.isApplied(limiter.limiter)) + require.True(t, c1.isApplied(limiter.limiter)) } }) t.Run("runStore store multiple Limiters", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 10 * time.Second, ReconcileCheckInterval: 10 * time.Millisecond} + c := Config{ReconcileCheckLimit: 10 * time.Second, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) ctx, cancel := context.WithCancel(context.Background()) m.Run(ctx) defer cancel() + + // Create a limiter for ipNoPrefix1 ipNoPrefix1 := Key([]byte(""), []byte("127.0.0.1")) - ipNoPrefix2 := Key([]byte(""), []byte("127.0.0.2")) + c1 := LimiterConfig{Rate: 1} limiters := m.limiters.Load() + m.UpdateConfig(c1, ipNoPrefix1) m.Allow(ipLimited{key: ipNoPrefix1}) retry.RunWith(&retry.Timer{Wait: 1 * time.Second, Timeout: 5 * time.Second}, t, func(r *retry.R) { l := m.limiters.Load() require.NotEqual(r, limiters, l) limiters = l }) + + // Check that ipNoPrefix1 have the expected limiter l, ok := m.limiters.Load().Get(ipNoPrefix1) require.True(t, ok) require.NotNil(t, l) limiter := l.(*Limiter) - require.True(t, c.isApplied(limiter.limiter)) + require.True(t, c1.isApplied(limiter.limiter)) + + // Create a limiter for ipNoPrefix2 + ipNoPrefix2 := Key([]byte(""), []byte("127.0.0.2")) + c2 := LimiterConfig{Rate: 2} + m.UpdateConfig(c2, ipNoPrefix2) m.Allow(ipLimited{key: ipNoPrefix2}) retry.RunWith(&retry.Timer{Wait: 1 * time.Second, Timeout: 5 * time.Second}, t, func(r *retry.R) { l := m.limiters.Load() require.NotEqual(r, limiters, l) limiters = l }) + + // Check that ipNoPrefix1 have the expected limiter l, ok = m.limiters.Load().Get(ipNoPrefix1) require.True(t, ok) require.NotNil(t, l) limiter = l.(*Limiter) - require.True(t, c.isApplied(limiter.limiter)) + require.True(t, c1.isApplied(limiter.limiter)) + + // Check that ipNoPrefix2 have the expected limiter l, ok = m.limiters.Load().Get(ipNoPrefix2) require.True(t, ok) require.NotNil(t, l) limiter = l.(*Limiter) - require.True(t, c.isApplied(limiter.limiter)) + require.True(t, c2.isApplied(limiter.limiter)) }) } @@ -202,26 +231,38 @@ func TestRateLimiterUpdateConfig(t *testing.T) { // Create a MultiLimiter m with a defaultConfig c and check the defaultConfig is applied t.Run("Allow a key and check defaultConfig is applied to that key", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for ipNoPrefix ipNoPrefix := Key([]byte(""), []byte("127.0.0.1")) + c1 := LimiterConfig{Rate: 1} + m.UpdateConfig(c1, ipNoPrefix) m.Allow(ipLimited{key: ipNoPrefix}) storeLimiter(m) + + // Verify the expected limiter is applied l, ok := m.limiters.Load().Get(ipNoPrefix) require.True(t, ok) require.NotNil(t, l) limiter := l.(*Limiter) - require.True(t, c.isApplied(limiter.limiter)) + require.True(t, c1.isApplied(limiter.limiter)) }) t.Run("Update nil prefix and make sure it's written in the root", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for nil prefix := []byte(nil) - c1 := LimiterConfig{Rate: 2} + c1 := LimiterConfig{Rate: 1} m.UpdateConfig(c1, prefix) + + // Verify the expected limiter is applied v, ok := m.limitersConfigs.Load().Get([]byte("")) require.True(t, ok) require.NotNil(t, v) @@ -230,25 +271,39 @@ func TestRateLimiterUpdateConfig(t *testing.T) { }) t.Run("Allow 2 keys with prefix and check defaultConfig is applied to those keys", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for ip prefix := []byte("namespace.write") ip := Key(prefix, []byte("127.0.0.1")) + c1 := LimiterConfig{Rate: 1} + m.UpdateConfig(c1, ip) m.Allow(ipLimited{key: ip}) storeLimiter(m) + + //Create a limiter for ip2 ip2 := Key(prefix, []byte("127.0.0.2")) + c2 := LimiterConfig{Rate: 2} + m.UpdateConfig(c2, ip2) m.Allow(ipLimited{key: ip2}) + + //Verify the config is applied for ip l, ok := m.limiters.Load().Get(ip) require.True(t, ok) require.NotNil(t, l) limiter := l.(*Limiter) - require.True(t, c.LimiterConfig.isApplied(limiter.limiter)) + require.True(t, c1.isApplied(limiter.limiter)) }) t.Run("Apply a defaultConfig to 'namespace.write' check the defaultConfig is applied to existing keys under that prefix", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for ip prefix := []byte("namespace.write") ip := Key(prefix, []byte("127.0.0.1")) c3 := LimiterConfig{Rate: 2} @@ -257,6 +312,8 @@ func TestRateLimiterUpdateConfig(t *testing.T) { m.reconcileConfig(m.limiters.Load().Txn()) m.Allow(ipLimited{key: ip}) storeLimiter(m) + + //Verify the config is applied for ip l3, ok3 := m.limiters.Load().Get(ip) require.True(t, ok3) require.NotNil(t, l3) @@ -264,31 +321,71 @@ func TestRateLimiterUpdateConfig(t *testing.T) { require.True(t, c3.isApplied(limiter3.limiter)) }) t.Run("Allow an IP with prefix and check prefix defaultConfig is applied to new keys under that prefix", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + m := NewMultiLimiter(c) + require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for ip + c1 := LimiterConfig{Rate: 3} + prefix := []byte("namespace.read") + m.UpdateConfig(c1, prefix) + ip := Key(prefix, []byte("127.0.0.1")) + m.Allow(ipLimited{key: ip}) + storeLimiter(m) + + //Verify the config is applied for ip + l, ok := m.limiters.Load().Get(ip) + require.True(t, ok) + require.NotNil(t, l) + limiter := l.(*Limiter) + require.True(t, c1.isApplied(limiter.limiter)) + }) + + t.Run("Allow an IP with prefix and check prefix defaultConfig is applied to new keys under that prefix, delete config and check default applied", func(t *testing.T) { + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Second, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for ip c1 := LimiterConfig{Rate: 3} prefix := []byte("namespace.read") m.UpdateConfig(c1, prefix) ip := Key(prefix, []byte("127.0.0.1")) m.Allow(ipLimited{key: ip}) storeLimiter(m) + + //Verify the config is applied for ip l, ok := m.limiters.Load().Get(ip) require.True(t, ok) require.NotNil(t, l) limiter := l.(*Limiter) require.True(t, c1.isApplied(limiter.limiter)) + + // Delete the prefix + m.DeleteConfig(prefix) + reconcile(m) + + // Verify the limiter is removed + _, ok = m.limiters.Load().Get(ip) + require.False(t, ok) }) t.Run("Allow an IP with prefix and check prefix config is applied to new keys under that prefix", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for ip c1 := LimiterConfig{Rate: 3} prefix := Key([]byte("ip.ratelimit"), []byte("127.0")) m.UpdateConfig(c1, prefix) ip := Key([]byte("ip.ratelimit"), []byte("127.0.0.1")) m.Allow(ipLimited{key: ip}) storeLimiter(m) + + //Verify the config is applied for ip load := m.limiters.Load() l, ok := load.Get(ip) require.True(t, ok) @@ -298,27 +395,38 @@ func TestRateLimiterUpdateConfig(t *testing.T) { }) t.Run("Allow an IP with 2 prefixes and check prefix config is applied to new keys under that prefix", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for "127.0" ip with config c1 c1 := LimiterConfig{Rate: 3} prefix := Key([]byte("ip.ratelimit"), []byte("127.0")) m.UpdateConfig(c1, prefix) + + //Create a limiter for "127.0.0" ip with config c2 prefix = Key([]byte("ip.ratelimit"), []byte("127.0.0")) c2 := LimiterConfig{Rate: 6} m.UpdateConfig(c2, prefix) ip := Key([]byte("ip.ratelimit"), []byte("127.0.0.1")) m.Allow(ipLimited{key: ip}) storeLimiter(m) + + // Verify that "127.0.0.1" have the right limiter config load := m.limiters.Load() l, ok := load.Get(ip) require.True(t, ok) require.NotNil(t, l) limiter := l.(*Limiter) require.True(t, c2.isApplied(limiter.limiter)) + + //Create a limiter for "127.0.1.1" ip with config c2 ip = Key([]byte("ip.ratelimit"), []byte("127.0.1.1")) m.Allow(ipLimited{key: ip}) storeLimiter(m) + + // Verify that "127.0.1.1" have the right limiter config load = m.limiters.Load() l, ok = load.Get(ip) require.True(t, ok) @@ -328,9 +436,12 @@ func TestRateLimiterUpdateConfig(t *testing.T) { }) t.Run("Allow an IP with prefix and check after it's cleaned new Allow would give it the right defaultConfig", func(t *testing.T) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + //Create a multilimiter + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(t, *m.defaultConfig.Load(), c) + + //Create a limiter for ip prefix := []byte("namespace.read") ip := Key(prefix, []byte("127.0.0.1")) c1 := LimiterConfig{Rate: 1} @@ -339,6 +450,8 @@ func TestRateLimiterUpdateConfig(t *testing.T) { reconcile(m) m.Allow(ipLimited{key: ip}) storeLimiter(m) + + //Verify the config is applied for ip l, ok := m.limiters.Load().Get(ip) require.True(t, ok) require.NotNil(t, l) @@ -348,14 +461,19 @@ func TestRateLimiterUpdateConfig(t *testing.T) { } func FuzzSingleConfig(f *testing.F) { - c := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} + c := Config{ReconcileCheckLimit: 100 * time.Millisecond, ReconcileCheckInterval: 10 * time.Millisecond} m := NewMultiLimiter(c) require.Equal(f, *m.defaultConfig.Load(), c) f.Add(Key(randIP())) f.Add(Key(randIP(), randIP())) f.Add(Key(randIP(), randIP(), randIP())) f.Add(Key(randIP(), randIP(), randIP(), randIP())) + c1 := LimiterConfig{ + Rate: 100, + Burst: 123, + } f.Fuzz(func(t *testing.T, ff []byte) { + m.UpdateConfig(c1, ff) m.Allow(Limited{key: ff}) storeLimiter(m) checkLimiter(t, ff, m.limiters.Load().Txn()) @@ -391,7 +509,7 @@ func FuzzUpdateConfig(f *testing.F) { f.Add(bytes.Join([][]byte{[]byte(""), Key(randIP()), Key(randIP(), randIP()), Key(randIP(), randIP(), randIP()), Key(randIP(), randIP(), randIP(), randIP())}, []byte(","))) f.Fuzz(func(t *testing.T, ff []byte) { - cm := Config{LimiterConfig: LimiterConfig{Rate: 0.1}, ReconcileCheckLimit: 1 * time.Millisecond, ReconcileCheckInterval: 1 * time.Millisecond} + cm := Config{ReconcileCheckLimit: 1 * time.Millisecond, ReconcileCheckInterval: 1 * time.Millisecond} m := NewMultiLimiter(cm) ctx, cancel := context.WithCancel(context.Background()) m.Run(ctx) @@ -443,7 +561,7 @@ func (i ipLimited) Key() []byte { } func BenchmarkTestRateLimiterFixedIP(b *testing.B) { - var Config = Config{LimiterConfig: LimiterConfig{Rate: 1.0, Burst: 500}, ReconcileCheckLimit: time.Microsecond, ReconcileCheckInterval: time.Millisecond} + var Config = Config{ReconcileCheckLimit: time.Microsecond, ReconcileCheckInterval: time.Millisecond} m := NewMultiLimiter(Config) ctx, cancel := context.WithCancel(context.Background()) m.Run(ctx) @@ -468,7 +586,7 @@ func BenchmarkTestRateLimiterAllowPrefill(b *testing.B) { for _, tc := range cases { b.Run(tc.name, func(b *testing.B) { - var Config = Config{LimiterConfig: LimiterConfig{Rate: 1.0, Burst: 500}, ReconcileCheckLimit: time.Second, ReconcileCheckInterval: time.Second} + var Config = Config{ReconcileCheckLimit: time.Second, ReconcileCheckInterval: time.Second} m := NewMultiLimiter(Config) var i uint64 for i = 0xdeaddead; i < 0xdeaddead+tc.prefill; i++ { @@ -501,7 +619,7 @@ func BenchmarkTestRateLimiterAllowConcurrencyPrefill(b *testing.B) { for _, tc := range cases { b.Run(tc.name, func(b *testing.B) { - var Config = Config{LimiterConfig: LimiterConfig{Rate: 1.0, Burst: 500}, ReconcileCheckLimit: time.Second, ReconcileCheckInterval: 100 * time.Second} + var Config = Config{ReconcileCheckLimit: time.Second, ReconcileCheckInterval: 100 * time.Second} m := NewMultiLimiter(Config) ctx, cancel := context.WithCancel(context.Background()) m.Run(ctx) @@ -530,7 +648,7 @@ func BenchmarkTestRateLimiterAllowConcurrencyPrefill(b *testing.B) { } func BenchmarkTestRateLimiterRandomIP(b *testing.B) { - var Config = Config{LimiterConfig: LimiterConfig{Rate: 1.0, Burst: 500}, ReconcileCheckLimit: time.Microsecond, ReconcileCheckInterval: time.Millisecond} + var Config = Config{ReconcileCheckLimit: time.Microsecond, ReconcileCheckInterval: time.Millisecond} m := NewMultiLimiter(Config) ctx, cancel := context.WithCancel(context.Background()) m.Run(ctx) diff --git a/agent/consul/rate/handler.go b/agent/consul/rate/handler.go index e8cb132f7ae1..d2c33ab88cce 100644 --- a/agent/consul/rate/handler.go +++ b/agent/consul/rate/handler.go @@ -1,4 +1,4 @@ -// package rate implements server-side RPC rate limiting. +// Package rate implements server-side RPC rate limiting. package rate import ( diff --git a/agent/consul/rate/handler_test.go b/agent/consul/rate/handler_test.go index 3cdb34fbcf55..6a74fe7caa79 100644 --- a/agent/consul/rate/handler_test.go +++ b/agent/consul/rate/handler_test.go @@ -420,3 +420,6 @@ func (m *mockLimiter) Run(ctx context.Context) { m.Called(ctx) } func (m *mockLimiter) UpdateConfig(cfg multilimiter.LimiterConfig, prefix []byte) { m.Called(cfg, prefix) } +func (m *mockLimiter) DeleteConfig(prefix []byte) { + m.Called(prefix) +} From 4845816c602a883074537330ccdcebf99531cf96 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:06:53 -0700 Subject: [PATCH 11/17] Changelog for audit logging fix. (#16700) * Changelog for audit logging fix. --- .changelog/16700.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/16700.txt diff --git a/.changelog/16700.txt b/.changelog/16700.txt new file mode 100644 index 000000000000..82da5936ddb5 --- /dev/null +++ b/.changelog/16700.txt @@ -0,0 +1,3 @@ +```release-note:bug +audit-logging: (Enterprise only) Fix a bug where `/agent/monitor` and `/agent/metrics` endpoints return a `Streaming not supported` error when audit logs are enabled. This also fixes the delay receiving logs when running `consul monitor` against an agent with audit logs enabled. +``` From e3fd7d32da36b96baced20557d8a3159b2075b40 Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Thu, 23 Mar 2023 09:00:38 -0700 Subject: [PATCH 12/17] Use GH issues type for edu board (#16750) --- .github/workflows/jira-issues.yaml | 2 +- .github/workflows/jira-pr.yaml | 2 +- website/content/docs/enterprise/index.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/jira-issues.yaml b/.github/workflows/jira-issues.yaml index f71727bf62d1..f3eabf888352 100644 --- a/.github/workflows/jira-issues.yaml +++ b/.github/workflows/jira-issues.yaml @@ -63,7 +63,7 @@ jobs: uses: tomhjp/gh-action-jira-create@v0.2.1 with: project: CE - issuetype: "Bug" + issuetype: "${{ steps.set-ticket-type.outputs.TYPE }}" summary: "${{ github.event.repository.name }} [${{ steps.set-ticket-type.outputs.TYPE }} #${{ github.event.issue.number }}]: ${{ github.event.issue.title }}" description: "GitHub URL: ${{ github.event.issue.html_url || github.event.pull_request.html_url }}\n\n${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created in GitHub by ${{ github.actor }}._" # customfield_10089 is "Issue Link", customfield_10371 is "Source" (use JIRA API to retrieve) diff --git a/.github/workflows/jira-pr.yaml b/.github/workflows/jira-pr.yaml index 4b872b6aaf88..33b66093382f 100644 --- a/.github/workflows/jira-pr.yaml +++ b/.github/workflows/jira-pr.yaml @@ -82,7 +82,7 @@ jobs: uses: tomhjp/gh-action-jira-create@v0.2.1 with: project: CE - issuetype: "Bug" + issuetype: "${{ steps.set-ticket-type.outputs.TYPE }}" summary: "${{ github.event.repository.name }} [${{ steps.set-ticket-type.outputs.TYPE }} #${{ github.event.issue.number }}]: ${{ github.event.issue.title }}" description: "GitHub URL: ${{ github.event.issue.html_url || github.event.pull_request.html_url }}\n\n${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created in GitHub by ${{ github.actor }}._" # customfield_10089 is "Issue Link", customfield_10371 is "Source" (use JIRA API to retrieve) diff --git a/website/content/docs/enterprise/index.mdx b/website/content/docs/enterprise/index.mdx index e63363e81069..b6805604b1e8 100644 --- a/website/content/docs/enterprise/index.mdx +++ b/website/content/docs/enterprise/index.mdx @@ -2,7 +2,7 @@ layout: docs page_title: Consul Enterprise description: >- - Consul Enterprise is a paid offering that extends Consul’s open source functions to support large and complex deployments. Learn about scaling infrastructure, simplifying operations, and making networks more resilient with Enterprise. + Consul Enterprise is a paid offering that extends Consul’s open source functions to support large and complex deployments. Learn about scaling infrastructure, simplifying operations, and making networks more resilient with Enterprise. Evaluate Enteprise features with the feature availability and compatibility matrix. --- # Consul Enterprise From 3df271959cf04bb79cf9d42bfabaf2edc13ca44a Mon Sep 17 00:00:00 2001 From: Poonam Jadhav Date: Thu, 23 Mar 2023 12:14:59 -0400 Subject: [PATCH 13/17] fix: remove unused tenancy category from rate limit spec (#16740) --- agent/consul/rate/handler.go | 1 - 1 file changed, 1 deletion(-) diff --git a/agent/consul/rate/handler.go b/agent/consul/rate/handler.go index d2c33ab88cce..f1860065d1b4 100644 --- a/agent/consul/rate/handler.go +++ b/agent/consul/rate/handler.go @@ -112,7 +112,6 @@ const ( OperationCategoryHealth OperationCategory = "Health" OperationCategoryIntention OperationCategory = "Intention" OperationCategoryKV OperationCategory = "KV" - OperationCategoryTenancy OperationCategory = "Tenancy" OperationCategoryPreparedQuery OperationCategory = "PreparedQuery" OperationCategorySession OperationCategory = "Session" OperationCategoryStatus OperationCategory = "Status" From d61f3dafac24b58e718dd8648c05c215b5a850a7 Mon Sep 17 00:00:00 2001 From: Nathan Coleman Date: Thu, 23 Mar 2023 11:21:27 -0500 Subject: [PATCH 14/17] Remove version bump from CRT workflow (#16728) This bumps the version to reflect the next patch release; however, we use a specific branch for each patch release and so never wind up cutting a release directly from the `release/1.15.x` (for example) where this is intended to work. --- .release/ci.hcl | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/.release/ci.hcl b/.release/ci.hcl index 062a925102d3..dfe69d2fc1eb 100644 --- a/.release/ci.hcl +++ b/.release/ci.hcl @@ -132,21 +132,9 @@ event "post-publish-website" { on = "always" } } -event "bump-version" { - depends = ["post-publish-website"] - action "bump-version" { - organization = "hashicorp" - repository = "crt-workflows-common" - workflow = "bump-version" - } - - notification { - on = "fail" - } -} event "update-ironbank" { - depends = ["bump-version"] + depends = ["post-publish-website"] action "update-ironbank" { organization = "hashicorp" repository = "crt-workflows-common" From 0b1dc4ec36729d95b87ddb24272c38ef0a93e903 Mon Sep 17 00:00:00 2001 From: John Eikenberry Date: Fri, 24 Mar 2023 16:54:11 +0000 Subject: [PATCH 15/17] tests instantiating clients w/o shutting down (#16755) noticed via their port still in use messages. --- agent/consul/client_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/agent/consul/client_test.go b/agent/consul/client_test.go index 97958b486621..982eb80ab8fc 100644 --- a/agent/consul/client_test.go +++ b/agent/consul/client_test.go @@ -824,6 +824,7 @@ func TestClient_ReloadConfig(t *testing.T) { deps := newDefaultDeps(t, &Config{NodeName: "node1", Datacenter: "dc1"}) c, err := NewClient(cfg, deps) require.NoError(t, err) + defer c.Shutdown() limiter := c.rpcLimiter.Load().(*rate.Limiter) require.Equal(t, rate.Limit(500), limiter.Limit()) @@ -869,7 +870,6 @@ func TestClient_ShortReconnectTimeout(t *testing.T) { func() bool { return len(cluster.Servers[0].LANMembersInAgentPartition()) == 2 && len(cluster.Clients[0].LANMembersInAgentPartition()) == 2 - }, time.Second, 50*time.Millisecond, @@ -901,6 +901,7 @@ func TestClient_RPC_Timeout(t *testing.T) { c.MaxQueryTime = 200 * time.Millisecond c.RPCHoldTimeout = 50 * time.Millisecond }) + defer c1.Shutdown() joinLAN(t, c1, s1) retry.Run(t, func(r *retry.R) { From a6831da95903cc1f0808f1551a3ac6c588129678 Mon Sep 17 00:00:00 2001 From: brian shore Date: Fri, 24 Mar 2023 10:27:10 -0700 Subject: [PATCH 16/17] RELENG-471: Remove obsolete load-test workflow (#16737) * Remove obsolete load-test workflow * remove load-tests from circleci config. --------- Co-authored-by: John Murret --- .circleci/config.yml | 96 --------------------------------- .github/workflows/load-test.yml | 69 ------------------------ 2 files changed, 165 deletions(-) delete mode 100644 .github/workflows/load-test.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 469223d7d355..47796555818d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,10 +9,6 @@ parameters: type: string default: "" description: "Commit to run load tests against" - trigger-load-test: - type: boolean - default: false - description: "Boolean whether to run the load test workflow" references: paths: @@ -1076,78 +1072,6 @@ jobs: path: *TEST_RESULTS_DIR - run: *notify-slack-failure - # Run load tests against a commit - load-test: - docker: - - image: hashicorp/terraform:latest - environment: - AWS_DEFAULT_REGION: us-east-2 - BUCKET: consul-ci-load-tests - BASH_ENV: /etc/profile - shell: /bin/sh -leo pipefail - steps: - - checkout - - run: apk add jq curl bash - - run: - name: export load-test credentials - command: | - echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID_LOAD_TEST" >> $BASH_ENV - echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY_LOAD_TEST" >> $BASH_ENV - - run: - name: export role arn - command: | - echo "export TF_VAR_role_arn=$ROLE_ARN_LOAD_TEST" >> $BASH_ENV - - run: - name: setup TF_VARs - command: | - # if pipeline.parameters.commit="" it was not triggered/set through the API - # so we use the latest commit from _this_ branch. This is the case for nightly tests. - if [ "<< pipeline.parameters.commit >>" = "" ]; then - LOCAL_COMMIT_SHA=$(git rev-parse HEAD) - else - LOCAL_COMMIT_SHA="<< pipeline.parameters.commit >>" - fi - echo "export LOCAL_COMMIT_SHA=${LOCAL_COMMIT_SHA}" >> $BASH_ENV - git checkout ${LOCAL_COMMIT_SHA} - - short_ref=$(git rev-parse --short ${LOCAL_COMMIT_SHA}) - echo "export TF_VAR_ami_owners=$LOAD_TEST_AMI_OWNERS" >> $BASH_ENV - echo "export TF_VAR_vpc_name=$short_ref" >> $BASH_ENV - echo "export TF_VAR_cluster_name=$short_ref" >> $BASH_ENV - echo "export TF_VAR_consul_download_url=https://${S3_ARTIFACT_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/${S3_ARTIFACT_PATH}/${LOCAL_COMMIT_SHA}.zip" >> $BASH_ENV - - run: - name: wait for dev build from test-integrations workflow - command: | - echo "curl-ing https://${S3_ARTIFACT_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/${S3_ARTIFACT_PATH}/${LOCAL_COMMIT_SHA}.zip" - until [ $SECONDS -ge 300 ] && exit 1; do - curl -o /dev/null --fail --silent "https://${S3_ARTIFACT_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/${S3_ARTIFACT_PATH}/${LOCAL_COMMIT_SHA}.zip" && exit - echo -n "." - sleep 2 - done - - run: - working_directory: .circleci/terraform/load-test - name: terraform init - command: | - short_ref=$(git rev-parse --short HEAD) - echo "Testing commit id: $short_ref" - terraform init \ - -backend-config="bucket=${BUCKET}" \ - -backend-config="key=${LOCAL_COMMIT_SHA}" \ - -backend-config="region=${AWS_DEFAULT_REGION}" \ - -backend-config="role_arn=${ROLE_ARN_LOAD_TEST}" - - run: - working_directory: .circleci/terraform/load-test - name: run terraform apply - command: | - terraform apply -auto-approve - - run: - working_directory: .circleci/terraform/load-test - when: always - name: terraform destroy - command: | - for i in $(seq 1 5); do terraform destroy -auto-approve && s=0 && break || s=$? && sleep 20; done; (exit $s) - - run: *notify-slack-failure - # The noop job is a used as a very fast job in the verify-ci workflow because every workflow # requires at least one job. It does nothing. noop: @@ -1164,7 +1088,6 @@ workflows: jobs: [noop] go-tests: - unless: << pipeline.parameters.trigger-load-test >> jobs: - check-go-mod: &filter-ignore-non-go-branches filters: @@ -1227,7 +1150,6 @@ workflows: - go-test-32bit: *filter-ignore-non-go-branches - noop build-distros: - unless: << pipeline.parameters.trigger-load-test >> jobs: - check-go-mod: *filter-ignore-non-go-branches - build-386: &require-check-go-mod @@ -1259,7 +1181,6 @@ workflows: context: consul-ci - noop test-integrations: - unless: << pipeline.parameters.trigger-load-test >> jobs: - dev-build: *filter-ignore-non-go-branches - dev-upload-s3: &dev-upload @@ -1303,7 +1224,6 @@ workflows: - noop frontend: - unless: << pipeline.parameters.trigger-load-test >> jobs: - frontend-cache: filters: @@ -1336,19 +1256,3 @@ workflows: requires: - ember-build-ent - noop - - load-test: - when: << pipeline.parameters.trigger-load-test >> - jobs: - - load-test - - nightly-jobs: - triggers: - - schedule: - cron: "0 4 * * *" # 4AM UTC <> 12AM EST <> 9PM PST should have no impact - filters: - branches: - only: - - main - jobs: - - load-test diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml deleted file mode 100644 index 61d23cde71d3..000000000000 --- a/.github/workflows/load-test.yml +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -name: Load Test - -on: - pull_request: - branches: - - main - types: [labeled] - workflow_dispatch: {} - -jobs: - trigger-load-test: - if: ${{ github.event.label.name == 'pr/load-test' }} - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Trigger CircleCI Load Test Pipeline - run: | - # build json payload to trigger CircleCI Load Test Pipeline - # This only runs the load test pipeline on the 'main' branch - jsonData=$(jq --null-input -r --arg commit ${{ github.event.pull_request.head.sha }} \ - '{branch:"main", parameters: {"commit": $commit, "trigger-load-test": true}}') - echo "Passing JSON data to CircleCI API: $jsonData" - load_test_pipeline_id=$(curl -X POST \ - -H "Circle-Token: ${{ secrets.CIRCLE_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d "$jsonData" \ - "https://circleci.com/api/v2/project/gh/${GITHUB_REPOSITORY}/pipeline" | jq -r '.id') - echo "LOAD_TEST_PIPELINE_ID=$load_test_pipeline_id" >> $GITHUB_ENV - - name: Post Load Test URL to PR - env: - PR_COMMENT_URL: ${{ github.event.pull_request.comments_url }} - run: | - echo "LOAD_TEST_PIPELINE_ID is: $LOAD_TEST_PIPELINE_ID" - # get load-test workflow - workflow= - # wait up to a minute for load-test workflow to start - until [ $SECONDS -ge 60 ] && exit 1; do - workflow=$(curl -s -X GET \ - -H "Circle-Token: ${{ secrets.CIRCLE_TOKEN }}" \ - -H "Content-Type: application/json" \ - "https://circleci.com/api/v2/pipeline/${LOAD_TEST_PIPELINE_ID}/workflow" | jq '.items[] | select(.name=="load-test")') - # if we found a workflow we exit - if [ -n "$workflow" ]; then - break - fi - echo -n "." - sleep 5 - done - echo "$workflow" - # get pipeline number - pipeline_number=$(echo "$workflow" | jq -r '.pipeline_number') - # get workflow id - workflow_id=$(echo "$workflow" | jq -r '.id') - # get project slug - project_slug=$(echo "$workflow" | jq -r '.project_slug') - # build load test URL - load_test_url="https://app.circleci.com/pipelines/${project_slug}/${pipeline_number}/workflows/${workflow_id}" - # comment URL to pull request - curl -X POST \ - -H "Authorization: token ${{ secrets.PR_COMMENT_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d "{\"body\": \"Load Test Pipeline Started at: $load_test_url\"}" \ - "$PR_COMMENT_URL" From a168d0e667ace4b43dc8233bad58422098f3155b Mon Sep 17 00:00:00 2001 From: malizz Date: Fri, 24 Mar 2023 12:03:00 -0700 Subject: [PATCH 17/17] add failover policy to ProxyConfigEntry in api (#16759) * add failover policy to ProxyConfigEntry in api * update docs --- api/config_entry.go | 19 ++++++++++--------- api/config_entry_test.go | 6 ++++++ .../connect/config-entries/proxy-defaults.mdx | 13 +++++++++++++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/api/config_entry.go b/api/config_entry.go index 9d734aa646a2..24254ec7090e 100644 --- a/api/config_entry.go +++ b/api/config_entry.go @@ -312,15 +312,16 @@ func (s *ServiceConfigEntry) GetModifyIndex() uint64 { return s.ModifyIndex type ProxyConfigEntry struct { Kind string Name string - Partition string `json:",omitempty"` - Namespace string `json:",omitempty"` - Mode ProxyMode `json:",omitempty"` - TransparentProxy *TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"` - Config map[string]interface{} `json:",omitempty"` - MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"` - Expose ExposeConfig `json:",omitempty"` - AccessLogs *AccessLogsConfig `json:",omitempty" alias:"access_logs"` - EnvoyExtensions []EnvoyExtension `json:",omitempty" alias:"envoy_extensions"` + Partition string `json:",omitempty"` + Namespace string `json:",omitempty"` + Mode ProxyMode `json:",omitempty"` + TransparentProxy *TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"` + Config map[string]interface{} `json:",omitempty"` + MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"` + Expose ExposeConfig `json:",omitempty"` + AccessLogs *AccessLogsConfig `json:",omitempty" alias:"access_logs"` + EnvoyExtensions []EnvoyExtension `json:",omitempty" alias:"envoy_extensions"` + FailoverPolicy *ServiceResolverFailoverPolicy `json:",omitempty" alias:"failover_policy"` Meta map[string]string `json:",omitempty"` CreateIndex uint64 diff --git a/api/config_entry_test.go b/api/config_entry_test.go index 30f7510402ff..a4fe2505f4e8 100644 --- a/api/config_entry_test.go +++ b/api/config_entry_test.go @@ -408,6 +408,9 @@ func TestDecodeConfigEntry(t *testing.T) { "Type": "file", "Path": "/tmp/logs.txt", "TextFormat": "[%START_TIME%]" + }, + "FailoverPolicy": { + "Mode": "default" } } `, @@ -440,6 +443,9 @@ func TestDecodeConfigEntry(t *testing.T) { Path: "/tmp/logs.txt", TextFormat: "[%START_TIME%]", }, + FailoverPolicy: &ServiceResolverFailoverPolicy{ + Mode: "default", + }, }, }, { diff --git a/website/content/docs/connect/config-entries/proxy-defaults.mdx b/website/content/docs/connect/config-entries/proxy-defaults.mdx index cb9b9991712f..bf75c130d2a3 100644 --- a/website/content/docs/connect/config-entries/proxy-defaults.mdx +++ b/website/content/docs/connect/config-entries/proxy-defaults.mdx @@ -472,6 +472,19 @@ spec: }, ], }, + { + name: 'FailoverPolicy', + type: 'ServiceResolverFailoverPolicy: ', + description: `Policy specifies the exact mechanism used for failover. + Added in v1.16.0.`, + children: [ + { + name: 'Mode', + type: 'string: ""', + description: 'One of `""`, `default`, or `order-by-locality`.', + }, + ], + }, { name: 'AccessLogs', type: 'AccessLogsConfig: ',