diff --git a/.changelog/2909.txt b/.changelog/2909.txt deleted file mode 100644 index cae7f44d45..0000000000 --- a/.changelog/2909.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: Add readOnlyRootFilesystem to the default restricted security context when runnning `consul-k8s` in a restricted namespaces. -``` \ No newline at end of file diff --git a/.changelog/3635.txt b/.changelog/3635.txt deleted file mode 100644 index c5c505c808..0000000000 --- a/.changelog/3635.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -helm: (datadog integration) updated `server-statefulset.yaml` templating to handle custom Unix Domain Socket paths. -``` \ No newline at end of file diff --git a/.changelog/3685.txt b/.changelog/3685.txt deleted file mode 100644 index 05241d820d..0000000000 --- a/.changelog/3685.txt +++ /dev/null @@ -1,6 +0,0 @@ -```release-note:bug -helm: corrected datadog openmetrics and consul-checks consul server URLs set during automation to use full consul deployment release name -``` -```release-note:bug -helm: bug fix for `prometheus.io` annotation omission while using datadog integration with openmetrics/prometheus and consul integration checks -``` \ No newline at end of file diff --git a/.changelog/3718.txt b/.changelog/3718.txt deleted file mode 100644 index 9e7cd4f59a..0000000000 --- a/.changelog/3718.txt +++ /dev/null @@ -1,4 +0,0 @@ -```release-note:breaking-change -api-gateway: The api-gateway stanza located under .Values.api-gateway was deprecated in -1.16.0 of Consul and is being removed as of 1.19.0 in favor of connectInject.apiGateway. -``` \ No newline at end of file diff --git a/.changelog/3767.txt b/.changelog/3767.txt deleted file mode 100644 index 1801c88739..0000000000 --- a/.changelog/3767.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -gateways: api-gateway now uses the Consul file-system-certificate by default for TLS -``` \ No newline at end of file diff --git a/.changelog/3943.txt b/.changelog/3943.txt deleted file mode 100644 index 3be45fc453..0000000000 --- a/.changelog/3943.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -control-plane: Add the ability to register services via CRD. -``` diff --git a/.changelog/3991.txt b/.changelog/3991.txt deleted file mode 100644 index 45ff3c90dd..0000000000 --- a/.changelog/3991.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -helm: adds ability to set the Image Pull Policy for all Consul images (consul, consul-k8s, consul-dataplane, consul-telemetry-collector) -``` diff --git a/.changelog/4003.txt b/.changelog/4000.txt similarity index 100% rename from .changelog/4003.txt rename to .changelog/4000.txt diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index aedbb51464..6901dfc5fd 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -26,7 +26,7 @@ jobs: run: echo "GOROOT=$(go env GOROOT)" >> "${GITHUB_ENV}" - name: golangci-lint-helm-gen - uses: golangci/golangci-lint-action@38e1018663fa5173f3968ea0777460d3de38f256 # v5.3.0 + uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 with: version: "v1.55.2" working-directory: hack/helm-reference-gen @@ -34,21 +34,21 @@ jobs: args: "--no-config --disable-all --enable gofmt,govet" - name: golangci-lint-control-plane - uses: golangci/golangci-lint-action@38e1018663fa5173f3968ea0777460d3de38f256 # v5.3.0 + uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 with: version: "v1.55.2" working-directory: control-plane skip-cache: true # We have seen sticky timeout bugs crop up with caching enabled, so disabling for now - name: golangci-lint-acceptance - uses: golangci/golangci-lint-action@38e1018663fa5173f3968ea0777460d3de38f256 # v5.3.0 + uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 with: version: "v1.55.2" working-directory: acceptance skip-cache: true # We have seen sticky timeout bugs crop up with caching enabled, so disabling for now - name: golangci-lint-cli - uses: golangci/golangci-lint-action@38e1018663fa5173f3968ea0777460d3de38f256 # v5.3.0 + uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 with: version: "v1.55.2" working-directory: acceptance diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index 22c7614eca..aa7f00cd88 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -27,4 +27,5 @@ jobs: repo: hashicorp/consul-k8s-workflows ref: main token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} - inputs: '{ "context":"${{ env.CONTEXT }}", "actor":"${{ github.actor }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ env.SHA }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' + # set "test-ce" to false when a new minor version is released + inputs: '{ "test-ce": false, "context":"${{ env.CONTEXT }}", "actor":"${{ github.actor }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ env.SHA }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' diff --git a/.github/workflows/nightly-acceptance.yml b/.github/workflows/nightly-acceptance.yml index c8ac870410..c213024498 100644 --- a/.github/workflows/nightly-acceptance.yml +++ b/.github/workflows/nightly-acceptance.yml @@ -23,4 +23,5 @@ jobs: repo: hashicorp/consul-k8s-workflows ref: main token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} - inputs: '{ "context":"${{ env.CONTEXT }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ github.sha }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' + # set "test-ce" to false when a new minor version is released + inputs: '{ "test-ce": true, "context":"${{ env.CONTEXT }}", "actor":"${{ github.actor }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ env.SHA }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5b2540cb7d..6eefc134e5 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -21,4 +21,5 @@ jobs: repo: hashicorp/consul-k8s-workflows ref: main token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} - inputs: '{ "context":"${{ env.CONTEXT }}", "actor":"${{ github.actor }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ env.SHA }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' + # set "test-ce" to false when a new minor version is released + inputs: '{ "test-ce": false, "context":"${{ env.CONTEXT }}", "actor":"${{ github.actor }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ env.SHA }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 9f1d3f4af9..010db3d690 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -40,7 +40,8 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: repository: hashicorp/security-scanner - token: ${{ secrets.HASHIBOT_PRODSEC_GITHUB_TOKEN }} + #TODO: replace w/ HASHIBOT_PRODSEC_GITHUB_TOKEN once provisioned + token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} path: security-scanner ref: main @@ -57,6 +58,6 @@ jobs: cat results.sarif | jq - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@c4fb451437765abf5018c6fbf22cce1a7da1e5cc # codeql-bundle-v2.17.1 + uses: github/codeql-action/upload-sarif@8fcfedf57053e09257688fce7a0beeb18b1b9ae3 # codeql-bundle-v2.17.2 with: - sarif_file: results.sarif + sarif_file: results.sarif \ No newline at end of file diff --git a/.github/workflows/weekly-acceptance-1-1-x.yml b/.github/workflows/weekly-acceptance-1-1-x.yml index 5aea9e3f2c..9bd2f295ab 100644 --- a/.github/workflows/weekly-acceptance-1-1-x.yml +++ b/.github/workflows/weekly-acceptance-1-1-x.yml @@ -26,4 +26,5 @@ jobs: repo: hashicorp/consul-k8s-workflows ref: main token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} - inputs: '{ "context":"${{ env.CONTEXT }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ github.sha }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' + # set "test-ce" to false when a new minor version is released + inputs: '{ "test-ce": true, "context":"${{ env.CONTEXT }}", "actor":"${{ github.actor }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ env.SHA }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' diff --git a/.github/workflows/weekly-acceptance-1-4-x.yml b/.github/workflows/weekly-acceptance-1-4-x.yml deleted file mode 100644 index eb8d50bc73..0000000000 --- a/.github/workflows/weekly-acceptance-1-4-x.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Dispatch to the consul-k8s-workflows with a weekly cron -# -# A separate file is needed for each release because the cron schedules are different for each release. -name: weekly-acceptance-1-4-x -on: - schedule: - # * is a special character in YAML so you have to quote this string - # Run weekly on Thursday at 3AM UTC/11PM EST/8PM PST - - cron: '0 3 * * 4' - -# these should be the only settings that you will ever need to change -env: - BRANCH: "release/1.4.x" - CONTEXT: "weekly" - -jobs: - cloud: - name: cloud - runs-on: ubuntu-latest - steps: - - uses: benc-uk/workflow-dispatch@25b02cc069be46d637e8fe2f1e8484008e9e9609 # v1.2.3 - name: cloud - with: - workflow: cloud.yml - repo: hashicorp/consul-k8s-workflows - ref: main - token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} - inputs: '{ "context":"${{ env.CONTEXT }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ github.sha }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' diff --git a/.github/workflows/weekly-acceptance-1-5-x.yml b/.github/workflows/weekly-acceptance-1-5-x.yml deleted file mode 100644 index ea245dc1d9..0000000000 --- a/.github/workflows/weekly-acceptance-1-5-x.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Dispatch to the consul-k8s-workflows with a weekly cron -# -# A separate file is needed for each release because the cron schedules are different for each release. -name: weekly-acceptance-1-5-x -on: - schedule: - # * is a special character in YAML so you have to quote this string - # Run weekly on Friday at 3AM UTC/11PM EST/8PM PST - - cron: '0 3 * * 5' - -# these should be the only settings that you will ever need to change -env: - BRANCH: "release/1.5.x" - CONTEXT: "weekly" - -jobs: - cloud: - name: cloud - runs-on: ubuntu-latest - steps: - - uses: benc-uk/workflow-dispatch@25b02cc069be46d637e8fe2f1e8484008e9e9609 # v1.2.3 - name: cloud - with: - workflow: cloud.yml - repo: hashicorp/consul-k8s-workflows - ref: main - token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} - inputs: '{ "context":"${{ env.CONTEXT }}", "repository":"${{ github.repository }}", "branch":"${{ env.BRANCH }}", "sha":"${{ github.sha }}", "token":"${{ secrets.ELEVATED_GITHUB_TOKEN }}" }' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d7f3c8d19..6ce0e9c2df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,46 +1,17 @@ -## 1.4.3 (May 24, 2024) - -IMPROVEMENTS: - -* upgrade go version to v1.22.3. [[GH-3994](https://github.com/hashicorp/consul-k8s/issues/3994)] -* Bump Dockerfile base image for `consul-k8s-control-plane` to `alpine:3.19`. [[GH-4016](https://github.com/hashicorp/consul-k8s/issues/4016)] - -## 1.3.6 (May 24, 2024) - -IMPROVEMENTS: - -* upgrade go version to v1.22.3. [[GH-3994](https://github.com/hashicorp/consul-k8s/issues/3994)] -* Bump Dockerfile base image for `consul-k8s-control-plane` to `alpine:3.19`. [[GH-4016](https://github.com/hashicorp/consul-k8s/issues/4016)] - -## 1.2.9 (May 24, 2024) - -IMPROVEMENTS: - -* upgrade go version to v1.22.3. [[GH-3994](https://github.com/hashicorp/consul-k8s/issues/3994)] -* Bump Dockerfile base image for `consul-k8s-control-plane` to `alpine:3.19`. [[GH-4016](https://github.com/hashicorp/consul-k8s/issues/4016)] - -## 1.1.13 (May 24, 2024) - -IMPROVEMENTS: - -* upgrade go version to v1.22.3. [[GH-3994](https://github.com/hashicorp/consul-k8s/issues/3994)] -* Bump Dockerfile base image for `consul-k8s-control-plane` to `alpine:3.19`. [[GH-4016](https://github.com/hashicorp/consul-k8s/issues/4016)] - - ## 1.4.2 (May 20, 2024) SECURITY: -* Upgrade Go to use 1.21.10. This addresses CVEs - [CVE-2024-24787](https://nvd.nist.gov/vuln/detail/CVE-2024-24787) and - [CVE-2024-24788](https://nvd.nist.gov/vuln/detail/CVE-2024-24788) [[GH-3980](https://github.com/hashicorp/consul-k8s/issues/3980)] +* Upgrade Go to use 1.21.10. This addresses CVEs +[CVE-2024-24787](https://nvd.nist.gov/vuln/detail/CVE-2024-24787) and +[CVE-2024-24788](https://nvd.nist.gov/vuln/detail/CVE-2024-24788) [[GH-3980](https://github.com/hashicorp/consul-k8s/issues/3980)] * Upgrade `helm/v3` to 3.14.4. This resolves the following security vulnerabilities: - [CVE-2024-25620](https://osv.dev/vulnerability/CVE-2024-25620) - [CVE-2024-26147](https://osv.dev/vulnerability/CVE-2024-26147) [[GH-3935](https://github.com/hashicorp/consul-k8s/issues/3935)] +[CVE-2024-25620](https://osv.dev/vulnerability/CVE-2024-25620) +[CVE-2024-26147](https://osv.dev/vulnerability/CVE-2024-26147) [[GH-3935](https://github.com/hashicorp/consul-k8s/issues/3935)] * Upgrade to use Go `1.21.9`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`http2`). [[GH-3893](https://github.com/hashicorp/consul-k8s/issues/3893)] +[CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`http2`). [[GH-3893](https://github.com/hashicorp/consul-k8s/issues/3893)] * Upgrade to use golang.org/x/net `v0.24.0`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`x/net`). [[GH-3893](https://github.com/hashicorp/consul-k8s/issues/3893)] +[CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`x/net`). [[GH-3893](https://github.com/hashicorp/consul-k8s/issues/3893)] FEATURES: @@ -53,8 +24,8 @@ IMPROVEMENTS: * control-plane: Add support for receiving iptables configuration via CNI arguments, to support Nomad transparent proxy [[GH-3795](https://github.com/hashicorp/consul-k8s/issues/3795)] * control-plane: Remove anyuid Security Context Constraints (SCC) requirement in OpenShift. [[GH-3813](https://github.com/hashicorp/consul-k8s/issues/3813)] * helm: only create the default Prometheus path annotation when it's not already specified within the component-specific - annotations. For example if the `client.annotations` value sets prometheus.io/path annotation, don't overwrite it with - the default value. [[GH-3846](https://github.com/hashicorp/consul-k8s/issues/3846)] +annotations. For example if the `client.annotations` value sets prometheus.io/path annotation, don't overwrite it with +the default value. [[GH-3846](https://github.com/hashicorp/consul-k8s/issues/3846)] * helm: support sync-lb-services-endpoints flag for syncCatalog [[GH-3905](https://github.com/hashicorp/consul-k8s/issues/3905)] * terminating-gateways: Remove unnecessary permissions from terminating gateways role [[GH-3928](https://github.com/hashicorp/consul-k8s/issues/3928)] @@ -67,93 +38,6 @@ BUG FIXES: * control-plane: fix a panic when an upstream annotation is malformed. [[GH-3956](https://github.com/hashicorp/consul-k8s/issues/3956)] * connect-inject: Fixed issue where on restart, if a managed-gateway-acl-role already existed the container would error [[GH-3978](https://github.com/hashicorp/consul-k8s/issues/3978)] -## 1.3.5 (May 20, 2024) - -SECURITY: - -* Upgrade Go to use 1.21.10. This addresses CVEs - [CVE-2024-24787](https://nvd.nist.gov/vuln/detail/CVE-2024-24787) and - [CVE-2024-24788](https://nvd.nist.gov/vuln/detail/CVE-2024-24788) [[GH-3980](https://github.com/hashicorp/consul-k8s/issues/3980)] -* Upgrade `helm/v3` to 3.14.4. This resolves the following security vulnerabilities: - [CVE-2024-25620](https://osv.dev/vulnerability/CVE-2024-25620) - [CVE-2024-26147](https://osv.dev/vulnerability/CVE-2024-26147) [[GH-3935](https://github.com/hashicorp/consul-k8s/issues/3935)] -* Upgrade to use Go `1.21.9`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`http2`). [[GH-3902](https://github.com/hashicorp/consul-k8s/issues/3902)] -* Upgrade to use golang.org/x/net `v0.24.0`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`x/net`). [[GH-3902](https://github.com/hashicorp/consul-k8s/issues/3902)] - -FEATURES: - -* Add support for configuring graceful startup proxy lifecycle management settings. [[GH-3878](https://github.com/hashicorp/consul-k8s/issues/3878)] - -IMPROVEMENTS: - -* control-plane: support , and <\n> as upstream separators. [[GH-3956](https://github.com/hashicorp/consul-k8s/issues/3956)] -* ConfigEntries controller: Only error for config entries from different datacenters when the config entries are different [[GH-3873](https://github.com/hashicorp/consul-k8s/issues/3873)] -* control-plane: Remove anyuid Security Context Constraints (SCC) requirement in OpenShift. [[GH-3813](https://github.com/hashicorp/consul-k8s/issues/3813)] -* helm: only create the default Prometheus path annotation when it's not already specified within the component-specific - annotations. For example if the `client.annotations` value sets prometheus.io/path annotation, don't overwrite it with - the default value. [[GH-3846](https://github.com/hashicorp/consul-k8s/issues/3846)] -* helm: support sync-lb-services-endpoints flag for syncCatalog [[GH-3905](https://github.com/hashicorp/consul-k8s/issues/3905)] -* terminating-gateways: Remove unnecessary permissions from terminating gateways role [[GH-3928](https://github.com/hashicorp/consul-k8s/issues/3928)] - -BUG FIXES: - -* Create Consul service with mode transparent-proxy even when a cluster IP is not assigned to the service.. [[GH-3974](https://github.com/hashicorp/consul-k8s/issues/3974)] -* api-gateway: Fix order of initialization for creating ACL role/policy to avoid error logs in consul when upgrading between versions. [[GH-3918](https://github.com/hashicorp/consul-k8s/issues/3918)] -* api-gateway: fix bug where multiple logical APIGateways would share the same ACL policy. [[GH-4001](https://github.com/hashicorp/consul-k8s/issues/4001)] -* control-plane: fix a panic when an upstream annotation is malformed. [[GH-3956](https://github.com/hashicorp/consul-k8s/issues/3956)] -* connect-inject: Fixed issue where on restart, if a managed-gateway-acl-role already existed the container would error [[GH-3978](https://github.com/hashicorp/consul-k8s/issues/3978)] - -## 1.2.8 (May 20, 2024) - -SECURITY: - -* Upgrade Go to use 1.21.10. This addresses CVEs - [CVE-2024-24787](https://nvd.nist.gov/vuln/detail/CVE-2024-24787) and - [CVE-2024-24788](https://nvd.nist.gov/vuln/detail/CVE-2024-24788) [[GH-3980](https://github.com/hashicorp/consul-k8s/issues/3980)] -* Upgrade `helm/v3` to 3.14.4. This resolves the following security vulnerabilities: - [CVE-2024-25620](https://osv.dev/vulnerability/CVE-2024-25620) - [CVE-2024-26147](https://osv.dev/vulnerability/CVE-2024-26147) [[GH-3935](https://github.com/hashicorp/consul-k8s/issues/3935)] -* Upgrade to use Go `1.21.9`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`http2`). [[GH-3901](https://github.com/hashicorp/consul-k8s/issues/3901)] -* Upgrade to use golang.org/x/net `v0.24.0`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`x/net`). [[GH-3901](https://github.com/hashicorp/consul-k8s/issues/3901)] - -IMPROVEMENTS: - -* ConfigEntries controller: Only error for config entries from different datacenters when the config entries are different [[GH-3873](https://github.com/hashicorp/consul-k8s/issues/3873)] -* control-plane: Remove anyuid Security Context Constraints (SCC) requirement in OpenShift. [[GH-3813](https://github.com/hashicorp/consul-k8s/issues/3813)] -* helm: only create the default Prometheus path annotation when it's not already specified within the component-specific - annotations. For example if the `client.annotations` value sets prometheus.io/path annotation, don't overwrite it with - the default value. [[GH-3846](https://github.com/hashicorp/consul-k8s/issues/3846)] -* helm: support sync-lb-services-endpoints flag for syncCatalog [[GH-3905](https://github.com/hashicorp/consul-k8s/issues/3905)] - -BUG FIXES: - -* api-gateway: Fix order of initialization for creating ACL role/policy to avoid error logs in consul when upgrading between versions. [[GH-3918](https://github.com/hashicorp/consul-k8s/issues/3918)] -* api-gateway: fix bug where multiple logical APIGateways would share the same ACL policy. [[GH-4002](https://github.com/hashicorp/consul-k8s/issues/4002)] -* connect-inject: Fixed issue where on restart, if a managed-gateway-acl-role already existed the container would error [[GH-3978](https://github.com/hashicorp/consul-k8s/issues/3978)] - -## 1.1.12 (May 20, 2024) - -SECURITY: - -* Upgrade Go to use 1.21.10. This addresses CVEs - [CVE-2024-24787](https://nvd.nist.gov/vuln/detail/CVE-2024-24787) and - [CVE-2024-24788](https://nvd.nist.gov/vuln/detail/CVE-2024-24788) [[GH-3980](https://github.com/hashicorp/consul-k8s/issues/3980)] -* Upgrade `helm/v3` to 3.14.4. This resolves the following security vulnerabilities: - [CVE-2024-25620](https://osv.dev/vulnerability/CVE-2024-25620) - [CVE-2024-26147](https://osv.dev/vulnerability/CVE-2024-26147) [[GH-3935](https://github.com/hashicorp/consul-k8s/issues/3935)] -* Upgrade to use Go `1.21.9`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`http2`). [[GH-3900](https://github.com/hashicorp/consul-k8s/issues/3900)] -* Upgrade to use golang.org/x/net `v0.24.0`. This resolves CVE - [CVE-2023-45288](https://nvd.nist.gov/vuln/detail/CVE-2023-45288) (`x/net`). [[GH-3900](https://github.com/hashicorp/consul-k8s/issues/3900)] - -IMPROVEMENTS: - -* ConfigEntries controller: Only error for config entries from different datacenters when the config entries are different [[GH-3873](https://github.com/hashicorp/consul-k8s/issues/3873)] - ## 1.4.1 (March 28, 2024) SECURITY: @@ -182,125 +66,6 @@ tokens were invalidated immediately on pod entering Terminating state. [[GH-3736 * control-plane: fix an issue where ACL tokens would prematurely be deleted and services would be deregistered if there was a K8s API error fetching the pod. [[GH-3758](https://github.com/hashicorp/consul-k8s/issues/3758)] -## 1.3.4 (March 28, 2024) - -SECURITY: - -* Update `google.golang.org/protobuf` to v1.33.0 to address [CVE-2024-24786](https://nvd.nist.gov/vuln/detail/CVE-2024-24786). [[GH-3719](https://github.com/hashicorp/consul-k8s/issues/3719)] -* Update the Consul Build Go base image to `alpine3.19`. This resolves CVEs -[CVE-2023-52425](https://nvd.nist.gov/vuln/detail/CVE-2023-52425) -[CVE-2023-52426⁠](https://nvd.nist.gov/vuln/detail/CVE-2023-52426) [[GH-3741](https://github.com/hashicorp/consul-k8s/issues/3741)] -* Upgrade `helm/v3` to 3.11.3. This resolves the following security vulnerabilities: -[CVE-2023-25165](https://osv.dev/vulnerability/CVE-2023-25165) -[CVE-2022-23524](https://osv.dev/vulnerability/CVE-2022-23524) -[CVE-2022-23526](https://osv.dev/vulnerability/CVE-2022-23526) -[CVE-2022-23525](https://osv.dev/vulnerability/CVE-2022-23525) [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade docker/distribution to 2.8.3+incompatible (latest) to resolve [CVE-2023-2253](https://osv.dev/vulnerability/CVE-2023-2253). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade docker/docker to 25.0.3+incompatible (latest) to resolve [GHSA-jq35-85cj-fj4p](https://osv.dev/vulnerability/GHSA-jq35-85cj-fj4p). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade filepath-securejoin to 0.2.4 (latest) to resolve [GO-2023-2048](https://osv.dev/vulnerability/GO-2023-2048). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade to use Go `1.21.8`. This resolves CVEs -[CVE-2024-24783](https://nvd.nist.gov/vuln/detail/CVE-2024-24783) (`crypto/x509`). -[CVE-2023-45290](https://nvd.nist.gov/vuln/detail/CVE-2023-45290) (`net/http`). -[CVE-2023-45289](https://nvd.nist.gov/vuln/detail/CVE-2023-45289) (`net/http`, `net/http/cookiejar`). -[CVE-2024-24785](https://nvd.nist.gov/vuln/detail/CVE-2024-24785) (`html/template`). -[CVE-2024-24784](https://nvd.nist.gov/vuln/detail/CVE-2024-24784) (`net/mail`). [[GH-3741](https://github.com/hashicorp/consul-k8s/issues/3741)] -* security: upgrade containerd to 1.7.13 (latest) to resolve [GHSA-7ww5-4wqc-m92c](https://osv.dev/vulnerability/GO-2023-2412). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] - -IMPROVEMENTS: - -* catalog: Topology zone and region information is now read from the Kubernetes endpoints and associated node and added to registered consul services under Metadata. [[GH-3693](https://github.com/hashicorp/consul-k8s/issues/3693)] -* control-plane: publish `consul-k8s-control-plane` and `consul-k8s-control-plane-fips` images to official HashiCorp AWS ECR. [[GH-3668](https://github.com/hashicorp/consul-k8s/issues/3668)] - -BUG FIXES: - -* api-gateway: Fix order of initialization for creating ACL role/policy to avoid error logs in consul. [[GH-3779](https://github.com/hashicorp/consul-k8s/issues/3779)] -* control-plane: fix an issue where ACL token cleanup did not respect a pod's GracefulShutdownPeriodSeconds and -tokens were invalidated immediately on pod entering Terminating state. [[GH-3736](https://github.com/hashicorp/consul-k8s/issues/3736)] -* control-plane: fix an issue where ACL tokens would prematurely be deleted and services would be deregistered if there -was a K8s API error fetching the pod. [[GH-3758](https://github.com/hashicorp/consul-k8s/issues/3758)] - -NOTES: - -* build: Releases will now also be available as Debian and RPM packages for the arm64 architecture, refer to the -[Official Packaging Guide](https://www.hashicorp.com/official-packaging-guide) for more information. [[GH-3428](https://github.com/hashicorp/consul-k8s/issues/3428)] - -## 1.2.7 (March 28, 2024) - -SECURITY: - -* Update `google.golang.org/protobuf` to v1.33.0 to address [CVE-2024-24786](https://nvd.nist.gov/vuln/detail/CVE-2024-24786). [[GH-3719](https://github.com/hashicorp/consul-k8s/issues/3719)] -* Update the Consul Build Go base image to `alpine3.19`. This resolves CVEs -[CVE-2023-52425](https://nvd.nist.gov/vuln/detail/CVE-2023-52425) -[CVE-2023-52426⁠](https://nvd.nist.gov/vuln/detail/CVE-2023-52426) [[GH-3741](https://github.com/hashicorp/consul-k8s/issues/3741)] -* Upgrade `helm/v3` to 3.11.3. This resolves the following security vulnerabilities: -[CVE-2023-25165](https://osv.dev/vulnerability/CVE-2023-25165) -[CVE-2022-23524](https://osv.dev/vulnerability/CVE-2022-23524) -[CVE-2022-23526](https://osv.dev/vulnerability/CVE-2022-23526) -[CVE-2022-23525](https://osv.dev/vulnerability/CVE-2022-23525) [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade docker/distribution to 2.8.3+incompatible (latest) to resolve [CVE-2023-2253](https://osv.dev/vulnerability/CVE-2023-2253). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade docker/docker to 25.0.3+incompatible (latest) to resolve [GHSA-jq35-85cj-fj4p](https://osv.dev/vulnerability/GHSA-jq35-85cj-fj4p). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade filepath-securejoin to 0.2.4 (latest) to resolve [GO-2023-2048](https://osv.dev/vulnerability/GO-2023-2048). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade to use Go `1.21.8`. This resolves CVEs -[CVE-2024-24783](https://nvd.nist.gov/vuln/detail/CVE-2024-24783) (`crypto/x509`). -[CVE-2023-45290](https://nvd.nist.gov/vuln/detail/CVE-2023-45290) (`net/http`). -[CVE-2023-45289](https://nvd.nist.gov/vuln/detail/CVE-2023-45289) (`net/http`, `net/http/cookiejar`). -[CVE-2024-24785](https://nvd.nist.gov/vuln/detail/CVE-2024-24785) (`html/template`). -[CVE-2024-24784](https://nvd.nist.gov/vuln/detail/CVE-2024-24784) (`net/mail`). [[GH-3741](https://github.com/hashicorp/consul-k8s/issues/3741)] -* security: upgrade containerd to 1.7.13 (latest) to resolve [GHSA-7ww5-4wqc-m92c](https://osv.dev/vulnerability/GO-2023-2412). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] - -IMPROVEMENTS: - -* catalog: Topology zone and region information is now read from the Kubernetes endpoints and associated node and added to registered consul services under Metadata. [[GH-3693](https://github.com/hashicorp/consul-k8s/issues/3693)] -* control-plane: publish `consul-k8s-control-plane` and `consul-k8s-control-plane-fips` images to official HashiCorp AWS ECR. [[GH-3668](https://github.com/hashicorp/consul-k8s/issues/3668)] - -BUG FIXES: - -* api-gateway: Fix order of initialization for creating ACL role/policy to avoid error logs in consul. [[GH-3779](https://github.com/hashicorp/consul-k8s/issues/3779)] -* control-plane: fix an issue where ACL token cleanup did not respect a pod's GracefulShutdownPeriodSeconds and -tokens were invalidated immediately on pod entering Terminating state. [[GH-3736](https://github.com/hashicorp/consul-k8s/issues/3736)] -* control-plane: fix an issue where ACL tokens would prematurely be deleted and services would be deregistered if there -was a K8s API error fetching the pod. [[GH-3758](https://github.com/hashicorp/consul-k8s/issues/3758)] - -NOTES: - -* build: Releases will now also be available as Debian and RPM packages for the arm64 architecture, refer to the -[Official Packaging Guide](https://www.hashicorp.com/official-packaging-guide) for more information. [[GH-3428](https://github.com/hashicorp/consul-k8s/issues/3428)] - -## 1.1.11 (March 28, 2024) - -SECURITY: - -* Update `google.golang.org/protobuf` to v1.33.0 to address [CVE-2024-24786](https://nvd.nist.gov/vuln/detail/CVE-2024-24786). [[GH-3719](https://github.com/hashicorp/consul-k8s/issues/3719)] -* Update the Consul Build Go base image to `alpine3.19`. This resolves CVEs -[CVE-2023-52425](https://nvd.nist.gov/vuln/detail/CVE-2023-52425) -[CVE-2023-52426⁠](https://nvd.nist.gov/vuln/detail/CVE-2023-52426) [[GH-3741](https://github.com/hashicorp/consul-k8s/issues/3741)] -* Upgrade `helm/v3` to 3.11.3. This resolves the following security vulnerabilities: -[CVE-2023-25165](https://osv.dev/vulnerability/CVE-2023-25165) -[CVE-2022-23524](https://osv.dev/vulnerability/CVE-2022-23524) -[CVE-2022-23526](https://osv.dev/vulnerability/CVE-2022-23526) -[CVE-2022-23525](https://osv.dev/vulnerability/CVE-2022-23525) [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade docker/distribution to 2.8.3+incompatible (latest) to resolve [CVE-2023-2253](https://osv.dev/vulnerability/CVE-2023-2253). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade docker/docker to 25.0.3+incompatible (latest) to resolve [GHSA-jq35-85cj-fj4p](https://osv.dev/vulnerability/GHSA-jq35-85cj-fj4p). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade filepath-securejoin to 0.2.4 (latest) to resolve [GO-2023-2048](https://osv.dev/vulnerability/GO-2023-2048). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] -* Upgrade to use Go `1.21.8`. This resolves CVEs -[CVE-2024-24783](https://nvd.nist.gov/vuln/detail/CVE-2024-24783) (`crypto/x509`). -[CVE-2023-45290](https://nvd.nist.gov/vuln/detail/CVE-2023-45290) (`net/http`). -[CVE-2023-45289](https://nvd.nist.gov/vuln/detail/CVE-2023-45289) (`net/http`, `net/http/cookiejar`). -[CVE-2024-24785](https://nvd.nist.gov/vuln/detail/CVE-2024-24785) (`html/template`). -[CVE-2024-24784](https://nvd.nist.gov/vuln/detail/CVE-2024-24784) (`net/mail`). [[GH-3741](https://github.com/hashicorp/consul-k8s/issues/3741)] -* security: upgrade containerd to 1.7.13 (latest) to resolve [GHSA-7ww5-4wqc-m92c](https://osv.dev/vulnerability/GO-2023-2412). [[GH-3625](https://github.com/hashicorp/consul-k8s/issues/3625)] - -IMPROVEMENTS: - -* control-plane: publish `consul-k8s-control-plane` and `consul-k8s-control-plane-fips` images to official HashiCorp AWS ECR. [[GH-3668](https://github.com/hashicorp/consul-k8s/issues/3668)] - -BUG FIXES: - -* control-plane: fix an issue where ACL token cleanup did not respect a pod's GracefulShutdownPeriodSeconds and -tokens were invalidated immediately on pod entering Terminating state. [[GH-3736](https://github.com/hashicorp/consul-k8s/issues/3736)] -* control-plane: fix an issue where ACL tokens would prematurely be deleted and services would be deregistered if there -was a K8s API error fetching the pod. [[GH-3758](https://github.com/hashicorp/consul-k8s/issues/3758)] - ## 1.4.0 (February 29, 2024) > NOTE: Consul K8s 1.4.x is compatible with Consul 1.18.x and Consul Dataplane 1.4.x. Refer to our [compatibility matrix](https://developer.hashicorp.com/consul/docs/k8s/compatibility) for more info. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 091ca798fc..5b06c27d8a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ 1. [Webhook](#webhook) 1. [Update command.go](#update-commandgo) 1. [Generating YAML](#generating-yaml) - 1. [Updating consul-helm](#updating-helm-chart) + 1. [Updating consul-helm](#updating-consul-helm) 1. [Testing a new CRD](#testing-a-new-crd) 1. [Update Consul K8s acceptance tests](#update-consul-k8s-acceptance-tests) 1. [Adding a new ACL Token](#adding-a-new-acl-token) @@ -340,14 +340,7 @@ rebase the branch on main, fixing any conflicts along the way before the code ca 1. Replace the names 1. Ensure you've correctly replaced the names in the kubebuilder annotation, ensure the plurality is correct ```go - // +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-ingressgateway,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=ingressgateways,versions=v1alpha1,name=mutate-ingressgateway.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 - ``` -1. Ensure you update the path to match the annotation in the `SetupWithManager` method: - ```go - func (v *IngressGatewayWebhook) SetupWithManager(mgr ctrl.Manager) { - v.decoder = admission.NewDecoder(mgr.GetScheme()) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-ingressgateway", &admission.Webhook{Handler: v}) -} + // +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-ingressgateway,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=ingressgateways,versions=v1alpha1,name=mutate-ingressgateway.consul.hashicorp.com,webhookVersions=v1beta1,sideEffects=None ``` ### Update command.go @@ -369,13 +362,16 @@ rebase the branch on main, fixing any conflicts along the way before the code ca return 1 } ``` -1. Update `control-plane/subcommand/inject-connect/command.go` and add your webhook +1. Update `control-plane/subcommand/inject-connect/command.go` and add your webhook (the path should match the kubebuilder annotation): ```go - (&v1alpha1.IngressGatewayWebhook - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(common.IngressGateway), - ConsulMeta: consulMeta, - }).SetupWithManager(mgr) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-ingressgateway", + &webhook.Admission{Handler: &v1alpha1.IngressGatewayWebhook{ + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.IngressGateway), + EnableConsulNamespaces: c.flagEnableNamespaces, + EnableNSMirroring: c.flagEnableNSMirroring, + }}) ``` ### Generating YAML diff --git a/acceptance/framework/config/config.go b/acceptance/framework/config/config.go index 370e276bc7..4f9a8648c2 100644 --- a/acceptance/framework/config/config.go +++ b/acceptance/framework/config/config.go @@ -70,9 +70,6 @@ type TestConfig struct { EnableEnterprise bool EnterpriseLicense string - SkipDataDogTests bool - DatadogHelmChartVersion string - EnableOpenshift bool EnablePodSecurityPolicies bool diff --git a/acceptance/framework/connhelper/connect_helper.go b/acceptance/framework/connhelper/connect_helper.go index 2746b43348..bbcaf7aff9 100644 --- a/acceptance/framework/connhelper/connect_helper.go +++ b/acceptance/framework/connhelper/connect_helper.go @@ -294,7 +294,7 @@ func (c *ConnectHelper) SetupAppNamespace(t *testing.T) { } // CreateResolverRedirect creates a resolver that redirects to a static-server, a corresponding k8s service, -// and intentions. This helper is primarily used to ensure that the virtual-ips are persisted to consul properly. +// and intentions. This helper is primarly used to ensure that the virtual-ips are persisted to consul properly. func (c *ConnectHelper) CreateResolverRedirect(t *testing.T) { logger.Log(t, "creating resolver redirect") opts := c.KubectlOptsForApp(t) diff --git a/acceptance/framework/consul/helm_cluster.go b/acceptance/framework/consul/helm_cluster.go index e12456876e..e037b53ef2 100644 --- a/acceptance/framework/consul/helm_cluster.go +++ b/acceptance/framework/consul/helm_cluster.go @@ -158,6 +158,7 @@ func (h *HelmCluster) Create(t *testing.T) { if h.ChartPath != "" { chartName = h.ChartPath } + // Retry the install in case previous tests have not finished cleaning up. retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 30}, t, func(r *retry.R) { err := helm.InstallE(r, h.helmOptions, chartName, h.releaseName) diff --git a/acceptance/framework/datadog/datadog.go b/acceptance/framework/datadog/datadog.go deleted file mode 100644 index 5ffefae4a7..0000000000 --- a/acceptance/framework/datadog/datadog.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package datadog - -import ( - "context" - "fmt" - "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "testing" - "time" - - "github.com/hashicorp/consul-k8s/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/logger" - - "github.com/gruntwork-io/terratest/modules/helm" - terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - terratestLogger "github.com/gruntwork-io/terratest/modules/logger" - "github.com/hashicorp/consul-k8s/acceptance/framework/environment" - "k8s.io/client-go/kubernetes" -) - -const ( - releaseLabel = "app.kubernetes.io/name" - OperatorReleaseName = "datadog-operator" - DefaultHelmChartVersion = "1.4.0" - datadogSecretName = "datadog-secret" - datadogAPIKey = "api-key" - datadogAppKey = "app-key" - datadogFakeAPIKey = "DD_FAKEAPIKEY" - datadogFakeAPPKey = "DD_FAKEAPPKEY" -) - -type DatadogCluster struct { - ctx environment.TestContext - - helmOptions *helm.Options - releaseName string - - kubectlOptions *terratestk8s.KubectlOptions - - kubernetesClient kubernetes.Interface - - noCleanupOnFailure bool - noCleanup bool - debugDirectory string - logger terratestLogger.TestLogger -} - -// releaseLabelSelector returns label selector that selects all pods -// from a Datadog installation. -func (d *DatadogCluster) releaseLabelSelector() string { - return fmt.Sprintf("%s=%s", releaseLabel, d.releaseName) -} - -func NewDatadogCluster(t *testing.T, ctx environment.TestContext, cfg *config.TestConfig, releaseName string, releaseNamespace string, helmValues map[string]string) *DatadogCluster { - logger := terratestLogger.New(logger.TestLogger{}) - - configureNamespace(t, ctx.KubernetesClient(t), cfg, releaseNamespace) - - createOrUpdateDatadogSecret(t, ctx.KubernetesClient(t), cfg, releaseNamespace) - - kopts := ctx.KubectlOptionsForNamespace(releaseNamespace) - - values := defaultHelmValues() - - ddHelmChartVersion := DefaultHelmChartVersion - if cfg.DatadogHelmChartVersion != "" { - ddHelmChartVersion = cfg.DatadogHelmChartVersion - } - - helpers.MergeMaps(values, helmValues) - datadogHelmOpts := &helm.Options{ - SetValues: values, - KubectlOptions: kopts, - Logger: logger, - Version: ddHelmChartVersion, - } - - helm.AddRepo(t, datadogHelmOpts, "datadog", "https://helm.datadoghq.com") - // Ignoring the error from `helm repo update` as it could fail due to stale cache or unreachable servers and we're - // asserting a chart version on Install which would fail in an obvious way should this not succeed. - _, err := helm.RunHelmCommandAndGetOutputE(t, &helm.Options{}, "repo", "update") - if err != nil { - logger.Logf(t, "Unable to update helm repository, proceeding anyway: %s.", err) - } - - return &DatadogCluster{ - ctx: ctx, - helmOptions: datadogHelmOpts, - kubectlOptions: kopts, - kubernetesClient: ctx.KubernetesClient(t), - noCleanupOnFailure: cfg.NoCleanupOnFailure, - noCleanup: cfg.NoCleanup, - debugDirectory: cfg.DebugDirectory, - logger: logger, - releaseName: releaseName, - } -} - -func (d *DatadogCluster) Create(t *testing.T) { - t.Helper() - - helpers.Cleanup(t, d.noCleanupOnFailure, d.noCleanup, func() { - d.Destroy(t) - }) - - helm.Install(t, d.helmOptions, "datadog/datadog-operator", d.releaseName) - // Wait for the datadog-operator to become ready - k8s.WaitForAllPodsToBeReady(t, d.kubernetesClient, d.helmOptions.KubectlOptions.Namespace, d.releaseLabelSelector()) -} - -func (d *DatadogCluster) Destroy(t *testing.T) { - t.Helper() - - k8s.WritePodsDebugInfoIfFailed(t, d.kubectlOptions, d.debugDirectory, d.releaseLabelSelector()) - // Ignore the error returned by the helm delete here so that we can - // always idempotent clean up resources in the cluster. - _ = helm.DeleteE(t, d.helmOptions, d.releaseName, true) -} - -func defaultHelmValues() map[string]string { - return map[string]string{ - "replicaCount": "1", - "image.tag": DefaultHelmChartVersion, - "image.repository": "gcr.io/datadoghq/operator", - } -} - -func configureNamespace(t *testing.T, client kubernetes.Interface, cfg *config.TestConfig, namespace string) { - ctx := context.Background() - - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: namespace, - Labels: map[string]string{}, - }, - } - if cfg.EnableRestrictedPSAEnforcement { - ns.ObjectMeta.Labels["pod-security.kubernetes.io/enforce"] = "restricted" - ns.ObjectMeta.Labels["pod-security.kubernetes.io/enforce-version"] = "latest" - } - - _, createErr := client.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{}) - if createErr == nil { - logger.Logf(t, "Created namespace %s", namespace) - return - } - - _, updateErr := client.CoreV1().Namespaces().Update(ctx, ns, metav1.UpdateOptions{}) - if updateErr == nil { - logger.Logf(t, "Updated namespace %s", namespace) - return - } - - require.Failf(t, "Failed to create or update namespace", "Namespace=%s, CreateError=%s, UpdateError=%s", namespace, createErr, updateErr) -} - -func createOrUpdateDatadogSecret(t *testing.T, client kubernetes.Interface, cfg *config.TestConfig, namespace string) { - secretMap := map[string]string{ - datadogAPIKey: datadogFakeAPIKey, - datadogAppKey: datadogFakeAPPKey, - } - createMultiKeyK8sSecret(t, client, cfg, namespace, datadogSecretName, secretMap) -} - -func createMultiKeyK8sSecret(t *testing.T, client kubernetes.Interface, cfg *config.TestConfig, namespace, secretName string, secretMap map[string]string) { - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 15}, t, func(r *retry.R) { - _, err := client.CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{}) - if errors.IsNotFound(err) { - _, err := client.CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - }, - StringData: secretMap, - Type: corev1.SecretTypeOpaque, - }, metav1.CreateOptions{}) - require.NoError(r, err) - } else { - require.NoError(r, err) - } - }) - - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - _ = client.CoreV1().Secrets(namespace).Delete(context.Background(), secretName, metav1.DeleteOptions{}) - }) -} diff --git a/acceptance/framework/flags/flags.go b/acceptance/framework/flags/flags.go index c956c3f7e3..c68983fe8c 100644 --- a/acceptance/framework/flags/flags.go +++ b/acceptance/framework/flags/flags.go @@ -25,8 +25,6 @@ type TestFlags struct { flagEnableOpenshift bool - flagSkipDatadogTests bool - flagEnablePodSecurityPolicies bool flagEnableCNI bool @@ -157,9 +155,6 @@ func (t *TestFlags) init() { flag.BoolVar(&t.flagDisablePeering, "disable-peering", false, "If true, the peering tests will not run.") - flag.BoolVar(&t.flagSkipDatadogTests, "skip-datadog", false, - "If true, datadog acceptance tests will not run.") - if t.flagEnterpriseLicense == "" { t.flagEnterpriseLicense = os.Getenv("CONSUL_ENT_LICENSE") } @@ -203,9 +198,11 @@ func (t *TestFlags) TestConfigFromFlags() *config.TestConfig { // if the Version is empty consulVersion will be nil consulVersion, _ := version.NewVersion(t.flagConsulVersion) consulDataplaneVersion, _ := version.NewVersion(t.flagConsulDataplaneVersion) + //vaultserverVersion, _ := version.NewVersion(t.flagVaultServerVersion) kubeEnvs := config.NewKubeTestConfigList(t.flagKubeconfigs, t.flagKubecontexts, t.flagKubeNamespaces) c := &config.TestConfig{ + EnableEnterprise: t.flagEnableEnterprise, EnterpriseLicense: t.flagEnterpriseLicense, @@ -214,8 +211,6 @@ func (t *TestFlags) TestConfigFromFlags() *config.TestConfig { EnableOpenshift: t.flagEnableOpenshift, - SkipDataDogTests: t.flagSkipDatadogTests, - EnablePodSecurityPolicies: t.flagEnablePodSecurityPolicies, EnableCNI: t.flagEnableCNI, diff --git a/acceptance/framework/resource/helpers.go b/acceptance/framework/resource/helpers.go deleted file mode 100644 index 4e94f73faf..0000000000 --- a/acceptance/framework/resource/helpers.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resource - -import ( - "context" - "time" - - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" - - "github.com/hashicorp/consul/proto-public/pbresource" - "github.com/hashicorp/consul/sdk/testutil" - "github.com/hashicorp/consul/sdk/testutil/retry" -) - -// ResourceTester is a helper for making assertions about resources. -type ResourceTester struct { - // resourceClient is the client to use for resource operations. - resourceClient pbresource.ResourceServiceClient - // timeout is the total time across which to apply retries. - timeout time.Duration - // wait is the wait time between retries. - wait time.Duration - // token is the token to use for requests when ACLs are enabled. - token string -} - -func NewResourceTester(resourceClient pbresource.ResourceServiceClient) *ResourceTester { - return &ResourceTester{ - resourceClient: resourceClient, - timeout: 7 * time.Second, - wait: 25 * time.Millisecond, - } -} - -func (rt *ResourceTester) retry(t testutil.TestingTB, fn func(r *retry.R)) { - t.Helper() - retryer := &retry.Timer{Timeout: rt.timeout, Wait: rt.wait} - retry.RunWith(retryer, t, fn) -} - -func (rt *ResourceTester) Context(t testutil.TestingTB) context.Context { - ctx := testutil.TestContext(t) - - if rt.token != "" { - md := metadata.New(map[string]string{ - "x-consul-token": rt.token, - }) - ctx = metadata.NewOutgoingContext(ctx, md) - } - - return ctx -} - -func (rt *ResourceTester) RequireResourceExists(t testutil.TestingTB, id *pbresource.ID) *pbresource.Resource { - t.Helper() - - rsp, err := rt.resourceClient.Read(rt.Context(t), &pbresource.ReadRequest{Id: id}) - require.NoError(t, err, "error reading %s with type %v", id.Name, id.Type) - require.NotNil(t, rsp) - return rsp.Resource -} - -func (rt *ResourceTester) RequireResourceNotFound(t testutil.TestingTB, id *pbresource.ID) { - t.Helper() - - rsp, err := rt.resourceClient.Read(rt.Context(t), &pbresource.ReadRequest{Id: id}) - require.Error(t, err) - require.Equal(t, codes.NotFound, status.Code(err)) - require.Nil(t, rsp) -} - -func (rt *ResourceTester) WaitForResourceExists(t testutil.TestingTB, id *pbresource.ID) *pbresource.Resource { - t.Helper() - - var res *pbresource.Resource - rt.retry(t, func(r *retry.R) { - res = rt.RequireResourceExists(r, id) - }) - - return res -} - -func (rt *ResourceTester) WaitForResourceNotFound(t testutil.TestingTB, id *pbresource.ID) { - t.Helper() - - rt.retry(t, func(r *retry.R) { - rt.RequireResourceNotFound(r, id) - }) -} diff --git a/acceptance/go.mod b/acceptance/go.mod index 1cac90636e..4957ba0cea 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -5,13 +5,12 @@ go 1.21.1 toolchain go1.22.0 require ( - github.com/go-logr/logr v1.2.4 github.com/google/uuid v1.3.0 github.com/gruntwork-io/terratest v0.46.7 github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240226161840-f3842c41cb2b - github.com/hashicorp/consul/api v1.29.1 - github.com/hashicorp/consul/proto-public v0.6.1 - github.com/hashicorp/consul/sdk v0.16.1 + github.com/hashicorp/consul/api v1.28.2 + github.com/hashicorp/consul/proto-public v0.6.0 + github.com/hashicorp/consul/sdk v0.16.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 @@ -49,7 +48,9 @@ require ( github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.3 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect @@ -108,7 +109,7 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pquerna/otp v1.2.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -121,6 +122,8 @@ require ( go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/otel/sdk v1.19.0 // indirect go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/mod v0.14.0 // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index e2ebe425ee..ffde55b356 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -20,6 +20,9 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.44.262 h1:gyXpcJptWoNkK+DiAiaBltlreoWKQXjAIh6FRh60F+I= github.com/aws/aws-sdk-go v1.44.262/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -27,11 +30,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -188,14 +188,12 @@ github.com/gruntwork-io/terratest v0.46.7 h1:oqGPBBO87SEsvBYaA0R5xOq+Lm2Xc5dmFVf github.com/gruntwork-io/terratest v0.46.7/go.mod h1:6gI5MlLeyF+SLwqocA5GBzcTix+XiuxCy1BPwKuT+WM= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240226161840-f3842c41cb2b h1:AdeWjUb+rxrRryC5ZHaL32oOZuxubOzV2q6oJ97UMT0= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240226161840-f3842c41cb2b/go.mod h1:TVaSJM7vYM/mtKGpVc/Lch53lrqLI9XAXJgy/gY8v4A= -github.com/hashicorp/consul-server-connection-manager v0.1.6 h1:ktj8Fi+dRXn9hhM+FXsfEJayhzzgTqfH08Ne5M6Fmug= -github.com/hashicorp/consul-server-connection-manager v0.1.6/go.mod h1:HngMIv57MT+pqCVeRQMa1eTB5dqnyMm8uxjyv+Hn8cs= -github.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc= -github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI= -github.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg= -github.com/hashicorp/consul/proto-public v0.6.1/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg= -github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= -github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= +github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= +github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= +github.com/hashicorp/consul/proto-public v0.6.0 h1:9qrBujmoTB5gQQ84kQO+YWvhjgYoYBNrOoHdo4cpHHM= +github.com/hashicorp/consul/proto-public v0.6.0/go.mod h1:JF6983XNCzvw4wDNOLEwLqOq2IPw7iyT+pkswHSz08U= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -218,8 +216,6 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-netaddrs v0.1.0 h1:TnlYvODD4C/wO+j7cX1z69kV5gOzI87u3OcUinANaW8= -github.com/hashicorp/go-netaddrs v0.1.0/go.mod h1:33+a/emi5R5dqRspOuZKO0E+Tuz5WV1F84eRWALkedA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= @@ -378,8 +374,8 @@ github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lF github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= @@ -461,8 +457,14 @@ go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1 go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -479,6 +481,7 @@ golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -581,6 +584,7 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -589,6 +593,7 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= diff --git a/acceptance/tests/api-gateway/api_gateway_external_servers_test.go b/acceptance/tests/api-gateway/api_gateway_external_servers_test.go index 43755f5b40..aa0934dc65 100644 --- a/acceptance/tests/api-gateway/api_gateway_external_servers_test.go +++ b/acceptance/tests/api-gateway/api_gateway_external_servers_test.go @@ -76,19 +76,8 @@ func TestAPIGateway_ExternalServers(t *testing.T) { require.NoError(t, err) logger.Log(t, "set consul config entry") - // Create certificate secret, we do this separately since - // applying the secret will make an invalid certificate that breaks other tests - logger.Log(t, "creating certificate secret") - out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-f", "../fixtures/bases/api-gateway/certificate.yaml") - require.NoError(t, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - // Ignore errors here because if the test ran as expected - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-f", "../fixtures/bases/api-gateway/certificate.yaml") - }) - logger.Log(t, "creating api-gateway resources") - out, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/api-gateway") + out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/api-gateway") require.NoError(t, err, out) helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { // Ignore errors here because if the test ran as expected diff --git a/acceptance/tests/api-gateway/api_gateway_lifecycle_test.go b/acceptance/tests/api-gateway/api_gateway_lifecycle_test.go index 59be62595b..e8fbc945f1 100644 --- a/acceptance/tests/api-gateway/api_gateway_lifecycle_test.go +++ b/acceptance/tests/api-gateway/api_gateway_lifecycle_test.go @@ -295,7 +295,7 @@ func TestAPIGateway_Lifecycle(t *testing.T) { // make sure our certificate exists logger.Log(t, "checking that the certificate is synchronized to Consul") - checkConsulExists(t, consulClient, api.FileSystemCertificate, certificateName) + checkConsulExists(t, consulClient, api.InlineCertificate, certificateName) // delete the certificate in Kubernetes logger.Log(t, "deleting the certificate in Kubernetes") @@ -304,7 +304,7 @@ func TestAPIGateway_Lifecycle(t *testing.T) { // make sure the certificate no longer exists in Consul logger.Log(t, "checking that the certificate is deleted from Consul") - checkConsulNotExists(t, consulClient, api.FileSystemCertificate, certificateName) + checkConsulNotExists(t, consulClient, api.InlineCertificate, certificateName) } func checkConsulNotExists(t *testing.T, client *api.Client, kind, name string, namespace ...string) { diff --git a/acceptance/tests/api-gateway/api_gateway_tenancy_test.go b/acceptance/tests/api-gateway/api_gateway_tenancy_test.go index 461fde1ecf..f7b0ac6d79 100644 --- a/acceptance/tests/api-gateway/api_gateway_tenancy_test.go +++ b/acceptance/tests/api-gateway/api_gateway_tenancy_test.go @@ -168,7 +168,7 @@ func TestAPIGateway_Tenancy(t *testing.T) { }) // we only sync validly referenced certificates over, so check to make sure it is not created. - checkConsulNotExists(t, consulClient, api.FileSystemCertificate, "certificate", namespaceForConsul(c.namespaceMirroring, certificateNamespace)) + checkConsulNotExists(t, consulClient, api.InlineCertificate, "certificate", namespaceForConsul(c.namespaceMirroring, certificateNamespace)) // now create reference grants createReferenceGrant(t, k8sClient, "gateway-certificate", gatewayNamespace, certificateNamespace) @@ -237,11 +237,11 @@ func TestAPIGateway_Tenancy(t *testing.T) { // and check to make sure that the certificate exists retryCheck(t, 30, func(r *retry.R) { - entry, _, err := consulClient.ConfigEntries().Get(api.FileSystemCertificate, "certificate", &api.QueryOptions{ + entry, _, err := consulClient.ConfigEntries().Get(api.InlineCertificate, "certificate", &api.QueryOptions{ Namespace: namespaceForConsul(c.namespaceMirroring, certificateNamespace), }) require.NoError(r, err) - certificate := entry.(*api.FileSystemCertificateConfigEntry) + certificate := entry.(*api.InlineCertificateConfigEntry) require.EqualValues(r, "certificate", certificate.Meta["k8s-name"]) require.EqualValues(r, certificateNamespace, certificate.Meta["k8s-namespace"]) diff --git a/acceptance/tests/api-gateway_v2/api_gateway_v2_test.go b/acceptance/tests/api-gateway_v2/api_gateway_v2_test.go deleted file mode 100644 index 9016d9c004..0000000000 --- a/acceptance/tests/api-gateway_v2/api_gateway_v2_test.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigatewayv2 - -import ( - "context" - "encoding/base64" - "fmt" - "strconv" - "testing" - "time" - - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/testutil/retry" - - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/acceptance/framework/logger" - meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/types" -) - -// Test that api gateway basic functionality works in a default installation and a secure installation for V2. -func TestAPIGateway_V2_Basic(t *testing.T) { - - cases := []struct { - secure bool - }{ - { - secure: false, - }, - { - secure: true, - }, - } - for _, c := range cases { - name := fmt.Sprintf("secure: %t", c.secure) - t.Run(name, func(t *testing.T) { - ctx := suite.Environment().DefaultContext(t) - cfg := suite.Config() - helmValues := map[string]string{ - "connectInject.enabled": "true", - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - "global.tls.enabled": strconv.FormatBool(c.secure), - "global.logLevel": "trace", - "global.experiments[0]": "resource-apis", - } - - releaseName := helpers.RandomName() - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - - consulCluster.Create(t) - - // Override the default proxy config settings for this test - consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) - _, _, err := consulClient.ConfigEntries().Set(&api.ProxyConfigEntry{ - Kind: api.ProxyDefaults, - Name: api.ProxyConfigGlobal, - Config: map[string]interface{}{ - "protocol": "http", - }, - }, nil) - require.NoError(t, err) - - logger.Log(t, "creating api-gateway resources") - out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/api-gateway-v2") - require.NoError(t, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - // Ignore errors here because if the test ran as expected - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-k", "../fixtures/bases/api-gateway-v2") - }) - - // Create certificate secret, we do this separately since - // applying the secret will make an invalid certificate that breaks other tests - logger.Log(t, "creating certificate secret") - out, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-f", "../fixtures/bases/api-gateway-v2/certificate.yaml") - require.NoError(t, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - // Ignore errors here because if the test ran as expected - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-f", "../fixtures/bases/api-gateway-v2/certificate.yaml") - }) - - // patch certificate with data - logger.Log(t, "patching certificate secret with generated data") - certificate := generateCertificate(t, nil, "gateway.test.local") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "secret", "certificate", "-p", fmt.Sprintf(`{"data":{"tls.crt":"%s","tls.key":"%s"}}`, base64.StdEncoding.EncodeToString(certificate.CertPEM), base64.StdEncoding.EncodeToString(certificate.PrivateKeyPEM)), "--type=merge") - - // We use the static-client pod so that we can make calls to the api gateway - // via kubectl exec without needing a route into the cluster from the test machine. - logger.Log(t, "creating static-client pod") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-client") - - logger.Log(t, "creating target tcp server") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server-tcp") - - logger.Log(t, "creating tcp-route") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "apply", "-f", "../fixtures/cases/api-gateways-v2/tcproute/route.yaml") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - // Ignore errors here because if the test ran as expected - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-f", "../fixtures/cases/api-gateways-v2/tcproute/route.yaml") - }) - - // Grab a kubernetes client so that we can verify binding - // behavior prior to issuing requests through the gateway. - k8sClient := ctx.ControllerRuntimeClient(t) - - // On startup, the controller can take upwards of 1m to perform - // leader election so we may need to wait a long time for - // the reconcile loop to run (hence the timeout here). - var gatewayAddress string - counter := &retry.Counter{Count: 120, Wait: 2 * time.Second} - retry.RunWith(counter, t, func(r *retry.R) { - var gateway meshv2beta1.APIGateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: "default"}, &gateway) - require.NoError(r, err) - - // check our finalizers - require.Len(r, gateway.Finalizers, 1) - require.EqualValues(r, gatewayFinalizer, gateway.Finalizers()[0]) - - // check our statuses - checkV2StatusCondition(r, gateway.APIGatewayStatus.Conditions, trueV2Condition("Accepted", "Accepted")) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Conditions, trueV2Condition("ConsulAccepted", "Accepted")) - require.Len(r, gateway.APIGatewayStatus.Listeners, 3) - - require.EqualValues(r, 1, gateway.APIGatewayStatus.Listeners[0].AttachedRoutes) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[0].Conditions, trueV2Condition("Accepted", "Accepted")) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[0].Conditions, falseV2Condition("Conflicted", "NoConflicts")) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[0].Conditions, trueV2Condition("ResolvedRefs", "ResolvedRefs")) - require.EqualValues(r, 1, gateway.APIGatewayStatus.Listeners[1].AttachedRoutes) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[1].Conditions, trueV2Condition("Accepted", "Accepted")) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[1].Conditions, falseV2Condition("Conflicted", "NoConflicts")) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[1].Conditions, trueV2Condition("ResolvedRefs", "ResolvedRefs")) - require.EqualValues(r, 1, gateway.APIGatewayStatus.Listeners[2].AttachedRoutes) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[2].Conditions, trueV2Condition("Accepted", "Accepted")) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[2].Conditions, falseV2Condition("Conflicted", "NoConflicts")) - checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[2].Conditions, trueV2Condition("ResolvedRefs", "ResolvedRefs")) - - // check that we have an address to use - require.Len(r, gateway.APIGatewayStatus.Addresses, 1) - // now we know we have an address, set it so we can use it - gatewayAddress = gateway.APIGatewayStatus.Addresses[0].Value - }) - - // now that we've satisfied those assertions, we know reconciliation is done - // so we can run assertions on the routes and the other objects - - // gateway class checks - var gatewayClass meshv2beta1.GatewayClass - err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway-class"}, &gatewayClass) - require.NoError(t, err) - - // check our finalizers - require.Len(t, gatewayClass.Finalizers, 1) - require.EqualValues(t, gatewayClassFinalizer, gatewayClass.Finalizers[0]) - - // tcp route checks - var tcpRoute meshv2beta1.TCPRoute - err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "tcp-route", Namespace: "default"}, &tcpRoute) - require.NoError(t, err) - - // check our finalizers - require.Len(t, tcpRoute.Finalizers, 1) - require.EqualValues(t, gatewayFinalizer, tcpRoute.Finalizers()[0]) - - // TODO check values actually created in the resource API - - // finally we check that we can actually route to the service via the gateway - k8sOptions := ctx.KubectlOptions(t) - targetTCPAddress := fmt.Sprintf("http://%s:81", gatewayAddress) - - // Test that we can make a call to the api gateway - // via the static-client pod. It should route to the static-server pod. - logger.Log(t, "trying calls to api gateway tcp") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, targetTCPAddress) - - }) - } -} diff --git a/acceptance/tests/api-gateway_v2/helpers.go b/acceptance/tests/api-gateway_v2/helpers.go deleted file mode 100644 index 124fa20450..0000000000 --- a/acceptance/tests/api-gateway_v2/helpers.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigatewayv2 - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - corev1 "k8s.io/api/core/v1" - "math/big" - "testing" - "time" - - "github.com/stretchr/testify/require" -) - -const ( - StaticClientName = "static-client" - gatewayClassControllerName = "mesh.consul.hashicorp.com/gateway-controller" - //TODO these values will likely need to be update to their V2 values for the test to pass. - gatewayClassFinalizer = "gateway-exists-finalizer.consul.hashicorp.com" - gatewayFinalizer = "gateway-finalizer.consul.hashicorp.com" -) - -type certificateInfo struct { - Cert *x509.Certificate - PrivateKey *rsa.PrivateKey - CertPEM []byte - PrivateKeyPEM []byte -} - -func checkV2StatusCondition(t require.TestingT, conditions []meshv2beta1.Condition, toCheck meshv2beta1.Condition) { - for _, c := range conditions { - if c.Type == toCheck.Type { - require.EqualValues(t, toCheck.Reason, c.Reason) - require.EqualValues(t, toCheck.Status, c.Status) - return - } - } - - t.Errorf("expected condition not found: %s", toCheck.Type) -} - -func trueV2Condition(conditionType, reason string) meshv2beta1.Condition { - return meshv2beta1.Condition{ - Type: meshv2beta1.ConditionType(conditionType), - Reason: reason, - Status: corev1.ConditionTrue, - } -} - -func falseV2Condition(conditionType, reason string) meshv2beta1.Condition { - return meshv2beta1.Condition{ - Type: meshv2beta1.ConditionType(conditionType), - Reason: reason, - Status: corev1.ConditionFalse, - } -} - -func generateCertificate(t *testing.T, ca *certificateInfo, commonName string) *certificateInfo { - t.Helper() - - bits := 2048 - privateKey, err := rsa.GenerateKey(rand.Reader, bits) - require.NoError(t, err) - - usage := x509.KeyUsageDigitalSignature - if ca == nil { - usage = x509.KeyUsageCertSign - } - - expiration := time.Now().AddDate(10, 0, 0) - cert := &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - Organization: []string{"Testing, INC."}, - Country: []string{"US"}, - Province: []string{""}, - Locality: []string{"San Francisco"}, - StreetAddress: []string{"Fake Street"}, - PostalCode: []string{"11111"}, - CommonName: commonName, - }, - IsCA: ca == nil, - NotBefore: time.Now().Add(-10 * time.Minute), - NotAfter: expiration, - SubjectKeyId: []byte{1, 2, 3, 4, 6}, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: usage, - BasicConstraintsValid: true, - } - caCert := cert - if ca != nil { - caCert = ca.Cert - } - caPrivateKey := privateKey - if ca != nil { - caPrivateKey = ca.PrivateKey - } - data, err := x509.CreateCertificate(rand.Reader, cert, caCert, &privateKey.PublicKey, caPrivateKey) - require.NoError(t, err) - - certBytes := pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: data, - }) - - privateKeyBytes := pem.EncodeToMemory(&pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(privateKey), - }) - - return &certificateInfo{ - Cert: cert, - CertPEM: certBytes, - PrivateKey: privateKey, - PrivateKeyPEM: privateKeyBytes, - } -} diff --git a/acceptance/tests/api-gateway_v2/main_test.go b/acceptance/tests/api-gateway_v2/main_test.go deleted file mode 100644 index 47f4c3b3cf..0000000000 --- a/acceptance/tests/api-gateway_v2/main_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigatewayv2 - -import ( - "fmt" - "os" - "testing" - - testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" -) - -var suite testsuite.Suite - -func TestMain(m *testing.M) { - runTests := os.Getenv("TEST_APIGW_V2") - if runTests != "TRUE" { - fmt.Println("skipping") - os.Exit(0) - } - suite = testsuite.NewSuite(m) - os.Exit(suite.Run()) -} diff --git a/acceptance/tests/datadog/datadog_test.go b/acceptance/tests/datadog/datadog_test.go deleted file mode 100644 index 319ea6a55d..0000000000 --- a/acceptance/tests/datadog/datadog_test.go +++ /dev/null @@ -1,423 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package datadog - -import ( - "context" - "encoding/json" - "fmt" - "strings" - "testing" - "time" - - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/datadog" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/acceptance/framework/logger" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - consulDogstatsDMetricQuery = "consul.memberlist.gossip" -) - -// TODO: Refactor test cases into single function that accepts Helm Values, Fixture Name, and Validation Callback -// TestDatadogDogstatsDUnixDomainSocket -// Acceptance test to verify e2e metrics configuration works as expected -// with live datadog API using histogram formatted metric -// -// Method: DogstatsD + Unix Domain Socket. -func TestDatadogDogstatsDUnixDomainSocket(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - ctx := env.DefaultContext(t) - - if cfg.SkipDataDogTests { - t.Skipf("skipping this test because -skip-datadog is set") - } - - acceptanceTestingTags := "acceptance_test:unix_domain_sockets" - helmValues := map[string]string{ - "global.datacenter": "dc1", - "global.metrics.enabled": "true", - "global.metrics.enableAgentMetrics": "true", - "global.metrics.disableAgentHostName": "true", - "global.metrics.enableHostMetrics": "true", - "global.metrics.datadog.enabled": "true", - "global.metrics.datadog.namespace": "datadog", - "global.metrics.datadog.dogstatsd.enabled": "true", - "global.metrics.datadog.dogstatsd.socketTransportType": "UDS", - "global.metrics.datadog.dogstatsd.dogstatsdTags[0]": "source:consul", - "global.metrics.datadog.dogstatsd.dogstatsdTags[1]": "consul_service:consul-server", - "global.metrics.datadog.dogstatsd.dogstatsdTags[2]": acceptanceTestingTags, - } - - releaseName := helpers.RandomName() - datadogOperatorRelease := datadog.OperatorReleaseName - - // Install the consul cluster in the default kubernetes ctx. - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - consulCluster.Create(t) - - // Deploy Datadog Agent via Datadog Operator and apply dogstatsd overlay - datadogNamespace := helmValues["global.metrics.datadog.namespace"] - logger.Log(t, fmt.Sprintf("deploying datadog-operator via helm | namespace: %s | release-name: %s", datadogNamespace, datadogOperatorRelease)) - datadogCluster := datadog.NewDatadogCluster(t, ctx, cfg, datadogOperatorRelease, datadogNamespace, map[string]string{}) - datadogCluster.Create(t) - - logger.Log(t, fmt.Sprintf("applying dogstatd over unix domain sockets kustomization patch to datadog-agent | namespace: %s", datadogNamespace)) - k8s.DeployKustomize(t, ctx.KubectlOptionsForNamespace(datadogNamespace), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/datadog-dogstatsd-uds") - k8s.WaitForAllPodsToBeReady(t, ctx.KubernetesClient(t), datadogNamespace, "agent.datadoghq.com/component=agent") - - // Retrieve datadog-agent pod name for exec - podList, err := ctx.KubernetesClient(t).CoreV1().Pods(datadogNamespace).List(context.Background(), metav1.ListOptions{LabelSelector: "agent.datadoghq.com/component=agent"}) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - ddAgentName := podList.Items[0].Name - - // Check the dogstats-stats of the local cluster agent to see if consul metrics - // are being seen by the agent - logger.Log(t, fmt.Sprintf("retrieving datadog-agent control api auth token from pod %s", ddAgentName)) - bearerToken, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "cat", "/etc/datadog-agent/auth_token") - require.NoError(t, err) - // Retry because sometimes the merged metrics server takes a couple hundred milliseconds - // to start. - logger.Log(t, fmt.Sprintf("scraping datadog-agent /agent/dogstatsd-stats endpoint for %s | auth-token: %s", consulDogstatsDMetricQuery, bearerToken)) - retry.RunWith(&retry.Counter{Count: 20, Wait: 2 * time.Second}, t, func(r *retry.R) { - metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "curl", "--silent", "--insecure", "--show-error", "--header", fmt.Sprintf("authorization: Bearer %s", bearerToken), "https://localhost:5001/agent/dogstatsd-stats") - require.NoError(r, err) - require.Contains(r, metricsOutput, consulDogstatsDMetricQuery) - }) -} - -// TestDatadogDogstatsDUDP -// Acceptance test to verify e2e metrics configuration works as expected -// with live datadog API using histogram formatted metric -// -// Method: DogstatsD + UDP to Kube Service DNS name on port 8125. -func TestDatadogDogstatsDUDP(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - ctx := env.DefaultContext(t) - - if cfg.SkipDataDogTests { - t.Skipf("skipping this test because -skip-datadog is set") - } - - acceptanceTestingTags := "acceptance_test:dogstatsd_udp" - helmValues := map[string]string{ - "global.datacenter": "dc1", - "global.metrics.enabled": "true", - "global.metrics.enableAgentMetrics": "true", - "global.metrics.disableAgentHostName": "true", - "global.metrics.enableHostMetrics": "true", - "global.metrics.datadog.enabled": "true", - "global.metrics.datadog.namespace": "datadog", - "global.metrics.datadog.dogstatsd.enabled": "true", - "global.metrics.datadog.dogstatsd.socketTransportType": "UDP", - "global.metrics.datadog.dogstatsd.dogstatsdAddr": "datadog-agent.datadog.svc.cluster.local", - "global.metrics.datadog.dogstatsd.dogstatsdTags[0]": "source:consul", - "global.metrics.datadog.dogstatsd.dogstatsdTags[1]": "consul_service:consul-server", - "global.metrics.datadog.dogstatsd.dogstatsdTags[2]": acceptanceTestingTags, - } - - releaseName := helpers.RandomName() - datadogOperatorRelease := datadog.OperatorReleaseName - - // Install the consul cluster in the default kubernetes ctx. - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - consulCluster.Create(t) - - // Deploy Datadog Agent via Datadog Operator and apply dogstatsd overlay. - datadogNamespace := helmValues["global.metrics.datadog.namespace"] - logger.Log(t, fmt.Sprintf("deploying datadog-operator via helm | namespace: %s | release-name: %s", datadogNamespace, datadogOperatorRelease)) - datadogCluster := datadog.NewDatadogCluster(t, ctx, cfg, datadogOperatorRelease, datadogNamespace, map[string]string{}) - datadogCluster.Create(t) - - logger.Log(t, fmt.Sprintf("applying dogstatd over UDP kustomization patch to datadog-agent | namespace: %s", datadogNamespace)) - k8s.DeployKustomize(t, ctx.KubectlOptionsForNamespace(datadogNamespace), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/datadog-dogstatsd-udp") - k8s.WaitForAllPodsToBeReady(t, ctx.KubernetesClient(t), datadogNamespace, "agent.datadoghq.com/component=agent") - - // Retrieve datadog-agent pod name for exec - podList, err := ctx.KubernetesClient(t).CoreV1().Pods(datadogNamespace).List(context.Background(), metav1.ListOptions{LabelSelector: "agent.datadoghq.com/component=agent"}) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - ddAgentName := podList.Items[0].Name - - // Check the dogstats-stats of the local cluster agent to see if consul metrics - // are being seen by the agent - logger.Log(t, fmt.Sprintf("retrieving datadog-agent control api auth token from pod %s", ddAgentName)) - bearerToken, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "cat", "/etc/datadog-agent/auth_token") - require.NoError(t, err) - // Retry because sometimes the merged metrics server takes a couple hundred milliseconds - // to start. - logger.Log(t, fmt.Sprintf("scraping datadog-agent /agent/dogstatsd-stats endpoint for %s | auth-token: %s", consulDogstatsDMetricQuery, bearerToken)) - retry.RunWith(&retry.Counter{Count: 20, Wait: 2 * time.Second}, t, func(r *retry.R) { - metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "curl", "--silent", "--insecure", "--show-error", "--header", fmt.Sprintf("authorization: Bearer %s", bearerToken), "https://localhost:5001/agent/dogstatsd-stats") - require.NoError(r, err) - require.Contains(r, metricsOutput, consulDogstatsDMetricQuery) - }) -} - -// TestDatadogConsulChecks -// Acceptance test to verify e2e metrics configuration works as expected -// with live datadog API using histogram formatted metric -// -// Method: Consul Integrated Datadog Checks. -func TestDatadogConsulChecks(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - ctx := env.DefaultContext(t) - - if cfg.SkipDataDogTests { - t.Skipf("skipping this test because -skip-datadog is set") - } - - helmValues := map[string]string{ - "global.datacenter": "dc1", - "global.metrics.enabled": "true", - "global.metrics.enableAgentMetrics": "true", - "global.metrics.disableAgentHostName": "true", - "global.metrics.enableHostMetrics": "true", - "global.metrics.datadog.enabled": "true", - "global.metrics.datadog.namespace": "datadog", - } - - releaseName := helpers.RandomName() - datadogOperatorRelease := datadog.OperatorReleaseName - - // Install the consul cluster in the default kubernetes ctx. - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - consulCluster.Create(t) - - // Deploy Datadog Agent via Datadog Operator and apply dogstatsd overlay. - datadogNamespace := helmValues["global.metrics.datadog.namespace"] - logger.Log(t, fmt.Sprintf("deploying datadog-operator via helm | namespace: %s | release-name: %s", datadogNamespace, datadogOperatorRelease)) - datadogCluster := datadog.NewDatadogCluster(t, ctx, cfg, datadogOperatorRelease, datadogNamespace, map[string]string{}) - datadogCluster.Create(t) - - logger.Log(t, fmt.Sprintf("applying datadog consul integration patch to datadog-agent | namespace: %s", datadogNamespace)) - k8s.DeployKustomize(t, ctx.KubectlOptionsForNamespace(datadogNamespace), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/datadog") - k8s.WaitForAllPodsToBeReady(t, ctx.KubernetesClient(t), datadogNamespace, "agent.datadoghq.com/component=agent") - - // Retrieve datadog-agent pod name for exec - podList, err := ctx.KubernetesClient(t).CoreV1().Pods(datadogNamespace).List(context.Background(), metav1.ListOptions{LabelSelector: "agent.datadoghq.com/component=agent"}) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - ddAgentName := podList.Items[0].Name - - // Check the dogstats-stats of the local cluster agent to see if consul metrics - // are being seen by the agent - logger.Log(t, fmt.Sprintf("retrieving datadog-agent control api auth token from pod %s", ddAgentName)) - bearerToken, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "cat", "/etc/datadog-agent/auth_token") - // Retry because sometimes the merged metrics server takes a couple hundred milliseconds - // to start. - logger.Log(t, fmt.Sprintf("scraping datadog-agent /agent/status endpoint | auth-token: %s", bearerToken)) - var metricsOutput string - retry.RunWith(&retry.Counter{Count: 20, Wait: 2 * time.Second}, t, func(r *retry.R) { - metricsOutput, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "curl", "--silent", "--insecure", "--show-error", "--header", fmt.Sprintf("authorization: Bearer %s", bearerToken), "https://localhost:5001/agent/status") - require.NoError(r, err) - }) - var root Root - err = json.Unmarshal([]byte(metricsOutput), &root) - require.NoError(t, err) - for _, check := range root.RunnerStats.Checks.Consul { - require.Equal(t, ``, check.LastError) - } -} - -// TestDatadogOpenmetrics -// Acceptance test to verify e2e metrics configuration works as expected -// with live datadog API using histogram formatted metric -// -// Method: Datadog Openmetrics Prometheus Metrics Collection. -func TestDatadogOpenmetrics(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - ctx := env.DefaultContext(t) - - if cfg.SkipDataDogTests { - t.Skipf("skipping this test because -skip-datadog is set") - } - - helmValues := map[string]string{ - "global.datacenter": "dc1", - "global.metrics.enabled": "true", - "global.metrics.enableAgentMetrics": "true", - "global.metrics.disableAgentHostName": "true", - "global.metrics.enableHostMetrics": "true", - "global.metrics.datadog.enabled": "true", - "global.metrics.datadog.namespace": "datadog", - "global.metrics.datadog.openMetricsPrometheus.enabled": "true", - } - - releaseName := helpers.RandomName() - datadogOperatorRelease := datadog.OperatorReleaseName - - // Install the consul cluster in the default kubernetes ctx. - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - consulCluster.Create(t) - - // Deploy Datadog Agent via Datadog Operator and apply dogstatsd overlay - datadogNamespace := helmValues["global.metrics.datadog.namespace"] - logger.Log(t, fmt.Sprintf("deploying datadog-operator via helm | namespace: %s | release-name: %s", datadogNamespace, datadogOperatorRelease)) - datadogCluster := datadog.NewDatadogCluster(t, ctx, cfg, datadogOperatorRelease, datadogNamespace, map[string]string{}) - datadogCluster.Create(t) - - logger.Log(t, fmt.Sprintf("applying datadog openmetrics patch to datadog-agent | namespace: %s", datadogNamespace)) - k8s.DeployKustomize(t, ctx.KubectlOptionsForNamespace(datadogNamespace), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/datadog-openmetrics") - k8s.WaitForAllPodsToBeReady(t, ctx.KubernetesClient(t), datadogNamespace, "agent.datadoghq.com/component=agent") - - // Retrieve datadog-agent pod name for exec - podList, err := ctx.KubernetesClient(t).CoreV1().Pods(datadogNamespace).List(context.Background(), metav1.ListOptions{LabelSelector: "agent.datadoghq.com/component=agent"}) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - ddAgentName := podList.Items[0].Name - - // Check the dogstats-stats of the local cluster agent to see if consul metrics - // are being seen by the agent - logger.Log(t, fmt.Sprintf("retrieving datadog-agent control api auth token from pod %s", ddAgentName)) - bearerToken, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "cat", "/etc/datadog-agent/auth_token") - // Retry because sometimes the merged metrics server takes a couple hundred milliseconds - // to start. - logger.Log(t, fmt.Sprintf("scraping datadog-agent /agent/status endpoint | auth-token: %s", bearerToken)) - var metricsOutput string - retry.RunWith(&retry.Counter{Count: 20, Wait: 2 * time.Second}, t, func(r *retry.R) { - metricsOutput, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "curl", "--silent", "--insecure", "--show-error", "--header", fmt.Sprintf("authorization: Bearer %s", bearerToken), "https://localhost:5001/agent/status") - require.NoError(r, err) - }) - var root Root - err = json.Unmarshal([]byte(metricsOutput), &root) - require.NoError(t, err) - for _, check := range root.RunnerStats.Checks.Openmetrics { - if strings.Contains(check.CheckID, "consul") { - require.Equal(t, ``, check.LastError) - break - } - continue - } -} - -// TestDatadogOTLPCollection -// Acceptance test to verify e2e metrics configuration works as expected -// with live datadog API using histogram formatted metric -// -// Method: Datadog otlp metrics collection via consul-telemetry collector using dd-agent gRPC receiver. -//func TestDatadogOTLPCollection(t *testing.T) { -// env := suite.Environment() -// cfg := suite.Config() -// ctx := env.DefaultContext(t) -// // ns := ctx.KubectlOptions(t).Namespace -// -// helmValues := map[string]string{ -// "global.datacenter": "dc1", -// "global.metrics.enabled": "true", -// "global.metrics.enableAgentMetrics": "true", -// "global.metrics.disableAgentHostName": "true", -// "global.metrics.enableHostMetrics": "true", -// "global.metrics.datadog.enabled": "true", -// "global.metrics.datadog.namespace": "datadog", -// "global.metrics.datadog.otlp.enabled": "true", -// "global.metrics.datadog.otlp.protocol": "http", -// "telemetryCollector.enabled": "true", -// } -// -// datadogOperatorHelmValues := map[string]string{ -// "replicaCount": "1", -// "image.tag": datadog.DefaultHelmChartVersion, -// "image.repository": "gcr.io/datadoghq/operator", -// } -// -// releaseName := helpers.RandomName() -// datadogOperatorRelease := datadog.OperatorReleaseName -// -// // Install the consul cluster in the default kubernetes ctx. -// consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) -// consulCluster.Create(t) -// -// // Deploy Datadog Agent via Datadog Operator and apply dogstatsd overlay -// datadogNamespace := helmValues["global.metrics.datadog.namespace"] -// logger.Log(t, fmt.Sprintf("deploying datadog-operator via helm | namespace: %s | release-name: %s", datadogNamespace, datadogOperatorRelease)) -// datadogCluster := datadog.NewDatadogCluster(t, ctx, cfg, datadogOperatorRelease, datadogNamespace, datadogOperatorHelmValues) -// datadogCluster.Create(t) -// -// logger.Log(t, fmt.Sprintf("applying datadog otlp HTTP endpoint collector patch to datadog-agent | namespace: %s", datadogNamespace)) -// k8s.DeployKustomize(t, ctx.KubectlOptionsForNamespace(datadogNamespace), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/datadog-otlp") -// k8s.WaitForAllPodsToBeReady(t, ctx.KubernetesClient(t), datadogNamespace, "agent.datadoghq.com/component=agent") -// -// // Retrieve datadog-agent pod name for exec -// podList, err := ctx.KubernetesClient(t).CoreV1().Pods(datadogNamespace).List(context.Background(), metav1.ListOptions{LabelSelector: "agent.datadoghq.com/component=agent"}) -// require.NoError(t, err) -// require.Len(t, podList.Items, 1) -// ddAgentName := podList.Items[0].Name -// -// // Check the dogstats-stats of the local cluster agent to see if consul metrics -// // are being seen by the agent -// bearerToken, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "cat /etc/datadog-agent/auth_token") -// metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptionsForNamespace(datadogNamespace), "exec", "pod/"+ddAgentName, "-c", "agent", "--", "curl", "--silent", "--insecure", "--show-error", "--header", fmt.Sprintf("authorization: Bearer %s", bearerToken), "https://localhost:5001/agent/dogstatsd-stats") -// require.NoError(t, err) -// require.Contains(t, metricsOutput, consulOTLPMetricQuery) -//} - -type ConsulCheck struct { - AverageExecutionTime int `json:"AverageExecutionTime"` - CheckConfigSource string `json:"CheckConfigSource"` - CheckID string `json:"CheckID"` - CheckName string `json:"CheckName"` - CheckVersion string `json:"CheckVersion"` - Events int `json:"Events"` - ExecutionTimes []int `json:"ExecutionTimes"` - LastError string `json:"LastError"` - LastExecutionTime int `json:"LastExecutionTime"` - LastSuccessDate int `json:"LastSuccessDate"` - MetricSamples int `json:"MetricSamples"` - ServiceChecks int `json:"ServiceChecks"` - TotalErrors int `json:"TotalErrors"` - TotalEvents int `json:"TotalEvents"` - TotalMetricSamples int `json:"TotalMetricSamples"` - TotalRuns int `json:"TotalRuns"` - TotalServiceChecks int `json:"TotalServiceChecks"` - TotalWarnings int `json:"TotalWarnings"` - UpdateTimestamp int `json:"UpdateTimestamp"` -} - -type OpenmetricsCheck struct { - AverageExecutionTime int `json:"AverageExecutionTime"` - CheckConfigSource string `json:"CheckConfigSource"` - CheckID string `json:"CheckID"` - CheckName string `json:"CheckName"` - CheckVersion string `json:"CheckVersion"` - Events int `json:"Events"` - ExecutionTimes []int `json:"ExecutionTimes"` - LastError string `json:"LastError"` - LastExecutionTime int `json:"LastExecutionTime"` - LastSuccessDate int64 `json:"LastSuccessDate"` - MetricSamples int `json:"MetricSamples"` - ServiceChecks int `json:"ServiceChecks"` - TotalErrors int `json:"TotalErrors"` - TotalEventPlatformEvents map[string]interface{} `json:"TotalEventPlatformEvents"` - TotalEvents int `json:"TotalEvents"` - TotalHistogramBuckets int `json:"TotalHistogramBuckets"` - TotalMetricSamples int `json:"TotalMetricSamples"` - TotalRuns int `json:"TotalRuns"` - TotalServiceChecks int `json:"TotalServiceChecks"` - TotalWarnings int `json:"TotalWarnings"` - UpdateTimestamp int64 `json:"UpdateTimestamp"` -} - -type Checks struct { - Consul map[string]ConsulCheck `json:"consul"` - Openmetrics map[string]OpenmetricsCheck `json:"openmetrics"` -} - -type RunnerStats struct { - Checks Checks `json:"Checks"` -} - -type Root struct { - RunnerStats RunnerStats `json:"runnerStats"` -} diff --git a/acceptance/tests/datadog/main_test.go b/acceptance/tests/datadog/main_test.go deleted file mode 100644 index aca6e26e5f..0000000000 --- a/acceptance/tests/datadog/main_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package datadog - -import ( - "os" - "testing" - - testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" -) - -var suite testsuite.Suite - -func TestMain(m *testing.M) { - suite = testsuite.NewSuite(m) - os.Exit(suite.Run()) - -} diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/apigateway.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/apigateway.yaml deleted file mode 100644 index c4fa0d6364..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway-v2/apigateway.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: mesh.consul.hashicorp.com/v2beta1 -kind: APIGateway -metadata: - name: gateway -spec: - gatewayClassName: gateway-class - listeners: - - protocol: TCP - port: 81 - name: tcp - allowedRoutes: - namespaces: - from: "All" diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/certificate.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/certificate.yaml deleted file mode 100644 index d35dc559e2..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway-v2/certificate.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: v1 -kind: Secret -metadata: - name: certificate -type: kubernetes.io/tls -data: - tls.crt: "" - tls.key: "" \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclass.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclass.yaml deleted file mode 100644 index 583ffc210a..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclass.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: mesh.consul.hashicorp.com/v2beta1 -kind: GatewayClass -metadata: - name: gateway-class -spec: - controllerName: "consul.hashicorp.com/gateway-controller" - parametersRef: - group: consul.hashicorp.com - kind: GatewayClassConfig - name: gateway-class-config diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclassconfig.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclassconfig.yaml deleted file mode 100644 index 049cdd708f..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclassconfig.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: mesh.consul.hashicorp.com/v2beta1 -kind: GatewayClassConfig -metadata: - name: gateway-class-config \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/kustomization.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/kustomization.yaml deleted file mode 100644 index 871949a1ab..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway-v2/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - gatewayclassconfig.yaml - - gatewayclass.yaml - - apigateway.yaml - - tcproute.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/tcproute.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/tcproute.yaml deleted file mode 100644 index c06b0e4ee0..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway-v2/tcproute.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: mesh.consul.hashicorp.com/v2beta1 -kind: TCPRoute -metadata: - name: tcp-route -spec: - parentRefs: - - name: gateway \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/datadog/datadog.yaml b/acceptance/tests/fixtures/bases/datadog/datadog.yaml deleted file mode 100644 index 1496a9ac93..0000000000 --- a/acceptance/tests/fixtures/bases/datadog/datadog.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -# https://github.com/DataDog/datadog-operator/blob/main/docs/configuration.v2alpha1.md -apiVersion: datadoghq.com/v2alpha1 -kind: DatadogAgent -metadata: - name: datadog -spec: - global: - clusterName: dc1 - registry: gcr.io/datadoghq - logLevel: debug - # Site is the Datadog intake site Agent data are sent to. Set to 'datadoghq.com' to - # send data to the US1 site (default). Set to 'datadoghq.eu' to send data to the EU site. - # fake-intake image is datadog spoof site URL used for testing. - # Default: 'datadoghq.com' - site: http://fake-intake.datadog.svc.cluster.local - credentials: - apiSecret: - secretName: datadog-secret - keyName: api-key - appSecret: - secretName: datadog-secret - keyName: app-key - # Requirement for kind cluster as tls verification prevents the agent from - # being able to obtain hostname from hostnameFile - # ref: https://docs.datadoghq.com/agent/troubleshooting/hostname_containers/?tab=operator - kubelet: - tlsVerify: false - features: - dogstatsd: - unixDomainSocketConfig: - enabled: false - hostPortConfig: - enabled: false - clusterChecks: - enabled: false - useClusterChecksRunners: false - admissionController: - enabled: false - mutateUnlabelled: false - apm: - enabled: false - # features.npm.enabled: false - # required as the /etc/passwd rootfs is mounted for this - # see: https://github.com/DataDog/helm-charts/issues/273 - npm: - enabled: false - logCollection: - enabled: false - containerCollectAll: false - # features.processDiscovery.enabled: false - # required as the /etc/passwd rootfs is mounted for this - # see: https://github.com/DataDog/helm-charts/issues/273 - processDiscovery: - enabled: false - # features.liveProcessCollection.enabled: false - # required as the /etc/passwd rootfs is mounted for this - # see: https://github.com/DataDog/helm-charts/issues/273 - liveProcessCollection: - enabled: false - liveContainerCollection: - enabled: false - orchestratorExplorer: - enabled: false - prometheusScrape: - enabled: false - enableServiceEndpoints: false - override: - clusterAgent: - replicas: 0 \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/datadog/fake-intake.yaml b/acceptance/tests/fixtures/bases/datadog/fake-intake.yaml deleted file mode 100644 index c330a4718d..0000000000 --- a/acceptance/tests/fixtures/bases/datadog/fake-intake.yaml +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: fake-intake - namespace: datadog ---- -apiVersion: v1 -kind: Service -metadata: - name: fake-intake - namespace: datadog -spec: - selector: - app: fake-intake - ports: - - port: 80 - targetPort: 80 - protocol: TCP - name: http ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: fake-intake - namespace: datadog -spec: - replicas: 1 - selector: - matchLabels: - app: fake-intake - template: - metadata: - name: fake-intake - namespace: datadog - labels: - app: fake-intake - tags.datadoghq.com/env: "dev" - tags.datadoghq.com/service: "fake-intake" - tags.datadoghq.com/version: "latest" - annotations: - 'consul.hashicorp.com/connect-inject': 'false' - 'consul.hashicorp.com/transparent-proxy': 'false' - 'consul.hashicorp.com/enable-metrics-merging': 'false' - 'consul.hashicorp.com/transparent-proxy-overwrite-probes': 'false' - spec: - serviceAccountName: fake-intake - containers: - - name: fake-intake - image: datadog/fakeintake:latest - ports: - - name: http - containerPort: 80 - protocol: TCP - securityContext: - privileged: true - runAsUser: 0 \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/datadog/kustomization.yaml b/acceptance/tests/fixtures/bases/datadog/kustomization.yaml deleted file mode 100644 index d2839c2a99..0000000000 --- a/acceptance/tests/fixtures/bases/datadog/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - - -resources: - - fake-intake.yaml - - datadog.yaml diff --git a/acceptance/tests/fixtures/cases/datadog-dogstatsd-udp/kustomization.yaml b/acceptance/tests/fixtures/cases/datadog-dogstatsd-udp/kustomization.yaml deleted file mode 100644 index dcfce4e9f8..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-dogstatsd-udp/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - ../../bases/datadog -patches: - - path: patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/datadog-dogstatsd-udp/patch.yaml b/acceptance/tests/fixtures/cases/datadog-dogstatsd-udp/patch.yaml deleted file mode 100644 index 69caaac697..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-dogstatsd-udp/patch.yaml +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: datadoghq.com/v2alpha1 -kind: DatadogAgent -metadata: - name: datadog -spec: - features: - dogstatsd: - unixDomainSocketConfig: - enabled: false - hostPortConfig: - enabled: true - hostPort: 8125 - mapperProfiles: - configData: |- - - name: consul - prefix: "consul." - mappings: - - match: 'consul\.raft\.replication\.appendEntries\.logs\.([0-9a-f-]+)' - match_type: "regex" - name: "consul.raft.replication.appendEntries.logs" - tags: - peer_id: "$1" - - match: 'consul\.raft\.replication\.appendEntries\.rpc\.([0-9a-f-]+)' - match_type: "regex" - name: "consul.raft.replication.appendEntries.rpc" - tags: - peer_id: "$1" - - match: 'consul\.raft\.replication\.heartbeat\.([0-9a-f-]+)' - match_type: "regex" - name: "consul.raft.replication.heartbeat" - tags: - peer_id: "$1" - override: - nodeAgent: - annotations: - 'consul.hashicorp.com/connect-inject': 'false' - 'consul.hashicorp.com/transparent-proxy': 'false' - tolerations: - - operator: Exists - env: - - name: DD_HISTOGRAM_PERCENTILES - value: '0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 0.95 0.99' - - name: DD_SECRET_BACKEND_COMMAND - value: /readsecret_multiple_providers.sh - containers: - agent: - env: - - name: DD_DOGSTATSD_METRICS_STATS_ENABLE - value: "true" - - name: DD_OTLP_CONFIG_LOGS_ENABLED - value: "true" - - name: DD_DOGSTATSD_NON_LOCAL_TRAFFIC - value: "true" - - name: DD_USE_V2_API_SERIES - value: "true" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/datadog-dogstatsd-uds/kustomization.yaml b/acceptance/tests/fixtures/cases/datadog-dogstatsd-uds/kustomization.yaml deleted file mode 100644 index dcfce4e9f8..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-dogstatsd-uds/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - ../../bases/datadog -patches: - - path: patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/datadog-dogstatsd-uds/patch.yaml b/acceptance/tests/fixtures/cases/datadog-dogstatsd-uds/patch.yaml deleted file mode 100644 index 2157940c8b..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-dogstatsd-uds/patch.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: datadoghq.com/v2alpha1 -kind: DatadogAgent -metadata: - name: datadog -spec: - features: - dogstatsd: - unixDomainSocketConfig: - enabled: true - path: "/var/run/datadog/dsd.socket" - hostPortConfig: - enabled: false - mapperProfiles: - configData: |- - - name: consul - prefix: "consul." - mappings: - - match: 'consul\.raft\.replication\.appendEntries\.logs\.([0-9a-f-]+)' - match_type: "regex" - name: "consul.raft.replication.appendEntries.logs" - tags: - peer_id: "$1" - - match: 'consul\.raft\.replication\.appendEntries\.rpc\.([0-9a-f-]+)' - match_type: "regex" - name: "consul.raft.replication.appendEntries.rpc" - tags: - peer_id: "$1" - - match: 'consul\.raft\.replication\.heartbeat\.([0-9a-f-]+)' - match_type: "regex" - name: "consul.raft.replication.heartbeat" - tags: - peer_id: "$1" - override: - nodeAgent: - annotations: - 'consul.hashicorp.com/connect-inject': 'false' - 'consul.hashicorp.com/transparent-proxy': 'false' - volumes: - - hostPath: - path: /var/run/datadog/ - name: dsdsocket - tolerations: - - operator: Exists - env: - - name: DD_HISTOGRAM_PERCENTILES - value: '0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 0.95 0.99' - - name: DD_SECRET_BACKEND_COMMAND - value: /readsecret_multiple_providers.sh - containers: - agent: - env: - - name: DD_DOGSTATSD_METRICS_STATS_ENABLE - value: "true" - - name: DD_OTLP_CONFIG_LOGS_ENABLED - value: "true" - - name: DD_DOGSTATSD_NON_LOCAL_TRAFFIC - value: "true" - - name: DD_USE_V2_API_SERIES - value: "true" - volumeMounts: - - name: dsdsocket - mountPath: /var/run/datadog diff --git a/acceptance/tests/fixtures/cases/datadog-openmetrics/kustomization.yaml b/acceptance/tests/fixtures/cases/datadog-openmetrics/kustomization.yaml deleted file mode 100644 index dcfce4e9f8..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-openmetrics/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - ../../bases/datadog -patches: - - path: patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/datadog-openmetrics/patch.yaml b/acceptance/tests/fixtures/cases/datadog-openmetrics/patch.yaml deleted file mode 100644 index 3672aaa7e4..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-openmetrics/patch.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: datadoghq.com/v2alpha1 -kind: DatadogAgent -metadata: - name: datadog -spec: - features: - prometheusScrape: - enabled: true - enableServiceEndpoints: true diff --git a/acceptance/tests/fixtures/cases/datadog-otlp-grpc/kustomization.yaml b/acceptance/tests/fixtures/cases/datadog-otlp-grpc/kustomization.yaml deleted file mode 100644 index dcfce4e9f8..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-otlp-grpc/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - ../../bases/datadog -patches: - - path: patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/datadog-otlp-grpc/patch.yaml b/acceptance/tests/fixtures/cases/datadog-otlp-grpc/patch.yaml deleted file mode 100644 index e72f70a855..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-otlp-grpc/patch.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: datadoghq.com/v2alpha1 -kind: DatadogAgent -metadata: - name: datadog -spec: - features: - # Sets: DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT: 0.0.0.0:4317 │ - # DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT: 0.0.0.0:4318 - otlp: - receiver: - protocols: - # Set to "0.0.0.0" as per the below reference docs - # ref: https://docs.datadoghq.com/opentelemetry/otlp_ingest_in_the_agent/?tab=host#enabling-otlp-ingestion-on-the-datadog-agent - grpc: - enabled: true - endpoint: "0.0.0.0:4317" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/datadog-otlp/kustomization.yaml b/acceptance/tests/fixtures/cases/datadog-otlp/kustomization.yaml deleted file mode 100644 index dcfce4e9f8..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-otlp/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - ../../bases/datadog -patches: - - path: patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/datadog-otlp/patch.yaml b/acceptance/tests/fixtures/cases/datadog-otlp/patch.yaml deleted file mode 100644 index 6d6a42c972..0000000000 --- a/acceptance/tests/fixtures/cases/datadog-otlp/patch.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: datadoghq.com/v2alpha1 -kind: DatadogAgent -metadata: - name: datadog -spec: - features: - # Sets: DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT: 0.0.0.0:4317 │ - # DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT: 0.0.0.0:4318 - otlp: - receiver: - protocols: - # Set to "0.0.0.0" as per the below reference docs - # ref: https://docs.datadoghq.com/opentelemetry/otlp_ingest_in_the_agent/?tab=host#enabling-otlp-ingestion-on-the-datadog-agent - http: - enabled: true - endpoint: "0.0.0.0:4318" \ No newline at end of file diff --git a/acceptance/tests/mesh_v2/mesh_inject_test.go b/acceptance/tests/mesh_v2/mesh_inject_test.go index e44a2296af..d54229d84b 100644 --- a/acceptance/tests/mesh_v2/mesh_inject_test.go +++ b/acceptance/tests/mesh_v2/mesh_inject_test.go @@ -37,6 +37,7 @@ func TestMeshInject_MultiportService(t *testing.T) { helmValues := map[string]string{ "global.experiments[0]": "resource-apis", + "global.image": "ndhanushkodi/consul-dev:expose2", // The UI is not supported for v2 in 1.17, so for now it must be disabled. "ui.enabled": "false", "connectInject.enabled": "true", diff --git a/acceptance/tests/partitions/partitions_gateway_test.go b/acceptance/tests/partitions/partitions_gateway_test.go index acf9226715..a90a790cb6 100644 --- a/acceptance/tests/partitions/partitions_gateway_test.go +++ b/acceptance/tests/partitions/partitions_gateway_test.go @@ -219,19 +219,8 @@ func TestPartitions_Gateway(t *testing.T) { logger.Log(t, "creating static-client pod in secondary partition cluster") k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-client") - // Create certificate secret, we do this separately since - // applying the secret will make an invalid certificate that breaks other tests - logger.Log(t, "creating certificate secret") - out, err := k8s.RunKubectlAndGetOutputE(t, secondaryPartitionClusterStaticServerOpts, "apply", "-f", "../fixtures/bases/api-gateway/certificate.yaml") - require.NoError(t, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - // Ignore errors here because if the test ran as expected - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, secondaryPartitionClusterStaticServerOpts, "delete", "-f", "../fixtures/bases/api-gateway/certificate.yaml") - }) - logger.Log(t, "creating api-gateway resources") - out, err = k8s.RunKubectlAndGetOutputE(t, secondaryPartitionClusterStaticServerOpts, "apply", "-k", "../fixtures/bases/api-gateway") + out, err := k8s.RunKubectlAndGetOutputE(t, secondaryPartitionClusterStaticServerOpts, "apply", "-k", "../fixtures/bases/api-gateway") require.NoError(t, err, out) helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { // Ignore errors here because if the test ran as expected diff --git a/acceptance/tests/peering/peering_gateway_test.go b/acceptance/tests/peering/peering_gateway_test.go index cafaa51064..542a215839 100644 --- a/acceptance/tests/peering/peering_gateway_test.go +++ b/acceptance/tests/peering/peering_gateway_test.go @@ -236,19 +236,8 @@ func TestPeering_Gateway(t *testing.T) { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/non-default-namespace") }) - // Create certificate secret, we do this separately since - // applying the secret will make an invalid certificate that breaks other tests - logger.Log(t, "creating certificate secret") - out, err := k8s.RunKubectlAndGetOutputE(t, staticClientOpts, "apply", "-f", "../fixtures/bases/api-gateway/certificate.yaml") - require.NoError(t, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - // Ignore errors here because if the test ran as expected - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, staticClientOpts, "delete", "-f", "../fixtures/bases/api-gateway/certificate.yaml") - }) - logger.Log(t, "creating api-gateway resources in client peer") - out, err = k8s.RunKubectlAndGetOutputE(t, staticClientOpts, "apply", "-k", "../fixtures/bases/api-gateway") + out, err := k8s.RunKubectlAndGetOutputE(t, staticClientOpts, "apply", "-k", "../fixtures/bases/api-gateway") require.NoError(t, err, out) helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { // Ignore errors here because if the test ran as expected diff --git a/acceptance/tests/sync/sync_catalog_test.go b/acceptance/tests/sync/sync_catalog_test.go index 8bc6480d8d..d4a0e9e99c 100644 --- a/acceptance/tests/sync/sync_catalog_test.go +++ b/acceptance/tests/sync/sync_catalog_test.go @@ -9,14 +9,13 @@ import ( "testing" "time" - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/stretchr/testify/require" - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" + "github.com/stretchr/testify/require" ) // Test that sync catalog works in both the default installation and @@ -108,7 +107,7 @@ func TestSyncCatalogWithIngress(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ "syncCatalog.enabled": "true", - "syncCatalog.ingress.enabled": "true", + "syncCatalog.ingres.enabled": "true", "global.tls.enabled": strconv.FormatBool(c.secure), "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), } diff --git a/acceptance/tests/tenancy_v2/namespace_test.go b/acceptance/tests/tenancy_v2/namespace_test.go deleted file mode 100644 index cb19565472..0000000000 --- a/acceptance/tests/tenancy_v2/namespace_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package tenancy_v2 - -import ( - "testing" - - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/acceptance/framework/logger" - "github.com/hashicorp/consul-k8s/acceptance/framework/resource" - "github.com/hashicorp/consul/proto-public/pbresource" - pbtenancy "github.com/hashicorp/consul/proto-public/pbtenancy/v2beta1" -) - -// TestTenancy_Namespace_Mirrored tests consul namespaces are created/deleted -// to mirror k8s namespaces in the default partition. -func TestTenancy_Namespace_Mirrored(t *testing.T) { - cfg := suite.Config() - cfg.SkipWhenCNI(t) - ctx := suite.Environment().DefaultContext(t) - - serverHelmValues := map[string]string{ - "server.enabled": "true", - "global.experiments[0]": "resource-apis", - "global.experiments[1]": "v2tenancy", - // The UI is not supported for v2 in 1.17, so for now it must be disabled. - "ui.enabled": "false", - } - - serverReleaseName := helpers.RandomName() - serverCluster := consul.NewHelmCluster(t, serverHelmValues, ctx, cfg, serverReleaseName) - serverCluster.Create(t) - - logger.Log(t, "creating namespace ns1 in k8s") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "namespace", "ns1") - - logger.Log(t, "waiting for namespace ns1 to be created in consul") - serverResourceClient := serverCluster.ResourceClient(t, false) - rtest := resource.NewResourceTester(serverResourceClient) - rtest.WaitForResourceExists(t, &pbresource.ID{ - Name: "ns1", - Type: pbtenancy.NamespaceType, - Tenancy: &pbresource.Tenancy{ - Partition: "default", - }, - }) - - logger.Log(t, "deleting namespace ns1 in k8s") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "namespace", "ns1") - - logger.Log(t, "waiting for namespace ns1 to be deleted in consul") - rtest.WaitForResourceNotFound(t, &pbresource.ID{ - Name: "ns1", - Type: pbtenancy.NamespaceType, - Tenancy: &pbresource.Tenancy{ - Partition: "default", - }, - }) -} diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 3dc8d13015..16be797490 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -3,8 +3,8 @@ apiVersion: v2 name: consul -version: 1.6.0-dev -appVersion: 1.20-dev +version: 1.4.3-dev +appVersion: 1.18-dev kubeVersion: ">=1.22.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io @@ -16,11 +16,11 @@ annotations: artifacthub.io/prerelease: true artifacthub.io/images: | - name: consul - image: docker.mirror.hashicorp.services/hashicorppreview/consul:1.20-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul:1.18-dev - name: consul-k8s-control-plane - image: docker.mirror.hashicorp.services/hashicorppreview/consul-k8s-control-plane:1.6-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul-k8s-control-plane:1.4-dev - name: consul-dataplane - image: docker.mirror.hashicorp.services/hashicorppreview/consul-dataplane:1.6-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul-dataplane:1.4-dev - name: envoy image: envoyproxy/envoy:v1.25.11 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 697959d5db..ca87485a78 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -19,7 +19,6 @@ as well as the global.name setting. {{- if not .Values.global.enablePodSecurityPolicies -}} securityContext: allowPrivilegeEscalation: false - readOnlyRootFilesystem: true capabilities: drop: - ALL @@ -246,7 +245,6 @@ This template is for an init container. {{- define "consul.getAutoEncryptClientCA" -}} - name: get-auto-encrypt-client-ca image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} command: - "/bin/sh" - "-ec" @@ -507,6 +505,7 @@ Fails if global.experiments.resourceAPIs is set along with any of these unsuppor - meshGateway.enabled - ingressGateways.enabled - terminatingGateways.enabled +- apiGateway.enabled Usage: {{ template "consul.validateResourceAPIs" . }} @@ -539,6 +538,9 @@ Usage: {{ template "consul.validateResourceAPIs" . }} {{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.terminatingGateways.enabled ) }} {{fail "When the value global.experiments.resourceAPIs is set, terminatingGateways.enabled is currently unsupported."}} {{- end }} +{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.apiGateway.enabled ) }} +{{fail "When the value global.experiments.resourceAPIs is set, apiGateway.enabled is currently unsupported."}} +{{- end }} {{- end }} {{/* @@ -682,23 +684,5 @@ Usage: {{ template "consul.versionInfo" }} {{- else }} {{- $sanitizedVersion = $versionInfo }} {{- end -}} -{{- printf "%s" $sanitizedVersion | trunc 63 | quote }} -{{- end -}} - -{{/* -Sets the imagePullPolicy for all Consul images (consul, consul-dataplane, consul-k8s, consul-telemetry-collector) -Valid values are: - IfNotPresent - Always - Never - In the case of empty, see https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy for details - -Usage: {{ template "consul.imagePullPolicy" . }} TODO: melisa should we name this differently ? -*/}} -{{- define "consul.imagePullPolicy" -}} -{{ if or (eq .Values.global.imagePullPolicy "IfNotPresent") (eq .Values.global.imagePullPolicy "Always") (eq .Values.global.imagePullPolicy "Never")}}imagePullPolicy: {{ .Values.global.imagePullPolicy }} -{{ else if eq .Values.global.imagePullPolicy "" }} -{{ else }} -{{fail "imagePullPolicy can only be IfNotPresent, Always, Never, or empty" }} -{{ end }} +{{- printf "%s" $sanitizedVersion | quote }} {{- end -}} \ No newline at end of file diff --git a/charts/consul/templates/api-gateway-controller-clusterrole.yaml b/charts/consul/templates/api-gateway-controller-clusterrole.yaml new file mode 100644 index 0000000000..eac2bd1f69 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-clusterrole.yaml @@ -0,0 +1,265 @@ +{{- if .Values.apiGateway.enabled }} +# The ClusterRole to enable the API Gateway controller to access required api endpoints. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +rules: +- apiGroups: + - api-gateway.consul.hashicorp.com + resources: + - gatewayclassconfigs + verbs: + - get + - list + - update + - watch +- apiGroups: + - api-gateway.consul.hashicorp.com + resources: + - gatewayclassconfigs/finalizers + verbs: + - update +- apiGroups: + - api-gateway.consul.hashicorp.com + resources: + - meshservices + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - get + - list + - update + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - list + - update +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - configmaps/status + verbs: + - get + - patch + - update +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - pods + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - get + - list + - update + - watch +- apiGroups: + - "" + resources: + - services + verbs: + - create + - get + - list + - update + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - get + - list + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - referencegrants + verbs: + - get + - list + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - referencepolicies + verbs: + - get + - list + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses/status + verbs: + - get + - patch + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways/status + verbs: + - get + - patch + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes/status + verbs: + - get + - patch + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - tcproutes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - tcproutes/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - tcproutes/status + verbs: + - get + - patch + - update +{{- if .Values.global.enablePodSecurityPolicies }} +- apiGroups: + - policy + resources: + - podsecuritypolicies + verbs: + - use +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + - rolebindings + verbs: + - create + - get + - list + - watch +{{- end }} +{{- end }} diff --git a/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml new file mode 100644 index 0000000000..d083a08129 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if .Values.apiGateway.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "consul.fullname" . }}-api-gateway-controller +subjects: +- kind: ServiceAccount + name: {{ template "consul.fullname" . }}-api-gateway-controller + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml new file mode 100644 index 0000000000..453be66054 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -0,0 +1,306 @@ +{{- if .Values.apiGateway.enabled }} +{{- if not .Values.client.grpc }}{{ fail "client.grpc must be true for api gateway" }}{{ end }} +{{- if not .Values.apiGateway.image}}{{ fail "apiGateway.image must be set to enable api gateway" }}{{ end }} +{{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} +{{ template "consul.validateRequiredCloudSecretsExist" . }} +{{ template "consul.validateCloudSecretKeys" . }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller + {{- if .Values.global.extraLabels }} + {{- toYaml .Values.global.extraLabels | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.apiGateway.controller.replicas }} + selector: + matchLabels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + release: {{ .Release.Name }} + component: api-gateway-controller + template: + metadata: + annotations: + consul.hashicorp.com/connect-inject: "false" + consul.hashicorp.com/mesh-inject: "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{ end }} + {{- if (and (.Values.global.secretsBackend.vault.vaultNamespace) (not (hasKey (default "" .Values.global.secretsBackend.vault.agentAnnotations | fromYaml) "vault.hashicorp.com/namespace")))}} + "vault.hashicorp.com/namespace": "{{ .Values.global.secretsBackend.vault.vaultNamespace }}" + {{- end }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- end }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + release: {{ .Release.Name }} + component: api-gateway-controller + {{- if .Values.global.extraLabels }} + {{- toYaml .Values.global.extraLabels | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ template "consul.fullname" . }}-api-gateway-controller + containers: + - name: api-gateway-controller + image: {{ .Values.apiGateway.image }} + ports: + - containerPort: 9090 + name: sds + protocol: TCP + env: + {{- if or (not (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots)) .Values.client.enabled }} + {{- if .Values.global.tls.enabled }} + - name: CONSUL_CACERT + {{- /* When Vault is being used as a secrets backend, auto-encrypt must be enabled. Since clients use a separate + root CA from servers when auto-encrypt is enabled, and our controller communicates with the agent when clients are + enabled, we only use the Vault server CA if clients are disabled and our controller will be communicating w/ the server. */}} + {{- if and (not .Values.client.enabled) .Values.global.secretsBackend.vault.enabled }} + value: /vault/secrets/serverca.crt + {{- else }} + value: /consul/tls/ca/tls.crt + {{- end }} + {{- end }} + {{- end }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.global.acls.manageSystemACLs }} + - name: CONSUL_HTTP_TOKEN_FILE + value: "/consul/login/acl-token" + # CONSUL_LOGIN_DATACENTER is passed to the gateway that gets created. The controller does not use this to log in + - name: CONSUL_LOGIN_DATACENTER + value: {{ .Values.global.datacenter }} + {{- end }} + - name: CONSUL_HTTP_ADDR + {{- if .Values.client.enabled }} + {{/* + We use client agent nodes if we have them to support backwards compatibility for Consul API Gateway + v0.4 and older, which requires connectivity between the registered Consul agent node and a + deployment for health checking (originating from the Consul node). Always leveraging the agents in + the case that they're explicitly opted into allows us to support users with agent node + + "externalServers" configuration upgrading a Helm chart without upgrading API gateways. + */}} + {{- if .Values.global.tls.enabled }} + value: $(HOST_IP):8501 + {{- else }} + value: $(HOST_IP):8500 + {{- end }} + {{- else if .Values.externalServers.enabled }} + {{/* + "externalServers" specified and running in "agentless" mode, this will only work with + Consul API Gateway v0.5 or newer + */}} + value: {{ first .Values.externalServers.hosts }}:{{ .Values.externalServers.httpsPort }} + {{- else }} + {{/* + We have local network connectivity between deployments and the internal cluster, this + should be supported in all versions of Consul API Gateway + */}} + {{- if .Values.global.tls.enabled }} + value: {{ template "consul.fullname" . }}-server:8501 + {{- else }} + value: {{ template "consul.fullname" . }}-server:8500 + {{- end }} + {{- end }} + - name: CONSUL_HTTP_SSL + value: "{{ .Values.global.tls.enabled }}" + {{- if and (not .Values.client.enabled) .Values.externalServers.enabled .Values.externalServers.tlsServerName }} + - name: CONSUL_TLS_SERVER_NAME + value: {{ .Values.externalServers.tlsServerName }} + {{- end }} + {{- if .Values.global.adminPartitions.enabled }} + - name: CONSUL_PARTITION + value: {{ .Values.global.adminPartitions.name }} + {{- if .Values.global.acls.manageSystemACLs }} + - name: CONSUL_LOGIN_PARTITION + value: {{ .Values.global.adminPartitions.name }} + {{- end }} + {{- end }} + {{- if not .Values.client.enabled }} + - name: CONSUL_DYNAMIC_SERVER_DISCOVERY + value: "true" + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec consul-api-gateway server \ + -sds-server-host {{ template "consul.fullname" . }}-api-gateway-controller.{{ .Release.Namespace }}.svc \ + -k8s-namespace {{ .Release.Namespace }} \ + {{- if .Values.global.enableConsulNamespaces }} + {{- if .Values.connectInject.consulNamespaces.consulDestinationNamespace }} + -consul-destination-namespace={{ .Values.connectInject.consulNamespaces.consulDestinationNamespace }} \ + {{- end }} + {{- if .Values.connectInject.consulNamespaces.mirroringK8S }} + -mirroring-k8s=true \ + {{- if .Values.connectInject.consulNamespaces.mirroringK8SPrefix }} + -mirroring-k8s-prefix={{ .Values.connectInject.consulNamespaces.mirroringK8SPrefix }} \ + {{- end }} + {{- end }} + {{- end }} + {{- if and .Values.global.federation.enabled .Values.global.federation.primaryDatacenter }} + -primary-datacenter={{ .Values.global.federation.primaryDatacenter }} \ + {{- end }} + -log-level {{ default .Values.global.logLevel .Values.apiGateway.logLevel }} \ + -log-json={{ .Values.global.logJSON }} + volumeMounts: + {{- if .Values.global.acls.manageSystemACLs }} + - name: consul-bin + mountPath: /consul-bin + {{- end }} + {{- if or (not (or (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) .Values.global.secretsBackend.vault.enabled)) .Values.client.enabled }} + {{- if .Values.global.tls.enabled }} + {{- if and .Values.client.enabled .Values.global.tls.enableAutoEncrypt }} + - name: consul-auto-encrypt-ca-cert + {{- else }} + - name: consul-ca-cert + {{- end }} + mountPath: /consul/tls/ca + readOnly: true + {{- end }} + {{- end }} + - mountPath: /consul/login + name: consul-data + readOnly: true + {{- if .Values.apiGateway.resources }} + resources: + {{- toYaml .Values.apiGateway.resources | nindent 12 }} + {{- end }} + {{- if .Values.global.acls.manageSystemACLs }} + lifecycle: + preStop: + exec: + command: ["/consul-bin/consul", "logout" ] + {{- end }} + volumes: + {{- if .Values.global.acls.manageSystemACLs }} + - name: consul-bin + emptyDir: { } + {{- end }} + {{- if .Values.global.tls.enabled }} + {{- if not (or (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) .Values.global.secretsBackend.vault.enabled) }} + - name: consul-ca-cert + secret: + {{- if .Values.global.tls.caCert.secretName }} + secretName: {{ .Values.global.tls.caCert.secretName }} + {{- else }} + secretName: {{ template "consul.fullname" . }}-ca-cert + {{- end }} + items: + - key: {{ default "tls.crt" .Values.global.tls.caCert.secretKey }} + path: tls.crt + {{- end }} + {{- if .Values.global.tls.enableAutoEncrypt }} + - name: consul-auto-encrypt-ca-cert + emptyDir: + medium: "Memory" + {{- end }} + {{- end }} + - name: consul-data + emptyDir: + medium: "Memory" + {{- if or .Values.global.acls.manageSystemACLs (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} + initContainers: + {{- if .Values.global.acls.manageSystemACLs }} + - name: copy-consul-bin + image: {{ .Values.global.image | quote }} + command: + - cp + - /bin/consul + - /consul-bin/consul + volumeMounts: + - name: consul-bin + mountPath: /consul-bin + {{- if .Values.apiGateway.initCopyConsulContainer }} + {{- if .Values.apiGateway.initCopyConsulContainer.resources }} + resources: {{ toYaml .Values.apiGateway.initCopyConsulContainer.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- end }} + {{- if (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} + {{- include "consul.getAutoEncryptClientCA" . | nindent 6 }} + {{- end }} + {{- if .Values.global.acls.manageSystemACLs }} + - name: api-gateway-controller-acl-init + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: CONSUL_LOGIN_META + value: "component=api-gateway-controller,pod=$(NAMESPACE)/$(POD_NAME)" + - name: CONSUL_LOGIN_DATACENTER + {{- if and .Values.global.federation.enabled .Values.global.federation.primaryDatacenter }} + value: {{ .Values.global.federation.primaryDatacenter }} + {{- else }} + value: {{ .Values.global.datacenter }} + {{- end}} + {{- include "consul.consulK8sConsulServerEnvVars" . | nindent 8 }} + image: {{ .Values.global.imageK8S }} + volumeMounts: + - mountPath: /consul/login + name: consul-data + readOnly: false + {{- if not (or (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) .Values.global.secretsBackend.vault.enabled) }} + {{- if .Values.global.tls.enabled }} + - name: consul-ca-cert + mountPath: /consul/tls/ca + readOnly: true + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec consul-k8s-control-plane acl-init \ + {{- if and .Values.global.federation.enabled .Values.global.federation.primaryDatacenter }} + -auth-method-name={{ template "consul.fullname" . }}-k8s-component-auth-method-{{ .Values.global.datacenter }} \ + {{- else }} + -auth-method-name={{ template "consul.fullname" . }}-k8s-component-auth-method \ + {{- end }} + -log-level={{ default .Values.global.logLevel .Values.apiGateway.logLevel }} \ + -log-json={{ .Values.global.logJSON }} + resources: + requests: + memory: "25Mi" + cpu: "50m" + limits: + memory: "25Mi" + cpu: "50m" + {{- end }} + {{- end }} + {{- if .Values.apiGateway.controller.priorityClassName }} + priorityClassName: {{ .Values.apiGateway.controller.priorityClassName | quote }} + {{- end }} + {{- if .Values.apiGateway.controller.nodeSelector }} + nodeSelector: + {{ tpl .Values.apiGateway.controller.nodeSelector . | indent 8 | trim }} + {{- end }} + {{- if .Values.apiGateway.controller.tolerations }} + tolerations: + {{ tpl .Values.apiGateway.controller.tolerations . | indent 8 | trim }} + {{- end }} +{{- end }} diff --git a/charts/consul/templates/api-gateway-controller-podsecuritypolicy.yaml b/charts/consul/templates/api-gateway-controller-podsecuritypolicy.yaml new file mode 100644 index 0000000000..390d084303 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-podsecuritypolicy.yaml @@ -0,0 +1,40 @@ +{{- if and .Values.apiGateway.enabled .Values.global.enablePodSecurityPolicies }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # This is redundant with non-root + disallow privilege escalation, + # but we can provide it for defense in depth. + requiredDropCapabilities: + - ALL + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'RunAsAny' + fsGroup: + rule: 'RunAsAny' + readOnlyRootFilesystem: true +{{- end }} diff --git a/charts/consul/templates/api-gateway-controller-service.yaml b/charts/consul/templates/api-gateway-controller-service.yaml new file mode 100644 index 0000000000..aa79ff9fc3 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-service.yaml @@ -0,0 +1,27 @@ +{{- if .Values.apiGateway.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller + annotations: + {{- if .Values.apiGateway.controller.service.annotations }} + {{ tpl .Values.apiGateway.controller.service.annotations . | nindent 4 | trim }} + {{- end }} +spec: + ports: + - name: sds + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: {{ template "consul.name" . }} + release: "{{ .Release.Name }}" + component: api-gateway-controller +{{- end }} diff --git a/charts/consul/templates/api-gateway-controller-serviceaccount.yaml b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml new file mode 100644 index 0000000000..98292a8dbe --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml @@ -0,0 +1,23 @@ +{{- if .Values.apiGateway.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller + {{- if .Values.apiGateway.serviceAccount.annotations }} + annotations: + {{ tpl .Values.apiGateway.serviceAccount.annotations . | nindent 4 | trim }} + {{- end }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range . }} + - name: {{ .name }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/consul/templates/api-gateway-gatewayclass.yaml b/charts/consul/templates/api-gateway-gatewayclass.yaml new file mode 100644 index 0000000000..d9ba85e633 --- /dev/null +++ b/charts/consul/templates/api-gateway-gatewayclass.yaml @@ -0,0 +1,18 @@ +{{- if (and .Values.apiGateway.enabled .Values.apiGateway.managedGatewayClass.enabled) }} +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: GatewayClass +metadata: + name: consul-api-gateway + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +spec: + controllerName: hashicorp.com/consul-api-gateway-controller + parametersRef: + group: api-gateway.consul.hashicorp.com + kind: GatewayClassConfig + name: consul-api-gateway +{{- end }} diff --git a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml new file mode 100644 index 0000000000..ba0e6c63db --- /dev/null +++ b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml @@ -0,0 +1,84 @@ +{{- if (and .Values.apiGateway.enabled .Values.apiGateway.managedGatewayClass.enabled) }} +apiVersion: api-gateway.consul.hashicorp.com/v1alpha1 +kind: GatewayClassConfig +metadata: + name: consul-api-gateway + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway +spec: + consul: + {{- if .Values.client.enabled }} + {{/* + We use client agent nodes if we have them to support backwards compatibility in <=0.4 releases which + require connectivity between the registered Consul agent node and a deployment for health checking + (originating from the Consul node). Always leveraging the agents in the case that they're explicitly + opted into allows us to support users with agent node + "externalServers" configuration upgrading a + helm chart without upgrading api gateways. Otherwise, using "externalServers" when provided + without local agents will break gateways <=0.4. + */}} + address: $(HOST_IP) + {{- else if .Values.externalServers.enabled }} + {{/* + "externalServers" specified and running in "agentless" mode, this will only work 0.5+ + */}} + address: {{ first .Values.externalServers.hosts }} + {{- else }} + {{/* + We have local network connectivity between deployments and the internal cluster, this + should be supported in all versions of api-gateway + */}} + address: {{ template "consul.fullname" . }}-server.{{ .Release.Namespace }}.svc + {{- end }} + authentication: + {{- if .Values.global.acls.manageSystemACLs }} + managed: true + method: {{ template "consul.fullname" . }}-k8s-auth-method + {{- if .Values.global.enablePodSecurityPolicies }} + podSecurityPolicy: {{ template "consul.fullname" . }}-api-gateway + {{- end }} + {{- end }} + {{- if .Values.global.tls.enabled }} + scheme: https + {{- else }} + scheme: http + {{- end }} + ports: + {{- if .Values.externalServers.enabled }} + grpc: {{ .Values.externalServers.grpcPort }} + http: {{ .Values.externalServers.httpsPort }} + {{- else }} + grpc: 8502 + {{- if .Values.global.tls.enabled }} + http: 8501 + {{- else }} + http: 8500 + {{- end }} + {{- end }} + {{- with .Values.apiGateway.managedGatewayClass.deployment }} + deployment: + {{- toYaml . | nindent 4 }} + {{- end }} + image: + consulAPIGateway: {{ .Values.apiGateway.image }} + envoy: {{ .Values.apiGateway.imageEnvoy }} + {{- if .Values.apiGateway.managedGatewayClass.nodeSelector }} + nodeSelector: + {{ tpl .Values.apiGateway.managedGatewayClass.nodeSelector . | indent 4 | trim }} + {{- end }} + {{- if .Values.apiGateway.managedGatewayClass.tolerations }} + tolerations: + {{ tpl .Values.apiGateway.managedGatewayClass.tolerations . | indent 4 | trim }} + {{- end }} + {{- if .Values.apiGateway.managedGatewayClass.copyAnnotations.service }} + copyAnnotations: + service: + {{ tpl .Values.apiGateway.managedGatewayClass.copyAnnotations.service.annotations . | nindent 6 | trim }} + {{- end }} + serviceType: {{ .Values.apiGateway.managedGatewayClass.serviceType }} + useHostPorts: {{ .Values.apiGateway.managedGatewayClass.useHostPorts }} + logLevel: {{ default .Values.global.logLevel .Values.apiGateway.managedGatewayClass.logLevel }} +{{- end }} diff --git a/charts/consul/templates/api-gateway-podsecuritypolicy.yaml b/charts/consul/templates/api-gateway-podsecuritypolicy.yaml new file mode 100644 index 0000000000..48f826f995 --- /dev/null +++ b/charts/consul/templates/api-gateway-podsecuritypolicy.yaml @@ -0,0 +1,45 @@ +{{- if and .Values.apiGateway.enabled .Values.global.enablePodSecurityPolicies }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "consul.fullname" . }}-api-gateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # This is redundant with non-root + disallow privilege escalation, + # but we can provide it for defense in depth. + requiredDropCapabilities: + - ALL + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + allowedCapabilities: + - NET_BIND_SERVICE + hostNetwork: false + hostIPC: false + hostPID: false + hostPorts: + - max: 65535 + min: 1025 + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'RunAsAny' + fsGroup: + rule: 'RunAsAny' + readOnlyRootFilesystem: true +{{- end }} diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 9c607385cf..cf0cb1d686 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -200,7 +200,6 @@ spec: containers: - name: consul image: "{{ default .Values.global.image .Values.client.image }}" - {{ template "consul.imagePullPolicy" . }} {{- if .Values.global.acls.manageSystemACLs }} lifecycle: preStop: @@ -503,7 +502,6 @@ spec: {{- if .Values.global.acls.manageSystemACLs }} - name: client-acl-init image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} env: - name: NAMESPACE valueFrom: @@ -556,7 +554,6 @@ spec: {{- if and .Values.global.tls.enabled (not .Values.global.tls.enableAutoEncrypt) }} - name: client-tls-init image: "{{ default .Values.global.image .Values.client.image }}" - {{ template "consul.imagePullPolicy" . }} env: - name: HOST_IP valueFrom: diff --git a/charts/consul/templates/cni-daemonset.yaml b/charts/consul/templates/cni-daemonset.yaml index a93e3aea90..258924f449 100644 --- a/charts/consul/templates/cni-daemonset.yaml +++ b/charts/consul/templates/cni-daemonset.yaml @@ -62,7 +62,6 @@ spec: # This container installs the consul CNI binaries and CNI network config file on each node - name: install-cni image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} securityContext: privileged: true command: diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index 9c8596b05b..c6845870ba 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -32,7 +32,6 @@ rules: - routetimeoutfilters - routeauthfilters - gatewaypolicies - - registrations {{- if .Values.global.peering.enabled }} - peeringacceptors - peeringdialers @@ -62,7 +61,6 @@ rules: - terminatinggateways/status - samenessgroups/status - controlplanerequestlimits/status - - registrations/status {{- if .Values.global.peering.enabled }} - peeringacceptors/status - peeringdialers/status @@ -104,7 +102,6 @@ rules: - grpcroutes - httproutes - meshgateways - - apigateways - tcproutes - proxyconfigurations verbs: @@ -124,7 +121,6 @@ rules: - grpcroutes/status - httproutes/status - meshgateways/status - - apigateways/status - tcproutes/status - proxyconfigurations/status verbs: diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 5aaa50a107..fe07c2581a 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -98,7 +98,6 @@ spec: containers: - name: sidecar-injector image: "{{ default .Values.global.imageK8S .Values.connectInject.image }}" - {{ template "consul.imagePullPolicy" . }} ports: - containerPort: 8080 name: webhook-server diff --git a/charts/consul/templates/connect-inject-validatingwebhookconfiguration.yaml b/charts/consul/templates/connect-inject-validatingwebhookconfiguration.yaml index 92068bbf68..8d01ace911 100644 --- a/charts/consul/templates/connect-inject-validatingwebhookconfiguration.yaml +++ b/charts/consul/templates/connect-inject-validatingwebhookconfiguration.yaml @@ -28,20 +28,4 @@ webhooks: name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} path: /validate-v1alpha1-gatewaypolicy -- name: validate-registration.consul.hashicorp.com - matchPolicy: Equivalent - rules: - - operations: [ "CREATE" , "UPDATE" ] - apiGroups: [ "consul.hashicorp.com" ] - apiVersions: [ "v1alpha1" ] - resources: [ "registrations" ] - failurePolicy: Fail - sideEffects: None - admissionReviewVersions: - - v1 - clientConfig: - service: - name: {{ template "consul.fullname" . }}-connect-injector - namespace: {{ .Release.Namespace }} - path: /validate-v1alpha1-registration {{- end }} diff --git a/charts/consul/templates/crd-apigateways.yaml b/charts/consul/templates/crd-apigateways.yaml index a01d40c027..755fb05b64 100644 --- a/charts/consul/templates/crd-apigateways.yaml +++ b/charts/consul/templates/crd-apigateways.yaml @@ -114,6 +114,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the + resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list resources + across all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -189,110 +196,41 @@ spec: type: object status: properties: - addresses: + conditions: + description: Conditions indicate the latest available observations + of a resource's current state. items: + description: 'Conditions define a readiness condition for a Consul + resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' properties: - type: - default: IPAddress + lastTransitionTime: + description: LastTransitionTime is the last time the condition + transitioned from one status to another. + format: date-time type: string - value: + message: + description: A human readable message indicating details about + the transition. type: string - required: - - type - - value - type: object - type: array - listeners: - items: - properties: - attachedRoutes: - format: int32 - type: integer - name: + reason: + description: The reason for the condition's last transition. type: string status: - properties: - conditions: - description: Conditions indicate the latest available observations - of a resource's current state. - items: - description: 'Conditions define a readiness condition - for a Consul resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' - properties: - lastTransitionTime: - description: LastTransitionTime is the last time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: A human readable message indicating details - about the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, - False, Unknown. - type: string - type: - description: Type of condition. - type: string - required: - - status - - type - type: object - type: array - lastSyncedTime: - description: LastSyncedTime is the last time the resource - successfully synced with Consul. - format: date-time - type: string - type: object + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string required: - - attachedRoutes - - name + - status + - type type: object type: array - status: - properties: - conditions: - description: Conditions indicate the latest available observations - of a resource's current state. - items: - description: 'Conditions define a readiness condition for a - Consul resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' - properties: - lastTransitionTime: - description: LastTransitionTime is the last time the condition - transitioned from one status to another. - format: date-time - type: string - message: - description: A human readable message indicating details - about the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, - Unknown. - type: string - type: - description: Type of condition. - type: string - required: - - status - - type - type: object - type: array - lastSyncedTime: - description: LastSyncedTime is the last time the resource successfully - synced with Consul. - format: date-time - type: string - type: object + lastSyncedTime: + description: LastSyncedTime is the last time the resource successfully + synced with Consul. + format: date-time + type: string type: object type: object served: true diff --git a/charts/consul/templates/crd-gatewayclassconfigs-v1.yaml b/charts/consul/templates/crd-gatewayclassconfigs-v1.yaml index a611e91b2b..41023c19dc 100644 --- a/charts/consul/templates/crd-gatewayclassconfigs-v1.yaml +++ b/charts/consul/templates/crd-gatewayclassconfigs-v1.yaml @@ -122,8 +122,7 @@ spec: description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. Requests cannot exceed - Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object type: object diff --git a/charts/consul/templates/crd-gatewayclassconfigs.yaml b/charts/consul/templates/crd-gatewayclassconfigs.yaml index 065efb0df8..93effd843b 100644 --- a/charts/consul/templates/crd-gatewayclassconfigs.yaml +++ b/charts/consul/templates/crd-gatewayclassconfigs.yaml @@ -1035,7 +1035,7 @@ spec: compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. - Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object type: object @@ -1117,7 +1117,7 @@ spec: compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. - Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object type: object @@ -1269,8 +1269,7 @@ spec: in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile - location. Must be set if type is "Localhost". Must NOT - be set for any other type. + location. Must only be set if type is "Localhost". type: string type: description: "type indicates which kind of seccomp profile @@ -1335,12 +1334,15 @@ spec: type: string hostProcess: description: HostProcess determines if a container should - be run as a 'Host Process' container. All of a Pod's - containers must have the same effective HostProcess - value (it is not allowed to have a mix of HostProcess - containers and non-HostProcess containers). In addition, - if HostProcess is true then HostNetwork must also be - set to true. + be run as a 'Host Process' container. This field is + alpha-level and will only be honored by components that + enable the WindowsHostProcessContainers feature flag. + Setting this field without the feature flag will result + in errors when validating the Pod. All of a Pod's containers + must have the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, if HostProcess + is true then HostNetwork must also be set to true. type: boolean runAsUserName: description: The UserName in Windows to run the entrypoint @@ -1450,19 +1452,14 @@ spec: type: object x-kubernetes-map-type: atomic matchLabelKeys: - description: "MatchLabelKeys is a set of pod label keys - to select the pods over which spreading will be calculated. + description: MatchLabelKeys is a set of pod label keys to + select the pods over which spreading will be calculated. The keys are used to lookup values from the incoming pod labels, those key-value labels are ANDed with labelSelector to select the group of existing pods over which spreading - will be calculated for the incoming pod. The same key - is forbidden to exist in both MatchLabelKeys and LabelSelector. - MatchLabelKeys cannot be set when LabelSelector isn't - set. Keys that don't exist in the incoming pod labels - will be ignored. A null or empty list means only match - against labelSelector. \n This is a beta field and requires - the MatchLabelKeysInPodTopologySpread feature gate to - be enabled (enabled by default)." + will be calculated for the incoming pod. Keys that don't + exist in the incoming pod labels will be ignored. A null + or empty list means only match against labelSelector. items: type: string type: array diff --git a/charts/consul/templates/crd-grpcroutes.yaml b/charts/consul/templates/crd-grpcroutes.yaml index 8766c8edbe..31812fff35 100644 --- a/charts/consul/templates/crd-grpcroutes.yaml +++ b/charts/consul/templates/crd-grpcroutes.yaml @@ -72,10 +72,9 @@ spec: description: 'NOTE: roughly equivalent to structs.ResourceReference' properties: port: - description: "For east/west this is the name of the Consul Service + description: For east/west this is the name of the Consul Service port to direct traffic to or empty to imply all. For north/south - this is TBD. \n For more details on potential values of this - field, see documentation for Service.ServicePort." + this is TBD. type: string ref: description: For east/west configuration, this should point @@ -107,6 +106,13 @@ spec: the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the resource + is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, provide + the wildcard value \"*\" to list resources across + all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -160,9 +166,7 @@ spec: description: "For east/west this is the name of the Consul Service port to direct traffic to or empty to imply using the same value as the parent ref. - For north/south this is TBD. \n For more details - on potential values of this field, see documentation - for Service.ServicePort." + \n For north/south this is TBD." type: string ref: description: For east/west configuration, this should @@ -195,6 +199,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer + the resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list + resources across all peers." + type: string type: object type: description: Type identifies the resource's type. diff --git a/charts/consul/templates/crd-httproutes.yaml b/charts/consul/templates/crd-httproutes.yaml index c829bf1fc3..3da6e1e637 100644 --- a/charts/consul/templates/crd-httproutes.yaml +++ b/charts/consul/templates/crd-httproutes.yaml @@ -72,10 +72,9 @@ spec: description: 'NOTE: roughly equivalent to structs.ResourceReference' properties: port: - description: "For east/west this is the name of the Consul Service + description: For east/west this is the name of the Consul Service port to direct traffic to or empty to imply all. For north/south - this is TBD. \n For more details on potential values of this - field, see documentation for Service.ServicePort." + this is TBD. type: string ref: description: For east/west configuration, this should point @@ -107,6 +106,13 @@ spec: the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the resource + is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, provide + the wildcard value \"*\" to list resources across + all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -163,9 +169,7 @@ spec: description: "For east/west this is the name of the Consul Service port to direct traffic to or empty to imply using the same value as the parent ref. - For north/south this is TBD. \n For more details - on potential values of this field, see documentation - for Service.ServicePort." + \n For north/south this is TBD." type: string ref: description: For east/west configuration, this should @@ -198,6 +202,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer + the resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list + resources across all peers." + type: string type: object type: description: Type identifies the resource's type. diff --git a/charts/consul/templates/crd-registrations.yaml b/charts/consul/templates/crd-registrations.yaml deleted file mode 100644 index e1e45d3574..0000000000 --- a/charts/consul/templates/crd-registrations.yaml +++ /dev/null @@ -1,251 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.12.1 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - name: registrations.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: Registration - listKind: RegistrationList - plural: registrations - singular: registration - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Registration defines the resource for working with service registrations. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of Registration. - properties: - address: - type: string - check: - description: HealthCheck is used to represent a single check. - properties: - checkId: - type: string - definition: - description: HealthCheckDefinition is used to store the details - about a health check's execution. - properties: - body: - type: string - deregisterCriticalServiceAfterDuration: - type: string - grpc: - type: string - grpcUseTLS: - type: boolean - header: - additionalProperties: - items: - type: string - type: array - type: object - http: - type: string - intervalDuration: - type: string - method: - type: string - osService: - type: string - tcp: - type: string - tcpUseTLS: - type: boolean - timeoutDuration: - type: string - tlsServerName: - type: string - tlsSkipVerify: - type: boolean - udp: - type: string - required: - - intervalDuration - type: object - exposedPort: - type: integer - name: - type: string - namespace: - type: string - node: - type: string - notes: - type: string - output: - type: string - partition: - type: string - serviceId: - type: string - serviceName: - type: string - status: - type: string - type: - type: string - required: - - checkId - - definition - - name - - serviceId - - serviceName - - status - type: object - datacenter: - type: string - id: - type: string - locality: - properties: - region: - type: string - zone: - type: string - type: object - node: - type: string - nodeMeta: - additionalProperties: - type: string - type: object - partition: - type: string - service: - properties: - address: - type: string - enableTagOverride: - type: boolean - id: - type: string - locality: - properties: - region: - type: string - zone: - type: string - type: object - meta: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - partition: - type: string - port: - type: integer - socketPath: - type: string - taggedAddresses: - additionalProperties: - properties: - address: - type: string - port: - type: integer - required: - - address - - port - type: object - type: object - tags: - items: - type: string - type: array - weights: - properties: - passing: - type: integer - warning: - type: integer - required: - - passing - - warning - type: object - required: - - address - - name - - port - type: object - skipNodeUpdate: - type: boolean - taggedAddresses: - additionalProperties: - type: string - type: object - type: object - status: - description: RegistrationStatus defines the observed state of Registration. - properties: - conditions: - description: Conditions indicate the latest available observations - of a resource's current state. - items: - description: 'Conditions define a readiness condition for a Consul - resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' - properties: - lastTransitionTime: - description: LastTransitionTime is the last time the condition - transitioned from one status to another. - format: date-time - type: string - message: - description: A human readable message indicating details about - the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of condition. - type: string - required: - - status - - type - type: object - type: array - lastSyncedTime: - description: LastSyncedTime is the last time the resource successfully - synced with Consul. - format: date-time - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} -{{- end }} diff --git a/charts/consul/templates/crd-tcproutes.yaml b/charts/consul/templates/crd-tcproutes.yaml index c0e87a9c3c..ae9d2cd080 100644 --- a/charts/consul/templates/crd-tcproutes.yaml +++ b/charts/consul/templates/crd-tcproutes.yaml @@ -66,10 +66,9 @@ spec: description: 'NOTE: roughly equivalent to structs.ResourceReference' properties: port: - description: "For east/west this is the name of the Consul Service + description: For east/west this is the name of the Consul Service port to direct traffic to or empty to imply all. For north/south - this is TBD. \n For more details on potential values of this - field, see documentation for Service.ServicePort." + this is TBD. type: string ref: description: For east/west configuration, this should point @@ -101,6 +100,13 @@ spec: the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the resource + is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, provide + the wildcard value \"*\" to list resources across + all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -145,9 +151,7 @@ spec: description: "For east/west this is the name of the Consul Service port to direct traffic to or empty to imply using the same value as the parent ref. - For north/south this is TBD. \n For more details - on potential values of this field, see documentation - for Service.ServicePort." + \n For north/south this is TBD." type: string ref: description: For east/west configuration, this should @@ -180,6 +184,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer + the resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list + resources across all peers." + type: string type: object type: description: Type identifies the resource's type. diff --git a/charts/consul/templates/crd-trafficpermissions.yaml b/charts/consul/templates/crd-trafficpermissions.yaml index 87727f4fbf..27ab6f5e3d 100644 --- a/charts/consul/templates/crd-trafficpermissions.yaml +++ b/charts/consul/templates/crd-trafficpermissions.yaml @@ -101,25 +101,23 @@ spec: when evaluating rules for the incoming connection. items: properties: - headers: - items: - properties: - exact: - type: string - invert: - type: boolean - name: - type: string - prefix: - type: string - present: - type: boolean - regex: - type: string - suffix: - type: string - type: object - type: array + header: + properties: + exact: + type: string + invert: + type: boolean + name: + type: string + prefix: + type: string + present: + type: boolean + regex: + type: string + suffix: + type: string + type: object methods: description: Methods is the list of HTTP methods. items: @@ -140,25 +138,23 @@ spec: type: array type: object type: array - headers: - items: - properties: - exact: - type: string - invert: - type: boolean - name: - type: string - prefix: - type: string - present: - type: boolean - regex: - type: string - suffix: - type: string - type: object - type: array + header: + properties: + exact: + type: string + invert: + type: boolean + name: + type: string + prefix: + type: string + present: + type: boolean + regex: + type: string + suffix: + type: string + type: object methods: description: Methods is the list of HTTP methods. If no methods are specified, this rule will apply to all methods. diff --git a/charts/consul/templates/create-federation-secret-job.yaml b/charts/consul/templates/create-federation-secret-job.yaml index 2092b97852..aff6b5a934 100644 --- a/charts/consul/templates/create-federation-secret-job.yaml +++ b/charts/consul/templates/create-federation-secret-job.yaml @@ -94,7 +94,6 @@ spec: containers: - name: create-federation-secret image: "{{ .Values.global.imageK8S }}" - {{ template "consul.imagePullPolicy" . }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} env: - name: NAMESPACE diff --git a/charts/consul/templates/enterprise-license-job.yaml b/charts/consul/templates/enterprise-license-job.yaml index 9dd0281978..8db9500a22 100644 --- a/charts/consul/templates/enterprise-license-job.yaml +++ b/charts/consul/templates/enterprise-license-job.yaml @@ -59,7 +59,6 @@ spec: containers: - name: apply-enterprise-license image: "{{ default .Values.global.image .Values.server.image }}" - {{ template "consul.imagePullPolicy" . }} env: - name: ENTERPRISE_LICENSE {{- if .Values.global.secretsBackend.vault.enabled }} @@ -126,7 +125,6 @@ spec: initContainers: - name: ent-license-acl-init image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} command: - "/bin/sh" - "-ec" diff --git a/charts/consul/templates/gateway-cleanup-job.yaml b/charts/consul/templates/gateway-cleanup-job.yaml index 0d38f6ec8b..0d4f84272c 100644 --- a/charts/consul/templates/gateway-cleanup-job.yaml +++ b/charts/consul/templates/gateway-cleanup-job.yaml @@ -38,7 +38,6 @@ spec: containers: - name: gateway-cleanup image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} command: - consul-k8s-control-plane diff --git a/charts/consul/templates/gateway-resources-configmap.yaml b/charts/consul/templates/gateway-resources-configmap.yaml index d00f9b3e86..842ba6690d 100644 --- a/charts/consul/templates/gateway-resources-configmap.yaml +++ b/charts/consul/templates/gateway-resources-configmap.yaml @@ -21,10 +21,9 @@ data: resources.json: | {{ toJson .Values.connectInject.apiGateway.managedGatewayClass.resources }} {{- end }} - {{- if and (mustHas "resource-apis" .Values.global.experiments) (or .Values.meshGateway.enabled .Values.connectInject.apiGateway.managedGatewayClass) }} + {{- if and (mustHas "resource-apis" .Values.global.experiments) .Values.meshGateway.enabled }} config.yaml: | gatewayClassConfigs: - {{- if .Values.meshGateway.enabled }} - apiVersion: mesh.consul.hashicorp.com/v2beta1 metadata: name: consul-mesh-gateway @@ -88,8 +87,7 @@ data: min: {{ .Values.meshGateway.replicas }} max: {{ .Values.meshGateway.replicas }} {{- if .Values.meshGateway.tolerations }} - tolerations: - {{ fromYamlArray .Values.meshGateway.tolerations | toJson }} + tolerations: {{ fromYamlArray .Values.meshGateway.tolerations | toJson }} {{- end }} service: {{- if .Values.meshGateway.service.annotations }} @@ -102,67 +100,6 @@ data: annotations: set: {{ toJson .Values.meshGateway.serviceAccount.annotations }} {{- end }} - {{- end }} - {{- if .Values.connectInject.apiGateway.managedGatewayClass }} - - apiVersion: mesh.consul.hashicorp.com/v2beta1 - metadata: - name: consul-api-gateway - kind: GatewayClassConfig - spec: - labels: - set: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: api-gateway - {{- if .Values.connectInject.apiGateway.managedGatewayClass.copyAnnotations }} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.copyAnnotations.service }} - annotations: - service: - {{ fromYamlArray .Values.connectInject.apiGateway.managedGatewayClass.copyAnnotations.service.annotations | toYaml }} - {{- end}} - {{- end}} - deployment: - {{- if .Values.connectInject.apiGateway.managedGatewayClass.nodeSelector }} - nodeSelector: - {{ fromYamlArray .Values.connectInject.apiGateway.managedGatewayClass.nodeSelector | toYaml }} - {{- end }} - initContainer: - {{- if .Values.connectInject.apiGateway.managedGatewayClass.mapPrivilegedContainerPorts }} - portModifier: {{ .Values.connectInject.apiGateway.managedGatewayClass.mapPrivilegedContainerPorts }} - {{- end }} - consul: - logging: - level: {{ .Values.global.logLevel }} - container: - {{- if .Values.connectInject.apiGateway.managedGatewayClass.mapPrivilegedContainerPorts }} - portModifier: {{ .Values.connectInject.apiGateway.managedGatewayClass.mapPrivilegedContainerPorts }} - {{- end }} - consul: - logging: - level: {{ .Values.global.logLevel }} - replicas: - default: {{ .Values.connectInject.apiGateway.managedGatewayClass.deployment.defaultInstances }} - min: {{ .Values.connectInject.apiGateway.managedGatewayClass.deployment.minInstances }} - max: {{ .Values.connectInject.apiGateway.managedGatewayClass.deployment.maxInstances }} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.tolerations }} - tolerations: - {{ fromYamlArray .Values.connectInject.apiGateway.managedGatewayClass.tolerations | toYaml }} - {{- end }} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.service }} - service: - annotations: - set: {{ toYaml .Values.connectInject.apiGateway.managedGatewayClass.service.annotations }} - {{- end }} - type: {{ .Values.connectInject.apiGateway.managedGatewayClass.serviceType }} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.serviceAccount }} - serviceAccount: - annotations: - set: {{ toYaml .Values.connectInject.apiGateway.managedGatewayClass.serviceAccount.annotations }} - {{- end }} - {{- end }} - {{- if .Values.meshGateway.enabled }} meshGateways: - apiVersion: mesh.consul.hashicorp.com/v2beta1 kind: MeshGateway @@ -170,6 +107,7 @@ data: name: mesh-gateway namespace: {{ .Release.Namespace }} annotations: + # TODO are these annotations even necessary? "consul.hashicorp.com/gateway-wan-address-source": {{ .Values.meshGateway.wanAddress.source | quote }} "consul.hashicorp.com/gateway-wan-address-static": {{ .Values.meshGateway.wanAddress.static | quote }} {{- if eq .Values.meshGateway.wanAddress.source "Service" }} @@ -190,6 +128,5 @@ data: workloads: prefixes: - "mesh-gateway" - {{- end }} {{- end }} {{- end }} diff --git a/charts/consul/templates/gateway-resources-job.yaml b/charts/consul/templates/gateway-resources-job.yaml index b5e7b056cc..ead22833e9 100644 --- a/charts/consul/templates/gateway-resources-job.yaml +++ b/charts/consul/templates/gateway-resources-job.yaml @@ -1,4 +1,3 @@ -{{- if .Values.apiGateway}}{{fail "[DEPRECATED and REMOVED] the apiGateway stanza is no longer supported as of Consul 1.19.0. Use connectInject.apiGateway instead."}}{{- end -}} {{- if .Values.connectInject.enabled }} apiVersion: batch/v1 kind: Job @@ -39,7 +38,6 @@ spec: containers: - name: gateway-resources image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} command: - consul-k8s-control-plane @@ -53,6 +51,29 @@ spec: - -heritage={{ .Release.Service }} - -release-name={{ .Release.Name }} - -component=api-gateway + {{- if .Values.apiGateway.enabled }} # Override values from the old stanza. To be removed after ~1.18 (t-eckert 2023-05-19) NET-6263 + {{- if .Values.apiGateway.managedGatewayClass.deployment }} + {{- if .Values.apiGateway.managedGatewayClass.deployment.defaultInstances }} + - -deployment-default-instances={{ .Values.apiGateway.managedGatewayClass.deployment.defaultInstances }} + {{- end}} + {{- if .Values.apiGateway.managedGatewayClass.deployment.maxInstances }} + - -deployment-max-instances={{ .Values.apiGateway.managedGatewayClass.deployment.maxInstances }} + {{- end}} + {{- if .Values.apiGateway.managedGatewayClass.deployment.minInstances }} + - -deployment-min-instances={{ .Values.apiGateway.managedGatewayClass.deployment.minInstances }} + {{- end}} + {{- end}} + {{- if .Values.apiGateway.managedGatewayClass.nodeSelector }} + - -node-selector={{ .Values.apiGateway.managedGatewayClass.nodeSelector }} + {{- end }} + {{- if .Values.apiGateway.managedGatewayClass.tolerations }} + - -tolerations={{ .Values.apiGateway.managedGatewayClass.tolerations }} + {{- end }} + {{- if .Values.apiGateway.managedGatewayClass.copyAnnotations.service }} + - -service-annotations={{ .Values.apiGateway.managedGatewayClass.copyAnnotations.service.annotations }} + {{- end }} + - -service-type={{ .Values.apiGateway.managedGatewayClass.serviceType }} + {{- else }} # the new stanza {{- if .Values.connectInject.apiGateway.managedGatewayClass.deployment }} {{- if .Values.connectInject.apiGateway.managedGatewayClass.deployment.defaultInstances }} - -deployment-default-instances={{ .Values.connectInject.apiGateway.managedGatewayClass.deployment.defaultInstances }} @@ -89,6 +110,7 @@ spec: {{- if .Values.connectInject.apiGateway.managedGatewayClass.metrics.port }} - -metrics-port={{ .Values.connectInject.apiGateway.managedGatewayClass.metrics.port }} {{- end }} + {{- end }} resources: requests: memory: "50Mi" diff --git a/charts/consul/templates/gossip-encryption-autogenerate-job.yaml b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml index 485064f80f..cea13c77fe 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-job.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml @@ -49,7 +49,6 @@ spec: containers: - name: gossip-encryption-autogen image: "{{ .Values.global.imageK8S }}" - {{ template "consul.imagePullPolicy" . }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} command: - "/bin/sh" diff --git a/charts/consul/templates/ingress-gateways-deployment.yaml b/charts/consul/templates/ingress-gateways-deployment.yaml index c7a38bb040..508ab64eff 100644 --- a/charts/consul/templates/ingress-gateways-deployment.yaml +++ b/charts/consul/templates/ingress-gateways-deployment.yaml @@ -160,9 +160,6 @@ spec: terminationGracePeriodSeconds: {{ default $defaults.terminationGracePeriodSeconds .terminationGracePeriodSeconds }} serviceAccountName: {{ template "consul.fullname" $root }}-{{ .name }} volumes: - - name: tmp - emptyDir: - medium: "Memory" - name: consul-service emptyDir: medium: "Memory" @@ -184,7 +181,6 @@ spec: # ingress-gateway-init registers the ingress gateway service with Consul. - name: ingress-gateway-init image: {{ $root.Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" $root }} {{- include "consul.restrictedSecurityContext" $ | nindent 8 }} env: - name: NAMESPACE @@ -225,8 +221,6 @@ spec: -log-level={{ default $root.Values.global.logLevel $root.Values.ingressGateways.logLevel }} \ -log-json={{ $root.Values.global.logJSON }} volumeMounts: - - name: tmp - mountPath: /tmp - name: consul-service mountPath: /consul/service {{- if $root.Values.global.tls.enabled }} @@ -246,14 +240,11 @@ spec: containers: - name: ingress-gateway image: {{ $root.Values.global.imageConsulDataplane | quote }} - {{ template "consul.imagePullPolicy" $root }} {{- include "consul.restrictedSecurityContext" $ | nindent 8 }} {{- if (default $defaults.resources .resources) }} resources: {{ toYaml (default $defaults.resources .resources) | nindent 10 }} {{- end }} volumeMounts: - - name: tmp - mountPath: /tmp - name: consul-service mountPath: /consul/service readOnly: true diff --git a/charts/consul/templates/mesh-gateway-deployment.yaml b/charts/consul/templates/mesh-gateway-deployment.yaml index 03bf2707a5..3d75d55613 100644 --- a/charts/consul/templates/mesh-gateway-deployment.yaml +++ b/charts/consul/templates/mesh-gateway-deployment.yaml @@ -128,7 +128,6 @@ spec: initContainers: - name: mesh-gateway-init image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} env: - name: NAMESPACE valueFrom: @@ -187,7 +186,6 @@ spec: containers: - name: mesh-gateway image: {{ .Values.global.imageConsulDataplane | quote }} - {{ template "consul.imagePullPolicy" . }} securityContext: capabilities: {{ if not .Values.meshGateway.hostNetwork}} diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml index 0ce8a921b2..21ad2930b8 100644 --- a/charts/consul/templates/partition-init-job.yaml +++ b/charts/consul/templates/partition-init-job.yaml @@ -85,7 +85,6 @@ spec: containers: - name: partition-init-job image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} env: {{- include "consul.consulK8sConsulServerEnvVars" . | nindent 10 }} diff --git a/charts/consul/templates/server-acl-init-cleanup-job.yaml b/charts/consul/templates/server-acl-init-cleanup-job.yaml index 3d7d6c8120..b47e04188f 100644 --- a/charts/consul/templates/server-acl-init-cleanup-job.yaml +++ b/charts/consul/templates/server-acl-init-cleanup-job.yaml @@ -61,7 +61,6 @@ spec: containers: - name: server-acl-init-cleanup image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} {{- if not .Values.server.containerSecurityContext.aclInit }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} {{- end }} diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index 0156c60f74..2e798a54d5 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -137,7 +137,6 @@ spec: containers: - name: server-acl-init-job image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} {{- if not .Values.server.containerSecurityContext.aclInit }} {{- include "consul.restrictedSecurityContext" . | nindent 8 }} {{- end }} @@ -305,6 +304,10 @@ spec: -partition-token-file=/vault/secrets/partition-token \ {{- end }} + {{- if .Values.apiGateway.enabled }} + -api-gateway-controller=true \ + {{- end }} + {{- if .Values.global.enableConsulNamespaces }} -enable-namespaces=true \ {{- /* syncCatalog must be enabled to set sync flags */}} diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index f8cb9b4def..315c8c4666 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -132,7 +132,7 @@ spec: {{- tpl .Values.server.annotations . | nindent 8 }} {{- end }} {{- if (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics) }} - {{- if (or (not .Values.global.metrics.datadog.enabled) (and .Values.global.metrics.datadog.enabled (.Values.global.metrics.datadog.dogstatsd.enabled))) }} + {{- if not .Values.global.metrics.datadog.openMetricsPrometheus.enabled }} "prometheus.io/scrape": "true" {{- if not (hasKey (default "" .Values.server.annotations | fromYaml) "prometheus.io/path")}} "prometheus.io/path": "/v1/agent/metrics" @@ -156,12 +156,12 @@ spec: "instances": [ { {{- if .Values.global.tls.enabled }} - "openmetrics_endpoint": "https://{{ template "consul.fullname" . }}-server.{{ .Release.Namespace }}.svc:8501/v1/agent/metrics?format=prometheus", + "openmetrics_endpoint": "https://consul-server.{{ .Release.Namespace }}.svc:8501/v1/agent/metrics?format=prometheus", "tls_cert": "/etc/datadog-agent/conf.d/consul.d/certs/tls.crt", "tls_private_key": "/etc/datadog-agent/conf.d/consul.d/certs/tls.key", "tls_ca_cert": "/etc/datadog-agent/conf.d/consul.d/ca/tls.crt", {{- else }} - "openmetrics_endpoint": "http://{{ template "consul.fullname" . }}-server.{{ .Release.Namespace }}.svc:8500/v1/agent/metrics?format=prometheus", + "openmetrics_endpoint": "http://consul-server.{{ .Release.Namespace }}.svc:8500/v1/agent/metrics?format=prometheus", {{- end }} {{- if ( .Values.global.acls.manageSystemACLs) }} "headers": { @@ -182,12 +182,12 @@ spec: "instances": [ { {{- if .Values.global.tls.enabled }} - "url": "https://{{ template "consul.fullname" . }}-server.{{ .Release.Namespace }}.svc:8501", + "url": "https://consul-server.{{ .Release.Namespace }}.svc:8501", "tls_cert": "/etc/datadog-agent/conf.d/consul.d/certs/tls.crt", "tls_private_key": "/etc/datadog-agent/conf.d/consul.d/certs/tls.key", "tls_ca_cert": "/etc/datadog-agent/conf.d/consul.d/ca/tls.crt", {{- else }} - "url": "http://{{ template "consul.fullname" . }}-server.{{ .Release.Namespace }}.svc:8500", + "url": "http://consul-server.consul.svc:8500", {{- end }} "use_prometheus_endpoint": true, {{- if ( .Values.global.acls.manageSystemACLs) }} @@ -226,8 +226,6 @@ spec: {{- toYaml .Values.server.securityContext | nindent 8 }} {{- end }} volumes: - - name: tmp - emptyDir: {} - name: config configMap: name: {{ template "consul.fullname" . }}-server-config @@ -296,7 +294,7 @@ spec: {{- if and .Values.global.metrics.datadog.enabled .Values.global.metrics.datadog.dogstatsd.enabled (eq .Values.global.metrics.datadog.dogstatsd.socketTransportType "UDS" ) }} - name: dsdsocket hostPath: - path: {{ dir .Values.global.metrics.datadog.dogstatsd.dogstatsdAddr | trimAll "\"" }} + path: /var/run/datadog type: DirectoryOrCreate {{- end }} {{- range .Values.server.extraVolumes }} @@ -321,7 +319,6 @@ spec: initContainers: - name: locality-init image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} env: - name: NODE_NAME valueFrom: @@ -339,7 +336,6 @@ spec: containers: - name: consul image: "{{ default .Values.global.image .Values.server.image | trimPrefix "\"" | trimSuffix "\"" }}" - {{ template "consul.imagePullPolicy" . }} imagePullPolicy: {{ .Values.global.imagePullPolicy }} env: - name: ADVERTISE_IP @@ -548,7 +544,7 @@ spec: {{- end }} {{- if and .Values.global.metrics.datadog.enabled .Values.global.metrics.datadog.dogstatsd.enabled (eq .Values.global.metrics.datadog.dogstatsd.socketTransportType "UDS" ) }} - name: dsdsocket - mountPath: {{ dir .Values.global.metrics.datadog.dogstatsd.dogstatsdAddr | trimAll "\"" }} + mountPath: /var/run/datadog readOnly: true {{- end }} {{- range .Values.server.extraVolumes }} @@ -566,9 +562,6 @@ spec: mountPath: /trusted-cas readOnly: false {{- end }} - - name: tmp - mountPath: /tmp - readOnly: false ports: {{- if (or (not .Values.global.tls.enabled) (not .Values.global.tls.httpsOnly)) }} - name: http @@ -659,7 +652,6 @@ spec: {{- if .Values.server.snapshotAgent.enabled }} - name: consul-snapshot-agent image: "{{ default .Values.global.image .Values.server.image }}" - {{ template "consul.imagePullPolicy" . }} env: {{- if .Values.server.snapshotAgent.caCert }} - name: SSL_CERT_DIR diff --git a/charts/consul/templates/sync-catalog-deployment.yaml b/charts/consul/templates/sync-catalog-deployment.yaml index 963e6b2485..3851f0a8e2 100644 --- a/charts/consul/templates/sync-catalog-deployment.yaml +++ b/charts/consul/templates/sync-catalog-deployment.yaml @@ -81,7 +81,6 @@ spec: containers: - name: sync-catalog image: "{{ default .Values.global.imageK8S .Values.syncCatalog.image }}" - {{ template "consul.imagePullPolicy" . }} {{- include "consul.restrictedSecurityContext" . | nindent 8 }} env: {{- include "consul.consulK8sConsulServerEnvVars" . | nindent 8 }} diff --git a/charts/consul/templates/telemetry-collector-deployment.yaml b/charts/consul/templates/telemetry-collector-deployment.yaml index 78326998f8..f7b6d7bd2e 100644 --- a/charts/consul/templates/telemetry-collector-deployment.yaml +++ b/charts/consul/templates/telemetry-collector-deployment.yaml @@ -143,7 +143,7 @@ spec: -service-name="" image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} + imagePullPolicy: IfNotPresent {{- if .Values.telemetryCollector.initContainer.resources }} resources: {{- toYaml .Values.telemetryCollector.initContainer.resources | nindent 12 }} @@ -171,7 +171,7 @@ spec: containers: - name: consul-telemetry-collector image: {{ .Values.telemetryCollector.image }} - {{ template "consul.imagePullPolicy" . }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} ports: - containerPort: 9090 name: metrics @@ -256,13 +256,9 @@ spec: {{- if eq (.Values.global.metrics.datadog.otlp.protocol | lower ) "http" }} - name: CO_OTEL_HTTP_ENDPOINT value: "http://$(HOST_IP):4318" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: "http://$(HOST_IP):4318" {{- else if eq (.Values.global.metrics.datadog.otlp.protocol | lower) "grpc" }} - name: CO_OTEL_HTTP_ENDPOINT - value: "http://$(HOST_IP):4317" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: "http://$(HOST_IP):4317" + value: "grpc://$(HOST_IP):4317" {{- end }} {{- end }} {{- include "consul.extraEnvironmentVars" .Values.telemetryCollector | nindent 12 }} @@ -299,7 +295,7 @@ spec: # consul-dataplane container - name: consul-dataplane image: "{{ .Values.global.imageConsulDataplane }}" - {{ template "consul.imagePullPolicy" . }} + imagePullPolicy: IfNotPresent command: - consul-dataplane args: diff --git a/charts/consul/templates/terminating-gateways-deployment.yaml b/charts/consul/templates/terminating-gateways-deployment.yaml index c4970979b1..9afe938e56 100644 --- a/charts/consul/templates/terminating-gateways-deployment.yaml +++ b/charts/consul/templates/terminating-gateways-deployment.yaml @@ -129,9 +129,6 @@ spec: terminationGracePeriodSeconds: 10 serviceAccountName: {{ template "consul.fullname" $root }}-{{ .name }} volumes: - - name: tmp - emptyDir: - medium: "Memory" - name: consul-service emptyDir: medium: "Memory" @@ -169,7 +166,6 @@ spec: # terminating-gateway-init registers the terminating gateway service with Consul. - name: terminating-gateway-init image: {{ $root.Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" $root }} {{- include "consul.restrictedSecurityContext" $ | nindent 10 }} env: - name: NAMESPACE @@ -210,8 +206,6 @@ spec: -log-level={{ default $root.Values.global.logLevel $root.Values.terminatingGateways.logLevel }} \ -log-json={{ $root.Values.global.logJSON }} volumeMounts: - - name: tmp - mountPath: /tmp - name: consul-service mountPath: /consul/service {{- if $root.Values.global.tls.enabled }} @@ -231,11 +225,8 @@ spec: containers: - name: terminating-gateway image: {{ $root.Values.global.imageConsulDataplane | quote }} - {{ template "consul.imagePullPolicy" $root }} {{- include "consul.restrictedSecurityContext" $ | nindent 10 }} volumeMounts: - - name: tmp - mountPath: /tmp - name: consul-service mountPath: /consul/service readOnly: true diff --git a/charts/consul/templates/tests/test-runner.yaml b/charts/consul/templates/tests/test-runner.yaml index 4c3e81ccea..b8b078003b 100644 --- a/charts/consul/templates/tests/test-runner.yaml +++ b/charts/consul/templates/tests/test-runner.yaml @@ -37,7 +37,6 @@ spec: containers: - name: consul-test image: "{{ .Values.global.image }}" - {{ template "consul.imagePullPolicy" . }} env: - name: HOST_IP valueFrom: diff --git a/charts/consul/templates/tls-init-cleanup-job.yaml b/charts/consul/templates/tls-init-cleanup-job.yaml index 5ebe236df5..9500410a53 100644 --- a/charts/consul/templates/tls-init-cleanup-job.yaml +++ b/charts/consul/templates/tls-init-cleanup-job.yaml @@ -49,7 +49,6 @@ spec: containers: - name: tls-init-cleanup image: "{{ .Values.global.image }}" - {{ template "consul.imagePullPolicy" . }} {{- if not .Values.server.containerSecurityContext.tlsInit }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} {{- end }} diff --git a/charts/consul/templates/tls-init-job.yaml b/charts/consul/templates/tls-init-job.yaml index 177472c9a4..41c0c2827e 100644 --- a/charts/consul/templates/tls-init-job.yaml +++ b/charts/consul/templates/tls-init-job.yaml @@ -64,7 +64,6 @@ spec: containers: - name: tls-init image: "{{ .Values.global.imageK8S }}" - {{ template "consul.imagePullPolicy" . }} {{- if not .Values.server.containerSecurityContext.tlsInit }} {{- include "consul.restrictedSecurityContext" . | nindent 10 }} {{- end }} diff --git a/charts/consul/templates/webhook-cert-manager-deployment.yaml b/charts/consul/templates/webhook-cert-manager-deployment.yaml index 0301331b9b..45c87c9ceb 100644 --- a/charts/consul/templates/webhook-cert-manager-deployment.yaml +++ b/charts/consul/templates/webhook-cert-manager-deployment.yaml @@ -51,7 +51,6 @@ spec: -deployment-name={{ template "consul.fullname" . }}-webhook-cert-manager \ -deployment-namespace={{ .Release.Namespace }} image: {{ .Values.global.imageK8S }} - {{ template "consul.imagePullPolicy" . }} name: webhook-cert-manager {{- include "consul.restrictedSecurityContext" . | nindent 8 }} resources: diff --git a/charts/consul/test/unit/api-gateway-controller-clusterrole.bats b/charts/consul/test/unit/api-gateway-controller-clusterrole.bats new file mode 100644 index 0000000000..f26fdfeebd --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-clusterrole.bats @@ -0,0 +1,45 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/ClusterRole: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-clusterrole.yaml \ + . +} + +@test "apiGateway/ClusterRole: enabled with apiGateway.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-clusterrole.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/ClusterRole: can use podsecuritypolicies with apiGateway.enabled=true and global.enablePodSecurityPolicies=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-clusterrole.yaml \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.rules[] | select((.resources[0] == "podsecuritypolicies") and (.verbs[0] == "use")) | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/ClusterRole: can create roles and rolebindings with apiGateway.enabled=true and global.enablePodSecurityPolicies=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-clusterrole.yaml \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.rules[] | select((.resources[0] == "roles") and (.resources[1] == "rolebindings") and (.verbs | contains(["create","get","list","watch"]))) | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats b/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats new file mode 100644 index 0000000000..3dfd94c36f --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats @@ -0,0 +1,22 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/ClusterRoleBinding: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-clusterrolebinding.yaml \ + . +} + +@test "apiGateway/ClusterRoleBinding: enabled with global.enabled false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-clusterrolebinding.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq -s 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats new file mode 100755 index 0000000000..696d5f7cbb --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -0,0 +1,1754 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/Deployment: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + . +} + +@test "apiGateway/Deployment: fails if no image is set" { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "apiGateway.image must be set to enable api gateway" ]] +} + +@test "apiGateway/Deployment: disable with apiGateway.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=false' \ + . +} + +@test "apiGateway/Deployment: disable with global.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'global.enabled=false' \ + . +} + +@test "apiGateway/Deployment: enable namespaces" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-consul-destination-namespace=default")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: enable namespace mirroring" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'connectInject.consulNamespaces.mirroringK8S=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirroring-k8s=true")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: enable namespace mirroring prefixes" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'connectInject.consulNamespaces.mirroringK8S=true' \ + --set 'connectInject.consulNamespaces.mirroringK8SPrefix=foo' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirroring-k8s-prefix=foo")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: container image overrides" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].image' | tee /dev/stderr) + [ "${actual}" = "\"bar\"" ] +} + +@test "apiGateway/Deployment: SDS host set correctly" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-sds-server-host release-name-consul-api-gateway-controller.default.svc")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# nodeSelector + +@test "apiGateway/Deployment: nodeSelector is not set by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.spec.template.spec.nodeSelector' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "apiGateway/Deployment: specified nodeSelector" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.controller.nodeSelector=testing' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.nodeSelector' | tee /dev/stderr) + [ "${actual}" = "testing" ] +} + +#-------------------------------------------------------------------- +# global.tls.enabled + +@test "apiGateway/Deployment: Adds tls-ca-cert volume when global.tls.enabled is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" != "" ] +} + +@test "apiGateway/Deployment: Adds tls-ca-cert volumeMounts when global.tls.enabled is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" != "" ] +} + +@test "apiGateway/Deployment: can overwrite CA secret with the provided one" { + cd `chart_dir` + local ca_cert_volume=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=foo-ca-cert' \ + --set 'global.tls.caCert.secretKey=key' \ + --set 'global.tls.caKey.secretName=foo-ca-key' \ + --set 'global.tls.caKey.secretKey=key' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name=="consul-ca-cert")' | tee /dev/stderr) + + # check that the provided ca cert secret is attached as a volume + local actual + actual=$(echo $ca_cert_volume | jq -r '.secret.secretName' | tee /dev/stderr) + [ "${actual}" = "foo-ca-cert" ] + + # check that the volume uses the provided secret key + actual=$(echo $ca_cert_volume | jq -r '.secret.items[0].key' | tee /dev/stderr) + [ "${actual}" = "key" ] +} + +#-------------------------------------------------------------------- +# global.tls.enableAutoEncrypt + +@test "apiGateway/Deployment: consul-auto-encrypt-ca-cert volume is added when TLS with auto-encrypt is enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name == "consul-auto-encrypt-ca-cert") | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: consul-auto-encrypt-ca-cert volumeMount is added when TLS with auto-encrypt is enabled with clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'client.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-auto-encrypt-ca-cert") | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: consul-ca-cert volumeMount is added when TLS with auto-encrypt is enabled without clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-ca-cert") | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: get-auto-encrypt-client-ca init container is created when TLS with auto-encrypt is enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "get-auto-encrypt-client-ca") | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: adds both init containers when TLS with auto-encrypt and ACLs + namespaces are enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers | length == 3' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: consul-ca-cert volume is not added if externalServers.enabled=true and externalServers.useSystemRoots=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo.com' \ + --set 'externalServers.useSystemRoots=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +#-------------------------------------------------------------------- +# global.acls.manageSystemACLs + +@test "apiGateway/Deployment: consul-logout preStop hook is added when ACLs are enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].lifecycle.preStop.exec.command[1]] | any(contains("logout"))' | tee /dev/stderr) + [ "${object}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_TOKEN_FILE is not set when acls are disabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[1].name] | any(contains("CONSUL_HTTP_TOKEN_FILE"))' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_TOKEN_FILE is set when acls are enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[1].name] | any(contains("CONSUL_HTTP_TOKEN_FILE"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_LOGIN_DATACENTER is set when acls are enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[2].name] | any(contains("CONSUL_LOGIN_DATACENTER"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: init container is created when global.acls.manageSystemACLs=true" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1]' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.name' | tee /dev/stderr) + [ "${actual}" = "api-gateway-controller-acl-init" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[0].name] | any(contains("NAMESPACE"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[1].name] | any(contains("POD_NAME"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[2].name] | any(contains("CONSUL_LOGIN_META"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[2].value] | any(contains("component=api-gateway-controller,pod=$(NAMESPACE)/$(POD_NAME)"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].name] | any(contains("CONSUL_LOGIN_DATACENTER"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '[.env[8].value] | any(contains("5s"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command and environment with tls enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.consulAPITimeout=5s' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "api-gateway-controller-acl-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "NAMESPACE") | [.valueFrom.fieldRef.fieldPath] | any(contains("metadata.namespace"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "POD_NAME") | [.valueFrom.fieldRef.fieldPath] | any(contains("metadata.name"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_LOGIN_META") | [.value] | any(contains("component=api-gateway-controller,pod=$(NAMESPACE)/$(POD_NAME)"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_ADDRESSES") | [.value] | any(contains("release-name-consul-server.default.svc"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_GRPC_PORT") | [.value] | any(contains("8502"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_HTTP_PORT") | [.value] | any(contains("8501"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_DATACENTER") | [.value] | any(contains("dc1"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_API_TIMEOUT") | [.value] | any(contains("5s"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_USE_TLS") | [.value] | any(contains("true"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_CACERT_FILE") | [.value] | any(contains("/consul/tls/ca/tls.crt"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[] | select(.name == "consul-ca-cert") | [.mountPath] | any(contains("/consul/tls/ca"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[] | select(.name == "consul-data") | [.mountPath] | any(contains("/consul/login"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command with Partitions enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=default' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "api-gateway-controller-acl-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("-auth-method-name=release-name-consul-k8s-component-auth-method"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "NAMESPACE") | [.valueFrom.fieldRef.fieldPath] | any(contains("metadata.namespace"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "POD_NAME") | [.valueFrom.fieldRef.fieldPath] | any(contains("metadata.name"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_LOGIN_META") | [.value] | any(contains("component=api-gateway-controller,pod=$(NAMESPACE)/$(POD_NAME)"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_ADDRESSES") | [.value] | any(contains("release-name-consul-server.default.svc"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_GRPC_PORT") | [.value] | any(contains("8502"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_HTTP_PORT") | [.value] | any(contains("8501"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_DATACENTER") | [.value] | any(contains("dc1"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_API_TIMEOUT") | [.value] | any(contains("5s"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_PARTITION") | [.value] | any(contains("default"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_LOGIN_PARTITION") | [.value] | any(contains("default"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_USE_TLS") | [.value] | any(contains("true"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_CACERT_FILE") | [.value] | any(contains("/consul/tls/ca/tls.crt"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[] | select(.name == "consul-ca-cert") | [.mountPath] | any(contains("/consul/tls/ca"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[] | select(.name == "consul-data") | [.mountPath] | any(contains("/consul/login"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: consul login datacenter is set to primary when when federation enabled in non-primary datacenter" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'meshGateway.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.datacenter=dc1' \ + --set 'global.federation.enabled=true' \ + --set 'global.federation.primaryDatacenter=dc2' \ + --set 'global.tls.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1]' | tee /dev/stderr) + + local actual=$(echo $object | + yq '[.env[3].name] | any(contains("CONSUL_LOGIN_DATACENTER"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].value] | any(contains("dc2"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: primary-datacenter flag provided when federation enabled in non-primary datacenter" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.datacenter=dc2' \ + --set 'global.federation.enabled=true' \ + --set 'global.federation.primaryDatacenter=dc1' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[] | select(.name == "api-gateway-controller")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-api-gateway server"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("-primary-datacenter=dc1"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command when federation enabled in non-primary datacenter" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.datacenter=dc2' \ + --set 'global.federation.enabled=true' \ + --set 'global.federation.primaryDatacenter=dc1' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "api-gateway-controller-acl-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("-auth-method-name=release-name-consul-k8s-component-auth-method-dc2"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].value] | any(contains("dc1"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command and environment with tls enabled and autoencrypt enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "api-gateway-controller-acl-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "NAMESPACE") | [.valueFrom.fieldRef.fieldPath] | any(contains("metadata.namespace"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "POD_NAME") | [.valueFrom.fieldRef.fieldPath] | any(contains("metadata.name"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_LOGIN_META") | [.value] | any(contains("component=api-gateway-controller,pod=$(NAMESPACE)/$(POD_NAME)"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_ADDRESSES") | [.value] | any(contains("release-name-consul-server.default.svc"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_GRPC_PORT") | [.value] | any(contains("8502"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_HTTP_PORT") | [.value] | any(contains("8501"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_DATACENTER") | [.value] | any(contains("dc1"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_API_TIMEOUT") | [.value] | any(contains("5s"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_USE_TLS") | [.value] | any(contains("true"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.env[] | select(.name == "CONSUL_CACERT_FILE") | [.value] | any(contains("/consul/tls/ca/tls.crt"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[] | select(.name == "consul-ca-cert") | [.mountPath] | any(contains("/consul/tls/ca"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[] | select(.name == "consul-data") | [.mountPath] | any(contains("/consul/login"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: init container for copy consul is created when global.acls.manageSystemACLs=true" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "copy-consul-bin")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("cp"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.volumeMounts[0] | any(contains("consul-bin"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: volumeMount for copy consul is created on container when global.acls.manageSystemACLs=true" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[0] | any(contains("consul-bin"))' | tee /dev/stderr) + + [ "${object}" = "true" ] +} + +@test "apiGateway/Deployment: volume for copy consul is created when global.acls.manageSystemACLs=true" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[0] | any(contains("consul-bin"))' | tee /dev/stderr) + + [ "${object}" = "true" ] +} + +@test "apiGateway/Deployment: auto-encrypt init container is created and is the first init-container when global.acls.manageSystemACLs=true and has correct command and environment with tls enabled and autoencrypt enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1]' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.name' | tee /dev/stderr) + [ "${actual}" = "get-auto-encrypt-client-ca" ] +} + +#-------------------------------------------------------------------- +# resources + +@test "apiGateway/Deployment: resources has default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].resources' | tee /dev/stderr) + + [ $(echo "${actual}" | yq -r '.requests.memory') = "100Mi" ] + [ $(echo "${actual}" | yq -r '.requests.cpu') = "100m" ] + [ $(echo "${actual}" | yq -r '.limits.memory') = "100Mi" ] + [ $(echo "${actual}" | yq -r '.limits.cpu') = "100m" ] +} + +@test "apiGateway/Deployment: resources can be overridden" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.resources.foo=bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].resources.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + +#-------------------------------------------------------------------- +# init container resources + +@test "apiGateway/Deployment: init container has default resources" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.initContainers[0].resources' | tee /dev/stderr) + + [ $(echo "${actual}" | yq -r '.requests.memory') = "25Mi" ] + [ $(echo "${actual}" | yq -r '.requests.cpu') = "50m" ] + [ $(echo "${actual}" | yq -r '.limits.memory') = "150Mi" ] + [ $(echo "${actual}" | yq -r '.limits.cpu') = "50m" ] +} + +@test "apiGateway/Deployment: init container resources can be set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'apiGateway.initCopyConsulContainer.resources.requests.memory=memory' \ + --set 'apiGateway.initCopyConsulContainer.resources.requests.cpu=cpu' \ + --set 'apiGateway.initCopyConsulContainer.resources.limits.memory=memory2' \ + --set 'apiGateway.initCopyConsulContainer.resources.limits.cpu=cpu2' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.initContainers[0].resources' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.requests.memory' | tee /dev/stderr) + [ "${actual}" = "memory" ] + + local actual=$(echo $object | yq -r '.requests.cpu' | tee /dev/stderr) + [ "${actual}" = "cpu" ] + + local actual=$(echo $object | yq -r '.limits.memory' | tee /dev/stderr) + [ "${actual}" = "memory2" ] + + local actual=$(echo $object | yq -r '.limits.cpu' | tee /dev/stderr) + [ "${actual}" = "cpu2" ] +} + +#-------------------------------------------------------------------- +# priorityClassName + +@test "apiGateway/Deployment: no priorityClassName by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) + + [ "${actual}" = "null" ] +} + +@test "apiGateway/Deployment: can set a priorityClassName" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.controller.priorityClassName=name' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) + + [ "${actual}" = "name" ] +} + +#-------------------------------------------------------------------- +# logLevel + +@test "apiGateway/Deployment: logLevel info by default from global" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual=$(echo "$cmd" | + yq 'any(contains("-log-level info"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: logLevel can be overridden" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.logLevel=debug' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual=$(echo "$cmd" | + yq 'any(contains("-log-level debug"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# replicas + +@test "apiGateway/Deployment: replicas defaults to 1" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.spec.replicas' | tee /dev/stderr) + + [ "${actual}" = "1" ] +} + +@test "apiGateway/Deployment: replicas can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.controller.replicas=3' \ + . | tee /dev/stderr | + yq '.spec.replicas' | tee /dev/stderr) + + [ "${actual}" = "3" ] +} + + +#-------------------------------------------------------------------- +# get-auto-encrypt-client-ca + +@test "apiGateway/Deployment: get-auto-encrypt-client-ca uses server's stateful set address by default and passes ca cert" { + cd `chart_dir` + local command=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "get-auto-encrypt-client-ca").command | join(" ")' | tee /dev/stderr) + + # check server address + actual=$(echo $command | jq ' . | contains("-server-addr=release-name-consul-server")') + [ "${actual}" = "true" ] + + # check server port + actual=$(echo $command | jq ' . | contains("-server-port=8501")') + [ "${actual}" = "true" ] + + # check server's CA cert + actual=$(echo $command | jq ' . | contains("-ca-file=/consul/tls/ca/tls.crt")') + [ "${actual}" = "true" ] + + # check consul-api-timeout + actual=$(echo $command | jq ' . | contains("-consul-api-timeout=5s")') + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# Vault + +@test "apiGateway/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} + +@test "apiGateway/Deployment: vault tls annotations are set when tls is enabled" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/cert/ca\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/cert/ca" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr)" + [ "${actual}" = "test" ] +} + +@test "apiGateway/Deployment: vault namespace annotations is set when global.secretsBackend.vault.vaultNamespace is set" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.vaultNamespace=vns' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/namespace"]' | tee /dev/stderr)" + [ "${actual}" = "vns" ] +} + +@test "apiGateway/Deployment: correct vault namespace annotations is set when global.secretsBackend.vault.vaultNamespace is set and agentAnnotations are set without vaultNamespace annotation" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.vaultNamespace=vns' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.agentAnnotations=vault.hashicorp.com/agent-extra-secret: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/namespace"]' | tee /dev/stderr)" + [ "${actual}" = "vns" ] +} + +@test "apiGateway/Deployment: correct vault namespace annotations is set when global.secretsBackend.vault.vaultNamespace is set and agentAnnotations are also set with vaultNamespace annotation" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.vaultNamespace=vns' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.agentAnnotations="vault.hashicorp.com/namespace": bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/namespace"]' | tee /dev/stderr)" + [ "${actual}" = "bar" ] +} + +@test "apiGateway/Deployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + +#-------------------------------------------------------------------- +# global.cloud + +@test "apiGateway/Deployment: fails when global.cloud.enabled is true and global.cloud.clientId.secretName is not set but global.cloud.clientSecret.secretName and global.cloud.resourceId.secretName is set" { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientSecret.secretName=client-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-id-key' \ + --set 'global.cloud.resourceId.secretName=client-resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=client-resource-id-key' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "When global.cloud.enabled is true, global.cloud.resourceId.secretName, global.cloud.clientId.secretName, and global.cloud.clientSecret.secretName must also be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.enabled is true and global.cloud.clientSecret.secretName is not set but global.cloud.clientId.secretName and global.cloud.resourceId.secretName is set" { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=resource-id-key' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "When global.cloud.enabled is true, global.cloud.resourceId.secretName, global.cloud.clientId.secretName, and global.cloud.clientSecret.secretName must also be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.enabled is true and global.cloud.resourceId.secretName is not set but global.cloud.clientId.secretName and global.cloud.clientSecret.secretName is set" { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "When global.cloud.enabled is true, global.cloud.resourceId.secretName, global.cloud.clientId.secretName, and global.cloud.clientSecret.secretName must also be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.resourceId.secretName is set but global.cloud.resourceId.secretKey is not set." { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "When either global.cloud.resourceId.secretName or global.cloud.resourceId.secretKey is defined, both must be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.authURL.secretName is set but global.cloud.authURL.secretKey is not set." { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=resource-id-key' \ + --set 'global.cloud.authUrl.secretName=auth-url-name' \ + . + [ "$status" -eq 1 ] + + [[ "$output" =~ "When either global.cloud.authUrl.secretName or global.cloud.authUrl.secretKey is defined, both must be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.authURL.secretKey is set but global.cloud.authURL.secretName is not set." { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=resource-id-key' \ + --set 'global.cloud.authUrl.secretKey=auth-url-key' \ + . + [ "$status" -eq 1 ] + + [[ "$output" =~ "When either global.cloud.authUrl.secretName or global.cloud.authUrl.secretKey is defined, both must be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.apiHost.secretName is set but global.cloud.apiHost.secretKey is not set." { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=resource-id-key' \ + --set 'global.cloud.apiHost.secretName=auth-url-name' \ + . + [ "$status" -eq 1 ] + + [[ "$output" =~ "When either global.cloud.apiHost.secretName or global.cloud.apiHost.secretKey is defined, both must be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.apiHost.secretKey is set but global.cloud.apiHost.secretName is not set." { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=resource-id-key' \ + --set 'global.cloud.apiHost.secretKey=auth-url-key' \ + . + [ "$status" -eq 1 ] + + [[ "$output" =~ "When either global.cloud.apiHost.secretName or global.cloud.apiHost.secretKey is defined, both must be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.scadaAddress.secretName is set but global.cloud.scadaAddress.secretKey is not set." { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=resource-id-key' \ + --set 'global.cloud.scadaAddress.secretName=scada-address-name' \ + . + [ "$status" -eq 1 ] + + [[ "$output" =~ "When either global.cloud.scadaAddress.secretName or global.cloud.scadaAddress.secretKey is defined, both must be set." ]] +} + +@test "apiGateway/Deployment: fails when global.cloud.scadaAddress.secretKey is set but global.cloud.scadaAddress.secretName is not set." { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc-foo' \ + --set 'global.domain=bar' \ + --set 'global.cloud.enabled=true' \ + --set 'global.cloud.clientId.secretName=client-id-name' \ + --set 'global.cloud.clientId.secretKey=client-id-key' \ + --set 'global.cloud.clientSecret.secretName=client-secret-id-name' \ + --set 'global.cloud.clientSecret.secretKey=client-secret-id-key' \ + --set 'global.cloud.resourceId.secretName=resource-id-name' \ + --set 'global.cloud.resourceId.secretKey=resource-id-key' \ + --set 'global.cloud.scadaAddress.secretKey=scada-address-key' \ + . + [ "$status" -eq 1 ] + + [[ "$output" =~ "When either global.cloud.scadaAddress.secretName or global.cloud.scadaAddress.secretKey is defined, both must be set." ]] +} + +#-------------------------------------------------------------------- +# CONSUL_HTTP_SSL + +@test "apiGateway/Deployment: CONSUL_HTTP_SSL set correctly when not using TLS." { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[2].value' | tee /dev/stderr) + [ "${actual}" = "\"false\"" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_SSL set correctly when using TLS." { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[3].value' | tee /dev/stderr) + [ "${actual}" = "\"true\"" ] +} + +#-------------------------------------------------------------------- +# CONSUL_HTTP_ADDR + +@test "apiGateway/Deployment: CONSUL_HTTP_ADDR set correctly with external servers, TLS, and no clients." { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.httpsPort=8501' \ + --set 'server.enabled=false' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[2].value] | any(contains("external-consul.host:8501"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_ADDR set correctly with external servers, no TLS, and no clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=false' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.httpsPort=8500' \ + --set 'server.enabled=false' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[1].value] | any(contains("external-consul.host:8500"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_ADDR set correctly with local servers, TLS, and clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'client.enabled=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[2].value] | any(contains("$(HOST_IP):8501"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_ADDR set correctly with local servers, no TLS, and clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=false' \ + --set 'client.enabled=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[1].value] | any(contains("$(HOST_IP):8500"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_ADDR set correctly with local servers, TLS, and no clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[2].value] | any(contains("release-name-consul-server:8501"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_HTTP_ADDR set correctly with local servers, no TLS, and no clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=false' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[1].value] | any(contains("release-name-consul-server:8500"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# externalServers tlsServerName + +@test "apiGateway/Deployment: CONSUL_TLS_SERVER_NAME can be set for externalServers" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.httpsPort=8501' \ + --set 'externalServers.tlsServerName=hashi' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[4].value == "hashi"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_TLS_SERVER_NAME will not be set for when clients are used" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.httpsPort=8501' \ + --set 'externalServers.tlsServerName=hashi' \ + --set 'client.enabled=true' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[] | select (.name == "api-gateway-controller") | .env[] | select(.name == "CONSUL_TLS_SERVER_NAME")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +#-------------------------------------------------------------------- +# Admin Partitions + +@test "apiGateway/Deployment: CONSUL_PARTITION is set when using admin partitions" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=hashi' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[3].value == "hashi"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_LOGIN_PARTITION is set when using admin partitions with ACLs" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=hashi' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[6].value == "hashi"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_DYNAMIC_SERVER_DISCOVERY is set when not using clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[3].value == "true"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_DYNAMIC_SERVER_DISCOVERY is not set when using clients" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'client.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[3]' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "apiGateway/Deployment: CONSUL_CACERT is set when using tls and clients even when useSystemRoots is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'server.enabled=false' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.useSystemRoots=true' \ + --set 'client.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[0].name == "CONSUL_CACERT"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_CACERT is set when using tls and internal servers" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'server.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[0].name == "CONSUL_CACERT"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_CACERT has correct path with Vault as secrets backend and client disabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'server.enabled=true' \ + --set 'client.enabled=false' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + . | tee /dev/stderr| + yq '.spec.template.spec.containers[0].env[0].value == "/vault/secrets/serverca.crt"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: CONSUL_CACERT is not set when using tls and useSystemRoots" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.tls.enabled=true' \ + --set 'server.enabled=false' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.useSystemRoots=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].env[0].name == "CONSUL_CACERT"' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: consul-ca-cert volume mount is not set when using externalServers and useSystemRoots" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'server.enabled=false' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.useSystemRoots=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +@test "apiGateway/Deployment: consul-ca-cert volume mount is not set when using Vault as a secrets backend" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'server.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +@test "apiGateway/Deployment: consul-ca-cert volume mount is not set on acl-init when using externalServers and useSystemRoots" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'server.enabled=false' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.useSystemRoots=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +@test "apiGateway/Deployment: consul-ca-cert volume mount is not set on acl-init when using Vault as secrets backend" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'server.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +@test "apiGateway/Deployment: consul-auto-encrypt-ca-cert volume mount is set when tls.enabled, client.enabled, externalServers, useSystemRoots, and autoencrypt" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'client.enabled=true' \ + --set 'server.enabled=false' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.useSystemRoots=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-auto-encrypt-ca-cert") | .mountPath' | tee /dev/stderr) + [ "${actual}" = '"/consul/tls/ca"' ] +} + +#-------------------------------------------------------------------- +# extraLabels + +@test "apiGateway/Deployment: no extra labels defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.labels | del(."app") | del(."chart") | del(."release") | del(."component")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "apiGateway/Deployment: extra global labels can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.extraLabels.foo=bar' \ + . | tee /dev/stderr) + local actualBar=$(echo "${actual}" | yq -r '.metadata.labels.foo' | tee /dev/stderr) + [ "${actualBar}" = "bar" ] + local actualTemplateBar=$(echo "${actual}" | yq -r '.spec.template.metadata.labels.foo' | tee /dev/stderr) + [ "${actualTemplateBar}" = "bar" ] +} + +@test "apiGateway/Deployment: multiple global extra labels can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.extraLabels.foo=bar' \ + --set 'global.extraLabels.baz=qux' \ + . | tee /dev/stderr) + local actualFoo=$(echo "${actual}" | yq -r '.metadata.labels.foo' | tee /dev/stderr) + local actualBaz=$(echo "${actual}" | yq -r '.metadata.labels.baz' | tee /dev/stderr) + [ "${actualFoo}" = "bar" ] + [ "${actualBaz}" = "qux" ] + local actualTemplateFoo=$(echo "${actual}" | yq -r '.spec.template.metadata.labels.foo' | tee /dev/stderr) + local actualTemplateBaz=$(echo "${actual}" | yq -r '.spec.template.metadata.labels.baz' | tee /dev/stderr) + [ "${actualTemplateFoo}" = "bar" ] + [ "${actualTemplateBaz}" = "qux" ] +} diff --git a/charts/consul/test/unit/api-gateway-controller-podsecuritypolicy.bats b/charts/consul/test/unit/api-gateway-controller-podsecuritypolicy.bats new file mode 100644 index 0000000000..dfd40c793f --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-podsecuritypolicy.bats @@ -0,0 +1,22 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/PodSecurityPolicy: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-podsecuritypolicy.yaml \ + . +} + +@test "apiGateway/PodSecurityPolicy: enabled with apiGateway.enabled=true and global.enablePodSecurityPolicies=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-podsecuritypolicy.yaml \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/api-gateway-controller-service.bats b/charts/consul/test/unit/api-gateway-controller-service.bats new file mode 100755 index 0000000000..47cb7ff9aa --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-service.bats @@ -0,0 +1,30 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/Service: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-service.yaml \ + . +} + +@test "apiGateway/Service: enable with apiGateway.enabled set to true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-service.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Service: disable with apiGateway.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-service.yaml \ + --set 'apiGateway.enabled=false' \ + . +} diff --git a/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats new file mode 100644 index 0000000000..22486799b2 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats @@ -0,0 +1,76 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/ServiceAccount: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + . +} + +@test "apiGateway/ServiceAccount: enabled with apiGateway.enabled true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq -s 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/ServiceAccount: disabled with apiGateway.enabled false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=false' \ + . +} +#-------------------------------------------------------------------- +# global.imagePullSecrets + +@test "apiGateway/ServiceAccount: can set image pull secrets" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.imagePullSecrets[0].name=my-secret' \ + --set 'global.imagePullSecrets[1].name=my-secret2' \ + . | tee /dev/stderr) + + local actual=$(echo "$object" | + yq -r '.imagePullSecrets[0].name' | tee /dev/stderr) + [ "${actual}" = "my-secret" ] + + local actual=$(echo "$object" | + yq -r '.imagePullSecrets[1].name' | tee /dev/stderr) + [ "${actual}" = "my-secret2" ] +} + +#-------------------------------------------------------------------- +# apiGateway.serviceAccount.annotations + +@test "apiGateway/ServiceAccount: no annotations by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.metadata.annotations | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "apiGateway/ServiceAccount: annotations when enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set "apiGateway.serviceAccount.annotations=foo: bar" \ + . | tee /dev/stderr | + yq -r '.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} diff --git a/charts/consul/test/unit/api-gateway-gatewayclass.bats b/charts/consul/test/unit/api-gateway-gatewayclass.bats new file mode 100755 index 0000000000..c79753c2f3 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-gatewayclass.bats @@ -0,0 +1,48 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/GatewayClass: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + . +} + +@test "apiGateway/GatewayClass: enable with global.enabled false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClass: disable with apiGateway.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'apiGateway.enabled=false' \ + . +} + +@test "apiGateway/GatewayClass: disable with global.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'global.enabled=false' \ + . +} + +@test "apiGateway/GatewayClass: disable with apiGateway.managedGatewayClass.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.managedGatewayClass.enabled=false' \ + . +} diff --git a/charts/consul/test/unit/api-gateway-gatewayclassconfig.bats b/charts/consul/test/unit/api-gateway-gatewayclassconfig.bats new file mode 100644 index 0000000000..742f31afa0 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-gatewayclassconfig.bats @@ -0,0 +1,186 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/GatewayClassConfig: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + . +} + +@test "apiGateway/GatewayClassConfig: enabled with apiGateway.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: deployment config disabled by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.spec | has("deployment") | not' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: deployment config enabled with defaultInstances=3" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.managedGatewayClass.deployment.defaultInstances=3' \ + . | tee /dev/stderr | + yq '.spec.deployment.defaultInstances == 3' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: deployment config enabled with maxInstances=3" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.managedGatewayClass.deployment.maxInstances=3' \ + . | tee /dev/stderr | + yq '.spec.deployment.maxInstances == 3' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: deployment config enabled with minInstances=3" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.managedGatewayClass.deployment.minInstances=3' \ + . | tee /dev/stderr | + yq '.spec.deployment.minInstances == 3' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: imageEnvoy can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'apiGateway.imageEnvoy=bar' \ + . | tee /dev/stderr | + yq '.spec.image.envoy' | tee /dev/stderr) + [ "${actual}" = "\"bar\"" ] +} + +#-------------------------------------------------------------------- +# Consul server address + +@test "apiGateway/GatewayClassConfig: Consul server address set with external servers and no clients." { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'server.enabled=false' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.consul.address == "external-consul.host"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: Consul server address set with external servers and clients." { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'server.enabled=false' \ + --set 'client.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.consul.address == "$(HOST_IP)"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: Consul server address set with local servers and no clients." { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'client.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.consul.address == "release-name-consul-server.default.svc"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClassConfig: Consul server address set with local servers and clients." { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'client.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.consul.address == "$(HOST_IP)"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# externalServers ports + +@test "apiGateway/GatewayClassConfig: ports for externalServers when not using TLS." { + cd `chart_dir` + local ports=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=false' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.grpcPort=1234' \ + --set 'externalServers.httpsPort=5678' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.consul.ports' | tee /dev/stderr) + + local actual + actual=$(echo $ports | jq -r '.grpc' | tee /dev/stderr) + [ "${actual}" = "1234" ] + + actual=$(echo $ports | jq -r '.http' | tee /dev/stderr) + [ "${actual}" = "5678" ] +} + +@test "apiGateway/GatewayClassConfig: ports for externalServers when using TLS." { + cd `chart_dir` + local ports=$(helm template \ + -s templates/api-gateway-gatewayclassconfig.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + --set 'global.tls.enabled=true' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=external-consul.host' \ + --set 'externalServers.grpcPort=1234' \ + --set 'externalServers.httpsPort=5678' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.consul.ports' | tee /dev/stderr) + + local actual + actual=$(echo $ports | jq -r '.grpc' | tee /dev/stderr) + [ "${actual}" = "1234" ] + + actual=$(echo $ports | jq -r '.http' | tee /dev/stderr) + [ "${actual}" = "5678" ] +} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 00fb346e26..77c23c4672 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -2824,6 +2824,8 @@ rollingUpdate: cd `chart_dir` run helm template \ -s templates/client-daemonset.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.datacenter=dc-foo' \ @@ -2842,6 +2844,8 @@ rollingUpdate: cd `chart_dir` run helm template \ -s templates/client-daemonset.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.datacenter=dc-foo' \ @@ -2861,6 +2865,8 @@ rollingUpdate: cd `chart_dir` run helm template \ -s templates/client-daemonset.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.datacenter=dc-foo' \ @@ -2883,6 +2889,8 @@ rollingUpdate: cd `chart_dir` run helm template \ -s templates/client-daemonset.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.datacenter=dc-foo' \ diff --git a/charts/consul/test/unit/gateway-resources-configmap.bats b/charts/consul/test/unit/gateway-resources-configmap.bats index ea3decc5c7..e827644792 100644 --- a/charts/consul/test/unit/gateway-resources-configmap.bats +++ b/charts/consul/test/unit/gateway-resources-configmap.bats @@ -94,28 +94,6 @@ target=templates/gateway-resources-configmap.yaml } -#-------------------------------------------------------------------- -# API Gateway logLevel configuration - -@test "gateway-resources/ConfigMap: API Gateway logLevel default configuration" { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'meshGateway.enabled=false' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.container.consul.logging.level') - [ "${actual}" = 'info' ] - - local actual=$(echo "$config" | yq -r '.initContainer.consul.logging.level') - [ "${actual}" = 'info' ] -} - - - @test "gateway-resources/ConfigMap: Mesh Gateway logLevel custom global configuration" { cd `chart_dir` local config=$(helm template \ @@ -221,17 +199,16 @@ target=templates/gateway-resources-configmap.yaml . | tee /dev/stderr | yq -r '.data["config.yaml"]' | yq -r '.meshGateways[0].metadata.annotations' | tee /dev/stderr) - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-address-source"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-address-source"]') [ "${actual}" = 'Service' ] - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-port"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-port"]') [ "${actual}" = '443' ] - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-address-static"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-address-static"]') [ "${actual}" = '' ] } - @test "gateway-resources/ConfigMap: Mesh Gateway WAN Address NodePort annotations" { cd `chart_dir` local annotations=$(helm template \ @@ -246,13 +223,13 @@ target=templates/gateway-resources-configmap.yaml . | tee /dev/stderr | yq -r '.data["config.yaml"]' | yq -r '.meshGateways[0].metadata.annotations' | tee /dev/stderr) - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-address-source"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-address-source"]') [ "${actual}" = 'Service' ] - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-port"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-port"]') [ "${actual}" = '30000' ] - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-address-static"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-address-static"]') [ "${actual}" = '' ] } @@ -269,209 +246,13 @@ target=templates/gateway-resources-configmap.yaml . | tee /dev/stderr | yq -r '.data["config.yaml"]' | yq -r '.meshGateways[0].metadata.annotations' | tee /dev/stderr) - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-address-source"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-address-source"]') [ "${actual}" = 'Static' ] - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-port"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-port"]') [ "${actual}" = '443' ] - local actual=$(echo "$annotations" | yq -r '.["consul.hashicorp.com/gateway-wan-address-static"]') + local actual=$(echo "$annotations" | jq -r '.["consul.hashicorp.com/gateway-wan-address-static"]') [ "${actual}" = '127.0.0.1' ] } -#-------------------------------------------------------------------- -# API Gateway Tests mapPrivilageContainerPorts - -@test "gateway-resources/ConfigMap: API Gateway mapPrivilageContainerPorts empty by default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.container.portModifier') - - [ "${actual}" = 'null' ] - - local actual=$(echo "$config" | yq -r '.initContainer.portModifier') - - [ "${actual}" = 'null' ] -} - - -@test "gateway-resources/ConfigMap: API Gateway mapPrivilageContainerPorts overrides default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - --set 'connectInject.apiGateway.managedGatewayClass.mapPrivilegedContainerPorts=80' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.container.portModifier') - - [ "${actual}" = '80' ] - - local actual=$(echo "$config" | yq -r '.initContainer.portModifier') - - [ "${actual}" = '80' ] -} - -#-------------------------------------------------------------------- -# API Gateway Tests deployment replicas - -@test "gateway-resources/ConfigMap: API Gateway deploymentConfig overrides default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - --set 'connectInject.apiGateway.managedGatewayClass.deployment.defaultInstances=2' \ - --set 'connectInject.apiGateway.managedGatewayClass.deployment.maxInstances=3' \ - --set 'connectInject.apiGateway.managedGatewayClass.deployment.minInstances=1' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.replicas.default') - [ "${actual}" = '2' ] - - local actual=$(echo "$config" | yq -r '.replicas.min') - [ "${actual}" = '1' ] - - local actual=$(echo "$config" | yq -r '.replicas.max') - [ "${actual}" = '3' ] -} - -@test "gateway-resources/ConfigMap: API Gateway deploymentConfig default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.replicas.default') - [ "${actual}" = '1' ] - - local actual=$(echo "$config" | yq -r '.replicas.min') - [ "${actual}" = '1' ] - - local actual=$(echo "$config" | yq -r '.replicas.max') - [ "${actual}" = '1' ] -} - -#-------------------------------------------------------------------- -# API Gateway Tests nodeSelector - -@test "gateway-resources/ConfigMap: API Gateway nodeSelector overrides default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - --set 'connectInject.apiGateway.managedGatewayClass.nodeSelector=- key: value' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.nodeSelector[0].key') - echo ${actual} - - [ "${actual}" = 'value' ] -} - -@test "gateway-resources/ConfigMap: API Gateway nodeSelector default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.nodeSelector') - [ "${actual}" = 'null' ] -} - -#-------------------------------------------------------------------- -# API Gateway Tests tolerations - -@test "gateway-resources/ConfigMap: API Gateway tolerations overrides default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - --set 'connectInject.apiGateway.managedGatewayClass.tolerations=- key: value' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.tolerations[0].key') - echo "${actual}" - - [ "${actual}" = 'value' ] -} - - - -@test "gateway-resources/ConfigMap: API Gateway tolerations default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.tolerations') - [ "${actual}" = 'null' ] -} - - -#-------------------------------------------------------------------- -# API Gateway Tests copyAnnotations - -@test "gateway-resources/ConfigMap: API Gateway copyAnnotations overrides default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - --set 'connectInject.apiGateway.managedGatewayClass.copyAnnotations.service.annotations=- annotation.name' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.annotations' | tee /dev/stderr) - - local actual=$(echo "$config" | yq -r '.service[0]') - echo "${actual}" - [ "${actual}" = 'annotation.name' ] -} - -@test "gateway-resources/ConfigMap: API Gateway copyAnnotations default { - cd `chart_dir` - local config=$(helm template \ - -s $target \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.logLevel=error' \ - . | tee /dev/stderr | - yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.annotations' | tee /dev/stderr) - - local actual=$(echo "$config" | jq -r '.service') - [ "${actual}" = 'null' ] -} - - -#-------------------------------------------------------------------- -# TODO openShiftSSCName \ No newline at end of file diff --git a/charts/consul/test/unit/gateway-resources-job.bats b/charts/consul/test/unit/gateway-resources-job.bats index 32173838fe..e38397231b 100644 --- a/charts/consul/test/unit/gateway-resources-job.bats +++ b/charts/consul/test/unit/gateway-resources-job.bats @@ -4,15 +4,6 @@ load _helpers target=templates/gateway-resources-job.yaml -@test "gatewayresources/Job: fails if .values.apiGateway is set" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'apiGateway.enabled=true' . - [ "$status" -eq 1 ] - [[ "$output" =~ "[DEPRECATED and REMOVED] the apiGateway stanza is no longer supported as of Consul 1.19.0. Use connectInject.apiGateway instead." ]] -} - @test "gatewayresources/Job: enabled by default" { cd `chart_dir` local actual=$(helm template \ @@ -40,6 +31,33 @@ target=templates/gateway-resources-job.yaml [ "$actual" = "true" ] } +#-------------------------------------------------------------------- +# fallback configuration +# to be removed in 1.17 (t-eckert 2023-05-23) + +@test "gatewayresources/Job: fallback configuration is used when apiGateway.enabled is true" { + cd `chart_dir` + local spec=$(helm template \ + -s $target \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=testing' \ + --set 'apiGateway.managedGatewayClass.nodeSelector=foo: bar' \ + --set 'apiGateway.managedGatewayClass.tolerations=- key: bar' \ + --set 'apiGateway.managedGatewayClass.copyAnnotations.service.annotations=- bingo' \ + --set 'apiGateway.managedGatewayClass.serviceType=LoadBalancer' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].args' | tee /dev/stderr) + + local actual=$(echo "$spec" | jq '.[9] | ."-node-selector=foo"') + [ "${actual}" = "\"bar\"" ] + + local actual=$(echo "$spec" | jq '.[10] | ."-tolerations=- key"') + [ "${actual}" = "\"bar\"" ] + + local actual=$(echo "$spec" | jq '.[11]') + [ "${actual}" = "\"-service-annotations=- bingo\"" ] +} + #-------------------------------------------------------------------- # configuration diff --git a/charts/consul/test/unit/helpers.bats b/charts/consul/test/unit/helpers.bats index 58f7fbf8a4..20772788f8 100644 --- a/charts/consul/test/unit/helpers.bats +++ b/charts/consul/test/unit/helpers.bats @@ -455,58 +455,14 @@ load _helpers [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, terminatingGateways.enabled is currently unsupported." ]] } - - - - -#-------------------------------------------------------------------- -# consul.imagePullPolicy -# These tests use test-runner.yaml to "unit test" the imagePullPolicy function - -@test "helper/consul.imagePullPolicy: bad input" { +@test "connectInject/Deployment: fails if resource-apis is set and apiGateway is enabled" { cd `chart_dir` run helm template \ -s templates/tests/test-runner.yaml \ - --set 'global.imagePullPolicy=Garbage' . - [ "$status" -eq 1 ] - [[ "$output" =~ "imagePullPolicy can only be IfNotPresent, Always, Never, or empty" ]] -} - -@test "helper/consul.imagePullPolicy: empty input" { - cd `chart_dir` - local output=$(helm template \ - -s templates/tests/test-runner.yaml \ - . | tee /dev/stderr | - yq -r '.spec.containers[0].imagePullPolicy' | tee /dev/stderr) - [ "${output}" = null ] -} - -@test "helper/consul.imagePullPolicy: IfNotPresent" { - cd `chart_dir` - local output=$(helm template \ - -s templates/tests/test-runner.yaml \ - --set 'global.imagePullPolicy=IfNotPresent' \ - . | tee /dev/stderr | - yq -r '.spec.containers[0].imagePullPolicy' | tee /dev/stderr) - [ "${output}" = "IfNotPresent" ] -} - -@test "helper/consul.imagePullPolicy: Always" { - cd `chart_dir` - local output=$(helm template \ - -s templates/tests/test-runner.yaml \ - --set 'global.imagePullPolicy=Always' \ - . | tee /dev/stderr | - yq -r '.spec.containers[0].imagePullPolicy' | tee /dev/stderr) - [ "${output}" = "Always" ] + --set 'connectInject.enabled=true' \ + --set 'global.experiments[0]=resource-apis' \ + --set 'ui.enabled=false' \ + --set 'apiGateway.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, apiGateway.enabled is currently unsupported." ]] } - -@test "helper/consul.imagePullPolicy: Never" { - cd `chart_dir` - local output=$(helm template \ - -s templates/tests/test-runner.yaml \ - --set 'global.imagePullPolicy=Never' \ - . | tee /dev/stderr | - yq -r '.spec.containers[0].imagePullPolicy' | tee /dev/stderr) - [ "${output}" = "Never" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 7d55518886..0f62803ec0 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -823,7 +823,7 @@ load _helpers local actual="$( echo "$consul_checks" | \ jq -r .consul.instances | jq -r .[0].url | tee /dev/stderr)" - [ "${actual}" = http://release-name-consul-server.default.svc:8500 ] + [ "${actual}" = "http://consul-server.consul.svc:8500" ] local actual="$( echo "$consul_checks" | \ jq -r .consul.instances | jq -r .[0].new_leader_checks | tee /dev/stderr)" @@ -866,7 +866,7 @@ load _helpers local actual="$( echo "$consul_checks" | \ jq -r .consul.instances | jq -r .[0].url | tee /dev/stderr)" - [ "${actual}" = "https://release-name-consul-server.default.svc:8501" ] + [ "${actual}" = "https://consul-server.default.svc:8501" ] local actual="$( echo "$consul_checks" | \ jq -r .consul.instances | jq -r .[0].tls_cert | tee /dev/stderr)" @@ -933,7 +933,7 @@ load _helpers local actual="$( echo "$consul_checks" | \ jq -r .openmetrics.instances | jq -r .[0].openmetrics_endpoint | tee /dev/stderr)" - [ "${actual}" = "http://release-name-consul-server.default.svc:8500/v1/agent/metrics?format=prometheus" ] + [ "${actual}" = "http://consul-server.default.svc:8500/v1/agent/metrics?format=prometheus" ] local actual="$( echo "$consul_checks" | \ jq -r .openmetrics.instances | jq -r .[0].headers | tee /dev/stderr)" @@ -971,7 +971,7 @@ load _helpers local actual="$( echo "$consul_checks" | \ jq -r .openmetrics.instances | jq -r .[0].openmetrics_endpoint | tee /dev/stderr)" - [ "${actual}" = "https://release-name-consul-server.default.svc:8501/v1/agent/metrics?format=prometheus" ] + [ "${actual}" = "https://consul-server.default.svc:8501/v1/agent/metrics?format=prometheus" ] local actual="$( echo "$consul_checks" | \ jq -r .openmetrics.instances | jq -r .[0].headers | tee /dev/stderr)" @@ -1020,7 +1020,7 @@ load _helpers local actual="$( echo "$consul_checks" | \ jq -r .openmetrics.instances | jq -r .[0].openmetrics_endpoint | tee /dev/stderr)" - [ "${actual}" = "http://release-name-consul-server.default.svc:8500/v1/agent/metrics?format=prometheus" ] + [ "${actual}" = "http://consul-server.default.svc:8500/v1/agent/metrics?format=prometheus" ] local actual="$( echo "$consul_checks" | \ jq -r .openmetrics.instances | jq -r '.[0].headers["X-Consul-Token"]' | tee /dev/stderr)" @@ -1083,37 +1083,6 @@ load _helpers [ "${actual}" = "consul-server" ] } -@test "server/StatefulSet: datadog unix socket path name rendering for hostPath volume and volumeMount using default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.metrics.enabled=true' \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.metrics.enableAgentMetrics=true' \ - --set 'global.metrics.datadog.enabled=true' \ - --set 'global.metrics.datadog.dogstatsd.enabled=true' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.volumes[] | select(.name=="dsdsocket") | .hostPath.path' | tee /dev/stderr) - - [ "${actual}" = "/var/run/datadog" ] -} - -@test "server/StatefulSet: datadog unix socket path name rendering for hostPath volume and volumeMount using non default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.metrics.enabled=true' \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.metrics.enableAgentMetrics=true' \ - --set 'global.metrics.datadog.enabled=true' \ - --set 'global.metrics.datadog.dogstatsd.enabled=true' \ - --set 'global.metrics.datadog.dogstatsd.dogstatsdAddr="/this/otherpath/datadog/dsd.socket"' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.volumes[] | select(.name=="dsdsocket") | .hostPath.path' | tee /dev/stderr) - - [ "${actual}" = "/this/otherpath/datadog" ] -} - #-------------------------------------------------------------------- # config-configmap @@ -1385,7 +1354,6 @@ load _helpers "drop": ["ALL"], "add": ["NET_BIND_SERVICE"] }, - "readOnlyRootFilesystem": true, "runAsNonRoot": true, "seccompProfile": { "type": "RuntimeDefault" @@ -1418,7 +1386,6 @@ load _helpers "drop": ["ALL"], "add": ["NET_BIND_SERVICE"] }, - "readOnlyRootFilesystem": true, "runAsNonRoot": true, "seccompProfile": { "type": "RuntimeDefault" diff --git a/charts/consul/test/unit/telemetry-collector-deployment.bats b/charts/consul/test/unit/telemetry-collector-deployment.bats index 949a5e8cd4..71f10d3934 100755 --- a/charts/consul/test/unit/telemetry-collector-deployment.bats +++ b/charts/consul/test/unit/telemetry-collector-deployment.bats @@ -1429,7 +1429,7 @@ MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ local actual=$(echo "$object" | yq -r '.[] | select(.name=="CO_OTEL_HTTP_ENDPOINT").value' | tee /dev/stderr) - [ "${actual}" = 'http://$(HOST_IP):4317' ] + [ "${actual}" = 'grpc://$(HOST_IP):4317' ] } @test "telemetryCollector/Deployment: DataDog OTLP Collector gRPC protocol verification, case-insensitive" { @@ -1448,5 +1448,5 @@ MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ local actual=$(echo "$object" | yq -r '.[] | select(.name=="CO_OTEL_HTTP_ENDPOINT").value' | tee /dev/stderr) - [ "${actual}" = 'http://$(HOST_IP):4317' ] + [ "${actual}" = 'grpc://$(HOST_IP):4317' ] } \ No newline at end of file diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 866fb29830..21cf3e1f9c 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -66,7 +66,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: docker.mirror.hashicorp.services/hashicorppreview/consul:1.20-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul:1.18-dev # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. @@ -86,12 +86,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: docker.mirror.hashicorp.services/hashicorppreview/consul-k8s-control-plane:1.6-dev - - # The image pull policy used globally for images controlled by Consul (consul, consul-dataplane, consul-k8s, consul-telemetry-collector). - # One of "IfNotPresent", "Always", "Never", and "". Refer to https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy - # @default: "" - imagePullPolicy: "" + imageK8S: docker.mirror.hashicorp.services/hashicorppreview/consul-k8s-control-plane:1.4-dev # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running @@ -793,7 +788,7 @@ global: # The name (and tag) of the consul-dataplane Docker image used for the # connect-injected sidecar proxies and mesh, terminating, and ingress gateways. # @default: hashicorp/consul-dataplane: - imageConsulDataplane: docker.mirror.hashicorp.services/hashicorppreview/consul-dataplane:1.6-dev + imageConsulDataplane: docker.mirror.hashicorp.services/hashicorppreview/consul-dataplane:1.4-dev # Configuration for running this Helm chart on the Red Hat OpenShift platform. # This Helm chart currently supports OpenShift v4.x+. @@ -907,14 +902,25 @@ global: # Consul feature flags that will be enabled across components. # Supported feature flags: - # - `v1dns`: - # When this flag is set, Consul agents use the legacy DNS implementation. - # This setting exists in the case a DNS bug is found after the refactoring introduced in v1.19.0. + # - `resource-apis`: + # _**Warning**_! This feature is under active development. It is not + # recommended for production use. Setting this flag during an + # upgrade could risk breaking your Consul cluster. + # If this flag is set, Consul components will use the + # V2 resources APIs for all operations. + # - `v2tenancy`: + # _**Warning**_! This feature is under active development. It is not + # recommended for production use. Setting this flag during an + # upgrade could risk breaking your Consul cluster. + # If this flag is set, Consul V2 resources (catalog, mesh, auth, etc) + # will use V2 implementations for tenancy (partitions and namesapces) + # instead of bridging to the existing V1 implementations. The + # `resource-apis` feature flag must also be set. # # Example: # # ```yaml - # experiments: [ "v1dns" ] + # experiments: [ "resource-apis" ] # ``` # @type: array experiments: [] @@ -3444,6 +3450,175 @@ terminatingGateways: gateways: - name: terminating-gateway +# [DEPRECATED] Use connectInject.apiGateway instead. +# Configuration settings for the Consul API Gateway integration +apiGateway: + # When true the helm chart will install the Consul API Gateway controller + enabled: false + + # Image to use for the api-gateway-controller pods and gateway instances + # + # ~> **Note:** Using API Gateway <= 0.4 with external servers requires setting `client.enabled: true`. + # @type: string + image: null + + # The name (and tag) of the Envoy Docker image used for the + # apiGateway. For other Consul compoenents, imageEnvoy has been replaced with Consul Dataplane. + # @default: envoyproxy/envoy: + imageEnvoy: "envoyproxy/envoy:v1.25.11" + + # Override global log verbosity level for api-gateway-controller pods. One of "debug", "info", "warn", or "error". + # @type: string + logLevel: info + + # Configuration settings for the optional GatewayClass installed by consul-k8s (enabled by default) + managedGatewayClass: + # When true a GatewayClass is configured to automatically work with Consul as installed by helm. + enabled: true + + # This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + # labels for gateway pod assignment, formatted as a multi-line string. + # + # Example: + # + # ```yaml + # nodeSelector: | + # beta.kubernetes.io/arch: amd64 + # ``` + # + # @type: string + nodeSelector: null + + # Toleration settings for gateway pods created with the managed gateway class. + # This should be a multi-line string matching the + # [Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) array in a Pod spec. + # + # @type: string + tolerations: null + + # This value defines the type of service created for gateways (e.g. LoadBalancer, ClusterIP) + serviceType: LoadBalancer + + # This value toggles if the gateway ports should be mapped to host ports + useHostPorts: false + + # Configuration settings for annotations to be copied from the Gateway to other child resources. + copyAnnotations: + # This value defines a list of annotations to be copied from the Gateway to the Service created, formatted as a multi-line string. + # + # Example: + # + # ```yaml + # service: + # annotations: | + # - external-dns.alpha.kubernetes.io/hostname + # ``` + # + # @type: string + service: null + + # This value defines the number of pods to deploy for each Gateway as well as a min and max number of pods for all Gateways + # + # Example: + # + # ```yaml + # deployment: + # defaultInstances: 3 + # maxInstances: 8 + # minInstances: 1 + # ``` + # + # @type: map + deployment: null + + # Configuration for the ServiceAccount created for the api-gateway component + serviceAccount: + # This value defines additional annotations for the client service account. This should be formatted as a multi-line + # string. + # + # ```yaml + # annotations: | + # "sample/annotation1": "foo" + # "sample/annotation2": "bar" + # ``` + # + # @type: string + annotations: null + + # Configuration for the api-gateway controller component + controller: + # This value sets the number of controller replicas to deploy. + replicas: 1 + + # Annotations to apply to the api-gateway-controller pods. + # + # ```yaml + # annotations: | + # "annotation-key": "annotation-value" + # ``` + # + # @type: string + annotations: null + + # This value references an existing + # Kubernetes [`priorityClassName`](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) + # that can be assigned to api-gateway-controller pods. + priorityClassName: "" + + # This value defines [`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + # labels for api-gateway-controller pod assignment, formatted as a multi-line string. + # + # Example: + # + # ```yaml + # nodeSelector: | + # beta.kubernetes.io/arch: amd64 + # ``` + # + # @type: string + nodeSelector: null + + # This value defines the tolerations for api-gateway-controller pod, this should be a multi-line string matching the + # [Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) array in a Pod spec. + # + # @type: string + tolerations: null + + # Configuration for the Service created for the api-gateway-controller + service: + # Annotations to apply to the api-gateway-controller service. + # + # ```yaml + # annotations: | + # "annotation-key": "annotation-value" + # ``` + # + # @type: string + annotations: null + + # The resource settings for api gateway pods. + # @recurse: false + # @type: map + resources: + requests: + memory: "100Mi" + cpu: "100m" + limits: + memory: "100Mi" + cpu: "100m" + + # The resource settings for the `copy-consul-bin` init container. + # @recurse: false + # @type: map + initCopyConsulContainer: + resources: + requests: + memory: "25Mi" + cpu: "50m" + limits: + memory: "150Mi" + cpu: "50m" + # Configuration settings for the webhook-cert-manager # `webhook-cert-manager` ensures that cert bundles are up to date for the mutating webhook. webhookCertManager: diff --git a/cli/go.mod b/cli/go.mod index 2429e34b6d..c86b3a849c 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -13,7 +13,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/hashicorp/consul-k8s/charts v0.0.0-00010101000000-000000000000 github.com/hashicorp/consul-k8s/version v0.0.0 - github.com/hashicorp/consul/troubleshoot v0.6.1 + github.com/hashicorp/consul/troubleshoot v0.6.0 github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/hcp-sdk-go v0.62.1-0.20230913154003-cf69c0370c54 github.com/kr/text v0.2.0 @@ -63,7 +63,7 @@ require ( github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/envoyproxy/go-control-plane v0.12.0 // indirect + github.com/envoyproxy/go-control-plane v0.11.1 // indirect github.com/envoyproxy/go-control-plane/xdsmatcher v0.0.0-20230524161521-aaaacbfbe53e // indirect github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect @@ -96,8 +96,8 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect - github.com/hashicorp/consul/api v1.29.1 // indirect - github.com/hashicorp/consul/envoyextensions v0.7.0 // indirect + github.com/hashicorp/consul/api v1.28.2 // indirect + github.com/hashicorp/consul/envoyextensions v0.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -143,7 +143,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rubenv/sql-migrate v1.5.2 // indirect diff --git a/cli/go.sum b/cli/go.sum index fc73cc7e77..70568c5bfb 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -120,8 +120,8 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= -github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/go-control-plane/xdsmatcher v0.0.0-20230524161521-aaaacbfbe53e h1:g8euodkL4GdSpVAjfzhssb07KgVmOUqyF4QOmwFumTs= github.com/envoyproxy/go-control-plane/xdsmatcher v0.0.0-20230524161521-aaaacbfbe53e/go.mod h1:/NGEcKqwNq3HAS2vCqHfsPx9sJZbkiNQ6dGx9gTE/NA= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -288,16 +288,14 @@ github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc= -github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI= -github.com/hashicorp/consul/envoyextensions v0.7.0 h1:DiZcA2tCgwD3tAoixBML3pYAPCKWLnOrKzzt843YTrU= -github.com/hashicorp/consul/envoyextensions v0.7.0/go.mod h1:oZlopILhl2oaJhcs2szKlFcdVYBWzjqEYaG4SSQdBjY= -github.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg= -github.com/hashicorp/consul/proto-public v0.6.1/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg= -github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= -github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= -github.com/hashicorp/consul/troubleshoot v0.6.1 h1:Nmk0fXjpgmMhEEzeBdV6+OcoD3bUJtKCP1ONo4vZPaw= -github.com/hashicorp/consul/troubleshoot v0.6.1/go.mod h1:Yenla7oy9UpI9vZr7puDLnfIFwYcmd1XBy4q2nAhea8= +github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= +github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= +github.com/hashicorp/consul/envoyextensions v0.6.0 h1:PtbJUVKBMSGKXnTdSIw1EGyjWvMrmFvXcZuVeIT79Ls= +github.com/hashicorp/consul/envoyextensions v0.6.0/go.mod h1:MwSQg5WUuAle1bGsJWS6/z/RNvs8Ob0sNvFZ98l/+Mc= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= +github.com/hashicorp/consul/troubleshoot v0.6.0 h1:5PKcTBrx/XDHZBPhpLqldJFZYNiO+LDXdi26Aa1J6BI= +github.com/hashicorp/consul/troubleshoot v0.6.0/go.mod h1:7fSd1Nn89vPxnZ8BiQTVS4fTygS42crtfm0psMoJJms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -517,8 +515,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= diff --git a/control-plane/Dockerfile b/control-plane/Dockerfile index 42a36e872f..26f4b90ef0 100644 --- a/control-plane/Dockerfile +++ b/control-plane/Dockerfile @@ -32,7 +32,6 @@ ARG CNI_BIN_NAME=consul-cni ARG VERSION ARG TARGETARCH ARG TARGETOS -ENV PRODUCT_NAME=$BIN_NAME LABEL name=${BIN_NAME} \ maintainer="Team Consul Kubernetes " \ @@ -43,6 +42,7 @@ LABEL name=${BIN_NAME} \ description="consul-k8s-control-plane provides first-class integrations between Consul and Kubernetes." \ org.opencontainers.image.licenses="MPL-2.0" +RUN mkdir -p /usr/share/doc/$PRODUCT_NAME COPY LICENSE /usr/share/doc/$PRODUCT_NAME/LICENSE.txt # Set ARGs as ENV so that they can be used in ENTRYPOINT/CMD @@ -84,7 +84,6 @@ FROM alpine:3.19 AS release-default ARG BIN_NAME=consul-k8s-control-plane ARG CNI_BIN_NAME=consul-cni ARG PRODUCT_VERSION -ENV PRODUCT_NAME=$BIN_NAME LABEL name=${BIN_NAME} \ maintainer="Team Consul Kubernetes " \ @@ -95,6 +94,7 @@ LABEL name=${BIN_NAME} \ description="consul-k8s-control-plane provides first-class integrations between Consul and Kubernetes." \ org.opencontainers.image.licenses="MPL-2.0" +RUN mkdir -p /usr/share/doc/$PRODUCT_NAME COPY LICENSE /usr/share/doc/$PRODUCT_NAME/LICENSE.txt # Set ARGs as ENV so that they can be used in ENTRYPOINT/CMD @@ -149,7 +149,8 @@ ARG VERSION # and the version to download. Example: PRODUCT_NAME=consul PRODUCT_VERSION=1.2.3. ENV BIN_NAME=$BIN_NAME ENV PRODUCT_VERSION=$PRODUCT_VERSION -ENV PRODUCT_NAME=$BIN_NAME + +ARG PRODUCT_NAME=$BIN_NAME LABEL name=$PRODUCT_NAME \ maintainer="Team Consul Kubernetes " \ @@ -160,6 +161,7 @@ LABEL name=$PRODUCT_NAME \ description="consul-k8s-control-plane provides first-class integrations between Consul and Kubernetes." \ org.opencontainers.image.licenses="MPL-2.0" +RUN mkdir -p /usr/share/doc/$PRODUCT_NAME COPY LICENSE /usr/share/doc/$PRODUCT_NAME/LICENSE.txt # Set ARGs as ENV so that they can be used in ENTRYPOINT/CMD diff --git a/control-plane/api-gateway/binding/binder.go b/control-plane/api-gateway/binding/binder.go index cbd46dd0e8..c704a6b04e 100644 --- a/control-plane/api-gateway/binding/binder.go +++ b/control-plane/api-gateway/binding/binder.go @@ -172,7 +172,10 @@ func (b *Binder) Snapshot() *Snapshot { for secret := range gatewaySecrets.Iter() { // ignore the error if the certificate cannot be processed and just don't add it into the final // sync set - b.config.Resources.TranslateFileSystemCertificate(secret.(types.NamespacedName)) + if err := b.config.Resources.TranslateInlineCertificate(secret.(types.NamespacedName)); err != nil { + b.config.Logger.Error(err, "error parsing referenced secret, ignoring") + continue + } } } diff --git a/control-plane/api-gateway/binding/binder_test.go b/control-plane/api-gateway/binding/binder_test.go index c975a6e791..b4a274c8fa 100644 --- a/control-plane/api-gateway/binding/binder_test.go +++ b/control-plane/api-gateway/binding/binder_test.go @@ -55,19 +55,19 @@ var ( ) type resourceMapResources struct { - grants []gwv1beta1.ReferenceGrant - secrets []corev1.Secret - gateways []gwv1beta1.Gateway - httpRoutes []gwv1beta1.HTTPRoute - tcpRoutes []gwv1alpha2.TCPRoute - meshServices []v1alpha1.MeshService - services []types.NamespacedName - jwtProviders []*v1alpha1.JWTProvider - gatewayPolicies []*v1alpha1.GatewayPolicy - externalAuthFilters []*v1alpha1.RouteAuthFilter - consulFileSystemCertificates []api.FileSystemCertificateConfigEntry - consulHTTPRoutes []api.HTTPRouteConfigEntry - consulTCPRoutes []api.TCPRouteConfigEntry + grants []gwv1beta1.ReferenceGrant + secrets []corev1.Secret + gateways []gwv1beta1.Gateway + httpRoutes []gwv1beta1.HTTPRoute + tcpRoutes []gwv1alpha2.TCPRoute + meshServices []v1alpha1.MeshService + services []types.NamespacedName + jwtProviders []*v1alpha1.JWTProvider + gatewayPolicies []*v1alpha1.GatewayPolicy + externalAuthFilters []*v1alpha1.RouteAuthFilter + consulInlineCertificates []api.InlineCertificateConfigEntry + consulHTTPRoutes []api.HTTPRouteConfigEntry + consulTCPRoutes []api.TCPRouteConfigEntry } func newTestResourceMap(t *testing.T, resources resourceMapResources) *common.ResourceMap { @@ -282,7 +282,7 @@ func TestBinder_Lifecycle(t *testing.T) { Protocol: "http", TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{{ - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "secret-one", }}, }, @@ -644,7 +644,7 @@ func TestBinder_Lifecycle(t *testing.T) { }, }, }, - consulFileSystemCertificates: []api.FileSystemCertificateConfigEntry{ + consulInlineCertificates: []api.InlineCertificateConfigEntry{ *certificateOne, *certificateTwo, }, @@ -771,7 +771,7 @@ func TestBinder_Lifecycle(t *testing.T) { expectedConsulDeletions: []api.ResourceReference{ {Kind: api.HTTPRoute, Name: "http-route-one"}, {Kind: api.TCPRoute, Name: "tcp-route-one"}, - {Kind: api.FileSystemCertificate, Name: "secret-two"}, + {Kind: api.InlineCertificate, Name: "secret-two"}, {Kind: api.APIGateway, Name: "gateway-deleted"}, }, }, @@ -3133,7 +3133,7 @@ func controlledBinder(config BinderConfig) BinderConfig { return config } -func generateTestCertificate(t *testing.T, namespace, name string) (*api.FileSystemCertificateConfigEntry, corev1.Secret) { +func generateTestCertificate(t *testing.T, namespace, name string) (*api.InlineCertificateConfigEntry, corev1.Secret) { privateKey, err := rsa.GenerateKey(rand.Reader, common.MinKeyLength) require.NoError(t, err) @@ -3180,7 +3180,8 @@ func generateTestCertificate(t *testing.T, namespace, name string) (*api.FileSys }, } - certificate := (common.ResourceTranslator{}).ToFileSystemCertificate(secret) + certificate, err := (common.ResourceTranslator{}).ToInlineCertificate(secret) + require.NoError(t, err) return certificate, secret } diff --git a/control-plane/api-gateway/binding/cleanup.go b/control-plane/api-gateway/binding/cleanup.go deleted file mode 100644 index 4b517a1813..0000000000 --- a/control-plane/api-gateway/binding/cleanup.go +++ /dev/null @@ -1,204 +0,0 @@ -package binding - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - mapset "github.com/deckarep/golang-set/v2" - "github.com/go-logr/logr" - "github.com/hashicorp/consul/api" - - "github.com/hashicorp/consul-k8s/control-plane/consul" -) - -const ( - oldACLRoleName = "managed-gateway-acl-role" - oldACLPolicyName = "api-gateway-token-policy" -) - -var sleepTime = 10 * time.Minute - -type Cleaner struct { - Logger logr.Logger - ConsulConfig *consul.Config - ServerMgr consul.ServerConnectionManager - AuthMethod string -} - -// Run periodically cleans up old ACL roles and policies as well as orphaned inline certificate config entries. -// When it detects that there are no more inline-certificates and that the old ACL role and policy are not in use, it exits. -func (c Cleaner) Run(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case <-time.After(sleepTime): - } - - client, err := consul.NewClientFromConnMgr(c.ConsulConfig, c.ServerMgr) - if err != nil { - c.Logger.Error(err, "failed to create Consul client") - continue - } - - aclsCleanedUp, err := c.cleanupACLRoleAndPolicy(client) - if err != nil { - c.Logger.Error(err, "failed to cleanup old ACL role and policy") - } - - inlineCertsAllCleanedUp, err := c.cleanupInlineCerts(client) - if err != nil { - c.Logger.Error(err, "failed to cleanup inline-certificate configuration entries") - } - - if aclsCleanedUp && inlineCertsAllCleanedUp { - c.Logger.Info("Cleanup complete") - return - } - } -} - -// cleanupACLRoleAndPolicy deletes the old shared gateway ACL role and policy if they exist. -func (c Cleaner) cleanupACLRoleAndPolicy(client *api.Client) (bool, error) { - existingRules, _, err := client.ACL().BindingRuleList(c.AuthMethod, &api.QueryOptions{}) - if err != nil { - if err.Error() == "Unexpected response code: 401 (ACL support disabled)" { - return true, nil - } - return false, fmt.Errorf("failed to list binding rules: %w", err) - } - - oldBindingRules := make(map[string]*api.ACLBindingRule) - - // here we need to find binding rules with the old name that have a matching selector to the new gateway specific binding rule - // so we first get all the old rules and put them into a map and then ensure we can delete the old rule by finding the new rule that replaces it - // by matching the selector - for _, rule := range existingRules { - if rule.BindName == oldACLRoleName { - oldBindingRules[rule.Selector] = rule - } - } - - rulesToDelete := mapset.NewSet[string]() - - for _, rule := range existingRules { - if ruleToDelete, ok := oldBindingRules[rule.Selector]; ok && rule.BindName != oldACLRoleName { - rulesToDelete.Add(ruleToDelete.ID) - } - } - - var mErr error - deletedRuleCount := 0 - for ruleID := range rulesToDelete.Iter() { - _, err := client.ACL().BindingRuleDelete(ruleID, &api.WriteOptions{}) - if ignoreNotFoundError(err) != nil { - mErr = errors.Join(mErr, fmt.Errorf("failed to delete binding rule: %w", err)) - } else { - c.Logger.Info("Deleted unused binding rule", "id", ruleID) - deletedRuleCount++ - } - } - - if mErr != nil { - return false, mErr - } - - if deletedRuleCount != len(oldBindingRules) { - return false, nil - } - - role, _, err := client.ACL().RoleReadByName(oldACLRoleName, &api.QueryOptions{}) - if ignoreNotFoundError(err) != nil { - return false, fmt.Errorf("failed to get role: %w", err) - } - - if role != nil { - _, err = client.ACL().RoleDelete(role.ID, &api.WriteOptions{}) - if err != nil { - return false, fmt.Errorf("failed to delete role: %w", err) - } - c.Logger.Info("Deleted unused ACL role", "id", role.ID) - } - - policy, _, err := client.ACL().PolicyReadByName(oldACLPolicyName, &api.QueryOptions{}) - if ignoreNotFoundError(err) != nil { - return false, fmt.Errorf("failed to get policy: %w", err) - } - - if policy != nil { - _, err = client.ACL().PolicyDelete(policy.ID, &api.WriteOptions{}) - if err != nil { - return false, fmt.Errorf("failed to delete policy: %w", err) - } - c.Logger.Info("Deleted unused ACL policy", "id", policy.ID) - } - - return true, nil -} - -// cleanupInlineCerts deletes all inline certs that are not used by any gateway. -func (c Cleaner) cleanupInlineCerts(client *api.Client) (bool, error) { - certs, _, err := client.ConfigEntries().List(api.InlineCertificate, &api.QueryOptions{}) - if err != nil { - return false, fmt.Errorf("failed to list the inline certs: %w", err) - } - - gateways, _, err := client.ConfigEntries().List(api.APIGateway, &api.QueryOptions{}) - if err != nil { - return false, fmt.Errorf("failed to list the gateways: %w", err) - } - - if len(certs) == 0 { - return true, nil - } - - certSet := mapset.NewSet[string]() - certsToKeep := mapset.NewSet[string]() - for _, cert := range certs { - certSet.Add(cert.GetName()) - } - - for _, gateway := range gateways { - gtw := gateway.(*api.APIGatewayConfigEntry) - for _, listener := range gtw.Listeners { - if len(listener.TLS.Certificates) == 0 { - continue - } - - for _, cert := range listener.TLS.Certificates { - if cert.Kind == api.InlineCertificate && certSet.Contains(cert.Name) { - certsToKeep.Add(cert.Name) - } - } - } - } - - certsToDelete := certSet.Difference(certsToKeep) - var mErr error - deletedCerts := 0 - for cert := range certsToDelete.Iter() { - _, err := client.ConfigEntries().Delete(api.InlineCertificate, cert, &api.WriteOptions{}) - if err != nil { - mErr = errors.Join(mErr, fmt.Errorf("failed to delete inline-certificate %s: %w", cert, err)) - continue - } - c.Logger.Info("Deleted unused inline-certificate", "name", cert) - deletedCerts++ - } - - return certSet.Cardinality() == deletedCerts, mErr -} - -func ignoreNotFoundError(err error) error { - if err == nil { - return nil - } - if strings.Contains(err.Error(), "Unexpected response code: 404") { - return nil - } - - return err -} diff --git a/control-plane/api-gateway/binding/cleanup_test.go b/control-plane/api-gateway/binding/cleanup_test.go deleted file mode 100644 index 78897fcb87..0000000000 --- a/control-plane/api-gateway/binding/cleanup_test.go +++ /dev/null @@ -1,355 +0,0 @@ -package binding - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "strconv" - "strings" - "testing" - "time" - - mapset "github.com/deckarep/golang-set/v2" - logrtest "github.com/go-logr/logr/testing" - "github.com/stretchr/testify/require" - - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/helper/test" - "github.com/hashicorp/consul/api" -) - -func TestCleaner_Run(t *testing.T) { - cases := map[string]struct { - bindingRules []*api.ACLBindingRule - expectedDeletedACLBindingRuleIDs mapset.Set[string] - aclRole *api.ACLRole - expectedDeletedACLRoleIDs mapset.Set[string] - aclPolicy *api.ACLPolicy - expectedDeletedACLPolicyIDs mapset.Set[string] - inlineCerts []*api.InlineCertificateConfigEntry - expxectedDeletedCertsName mapset.Set[string] - apiGateways []*api.APIGatewayConfigEntry - }{ - // add binding rules that match on selector and name to be cleaned up - "all old roles/policies/bindingrules and inline certs get cleaned up": { - bindingRules: []*api.ACLBindingRule{ - { - ID: "1223445", - BindName: "totally-valid-name", - Selector: "non-matching selector", - }, - { - ID: "1234", - BindName: oldACLRoleName, - Selector: "matching selector", - }, - { - ID: "4567", - BindName: "new role", - Selector: "matching selector", - }, - }, - expectedDeletedACLBindingRuleIDs: mapset.NewSet("1234"), - aclRole: &api.ACLRole{ - ID: "abcd", - Name: oldACLRoleName, - }, - expectedDeletedACLRoleIDs: mapset.NewSet("abcd"), - aclPolicy: &api.ACLPolicy{ - ID: "defg", - Name: oldACLPolicyName, - }, - expectedDeletedACLPolicyIDs: mapset.NewSet("defg"), - inlineCerts: []*api.InlineCertificateConfigEntry{ - { - Kind: api.InlineCertificate, - Name: "my-inline-cert", - }, - }, - expxectedDeletedCertsName: mapset.NewSet("my-inline-cert"), - apiGateways: []*api.APIGatewayConfigEntry{ - { - Kind: api.APIGateway, - Name: "my-api-gateway", - Listeners: []api.APIGatewayListener{ - { - Name: "listener", - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{ - { - Kind: api.FileSystemCertificate, - Name: "cert", - }, - }, - }, - }, - }, - }, - }, - }, - "acl roles/policies/binding-rules do not get cleaned up because they are still being referenced": { - bindingRules: []*api.ACLBindingRule{ - { - ID: "1234", - BindName: oldACLRoleName, - Selector: "matching selector", - }, - { - ID: "1223445", - BindName: "totally-valid-name", - Selector: "non-matching selector", - }, - }, - expectedDeletedACLBindingRuleIDs: mapset.NewSet[string](), - aclRole: &api.ACLRole{ - ID: "abcd", - Name: oldACLRoleName, - }, - expectedDeletedACLRoleIDs: mapset.NewSet[string](), - aclPolicy: &api.ACLPolicy{ - ID: "defg", - Name: oldACLPolicyName, - }, - expectedDeletedACLPolicyIDs: mapset.NewSet[string](), - inlineCerts: []*api.InlineCertificateConfigEntry{ - { - Kind: api.InlineCertificate, - Name: "my-inline-cert", - }, - }, - expxectedDeletedCertsName: mapset.NewSet("my-inline-cert"), - apiGateways: []*api.APIGatewayConfigEntry{ - { - Kind: api.APIGateway, - Name: "my-api-gateway", - Listeners: []api.APIGatewayListener{ - { - Name: "listener", - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{ - { - Kind: api.FileSystemCertificate, - Name: "cert", - }, - }, - }, - }, - }, - }, - }, - }, - "acl roles/policies aren't deleted because one binding-rule still references them": { - bindingRules: []*api.ACLBindingRule{ - { - ID: "1234", - BindName: oldACLRoleName, - Selector: "matching selector", - }, - { - ID: "5678", - BindName: "new-name", - Selector: "matching selector", - }, - { - ID: "101010", - BindName: oldACLRoleName, - Selector: "selector to another gateway", - }, - { - ID: "1223445", - BindName: "totally-valid-name", - Selector: "non-matching selector", - }, - }, - expectedDeletedACLBindingRuleIDs: mapset.NewSet("1234"), - aclRole: &api.ACLRole{ - ID: "abcd", - Name: oldACLRoleName, - }, - expectedDeletedACLRoleIDs: mapset.NewSet[string](), - aclPolicy: &api.ACLPolicy{ - ID: "defg", - Name: oldACLPolicyName, - }, - expectedDeletedACLPolicyIDs: mapset.NewSet[string](), - inlineCerts: []*api.InlineCertificateConfigEntry{ - { - Kind: api.InlineCertificate, - Name: "my-inline-cert", - }, - }, - expxectedDeletedCertsName: mapset.NewSet("my-inline-cert"), - apiGateways: []*api.APIGatewayConfigEntry{ - { - Kind: api.APIGateway, - Name: "my-api-gateway", - Listeners: []api.APIGatewayListener{ - { - Name: "listener", - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{ - { - Kind: api.FileSystemCertificate, - Name: "cert", - }, - }, - }, - }, - }, - }, - }, - }, - "inline cert does not get cleaned up because it is still being referenced": { - bindingRules: []*api.ACLBindingRule{ - { - ID: "1223445", - BindName: "totally-valid-name", - Selector: "non-matching selector", - }, - { - ID: "1234", - BindName: oldACLRoleName, - Selector: "matching selector", - }, - { - ID: "4567", - BindName: "new role", - Selector: "matching selector", - }, - }, - expectedDeletedACLBindingRuleIDs: mapset.NewSet("1234"), - aclRole: &api.ACLRole{ - ID: "abcd", - Name: oldACLRoleName, - }, - expectedDeletedACLRoleIDs: mapset.NewSet("abcd"), - aclPolicy: &api.ACLPolicy{ - ID: "defg", - Name: oldACLPolicyName, - }, - expectedDeletedACLPolicyIDs: mapset.NewSet("defg"), - inlineCerts: []*api.InlineCertificateConfigEntry{ - { - Kind: api.InlineCertificate, - Name: "my-inline-cert", - }, - }, - expxectedDeletedCertsName: mapset.NewSet[string](), - apiGateways: []*api.APIGatewayConfigEntry{ - { - Kind: api.APIGateway, - Name: "my-api-gateway", - Listeners: []api.APIGatewayListener{ - { - Name: "listener", - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{ - { - Kind: api.FileSystemCertificate, - Name: "cert", - }, - }, - }, - }, - }, - }, - { - Kind: api.APIGateway, - Name: "my-api-gateway-2", - Listeners: []api.APIGatewayListener{ - { - Name: "listener", - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{ - { - Kind: api.InlineCertificate, - Name: "my-inline-cert", - }, - }, - }, - }, - }, - }, - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - deletedCertsName := mapset.NewSet[string]() - deletedACLPolicyIDs := mapset.NewSet[string]() - deletedACLRoleIDs := mapset.NewSet[string]() - deletedACLBindingRuleIDs := mapset.NewSet[string]() - - consulServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - path := r.URL.Path - method := r.Method - switch { - case path == "/v1/acl/binding-rules": - val, err := json.Marshal(tc.bindingRules) - require.NoError(t, err) - fmt.Fprintln(w, string(val)) - case strings.HasPrefix(path, "/v1/acl/binding-rule/") && method == "DELETE": - deletedACLBindingRuleIDs.Add(strings.TrimPrefix(path, "/v1/acl/binding-rule/")) - case strings.HasPrefix(path, "/v1/acl/role/name/"): - val, err := json.Marshal(tc.aclRole) - require.NoError(t, err) - fmt.Fprintln(w, string(val)) - case strings.HasPrefix(path, "/v1/acl/role/") && method == "DELETE": - deletedACLRoleIDs.Add(strings.TrimPrefix(path, "/v1/acl/role/")) - case strings.HasPrefix(path, "/v1/acl/policy/name/"): - val, err := json.Marshal(tc.aclPolicy) - require.NoError(t, err) - fmt.Fprintln(w, string(val)) - case strings.HasPrefix(path, "/v1/acl/policy/") && method == "DELETE": - deletedACLPolicyIDs.Add(strings.TrimPrefix(path, "/v1/acl/policy/")) - case path == "/v1/config/inline-certificate" && method == "GET": - val, err := json.Marshal(tc.inlineCerts) - require.NoError(t, err) - fmt.Fprintln(w, string(val)) - case path == "/v1/config/api-gateway": - val, err := json.Marshal(tc.apiGateways) - require.NoError(t, err) - fmt.Fprintln(w, string(val)) - case strings.HasPrefix(path, "/v1/config/inline-certificate/") && method == "DELETE": - deletedCertsName.Add(strings.TrimPrefix(path, "/v1/config/inline-certificate/")) - default: - w.WriteHeader(500) - fmt.Fprintln(w, "Mock Server not configured for this route: "+r.URL.Path) - } - })) - defer consulServer.Close() - - serverURL, err := url.Parse(consulServer.URL) - require.NoError(t, err) - - port, err := strconv.Atoi(serverURL.Port()) - require.NoError(t, err) - - c := Cleaner{ - Logger: logrtest.NewTestLogger(t), - ConsulConfig: &consul.Config{ - APIClientConfig: &api.Config{}, - HTTPPort: port, - GRPCPort: port, - APITimeout: 0, - }, - ServerMgr: test.MockConnMgrForIPAndPort(t, serverURL.Hostname(), port, false), - AuthMethod: "consul-k8s-auth-method", - } - - // if these get flakey increase the times here - sleepTime = 50 * time.Millisecond - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) - c.Run(ctx) - cancel() - require.ElementsMatch(t, mapset.Sorted(tc.expectedDeletedACLBindingRuleIDs), mapset.Sorted(deletedACLBindingRuleIDs)) - require.ElementsMatch(t, mapset.Sorted(tc.expectedDeletedACLRoleIDs), mapset.Sorted(deletedACLRoleIDs)) - require.ElementsMatch(t, mapset.Sorted(tc.expectedDeletedACLPolicyIDs), mapset.Sorted(deletedACLPolicyIDs)) - require.ElementsMatch(t, mapset.Sorted(tc.expxectedDeletedCertsName), mapset.Sorted(deletedCertsName)) - }) - } -} diff --git a/control-plane/api-gateway/cache/consul.go b/control-plane/api-gateway/cache/consul.go index 21c8dcd3ec..8d2f5de9c9 100644 --- a/control-plane/api-gateway/cache/consul.go +++ b/control-plane/api-gateway/cache/consul.go @@ -60,7 +60,7 @@ const ( apiTimeout = 5 * time.Minute ) -var Kinds = []string{api.APIGateway, api.HTTPRoute, api.TCPRoute, api.FileSystemCertificate, api.JWTProvider} +var Kinds = []string{api.APIGateway, api.HTTPRoute, api.TCPRoute, api.InlineCertificate, api.JWTProvider} type Config struct { ConsulClientConfig *consul.Config @@ -758,12 +758,6 @@ func ignoreACLsDisabled(err error) error { return err } -// isPolicyExistsErr returns true if err is due to trying to call the -// policy create API when the policy already exists. -func isPolicyExistsErr(err error, policyName string) bool { - return isExistsErr(err, "Policy", policyName) -} - // isExistsErr returns true if err is due to trying to call an API for a given type and it already exists. func isExistsErr(err error, typeName, name string) bool { return err != nil && @@ -776,3 +770,9 @@ func isExistsErr(err error, typeName, name string) bool { func isRoleExistsErr(err error, roleName string) bool { return isExistsErr(err, "Role", roleName) } + +// isPolicyExistsErr returns true if err is due to trying to call the +// policy create API when the policy already exists. +func isPolicyExistsErr(err error, policyName string) bool { + return isExistsErr(err, "Policy", policyName) +} diff --git a/control-plane/api-gateway/cache/consul_test.go b/control-plane/api-gateway/cache/consul_test.go index 10ea7fc1ab..6ff8661498 100644 --- a/control-plane/api-gateway/cache/consul_test.go +++ b/control-plane/api-gateway/cache/consul_test.go @@ -1539,9 +1539,9 @@ func Test_Run(t *testing.T) { tcpRoute := setupTCPRoute() tcpRoutes := []*api.TCPRouteConfigEntry{tcpRoute} - // setup file-system certs - fileSystemCert := setupFileSystemCertificate() - certs := []*api.FileSystemCertificateConfigEntry{fileSystemCert} + // setup inline certs + inlineCert := setupInlineCertificate() + certs := []*api.InlineCertificateConfigEntry{inlineCert} // setup jwt providers jwtProvider := setupJWTProvider() @@ -1573,7 +1573,7 @@ func Test_Run(t *testing.T) { return } fmt.Fprintln(w, string(val)) - case "/v1/config/file-system-certificate": + case "/v1/config/inline-certificate": val, err := json.Marshal(certs) if err != nil { w.WriteHeader(500) @@ -1627,7 +1627,7 @@ func Test_Run(t *testing.T) { } expectedCache := loadedReferenceMaps([]api.ConfigEntry{ - gw, tcpRoute, httpRouteOne, httpRouteTwo, fileSystemCert, jwtProvider, + gw, tcpRoute, httpRouteOne, httpRouteTwo, inlineCert, jwtProvider, }) ctx, cancelFn := context.WithCancel(context.Background()) @@ -1677,11 +1677,11 @@ func Test_Run(t *testing.T) { }) certNsn := types.NamespacedName{ - Name: fileSystemCert.Name, - Namespace: fileSystemCert.Namespace, + Name: inlineCert.Name, + Namespace: inlineCert.Namespace, } - certSubscriber := c.Subscribe(ctx, api.FileSystemCertificate, func(cfe api.ConfigEntry) []types.NamespacedName { + certSubscriber := c.Subscribe(ctx, api.InlineCertificate, func(cfe api.ConfigEntry) []types.NamespacedName { return []types.NamespacedName{ {Name: cfe.GetName(), Namespace: cfe.GetNamespace()}, } @@ -1968,10 +1968,10 @@ func setupTCPRoute() *api.TCPRouteConfigEntry { } } -func setupFileSystemCertificate() *api.FileSystemCertificateConfigEntry { - return &api.FileSystemCertificateConfigEntry{ - Kind: api.FileSystemCertificate, - Name: "file-system-cert", +func setupInlineCertificate() *api.InlineCertificateConfigEntry { + return &api.InlineCertificateConfigEntry{ + Kind: api.InlineCertificate, + Name: "inline-cert", Certificate: "cert", PrivateKey: "super secret", Meta: map[string]string{ diff --git a/control-plane/api-gateway/common/diff.go b/control-plane/api-gateway/common/diff.go index 6f6b20b4cc..7db86807b7 100644 --- a/control-plane/api-gateway/common/diff.go +++ b/control-plane/api-gateway/common/diff.go @@ -70,8 +70,8 @@ func EntriesEqual(a, b api.ConfigEntry) bool { if bCast, ok := b.(*api.TCPRouteConfigEntry); ok { return tcpRoutesEqual(aCast, bCast) } - case *api.FileSystemCertificateConfigEntry: - if bCast, ok := b.(*api.FileSystemCertificateConfigEntry); ok { + case *api.InlineCertificateConfigEntry: + if bCast, ok := b.(*api.InlineCertificateConfigEntry); ok { return certificatesEqual(aCast, bCast) } } @@ -323,7 +323,7 @@ func (e entryComparator) tcpRouteServicesEqual(a, b api.TCPService) bool { orDefault(a.Partition, e.partitionA) == orDefault(b.Partition, e.partitionB) } -func certificatesEqual(a, b *api.FileSystemCertificateConfigEntry) bool { +func certificatesEqual(a, b *api.InlineCertificateConfigEntry) bool { if a == nil || b == nil { return false } @@ -336,7 +336,7 @@ func certificatesEqual(a, b *api.FileSystemCertificateConfigEntry) bool { }).certificatesEqual(*a, *b) } -func (e entryComparator) certificatesEqual(a, b api.FileSystemCertificateConfigEntry) bool { +func (e entryComparator) certificatesEqual(a, b api.InlineCertificateConfigEntry) bool { return a.Kind == b.Kind && a.Name == b.Name && e.namespaceA == e.namespaceB && diff --git a/control-plane/api-gateway/common/diff_test.go b/control-plane/api-gateway/common/diff_test.go index ae256a1b6b..04312c8162 100644 --- a/control-plane/api-gateway/common/diff_test.go +++ b/control-plane/api-gateway/common/diff_test.go @@ -32,7 +32,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -93,7 +93,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -157,7 +157,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -218,7 +218,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -282,7 +282,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -343,7 +343,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -407,7 +407,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -468,7 +468,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -532,7 +532,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -593,7 +593,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -657,7 +657,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -718,7 +718,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -782,7 +782,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -843,7 +843,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -907,7 +907,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -968,7 +968,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1032,7 +1032,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1093,7 +1093,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1157,7 +1157,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1218,7 +1218,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1282,7 +1282,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert-2", SectionName: "section", Partition: "partition", @@ -1343,7 +1343,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1407,7 +1407,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1468,7 +1468,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1532,7 +1532,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1593,7 +1593,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1657,7 +1657,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1718,7 +1718,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1782,7 +1782,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1843,7 +1843,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1907,7 +1907,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -1968,7 +1968,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -2032,7 +2032,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", @@ -2093,7 +2093,7 @@ func TestEntriesEqual(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: "cert", SectionName: "section", Partition: "partition", diff --git a/control-plane/api-gateway/common/helm_config.go b/control-plane/api-gateway/common/helm_config.go index d551757c5b..ecf245c04c 100644 --- a/control-plane/api-gateway/common/helm_config.go +++ b/control-plane/api-gateway/common/helm_config.go @@ -18,9 +18,7 @@ type HelmConfig struct { // ImageDataplane is the Consul Dataplane image to use in gateway deployments. ImageDataplane string // ImageConsulK8S is the Consul Kubernetes Control Plane image to use in gateway deployments. - ImageConsulK8S string - // GlobalImagePullPolicy is the pull policy to use for all images used in gateway deployments. - GlobalImagePullPolicy string + ImageConsulK8S string ConsulDestinationNamespace string NamespaceMirroringPrefix string EnableNamespaces bool diff --git a/control-plane/api-gateway/common/resources.go b/control-plane/api-gateway/common/resources.go index 514bb3c92a..051c914ae7 100644 --- a/control-plane/api-gateway/common/resources.go +++ b/control-plane/api-gateway/common/resources.go @@ -191,7 +191,7 @@ func (s *ResourceMap) Certificate(key types.NamespacedName) *corev1.Secret { if !s.certificates.Contains(key) { return nil } - consulKey := NormalizeMeta(s.toConsulReference(api.FileSystemCertificate, key)) + consulKey := NormalizeMeta(s.toConsulReference(api.InlineCertificate, key)) if secret, ok := s.certificateGateways[consulKey]; ok { return secret.secret } @@ -201,7 +201,7 @@ func (s *ResourceMap) Certificate(key types.NamespacedName) *corev1.Secret { func (s *ResourceMap) ReferenceCountCertificate(secret corev1.Secret) { key := client.ObjectKeyFromObject(&secret) s.certificates.Add(key) - consulKey := NormalizeMeta(s.toConsulReference(api.FileSystemCertificate, key)) + consulKey := NormalizeMeta(s.toConsulReference(api.InlineCertificate, key)) if _, ok := s.certificateGateways[consulKey]; !ok { s.certificateGateways[consulKey] = &certificate{ secret: &secret, @@ -231,7 +231,7 @@ func (s *ResourceMap) ReferenceCountGateway(gateway gwv1beta1.Gateway) { set.certificates.Add(certificateKey) - consulCertificateKey := s.toConsulReference(api.FileSystemCertificate, certificateKey) + consulCertificateKey := s.toConsulReference(api.InlineCertificate, certificateKey) certificate, ok := s.certificateGateways[NormalizeMeta(consulCertificateKey)] if ok { certificate.gateways.Add(key) @@ -270,7 +270,7 @@ func (s *ResourceMap) ResourcesToGC(key types.NamespacedName) []api.ResourceRefe // the route altogether toGC = append(toGC, id) } - case api.FileSystemCertificate: + case api.InlineCertificate: if s.processedCertificates.Contains(id) { continue } @@ -323,7 +323,7 @@ func (s *ResourceMap) ReferenceCountConsulTCPRoute(route api.TCPRouteConfigEntry s.consulTCPRoutes[NormalizeMeta(key)] = set } -func (s *ResourceMap) ReferenceCountConsulCertificate(cert api.FileSystemCertificateConfigEntry) { +func (s *ResourceMap) ReferenceCountConsulCertificate(cert api.InlineCertificateConfigEntry) { key := s.objectReference(&cert) var referenced *certificate @@ -644,29 +644,36 @@ func (s *ResourceMap) CanGCTCPRouteOnUnbind(id api.ResourceReference) bool { return true } -func (s *ResourceMap) TranslateFileSystemCertificate(key types.NamespacedName) { - consulKey := s.toConsulReference(api.FileSystemCertificate, key) +func (s *ResourceMap) TranslateInlineCertificate(key types.NamespacedName) error { + consulKey := s.toConsulReference(api.InlineCertificate, key) certificate, ok := s.certificateGateways[NormalizeMeta(consulKey)] if !ok { - return + return nil } if certificate.secret == nil { - return + return nil } - // add to the processed set so that we don't GC it. + consulCertificate, err := s.translator.ToInlineCertificate(*certificate.secret) + if err != nil { + return err + } + + // add to the processed set so we don't GC it. s.processedCertificates.Add(consulKey) s.consulMutations = append(s.consulMutations, &ConsulUpdateOperation{ - Entry: s.translator.ToFileSystemCertificate(*certificate.secret), + Entry: consulCertificate, // just swallow the error and log it since we can't propagate status back on a certificate. - OnUpdate: func(err error) { + OnUpdate: func(error) { if err != nil { s.logger.Error(err, "error syncing certificate to Consul") } }, }) + + return nil } func (s *ResourceMap) Mutations() []*ConsulUpdateOperation { diff --git a/control-plane/api-gateway/common/translation.go b/control-plane/api-gateway/common/translation.go index d955b0212d..5161e6b033 100644 --- a/control-plane/api-gateway/common/translation.go +++ b/control-plane/api-gateway/common/translation.go @@ -4,7 +4,6 @@ package common import ( - "fmt" "strings" corev1 "k8s.io/api/core/v1" @@ -110,7 +109,7 @@ func (t ResourceTranslator) toAPIGatewayListener(gateway gwv1beta1.Gateway, list ref := IndexedNamespacedNameWithDefault(ref.Name, ref.Namespace, namespace) if resources.Certificate(ref) != nil { - certificates = append(certificates, t.NonNormalizedConfigEntryReference(api.FileSystemCertificate, ref)) + certificates = append(certificates, t.NonNormalizedConfigEntryReference(api.InlineCertificate, ref)) } } } @@ -530,19 +529,31 @@ func (t ResourceTranslator) translateTCPRouteRule(route gwv1alpha2.TCPRoute, ref return api.TCPService{}, false } -func (t ResourceTranslator) ToFileSystemCertificate(secret corev1.Secret) *api.FileSystemCertificateConfigEntry { - return &api.FileSystemCertificateConfigEntry{ - Kind: api.FileSystemCertificate, +func (t ResourceTranslator) ToInlineCertificate(secret corev1.Secret) (*api.InlineCertificateConfigEntry, error) { + certificate, privateKey, err := ParseCertificateData(secret) + if err != nil { + return nil, err + } + + err = ValidateKeyLength(privateKey) + if err != nil { + return nil, err + } + + namespace := t.Namespace(secret.Namespace) + + return &api.InlineCertificateConfigEntry{ + Kind: api.InlineCertificate, Name: secret.Name, - Namespace: t.Namespace(secret.Namespace), + Namespace: namespace, Partition: t.ConsulPartition, - Certificate: fmt.Sprintf("/consul/gateway-certificates/%s_%s_tls.crt", secret.Namespace, secret.Name), - PrivateKey: fmt.Sprintf("/consul/gateway-certificates/%s_%s_tls.key", secret.Namespace, secret.Name), + Certificate: strings.TrimSpace(certificate), + PrivateKey: strings.TrimSpace(privateKey), Meta: t.addDatacenterToMeta(map[string]string{ constants.MetaKeyKubeNS: secret.Namespace, constants.MetaKeyKubeName: secret.Name, }), - } + }, nil } func EntryToNamespacedName(entry api.ConfigEntry) types.NamespacedName { diff --git a/control-plane/api-gateway/common/translation_test.go b/control-plane/api-gateway/common/translation_test.go index e841464b9a..4331e2b77a 100644 --- a/control-plane/api-gateway/common/translation_test.go +++ b/control-plane/api-gateway/common/translation_test.go @@ -303,7 +303,7 @@ func TestTranslator_ToAPIGateway(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: listenerOneCertName, Namespace: listenerOneCertConsulNamespace, }, @@ -321,7 +321,7 @@ func TestTranslator_ToAPIGateway(t *testing.T) { TLS: api.APIGatewayTLSConfiguration{ Certificates: []api.ResourceReference{ { - Kind: api.FileSystemCertificate, + Kind: api.InlineCertificate, Name: listenerTwoCertName, Namespace: listenerTwoCertConsulNamespace, }, diff --git a/control-plane/api-gateway/controllers/gateway_controller.go b/control-plane/api-gateway/controllers/gateway_controller.go index 004b2bc1b1..8fb6a1faec 100644 --- a/control-plane/api-gateway/controllers/gateway_controller.go +++ b/control-plane/api-gateway/controllers/gateway_controller.go @@ -136,10 +136,10 @@ func (r *GatewayController) Reconcile(ctx context.Context, req ctrl.Request) (ct return ctrl.Result{}, err } - // fetch our file-system-certificates from cache, this needs to happen + // fetch our inline certificates from cache, this needs to happen // here since the certificates need to be reference counted before // the gateways. - r.fetchConsulFileSystemCertificates(resources) + r.fetchConsulInlineCertificates(resources) // add our current gateway even if it's not controlled by us so we // can garbage collect any resources for it. @@ -365,7 +365,10 @@ func configEntriesTo[T api.ConfigEntry](entries []api.ConfigEntry) []T { func (r *GatewayController) deleteGatekeeperResources(ctx context.Context, log logr.Logger, gw *gwv1beta1.Gateway) error { gk := gatekeeper.New(log, r.Client) - err := gk.Delete(ctx, *gw) + err := gk.Delete(ctx, types.NamespacedName{ + Namespace: gw.Namespace, + Name: gw.Name, + }) if err != nil { return err } @@ -384,7 +387,7 @@ func (r *GatewayController) updateGatekeeperResources(ctx context.Context, log l } // SetupWithGatewayControllerManager registers the controller with the given manager. -func SetupGatewayControllerWithManager(ctx context.Context, mgr ctrl.Manager, config GatewayControllerConfig) (*cache.Cache, binding.Cleaner, error) { +func SetupGatewayControllerWithManager(ctx context.Context, mgr ctrl.Manager, config GatewayControllerConfig) (*cache.Cache, error) { cacheConfig := cache.Config{ ConsulClientConfig: config.ConsulClientConfig, ConsulServerConnMgr: config.ConsulServerConnMgr, @@ -420,14 +423,7 @@ func SetupGatewayControllerWithManager(ctx context.Context, mgr ctrl.Manager, co gatewayCache: gwc, } - cleaner := binding.Cleaner{ - Logger: mgr.GetLogger(), - ConsulConfig: config.ConsulClientConfig, - ServerMgr: config.ConsulServerConnMgr, - AuthMethod: config.HelmConfig.AuthMethod, - } - - return c, cleaner, ctrl.NewControllerManagedBy(mgr). + return c, ctrl.NewControllerManagedBy(mgr). For(&gwv1beta1.Gateway{}). Owns(&appsv1.Deployment{}). Owns(&corev1.Service{}). @@ -481,8 +477,8 @@ func SetupGatewayControllerWithManager(ctx context.Context, mgr ctrl.Manager, co &handler.EnqueueRequestForObject{}, ). WatchesRawSource( - // Subscribe to changes from Consul for FileSystemCertificates - &source.Channel{Source: c.Subscribe(ctx, api.FileSystemCertificate, r.transformConsulFileSystemCertificate(ctx)).Events()}, + // Subscribe to changes from Consul for InlineCertificates + &source.Channel{Source: c.Subscribe(ctx, api.InlineCertificate, r.transformConsulInlineCertificate(ctx)).Events()}, &handler.EnqueueRequestForObject{}, ). WatchesRawSource( @@ -664,7 +660,7 @@ func (r *GatewayController) transformConsulTCPRoute(ctx context.Context) func(en } } -func (r *GatewayController) transformConsulFileSystemCertificate(ctx context.Context) func(entry api.ConfigEntry) []types.NamespacedName { +func (r *GatewayController) transformConsulInlineCertificate(ctx context.Context) func(entry api.ConfigEntry) []types.NamespacedName { return func(entry api.ConfigEntry) []types.NamespacedName { certificateKey := api.ResourceReference{ Kind: entry.GetKind(), @@ -1216,8 +1212,8 @@ func (c *GatewayController) fetchConsulTCPRoutes(ref api.ResourceReference, reso } } -func (c *GatewayController) fetchConsulFileSystemCertificates(resources *common.ResourceMap) { - for _, cert := range configEntriesTo[*api.FileSystemCertificateConfigEntry](c.cache.List(api.FileSystemCertificate)) { +func (c *GatewayController) fetchConsulInlineCertificates(resources *common.ResourceMap) { + for _, cert := range configEntriesTo[*api.InlineCertificateConfigEntry](c.cache.List(api.InlineCertificate)) { resources.ReferenceCountConsulCertificate(*cert) } } diff --git a/control-plane/api-gateway/controllers/gateway_controller_integration_test.go b/control-plane/api-gateway/controllers/gateway_controller_integration_test.go index b9a3f9cc9e..3c64f488c9 100644 --- a/control-plane/api-gateway/controllers/gateway_controller_integration_test.go +++ b/control-plane/api-gateway/controllers/gateway_controller_integration_test.go @@ -153,7 +153,7 @@ func TestControllerDoesNotInfinitelyReconcile(t *testing.T) { gwSub := resourceCache.Subscribe(ctx, api.APIGateway, gwCtrl.transformConsulGateway) httpRouteSub := resourceCache.Subscribe(ctx, api.HTTPRoute, gwCtrl.transformConsulHTTPRoute(ctx)) tcpRouteSub := resourceCache.Subscribe(ctx, api.TCPRoute, gwCtrl.transformConsulTCPRoute(ctx)) - fileSystemCertSub := resourceCache.Subscribe(ctx, api.FileSystemCertificate, gwCtrl.transformConsulFileSystemCertificate(ctx)) + inlineCertSub := resourceCache.Subscribe(ctx, api.InlineCertificate, gwCtrl.transformConsulInlineCertificate(ctx)) cert := tc.certFn(t, ctx, k8sClient, tc.namespace) k8sGWObj := tc.gwFn(t, ctx, k8sClient, tc.namespace) @@ -227,7 +227,7 @@ func TestControllerDoesNotInfinitelyReconcile(t *testing.T) { tcpRouteDone = true w.Done() } - case <-fileSystemCertSub.Events(): + case <-inlineCertSub.Events(): } } }(wg) @@ -257,7 +257,7 @@ func TestControllerDoesNotInfinitelyReconcile(t *testing.T) { gwRef := gwCtrl.Translator.ConfigEntryReference(api.APIGateway, gwNamespaceName) httpRouteRef := gwCtrl.Translator.ConfigEntryReference(api.HTTPRoute, httpRouteNamespaceName) tcpRouteRef := gwCtrl.Translator.ConfigEntryReference(api.TCPRoute, tcpRouteNamespaceName) - certRef := gwCtrl.Translator.ConfigEntryReference(api.FileSystemCertificate, certNamespaceName) + certRef := gwCtrl.Translator.ConfigEntryReference(api.InlineCertificate, certNamespaceName) curGWModifyIndex := resourceCache.Get(gwRef).GetModifyIndex() curHTTPRouteModifyIndex := resourceCache.Get(httpRouteRef).GetModifyIndex() diff --git a/control-plane/api-gateway/gatekeeper/dataplane.go b/control-plane/api-gateway/gatekeeper/dataplane.go index f4b6e25a88..16839cbb09 100644 --- a/control-plane/api-gateway/gatekeeper/dataplane.go +++ b/control-plane/api-gateway/gatekeeper/dataplane.go @@ -23,11 +23,10 @@ const ( consulDataplaneDNSBindHost = "127.0.0.1" consulDataplaneDNSBindPort = 8600 defaultEnvoyProxyConcurrency = 1 - volumeNameForConnectInject = "consul-connect-inject-data" - volumeNameForTLSCerts = "consul-gateway-tls-certificates" + volumeName = "consul-connect-inject-data" ) -func consulDataplaneContainer(metrics common.MetricsConfig, config common.HelmConfig, gcc v1alpha1.GatewayClassConfig, name, namespace string, mounts []corev1.VolumeMount) (corev1.Container, error) { +func consulDataplaneContainer(metrics common.MetricsConfig, config common.HelmConfig, gcc v1alpha1.GatewayClassConfig, name, namespace string) (corev1.Container, error) { // Extract the service account token's volume mount. var ( err error @@ -54,9 +53,8 @@ func consulDataplaneContainer(metrics common.MetricsConfig, config common.HelmCo } container := corev1.Container{ - Name: name, - Image: config.ImageDataplane, - ImagePullPolicy: corev1.PullPolicy(config.GlobalImagePullPolicy), + Name: name, + Image: config.ImageDataplane, // We need to set tmp dir to an ephemeral volume that we're mounting so that // consul-dataplane can write files to it. Otherwise, it wouldn't be able to @@ -79,7 +77,12 @@ func consulDataplaneContainer(metrics common.MetricsConfig, config common.HelmCo Value: "$(NODE_NAME)-virtual", }, }, - VolumeMounts: mounts, + VolumeMounts: []corev1.VolumeMount{ + { + Name: volumeName, + MountPath: "/consul/connect-inject", + }, + }, Args: args, ReadinessProbe: probe, } diff --git a/control-plane/api-gateway/gatekeeper/deployment.go b/control-plane/api-gateway/gatekeeper/deployment.go index 61ef1fd318..d3bb56a69f 100644 --- a/control-plane/api-gateway/gatekeeper/deployment.go +++ b/control-plane/api-gateway/gatekeeper/deployment.go @@ -107,9 +107,7 @@ func (g *Gatekeeper) deployment(gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayC annotations[constants.AnnotationPrometheusPort] = strconv.Itoa(metrics.Port) } - volumes, mounts := volumesAndMounts(gateway) - - container, err := consulDataplaneContainer(metrics, config, gcc, gateway.Name, gateway.Namespace, mounts) + container, err := consulDataplaneContainer(metrics, config, gcc, gateway.Name, gateway.Namespace) if err != nil { return nil, err } @@ -131,7 +129,14 @@ func (g *Gatekeeper) deployment(gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayC Annotations: annotations, }, Spec: corev1.PodSpec{ - Volumes: volumes, + Volumes: []corev1.Volume{ + { + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{Medium: corev1.StorageMediumMemory}, + }, + }, + }, InitContainers: []corev1.Container{ initContainer, }, diff --git a/control-plane/api-gateway/gatekeeper/gatekeeper.go b/control-plane/api-gateway/gatekeeper/gatekeeper.go index 538444303f..6cb7170fc8 100644 --- a/control-plane/api-gateway/gatekeeper/gatekeeper.go +++ b/control-plane/api-gateway/gatekeeper/gatekeeper.go @@ -8,12 +8,11 @@ import ( "fmt" "github.com/go-logr/logr" + "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" + "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) // Gatekeeper is used to manage the lifecycle of Gateway deployments and services. @@ -51,10 +50,6 @@ func (g *Gatekeeper) Upsert(ctx context.Context, gateway gwv1beta1.Gateway, gcc return err } - if err := g.upsertSecret(ctx, gateway); err != nil { - return err - } - if err := g.upsertDeployment(ctx, gateway, gcc, config); err != nil { return err } @@ -64,18 +59,13 @@ func (g *Gatekeeper) Upsert(ctx context.Context, gateway gwv1beta1.Gateway, gcc // Delete removes the resources for handling routing of network traffic. // This is done in the reverse order of Upsert due to dependencies between resources. -func (g *Gatekeeper) Delete(ctx context.Context, gateway gwv1beta1.Gateway) error { - gatewayName := g.namespacedName(gateway) +func (g *Gatekeeper) Delete(ctx context.Context, gatewayName types.NamespacedName) error { g.Log.V(1).Info(fmt.Sprintf("Delete Gateway Deployment %s/%s", gatewayName.Namespace, gatewayName.Name)) if err := g.deleteDeployment(ctx, gatewayName); err != nil { return err } - if err := g.deleteSecret(ctx, gateway); err != nil { - return err - } - if err := g.deleteService(ctx, gatewayName); err != nil { return err } diff --git a/control-plane/api-gateway/gatekeeper/gatekeeper_test.go b/control-plane/api-gateway/gatekeeper/gatekeeper_test.go index cf8c325364..8c0d842d49 100644 --- a/control-plane/api-gateway/gatekeeper/gatekeeper_test.go +++ b/control-plane/api-gateway/gatekeeper/gatekeeper_test.go @@ -93,10 +93,8 @@ type testCase struct { type resources struct { deployments []*appsv1.Deployment - namespaces []*corev1.Namespace roles []*rbac.Role roleBindings []*rbac.RoleBinding - secrets []*corev1.Secret services []*corev1.Service serviceAccounts []*corev1.ServiceAccount } @@ -148,7 +146,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{}, }, @@ -198,9 +195,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, services: []*corev1.Service{ configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -253,9 +247,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, services: []*corev1.Service{ configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -314,9 +305,6 @@ func TestUpsert(t *testing.T) { roleBindings: []*rbac.RoleBinding{ configureRoleBinding(name, namespace, labels, "1"), }, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, services: []*corev1.Service{ configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -371,7 +359,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 5, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{}, }, @@ -409,7 +396,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 2, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{}, }, @@ -452,9 +438,6 @@ func TestUpsert(t *testing.T) { roleBindings: []*rbac.RoleBinding{ configureRoleBinding(name, namespace, labels, "1"), }, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, services: []*corev1.Service{ configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -478,9 +461,6 @@ func TestUpsert(t *testing.T) { roleBindings: []*rbac.RoleBinding{ configureRoleBinding(name, namespace, labels, "1"), }, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, services: []*corev1.Service{ configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -543,9 +523,6 @@ func TestUpsert(t *testing.T) { roleBindings: []*rbac.RoleBinding{ configureRoleBinding(name, namespace, labels, "1"), }, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, services: []*corev1.Service{ configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -574,9 +551,6 @@ func TestUpsert(t *testing.T) { roleBindings: []*rbac.RoleBinding{ configureRoleBinding(name, namespace, labels, "1"), }, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, services: []*corev1.Service{ configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -630,7 +604,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 5, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{}, }, @@ -684,7 +657,6 @@ func TestUpsert(t *testing.T) { finalResources: resources{ deployments: []*appsv1.Deployment{}, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{ configureService(name, namespace, labels, externalAndCopyAnnotations, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -754,7 +726,6 @@ func TestUpsert(t *testing.T) { finalResources: resources{ deployments: []*appsv1.Deployment{}, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{ configureService(name, namespace, labels, copyAnnotations, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ { @@ -812,7 +783,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 8, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{}, }, @@ -854,7 +824,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 2, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{}, }, @@ -896,7 +865,6 @@ func TestUpsert(t *testing.T) { configureDeployment(name, namespace, labels, 5, nil, nil, "", "1"), }, roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{}, }, @@ -940,178 +908,12 @@ func TestUpsert(t *testing.T) { roleBindings: []*rbac.RoleBinding{ configureRoleBinding(name, namespace, labels, "1"), }, - secrets: []*corev1.Secret{}, services: []*corev1.Service{}, serviceAccounts: []*corev1.ServiceAccount{ configureServiceAccount(name, namespace, labels, "1"), }, }, }, - "create a new gateway with TLS certificate reference in the same namespace": { - gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{ - { - Name: "Listener 1", - Port: 443, - Protocol: "TCP", - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - { - Namespace: common.PointerTo(gwv1beta1.Namespace(namespace)), - Name: "tls-cert", - }, - }, - }, - }, - }, - }, - }, - gatewayClassConfig: v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-gatewayclassconfig", - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - DeploymentSpec: v1alpha1.DeploymentSpec{ - DefaultInstances: common.PointerTo(int32(3)), - MaxInstances: common.PointerTo(int32(3)), - MinInstances: common.PointerTo(int32(1)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - OpenshiftSCCName: "test-api-gateway", - }, - }, - helmConfig: common.HelmConfig{ - EnableOpenShift: false, - ImageDataplane: "hashicorp/consul-dataplane", - }, - initialResources: resources{ - secrets: []*corev1.Secret{ - { - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tls-cert", - Namespace: namespace, - }, - Data: map[string][]byte{ - corev1.TLSCertKey: []byte("cert"), - corev1.TLSPrivateKeyKey: []byte("key"), - }, - Type: corev1.SecretTypeTLS, - }, - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - roleBindings: []*rbac.RoleBinding{}, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", map[string][]byte{ - "default_tls-cert_tls.crt": []byte("cert"), - "default_tls-cert_tls.key": []byte("key"), - }), - }, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "create a new gateway with TLS certificate reference in a different namespace": { - gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{ - { - Name: "Listener 1", - Port: 443, - Protocol: "TCP", - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - { - Namespace: common.PointerTo(gwv1beta1.Namespace("non-default")), - Name: "tls-cert", - }, - }, - }, - }, - }, - }, - }, - gatewayClassConfig: v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-gatewayclassconfig", - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - DeploymentSpec: v1alpha1.DeploymentSpec{ - DefaultInstances: common.PointerTo(int32(3)), - MaxInstances: common.PointerTo(int32(3)), - MinInstances: common.PointerTo(int32(1)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - OpenshiftSCCName: "test-api-gateway", - }, - }, - helmConfig: common.HelmConfig{ - EnableOpenShift: false, - ImageDataplane: "hashicorp/consul-dataplane", - }, - initialResources: resources{ - namespaces: []*corev1.Namespace{ - { - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Namespace", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "non-default", - }, - }, - }, - secrets: []*corev1.Secret{ - { - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tls-cert", - Namespace: "non-default", - }, - Data: map[string][]byte{ - corev1.TLSCertKey: []byte("cert"), - corev1.TLSPrivateKeyKey: []byte("key"), - }, - Type: corev1.SecretTypeTLS, - }, - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - roleBindings: []*rbac.RoleBinding{}, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", map[string][]byte{ - "non-default_tls-cert_tls.crt": []byte("cert"), - "non-default_tls-cert_tls.key": []byte("key"), - }), - }, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, } for name, tc := range cases { @@ -1298,73 +1100,6 @@ func TestDelete(t *testing.T) { serviceAccounts: []*corev1.ServiceAccount{}, }, }, - "delete a gateway deployment with a Secret": { - gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: gwv1beta1.GatewaySpec{ - Listeners: listeners, - }, - }, - gatewayClassConfig: v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-gatewayclassconfig", - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - DeploymentSpec: v1alpha1.DeploymentSpec{ - DefaultInstances: common.PointerTo(int32(3)), - MaxInstances: common.PointerTo(int32(3)), - MinInstances: common.PointerTo(int32(1)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - ServiceType: (*corev1.ServiceType)(common.PointerTo("NodePort")), - }, - }, - helmConfig: common.HelmConfig{ - AuthMethod: "method", - ImageDataplane: dataplaneImage, - }, - initialResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{ - configureRole(name, namespace, labels, "1", false), - }, - roleBindings: []*rbac.RoleBinding{ - configureRoleBinding(name, namespace, labels, "1"), - }, - secrets: []*corev1.Secret{ - configureSecret(name, namespace, labels, "1", nil), - }, - services: []*corev1.Service{ - configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ - { - Name: "Listener 1", - Protocol: "TCP", - Port: 8080, - }, - { - Name: "Listener 2", - Protocol: "TCP", - Port: 8081, - }, - }, "1", true, false), - }, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{}, - roles: []*rbac.Role{}, - secrets: []*corev1.Secret{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, } for name, tc := range cases { @@ -1383,7 +1118,10 @@ func TestDelete(t *testing.T) { gatekeeper := New(log, client) - err := gatekeeper.Delete(context.Background(), tc.gateway) + err := gatekeeper.Delete(context.Background(), types.NamespacedName{ + Namespace: tc.gateway.Namespace, + Name: tc.gateway.Name, + }) require.NoError(t, err) require.NoError(t, validateResourcesExist(t, client, tc.helmConfig, tc.finalResources, false)) require.NoError(t, validateResourcesAreDeleted(t, client, tc.initialResources)) @@ -1396,10 +1134,6 @@ func joinResources(resources resources) (objs []client.Object) { objs = append(objs, deployment) } - for _, namespace := range resources.namespaces { - objs = append(objs, namespace) - } - for _, role := range resources.roles { objs = append(objs, role) } @@ -1408,10 +1142,6 @@ func joinResources(resources resources) (objs []client.Object) { objs = append(objs, roleBinding) } - for _, secret := range resources.secrets { - objs = append(objs, secret) - } - for _, service := range resources.services { objs = append(objs, service) } @@ -1484,35 +1214,6 @@ func validateResourcesExist(t *testing.T, client client.Client, helmConfig commo assert.True(t, hasDataplaneContainer) } - for _, namespace := range resources.namespaces { - actual := &corev1.Namespace{} - err := client.Get(context.Background(), types.NamespacedName{Name: namespace.Name}, actual) - if err != nil { - return err - } - - // Patch the createdAt label - actual.Labels[createdAtLabelKey] = createdAtLabelValue - - require.Equal(t, namespace, actual) - } - - for _, expected := range resources.secrets { - actual := &corev1.Secret{} - err := client.Get(context.Background(), types.NamespacedName{ - Name: expected.Name, - Namespace: expected.Namespace, - }, actual) - if err != nil { - return err - } - - // Patch the createdAt label - actual.Labels[createdAtLabelKey] = createdAtLabelValue - - require.Equal(t, expected, actual) - } - for _, expected := range resources.roles { actual := &rbac.Role{} err := client.Get(context.Background(), types.NamespacedName{ @@ -1711,31 +1412,6 @@ func configureDeployment(name, namespace string, labels map[string]string, repli } } -func configureSecret(name, namespace string, labels map[string]string, resourceVersion string, data map[string][]byte) *corev1.Secret { - return &corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - Labels: labels, - ResourceVersion: resourceVersion, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "gateway.networking.k8s.io/v1beta1", - Kind: "Gateway", - Name: name, - Controller: common.PointerTo(true), - BlockOwnerDeletion: common.PointerTo(true), - }, - }, - }, - Data: data, - } -} - func configureRole(name, namespace string, labels map[string]string, resourceVersion string, openshiftEnabled bool) *rbac.Role { rules := []rbac.PolicyRule{} diff --git a/control-plane/api-gateway/gatekeeper/init.go b/control-plane/api-gateway/gatekeeper/init.go index b30bafc240..59d55ee7f1 100644 --- a/control-plane/api-gateway/gatekeeper/init.go +++ b/control-plane/api-gateway/gatekeeper/init.go @@ -47,7 +47,7 @@ func initContainer(config common.HelmConfig, name, namespace string) (corev1.Con // Create expected volume mounts volMounts := []corev1.VolumeMount{ { - Name: volumeNameForConnectInject, + Name: volumeName, MountPath: "/consul/connect-inject", }, } @@ -69,9 +69,8 @@ func initContainer(config common.HelmConfig, name, namespace string) (corev1.Con initContainerName := injectInitContainerName container := corev1.Container{ - Name: initContainerName, - Image: config.ImageConsulK8S, - ImagePullPolicy: corev1.PullPolicy(config.GlobalImagePullPolicy), + Name: initContainerName, + Image: config.ImageConsulK8S, Env: []corev1.EnvVar{ { diff --git a/control-plane/api-gateway/gatekeeper/ownership.go b/control-plane/api-gateway/gatekeeper/ownership.go deleted file mode 100644 index babf5aa812..0000000000 --- a/control-plane/api-gateway/gatekeeper/ownership.go +++ /dev/null @@ -1,16 +0,0 @@ -package gatekeeper - -import ( - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func isOwnedByGateway(o client.Object, gateway gwv1beta1.Gateway) bool { - for _, ref := range o.GetOwnerReferences() { - if ref.UID == gateway.GetUID() && ref.Name == gateway.GetName() { - // We found our gateway! - return true - } - } - return false -} diff --git a/control-plane/api-gateway/gatekeeper/secret.go b/control-plane/api-gateway/gatekeeper/secret.go deleted file mode 100644 index dfef33c23d..0000000000 --- a/control-plane/api-gateway/gatekeeper/secret.go +++ /dev/null @@ -1,129 +0,0 @@ -package gatekeeper - -import ( - "context" - "fmt" - - corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - controllerruntime "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" -) - -func (g *Gatekeeper) upsertSecret(ctx context.Context, gateway gwv1beta1.Gateway) error { - desiredSecret, err := g.secret(ctx, gateway) - if err != nil { - return fmt.Errorf("failed to create certificate secret for gateway %s/%s: %w", gateway.Namespace, gateway.Name, err) - } - - // If the Secret already exists, ensure that we own the Secret - existingSecret := &corev1.Secret{ObjectMeta: desiredSecret.ObjectMeta} - err = g.Client.Get(ctx, g.namespacedName(gateway), existingSecret) - if err != nil && !k8serrors.IsNotFound(err) { - return fmt.Errorf("failed to fetch existing Secret %s/%s: %w", gateway.Namespace, gateway.Name, err) - } else if !k8serrors.IsNotFound(err) { - if !isOwnedByGateway(existingSecret, gateway) { - return fmt.Errorf("existing Secret %s/%s is not owned by Gateway %s/%s", existingSecret.Namespace, existingSecret.Name, gateway.Namespace, gateway.Name) - } - } - - mutator := newSecretMutator(existingSecret, desiredSecret, gateway, g.Client.Scheme()) - - result, err := controllerruntime.CreateOrUpdate(ctx, g.Client, existingSecret, mutator) - if err != nil { - return err - } - - switch result { - case controllerutil.OperationResultCreated: - g.Log.V(1).Info("Created Secret") - case controllerutil.OperationResultUpdated: - g.Log.V(1).Info("Updated Secret") - case controllerutil.OperationResultNone: - g.Log.V(1).Info("No change to Secret") - } - - return nil -} - -func (g *Gatekeeper) deleteSecret(ctx context.Context, gw gwv1beta1.Gateway) error { - secret := &corev1.Secret{} - if err := g.Client.Get(ctx, g.namespacedName(gw), secret); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - if !isOwnedByGateway(secret, gw) { - return fmt.Errorf("existing Secret %s/%s is not owned by Gateway %s/%s", secret.Namespace, secret.Name, gw.Namespace, gw.Name) - } - - if err := g.Client.Delete(ctx, secret); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - return nil -} - -func (g *Gatekeeper) secret(ctx context.Context, gateway gwv1beta1.Gateway) (*corev1.Secret, error) { - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: gateway.Namespace, - Name: gateway.Name, - Labels: common.LabelsForGateway(&gateway), - }, - Data: map[string][]byte{}, - Type: corev1.SecretTypeOpaque, - } - - for _, listener := range gateway.Spec.Listeners { - if listener.TLS == nil { - continue - } - - for _, ref := range listener.TLS.CertificateRefs { - // Only take action on Secret references - if !common.NilOrEqual(ref.Group, "") || !common.NilOrEqual(ref.Kind, common.KindSecret) { - continue - } - - key := types.NamespacedName{ - Namespace: common.ValueOr(ref.Namespace, gateway.Namespace), - Name: string(ref.Name), - } - - referencedSecret := &corev1.Secret{} - if err := g.Client.Get(ctx, key, referencedSecret); err != nil && k8serrors.IsNotFound(err) { - // If the referenced Secret is not found, log a message and continue. - // The issue will be raised on the Gateway status by the validation process. - g.Log.V(1).Info(fmt.Sprintf("Referenced certificate secret %s/%s not found", key.Namespace, key.Name)) - } else if err != nil { - return nil, fmt.Errorf("failed to fetch certificate secret %s/%s: %w", key.Namespace, key.Name, err) - } - - prefix := fmt.Sprintf("%s_%s_", key.Namespace, key.Name) - for k, v := range referencedSecret.Data { - secret.Data[prefix+k] = v - } - } - } - - return secret, nil -} - -func newSecretMutator(existing, desired *corev1.Secret, gateway gwv1beta1.Gateway, scheme *runtime.Scheme) resourceMutator { - return func() error { - existing.Data = desired.Data - return controllerruntime.SetControllerReference(&gateway, existing, scheme) - } -} diff --git a/control-plane/api-gateway/gatekeeper/volumes.go b/control-plane/api-gateway/gatekeeper/volumes.go deleted file mode 100644 index ef8c414575..0000000000 --- a/control-plane/api-gateway/gatekeeper/volumes.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" -) - -// volumesAndMounts generates the list of volumes for the Deployment and the list of volume -// mounts for the primary container in the Deployment. There are two volumes that are created: -// - one empty volume for holding connect-inject data -// - one volume holding all TLS certificates referenced by the Gateway. -func volumesAndMounts(gateway v1beta1.Gateway) ([]corev1.Volume, []corev1.VolumeMount) { - volumes := []corev1.Volume{ - { - Name: volumeNameForConnectInject, - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{Medium: corev1.StorageMediumMemory}, - }, - }, - { - Name: volumeNameForTLSCerts, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: gateway.Name, - DefaultMode: common.PointerTo(int32(444)), - Optional: common.PointerTo(false), - }, - }, - }, - } - - mounts := []corev1.VolumeMount{ - { - Name: volumeNameForConnectInject, - MountPath: "/consul/connect-inject", - }, - { - Name: volumeNameForTLSCerts, - MountPath: "/consul/gateway-certificates", - }, - } - - return volumes, mounts -} diff --git a/control-plane/api/auth/v2beta1/traffic_permissions_types_test.go b/control-plane/api/auth/v2beta1/traffic_permissions_types_test.go index 85bedb6c40..170f02fb20 100644 --- a/control-plane/api/auth/v2beta1/traffic_permissions_types_test.go +++ b/control-plane/api/auth/v2beta1/traffic_permissions_types_test.go @@ -604,7 +604,7 @@ func TestTrafficPermissions_ObjectMeta(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. // TODO: add when implemented -//func TestTrafficPermissions_DefaultNamespaceFields(t *testing.T) +// func TestTrafficPermissions_DefaultNamespaceFields(t *testing.T) func TestTrafficPermissions_Validate(t *testing.T) { cases := []struct { diff --git a/control-plane/api/common/common.go b/control-plane/api/common/common.go index 077be60a9b..53d4c42e96 100644 --- a/control-plane/api/common/common.go +++ b/control-plane/api/common/common.go @@ -28,16 +28,14 @@ const ( ControlPlaneRequestLimit string = "controlplanerequestlimit" RouteAuthFilter string = "routeauthfilter" GatewayPolicy string = "gatewaypolicy" - Registration string = "registration" - // V2 resources. + // V2 config entries. TrafficPermissions string = "trafficpermissions" GRPCRoute string = "grpcroute" HTTPRoute string = "httproute" TCPRoute string = "tcproute" ProxyConfiguration string = "proxyconfiguration" MeshGateway string = "meshgateway" - APIGateway string = "apigateway" GatewayClass string = "gatewayclass" GatewayClassConfig string = "gatewayclassconfig" MeshConfiguration string = "meshconfiguration" diff --git a/control-plane/api/mesh/v2beta1/api_gateway_types.go b/control-plane/api/mesh/v2beta1/api_gateway_types.go index 18bd4ad5b1..d9da1d1947 100644 --- a/control-plane/api/mesh/v2beta1/api_gateway_types.go +++ b/control-plane/api/mesh/v2beta1/api_gateway_types.go @@ -12,9 +12,6 @@ import ( "google.golang.org/protobuf/testing/protocmp" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/hashicorp/consul-k8s/control-plane/api/common" inject "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" @@ -25,7 +22,7 @@ const ( ) func init() { - MeshSchemeBuilder.Register(&APIGateway{}, &APIGatewayList{}) + MeshSchemeBuilder.Register(&GatewayClass{}, &GatewayClassList{}) } // +kubebuilder:object:root=true @@ -40,26 +37,8 @@ type APIGateway struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec pbmesh.APIGateway `json:"spec,omitempty"` - APIGatewayStatus `json:"status,omitempty"` -} - -type APIGatewayStatus struct { - Status `json:"status,omitempty"` - Addresses []GatewayAddress `json:"addresses,omitempty"` - Listeners []ListenerStatus `json:"listeners,omitempty"` -} - -type ListenerStatus struct { - Status `json:"status,omitempty"` - Name string `json:"name"` - AttachedRoutes int32 `json:"attachedRoutes"` -} - -type GatewayAddress struct { - // +kubebuilder:default=IPAddress - Type string `json:"type"` - Value string `json:"value"` + Spec pbmesh.APIGateway `json:"spec,omitempty"` + Status `json:"status,omitempty"` } // +kubebuilder:object:root=true @@ -71,20 +50,6 @@ type APIGatewayList struct { Items []*APIGateway `json:"items"` } -func (in *APIGatewayList) ReconcileRequests() []reconcile.Request { - requests := make([]reconcile.Request, 0, len(in.Items)) - - for _, item := range in.Items { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: item.Name, - Namespace: item.Namespace, - }, - }) - } - return requests -} - func (in *APIGateway) ResourceID(namespace, partition string) *pbresource.ID { return &pbresource.ID{ Name: in.Name, @@ -179,27 +144,3 @@ func (in *APIGateway) Validate(tenancy common.ConsulTenancyConfig) error { // DefaultNamespaceFields is required as part of the common.MeshConfig interface. func (in *APIGateway) DefaultNamespaceFields(tenancy common.ConsulTenancyConfig) {} - -// ListenersToServicePorts converts the APIGateway listeners to ServicePorts. -func (in *APIGateway) ListenersToServicePorts(portModifier int32) []corev1.ServicePort { - ports := []corev1.ServicePort{} - - for _, listener := range in.Spec.Listeners { - port := int32(listener.Port) - ports = append(ports, corev1.ServicePort{ - Name: listener.Name, - Port: port, - TargetPort: intstr.IntOrString{ - IntVal: port + portModifier, - }, - Protocol: corev1.Protocol(listener.Protocol), - }) - } - - return ports -} - -func (in *APIGateway) ListenersToContainerPorts(_ int32, _ int32) []corev1.ContainerPort { - // TODO: check if this is actually needed: we don't map any container ports in v1 - return []corev1.ContainerPort{} -} diff --git a/control-plane/api/mesh/v2beta1/grpc_route_types_test.go b/control-plane/api/mesh/v2beta1/grpc_route_types_test.go index c5ae7864de..07f010bd97 100644 --- a/control-plane/api/mesh/v2beta1/grpc_route_types_test.go +++ b/control-plane/api/mesh/v2beta1/grpc_route_types_test.go @@ -597,7 +597,7 @@ func TestGRPCRoute_ObjectMeta(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. // TODO: add when implemented -//func TestGRPCRoute_DefaultNamespaceFields(t *testing.T) +// func TestGRPCRoute_DefaultNamespaceFields(t *testing.T) func TestGRPCRoute_Validate(t *testing.T) { cases := []struct { diff --git a/control-plane/api/mesh/v2beta1/http_route_types_test.go b/control-plane/api/mesh/v2beta1/http_route_types_test.go index 7c9996f185..ecebfb7600 100644 --- a/control-plane/api/mesh/v2beta1/http_route_types_test.go +++ b/control-plane/api/mesh/v2beta1/http_route_types_test.go @@ -803,7 +803,7 @@ func TestHTTPRoute_ObjectMeta(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. // TODO: add when implemented -//func TestHTTPRoute_DefaultNamespaceFields(t *testing.T) +// func TestHTTPRoute_DefaultNamespaceFields(t *testing.T) func TestHTTPRoute_Validate(t *testing.T) { cases := []struct { diff --git a/control-plane/api/mesh/v2beta1/mesh_configuration_types.go b/control-plane/api/mesh/v2beta1/mesh_configuration_types.go index 32a19ae2e7..5468168380 100644 --- a/control-plane/api/mesh/v2beta1/mesh_configuration_types.go +++ b/control-plane/api/mesh/v2beta1/mesh_configuration_types.go @@ -7,13 +7,14 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/consul-k8s/control-plane/api/common" - inject "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" "github.com/hashicorp/consul/proto-public/pbresource" "google.golang.org/protobuf/testing/protocmp" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/hashicorp/consul-k8s/control-plane/api/common" + inject "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" ) const ( diff --git a/control-plane/api/mesh/v2beta1/mesh_gateway_types.go b/control-plane/api/mesh/v2beta1/mesh_gateway_types.go index 4531a2089e..922fd272c2 100644 --- a/control-plane/api/mesh/v2beta1/mesh_gateway_types.go +++ b/control-plane/api/mesh/v2beta1/mesh_gateway_types.go @@ -12,9 +12,6 @@ import ( "google.golang.org/protobuf/testing/protocmp" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/hashicorp/consul-k8s/control-plane/api/common" inject "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" @@ -53,20 +50,6 @@ type MeshGatewayList struct { Items []*MeshGateway `json:"items"` } -func (in *MeshGatewayList) ReconcileRequests() []reconcile.Request { - requests := make([]reconcile.Request, 0, len(in.Items)) - - for _, item := range in.Items { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: item.Name, - Namespace: item.Namespace, - }, - }) - } - return requests -} - func (in *MeshGateway) ResourceID(_, partition string) *pbresource.ID { return &pbresource.ID{ Name: in.Name, @@ -74,6 +57,7 @@ func (in *MeshGateway) ResourceID(_, partition string) *pbresource.ID { Tenancy: &pbresource.Tenancy{ Partition: partition, Namespace: "", // Namespace is always unset because MeshGateway is partition-scoped + }, } } @@ -162,38 +146,3 @@ func (in *MeshGateway) Validate(tenancy common.ConsulTenancyConfig) error { // DefaultNamespaceFields is required as part of the common.MeshConfig interface. func (in *MeshGateway) DefaultNamespaceFields(tenancy common.ConsulTenancyConfig) {} - -// ListenersToServicePorts converts the MeshGateway listeners to ServicePorts. -func (in *MeshGateway) ListenersToServicePorts(portModifier int32) []corev1.ServicePort { - ports := []corev1.ServicePort{} - - for _, listener := range in.Spec.Listeners { - port := int32(listener.Port) - - ports = append(ports, corev1.ServicePort{ - Name: listener.Name, - Port: port, - TargetPort: intstr.IntOrString{ - IntVal: port + portModifier, - }, - Protocol: corev1.Protocol(listener.Protocol), - }) - } - return ports -} - -func (in *MeshGateway) ListenersToContainerPorts(portModifier int32, hostPort int32) []corev1.ContainerPort { - ports := []corev1.ContainerPort{} - - for _, listener := range in.Spec.Listeners { - port := int32(listener.Port) - - ports = append(ports, corev1.ContainerPort{ - Name: listener.Name, - ContainerPort: port + portModifier, - HostPort: hostPort, - Protocol: corev1.Protocol(listener.Protocol), - }) - } - return ports -} diff --git a/control-plane/api/mesh/v2beta1/proxy_configuration_types_test.go b/control-plane/api/mesh/v2beta1/proxy_configuration_types_test.go index 55e6ce45a9..936f3dd9c2 100644 --- a/control-plane/api/mesh/v2beta1/proxy_configuration_types_test.go +++ b/control-plane/api/mesh/v2beta1/proxy_configuration_types_test.go @@ -509,7 +509,7 @@ func TestProxyConfiguration_ObjectMeta(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. // TODO: add when implemented -//func TestProxyConfiguration_DefaultNamespaceFields(t *testing.T) +// func TestProxyConfiguration_DefaultNamespaceFields(t *testing.T) func constructProxyConfigurationResource(tp *pbmesh.ProxyConfiguration, name, namespace, partition string) *pbresource.Resource { data := inject.ToProtoAny(tp) diff --git a/control-plane/api/mesh/v2beta1/tcp_route_types_test.go b/control-plane/api/mesh/v2beta1/tcp_route_types_test.go index f03e5232db..fd139058d7 100644 --- a/control-plane/api/mesh/v2beta1/tcp_route_types_test.go +++ b/control-plane/api/mesh/v2beta1/tcp_route_types_test.go @@ -379,7 +379,7 @@ func TestTCPRoute_ObjectMeta(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. // TODO: add when implemented -//func TestTCPRoute_DefaultNamespaceFields(t *testing.T) +// func TestTCPRoute_DefaultNamespaceFields(t *testing.T) func TestTCPRoute_Validate(t *testing.T) { cases := []struct { diff --git a/control-plane/api/mesh/v2beta1/zz_generated.deepcopy.go b/control-plane/api/mesh/v2beta1/zz_generated.deepcopy.go index d4ca224b61..9cc59efb3e 100644 --- a/control-plane/api/mesh/v2beta1/zz_generated.deepcopy.go +++ b/control-plane/api/mesh/v2beta1/zz_generated.deepcopy.go @@ -16,7 +16,7 @@ func (in *APIGateway) DeepCopyInto(out *APIGateway) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - in.APIGatewayStatus.DeepCopyInto(&out.APIGatewayStatus) + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIGateway. @@ -73,34 +73,6 @@ func (in *APIGatewayList) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *APIGatewayStatus) DeepCopyInto(out *APIGatewayStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]GatewayAddress, len(*in)) - copy(*out, *in) - } - if in.Listeners != nil { - in, out := &in.Listeners, &out.Listeners - *out = make([]ListenerStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIGatewayStatus. -func (in *APIGatewayStatus) DeepCopy() *APIGatewayStatus { - if in == nil { - return nil - } - out := new(APIGatewayStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Condition) DeepCopyInto(out *Condition) { *out = *in @@ -201,21 +173,6 @@ func (in *GRPCRouteList) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GatewayAddress) DeepCopyInto(out *GatewayAddress) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayAddress. -func (in *GatewayAddress) DeepCopy() *GatewayAddress { - if in == nil { - return nil - } - out := new(GatewayAddress) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayClass) DeepCopyInto(out *GatewayClass) { *out = *in @@ -724,22 +681,6 @@ func (in *HTTPRouteList) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ListenerStatus) DeepCopyInto(out *ListenerStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ListenerStatus. -func (in *ListenerStatus) DeepCopy() *ListenerStatus { - if in == nil { - return nil - } - out := new(ListenerStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MeshConfiguration) DeepCopyInto(out *MeshConfiguration) { *out = *in diff --git a/control-plane/api/multicluster/v2/exported_services_types.go b/control-plane/api/multicluster/v2/exported_services_types.go index 032e10bd03..2e746efbee 100644 --- a/control-plane/api/multicluster/v2/exported_services_types.go +++ b/control-plane/api/multicluster/v2/exported_services_types.go @@ -57,6 +57,7 @@ func (in *ExportedServices) ResourceID(_, partition string) *pbresource.ID { Tenancy: &pbresource.Tenancy{ Partition: partition, Namespace: "", // Namespace is always unset because ExportedServices is partition-scoped + }, } } diff --git a/control-plane/api/v1alpha1/registration_types.go b/control-plane/api/v1alpha1/registration_types.go deleted file mode 100644 index f3190aef87..0000000000 --- a/control-plane/api/v1alpha1/registration_types.go +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "errors" - "maps" - "slices" - "time" - - capi "github.com/hashicorp/consul/api" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func init() { - SchemeBuilder.Register(&Registration{}, &RegistrationList{}) -} - -// +genclient -// +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster -// +kubebuilder:subresource:status - -// Registration defines the resource for working with service registrations. -type Registration struct { - // Standard Kubernetes resource metadata. - metav1.TypeMeta `json:",inline"` - - // Standard object's metadata. - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Spec defines the desired state of Registration. - Spec RegistrationSpec `json:"spec,omitempty"` - - Status RegistrationStatus `json:"status,omitempty"` -} - -// RegistrationStatus defines the observed state of Registration. -type RegistrationStatus struct { - // Conditions indicate the latest available observations of a resource's current state. - // +optional - // +patchMergeKey=type - // +patchStrategy=merge - Conditions Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` - // LastSyncedTime is the last time the resource successfully synced with Consul. - // +optional - LastSyncedTime *metav1.Time `json:"lastSyncedTime,omitempty" description:"last time the condition transitioned from one status to another"` -} - -// +k8s:deepcopy-gen=true - -// RegistrationSpec specifies the desired state of the Config CRD. -type RegistrationSpec struct { - ID string `json:"id,omitempty"` - Node string `json:"node,omitempty"` - Address string `json:"address,omitempty"` - TaggedAddresses map[string]string `json:"taggedAddresses,omitempty"` - NodeMeta map[string]string `json:"nodeMeta,omitempty"` - Datacenter string `json:"datacenter,omitempty"` - Service Service `json:"service,omitempty"` - SkipNodeUpdate bool `json:"skipNodeUpdate,omitempty"` - Partition string `json:"partition,omitempty"` - HealthCheck *HealthCheck `json:"check,omitempty"` - Locality *Locality `json:"locality,omitempty"` -} - -// +k8s:deepcopy-gen=true - -type Service struct { - ID string `json:"id,omitempty"` - Name string `json:"name"` - Tags []string `json:"tags,omitempty"` - Meta map[string]string `json:"meta,omitempty"` - Port int `json:"port"` - Address string `json:"address"` - SocketPath string `json:"socketPath,omitempty"` - TaggedAddresses map[string]ServiceAddress `json:"taggedAddresses,omitempty"` - Weights Weights `json:"weights,omitempty"` - EnableTagOverride bool `json:"enableTagOverride,omitempty"` - Locality *Locality `json:"locality,omitempty"` - Namespace string `json:"namespace,omitempty"` - Partition string `json:"partition,omitempty"` -} - -// +k8s:deepcopy-gen=true - -type ServiceAddress struct { - Address string `json:"address"` - Port int `json:"port"` -} - -// +k8s:deepcopy-gen=true - -type Weights struct { - Passing int `json:"passing"` - Warning int `json:"warning"` -} - -// +k8s:deepcopy-gen=true - -type Locality struct { - Region string `json:"region,omitempty"` - Zone string `json:"zone,omitempty"` -} - -// +k8s:deepcopy-gen=true - -// HealthCheck is used to represent a single check. -type HealthCheck struct { - Node string `json:"node,omitempty"` - CheckID string `json:"checkId"` - Name string `json:"name"` - Status string `json:"status"` - Notes string `json:"notes,omitempty"` - Output string `json:"output,omitempty"` - ServiceID string `json:"serviceId"` - ServiceName string `json:"serviceName"` - Type string `json:"type,omitempty"` - ExposedPort int `json:"exposedPort,omitempty"` - Definition HealthCheckDefinition `json:"definition"` - Namespace string `json:"namespace,omitempty"` - Partition string `json:"partition,omitempty"` -} - -// HealthCheckDefinition is used to store the details about -// a health check's execution. -type HealthCheckDefinition struct { - HTTP string `json:"http,omitempty"` - Header map[string][]string `json:"header,omitempty"` - Method string `json:"method,omitempty"` - Body string `json:"body,omitempty"` - TLSServerName string `json:"tlsServerName,omitempty"` - TLSSkipVerify bool `json:"tlsSkipVerify,omitempty"` - TCP string `json:"tcp,omitempty"` - TCPUseTLS bool `json:"tcpUseTLS,omitempty"` - UDP string `json:"udp,omitempty"` - GRPC string `json:"grpc,omitempty"` - OSService string `json:"osService,omitempty"` - GRPCUseTLS bool `json:"grpcUseTLS,omitempty"` - IntervalDuration string `json:"intervalDuration"` - TimeoutDuration string `json:"timeoutDuration,omitempty"` - DeregisterCriticalServiceAfterDuration string `json:"deregisterCriticalServiceAfterDuration,omitempty"` -} - -// +kubebuilder:object:root=true - -// RegistrationList is a list of Registration resources. -type RegistrationList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata"` - - // Items is the list of Registrations. - Items []Registration `json:"items"` -} - -// ToCatalogRegistration converts a Registration to a Consul CatalogRegistration. -func (r *Registration) ToCatalogRegistration() (*capi.CatalogRegistration, error) { - check, err := copyHealthCheck(r.Spec.HealthCheck) - if err != nil { - return nil, err - } - - return &capi.CatalogRegistration{ - ID: r.Spec.ID, - Node: r.Spec.Node, - Address: r.Spec.Address, - TaggedAddresses: maps.Clone(r.Spec.TaggedAddresses), - NodeMeta: maps.Clone(r.Spec.NodeMeta), - Datacenter: r.Spec.Datacenter, - Service: &capi.AgentService{ - ID: r.Spec.Service.ID, - Service: r.Spec.Service.Name, - Tags: slices.Clone(r.Spec.Service.Tags), - Meta: maps.Clone(r.Spec.Service.Meta), - Port: r.Spec.Service.Port, - Address: r.Spec.Service.Address, - SocketPath: r.Spec.Service.SocketPath, - TaggedAddresses: copyTaggedAddresses(r.Spec.Service.TaggedAddresses), - Weights: capi.AgentWeights(r.Spec.Service.Weights), - EnableTagOverride: r.Spec.Service.EnableTagOverride, - Namespace: r.Spec.Service.Namespace, - Partition: r.Spec.Service.Partition, - Locality: copyLocality(r.Spec.Service.Locality), - }, - Check: check, - SkipNodeUpdate: r.Spec.SkipNodeUpdate, - Partition: r.Spec.Partition, - Locality: copyLocality(r.Spec.Locality), - }, nil -} - -func copyTaggedAddresses(taggedAddresses map[string]ServiceAddress) map[string]capi.ServiceAddress { - if taggedAddresses == nil { - return nil - } - result := make(map[string]capi.ServiceAddress, len(taggedAddresses)) - for k, v := range taggedAddresses { - result[k] = capi.ServiceAddress(v) - } - return result -} - -func copyLocality(locality *Locality) *capi.Locality { - if locality == nil { - return nil - } - return &capi.Locality{ - Region: locality.Region, - Zone: locality.Zone, - } -} - -var ( - ErrInvalidInterval = errors.New("invalid value for IntervalDuration") - ErrInvalidTimeout = errors.New("invalid value for TimeoutDuration") - ErrInvalidDergisterAfter = errors.New("invalid value for DeregisterCriticalServiceAfterDuration") -) - -func copyHealthCheck(healthCheck *HealthCheck) (*capi.AgentCheck, error) { - if healthCheck == nil { - return nil, nil - } - - // TODO: handle error - intervalDuration, err := time.ParseDuration(healthCheck.Definition.IntervalDuration) - if err != nil { - return nil, ErrInvalidInterval - } - - timeoutDuration, err := time.ParseDuration(healthCheck.Definition.TimeoutDuration) - if err != nil { - return nil, ErrInvalidTimeout - } - - deregisterAfter, err := time.ParseDuration(healthCheck.Definition.DeregisterCriticalServiceAfterDuration) - if err != nil { - return nil, ErrInvalidDergisterAfter - } - - return &capi.AgentCheck{ - Node: healthCheck.Node, - Notes: healthCheck.Notes, - ServiceName: healthCheck.ServiceName, - CheckID: healthCheck.CheckID, - Name: healthCheck.Name, - Type: healthCheck.Type, - Status: healthCheck.Status, - ServiceID: healthCheck.ServiceID, - ExposedPort: healthCheck.ExposedPort, - Output: healthCheck.Output, - Namespace: healthCheck.Namespace, - Partition: healthCheck.Partition, - Definition: capi.HealthCheckDefinition{ - HTTP: healthCheck.Definition.HTTP, - TCP: healthCheck.Definition.TCP, - GRPC: healthCheck.Definition.GRPC, - GRPCUseTLS: healthCheck.Definition.GRPCUseTLS, - Method: healthCheck.Definition.Method, - Header: healthCheck.Definition.Header, - Body: healthCheck.Definition.Body, - TLSServerName: healthCheck.Definition.TLSServerName, - TLSSkipVerify: healthCheck.Definition.TLSSkipVerify, - OSService: healthCheck.Definition.OSService, - IntervalDuration: intervalDuration, - TimeoutDuration: timeoutDuration, - DeregisterCriticalServiceAfterDuration: deregisterAfter, - }, - }, nil -} - -// ToCatalogDeregistration converts a Registration to a Consul CatalogDeregistration. -func (r *Registration) ToCatalogDeregistration() *capi.CatalogDeregistration { - checkID := "" - if r.Spec.HealthCheck != nil { - checkID = r.Spec.HealthCheck.CheckID - } - - return &capi.CatalogDeregistration{ - Node: r.Spec.Node, - Address: r.Spec.Address, - Datacenter: r.Spec.Datacenter, - ServiceID: r.Spec.Service.ID, - CheckID: checkID, - Namespace: r.Spec.Service.Namespace, - Partition: r.Spec.Service.Partition, - } -} - -func (r *Registration) EqualExceptStatus(other *Registration) bool { - if r == nil || other == nil { - return false - } - - if r.Spec.ID != other.Spec.ID { - return false - } - - if r.Spec.Node != other.Spec.Node { - return false - } - - if r.Spec.Address != other.Spec.Address { - return false - } - - if !maps.Equal(r.Spec.TaggedAddresses, other.Spec.TaggedAddresses) { - return false - } - - if !maps.Equal(r.Spec.NodeMeta, other.Spec.NodeMeta) { - return false - } - - if r.Spec.Datacenter != other.Spec.Datacenter { - return false - } - - if !r.Spec.Service.Equal(&other.Spec.Service) { - return false - } - - if r.Spec.SkipNodeUpdate != other.Spec.SkipNodeUpdate { - return false - } - - if r.Spec.Partition != other.Spec.Partition { - return false - } - - if !r.Spec.HealthCheck.Equal(other.Spec.HealthCheck) { - return false - } - - if !r.Spec.Locality.Equal(other.Spec.Locality) { - return false - } - - return true -} - -func (s *Service) Equal(other *Service) bool { - if s == nil && other == nil { - return true - } - - if s == nil || other == nil { - return false - } - - if s.ID != other.ID { - return false - } - - if s.Name != other.Name { - return false - } - - if !slices.Equal(s.Tags, other.Tags) { - return false - } - - if !maps.Equal(s.Meta, other.Meta) { - return false - } - - if s.Port != other.Port { - return false - } - - if s.Address != other.Address { - return false - } - - if s.SocketPath != other.SocketPath { - return false - } - - if !maps.Equal(s.TaggedAddresses, other.TaggedAddresses) { - return false - } - - if !s.Weights.Equal(other.Weights) { - return false - } - - if s.EnableTagOverride != other.EnableTagOverride { - return false - } - - if s.Namespace != other.Namespace { - return false - } - - if s.Partition != other.Partition { - return false - } - - if !s.Locality.Equal(other.Locality) { - return false - } - return true -} - -func (l *Locality) Equal(other *Locality) bool { - if l == nil && other == nil { - return true - } - - if l == nil || other == nil { - return false - } - if l.Region != other.Region { - return false - } - if l.Zone != other.Zone { - return false - } - return true -} - -func (w Weights) Equal(other Weights) bool { - if w.Passing != other.Passing { - return false - } - - if w.Warning != other.Warning { - return false - } - return true -} - -func (h *HealthCheck) Equal(other *HealthCheck) bool { - if h == nil && other == nil { - return true - } - - if h == nil || other == nil { - return false - } - - if h.Node != other.Node { - return false - } - - if h.CheckID != other.CheckID { - return false - } - - if h.Name != other.Name { - return false - } - - if h.Status != other.Status { - return false - } - - if h.Notes != other.Notes { - return false - } - - if h.Output != other.Output { - return false - } - - if h.ServiceID != other.ServiceID { - return false - } - - if h.ServiceName != other.ServiceName { - return false - } - - if h.Type != other.Type { - return false - } - - if h.ExposedPort != other.ExposedPort { - return false - } - - if h.Namespace != other.Namespace { - return false - } - - if h.Partition != other.Partition { - return false - } - - if !h.Definition.Equal(other.Definition) { - return false - } - - return true -} - -func (h HealthCheckDefinition) Equal(other HealthCheckDefinition) bool { - if h.HTTP != other.HTTP { - return false - } - - if len(h.Header) != len(other.Header) { - return false - } - - for k, v := range h.Header { - otherValues, ok := other.Header[k] - if !ok { - return false - } - - if !slices.Equal(v, otherValues) { - return false - } - } - - if h.Method != other.Method { - return false - } - - if h.Body != other.Body { - return false - } - - if h.TLSServerName != other.TLSServerName { - return false - } - - if h.TLSSkipVerify != other.TLSSkipVerify { - return false - } - - if h.TCP != other.TCP { - return false - } - - if h.TCPUseTLS != other.TCPUseTLS { - return false - } - - if h.UDP != other.UDP { - return false - } - - if h.GRPC != other.GRPC { - return false - } - - if h.OSService != other.OSService { - return false - } - - if h.GRPCUseTLS != other.GRPCUseTLS { - return false - } - - if h.IntervalDuration != other.IntervalDuration { - return false - } - - if h.TimeoutDuration != other.TimeoutDuration { - return false - } - - if h.DeregisterCriticalServiceAfterDuration != other.DeregisterCriticalServiceAfterDuration { - return false - } - - return true -} - -func (r *Registration) KubernetesName() string { - return r.ObjectMeta.Name -} diff --git a/control-plane/api/v1alpha1/registration_types_test.go b/control-plane/api/v1alpha1/registration_types_test.go deleted file mode 100644 index 8c3744efb9..0000000000 --- a/control-plane/api/v1alpha1/registration_types_test.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "testing" - "time" - - capi "github.com/hashicorp/consul/api" - - "github.com/stretchr/testify/require" -) - -func TestToCatalogRegistration(tt *testing.T) { - cases := map[string]struct { - registration *Registration - expected *capi.CatalogRegistration - }{ - "minimal registration": { - registration: &Registration{ - Spec: RegistrationSpec{ - ID: "node-id", - Node: "node-virtual", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - expected: &capi.CatalogRegistration{ - ID: "node-id", - Node: "node-virtual", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: &capi.AgentService{ - ID: "service-id", - Service: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - "maximal registration": { - registration: &Registration{ - Spec: RegistrationSpec{ - ID: "node-id", - Node: "node-virtual", - Address: "127.0.0.1", - TaggedAddresses: map[string]string{ - "lan": "8080", - }, - NodeMeta: map[string]string{ - "n1": "m1", - }, - Datacenter: "dc1", - Service: Service{ - ID: "service-id", - Name: "service-name", - Tags: []string{"tag1", "tag2"}, - Meta: map[string]string{ - "m1": "1", - "m2": "2", - }, - Port: 8080, - Address: "127.0.0.1", - TaggedAddresses: map[string]ServiceAddress{ - "lan": { - Address: "10.0.0.10", - Port: 5000, - }, - }, - Weights: Weights{ - Passing: 50, - Warning: 100, - }, - EnableTagOverride: true, - Locality: &Locality{ - Region: "us-east-1", - Zone: "auto", - }, - Namespace: "n1", - Partition: "p1", - }, - Partition: "p1", - HealthCheck: &HealthCheck{ - Node: "node-virtual", - CheckID: "service-check", - Name: "service-health", - Status: "passing", - Notes: "all about that service", - Output: "healthy", - ServiceID: "service-id", - ServiceName: "service-name", - Type: "readiness", - ExposedPort: 19000, - Definition: HealthCheckDefinition{ - HTTP: "/health", - TCP: "tcp-check", - Header: map[string][]string{ - "Content-Type": {"application/json"}, - }, - Method: "GET", - TLSServerName: "my-secure-tls-server", - TLSSkipVerify: true, - Body: "some-body", - GRPC: "/grpc-health-check", - GRPCUseTLS: true, - OSService: "osservice-name", - IntervalDuration: "5s", - TimeoutDuration: "10s", - DeregisterCriticalServiceAfterDuration: "30s", - }, - Namespace: "n1", - Partition: "p1", - }, - Locality: &Locality{ - Region: "us-east-1", - Zone: "auto", - }, - }, - }, - expected: &capi.CatalogRegistration{ - ID: "node-id", - Node: "node-virtual", - Address: "127.0.0.1", - TaggedAddresses: map[string]string{ - "lan": "8080", - }, - NodeMeta: map[string]string{ - "n1": "m1", - }, - Datacenter: "dc1", - Service: &capi.AgentService{ - ID: "service-id", - Service: "service-name", - Tags: []string{"tag1", "tag2"}, - Meta: map[string]string{ - "m1": "1", - "m2": "2", - }, - Port: 8080, - Address: "127.0.0.1", - TaggedAddresses: map[string]capi.ServiceAddress{ - "lan": { - Address: "10.0.0.10", - Port: 5000, - }, - }, - Weights: capi.AgentWeights{ - Passing: 50, - Warning: 100, - }, - EnableTagOverride: true, - Locality: &capi.Locality{ - Region: "us-east-1", - Zone: "auto", - }, - Namespace: "n1", - Partition: "p1", - }, - Check: &capi.AgentCheck{ - Node: "node-virtual", - CheckID: "service-check", - Name: "service-health", - Status: "passing", - Notes: "all about that service", - Output: "healthy", - ServiceID: "service-id", - ServiceName: "service-name", - Type: "readiness", - ExposedPort: 19000, - Definition: capi.HealthCheckDefinition{ - HTTP: "/health", - TCP: "tcp-check", - Header: map[string][]string{ - "Content-Type": {"application/json"}, - }, - Method: "GET", - TLSServerName: "my-secure-tls-server", - TLSSkipVerify: true, - Body: "some-body", - GRPC: "/grpc-health-check", - GRPCUseTLS: true, - OSService: "osservice-name", - IntervalDuration: toDuration(tt, "5s"), - TimeoutDuration: toDuration(tt, "10s"), - DeregisterCriticalServiceAfterDuration: toDuration(tt, "30s"), - }, - Namespace: "n1", - Partition: "p1", - }, - SkipNodeUpdate: false, - Partition: "p1", - Locality: &capi.Locality{ - Region: "us-east-1", - Zone: "auto", - }, - }, - }, - } - - for name, tc := range cases { - tc := tc - tt.Run(name, func(t *testing.T) { - t.Parallel() - actual, err := tc.registration.ToCatalogRegistration() - require.NoError(t, err) - require.Equal(t, tc.expected, actual) - }) - } -} - -func TestToCatalogDeregistration(tt *testing.T) { - cases := map[string]struct { - registration *Registration - expected *capi.CatalogDeregistration - }{ - "with health check": { - registration: &Registration{ - Spec: RegistrationSpec{ - ID: "node-id", - Node: "node-virtual", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: Service{ - ID: "service-id", - Namespace: "n1", - Partition: "p1", - }, - HealthCheck: &HealthCheck{ - CheckID: "checkID", - }, - }, - }, - expected: &capi.CatalogDeregistration{ - Node: "node-virtual", - Address: "127.0.0.1", - Datacenter: "dc1", - ServiceID: "service-id", - CheckID: "checkID", - Namespace: "n1", - Partition: "p1", - }, - }, - "no health check": { - registration: &Registration{ - Spec: RegistrationSpec{ - ID: "node-id", - Node: "node-virtual", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: Service{ - ID: "service-id", - Namespace: "n1", - Partition: "p1", - }, - }, - }, - expected: &capi.CatalogDeregistration{ - Node: "node-virtual", - Address: "127.0.0.1", - Datacenter: "dc1", - ServiceID: "service-id", - CheckID: "", - Namespace: "n1", - Partition: "p1", - }, - }, - } - - for name, tc := range cases { - tc := tc - tt.Run(name, func(t *testing.T) { - t.Parallel() - actual := tc.registration.ToCatalogDeregistration() - require.Equal(t, tc.expected, actual) - }) - } -} - -func toDuration(t *testing.T, d string) time.Duration { - t.Helper() - duration, err := time.ParseDuration(d) - if err != nil { - t.Fatal(err) - } - return duration -} diff --git a/control-plane/api/v1alpha1/registration_webhook.go b/control-plane/api/v1alpha1/registration_webhook.go deleted file mode 100644 index e2a69f3b0b..0000000000 --- a/control-plane/api/v1alpha1/registration_webhook.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "context" - "errors" - "fmt" - "net/http" - "time" - - "github.com/go-logr/logr" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" -) - -// +kubebuilder:object:generate=false - -type RegistrationWebhook struct { - Logger logr.Logger - - // ConsulMeta contains metadata specific to the Consul installation. - ConsulMeta common.ConsulMeta - - decoder *admission.Decoder - client.Client -} - -// +kubebuilder:webhook:verbs=create;update,path=/validate-v1alpha1-registration,mutating=false,failurePolicy=fail,groups=consul.hashicorp.com,resources=registrations,versions=v1alpha1,name=validate-registration.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 - -func (v *RegistrationWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { - resource := &Registration{} - decodeErr := v.decoder.Decode(req, resource) - if decodeErr != nil { - return admission.Errored(http.StatusBadRequest, decodeErr) - } - - var err error - - err = errors.Join(err, validateRequiredFields(resource)) - err = errors.Join(err, validateHealthChecks(resource)) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - return admission.Allowed("registration is valid") -} - -func (v *RegistrationWebhook) SetupWithManager(mgr ctrl.Manager) { - v.Logger.Info("setting up registration webhook") - v.decoder = admission.NewDecoder(mgr.GetScheme()) - mgr.GetWebhookServer().Register("/validate-v1alpha1-registration", &admission.Webhook{Handler: v}) -} - -func validateRequiredFields(registration *Registration) error { - var err error - if registration.Spec.Node == "" { - err = errors.Join(err, errors.New("registration.Spec.Node is required")) - } - if registration.Spec.Service.Name == "" { - err = errors.Join(err, errors.New("registration.Spec.Service.Name is required")) - } - if registration.Spec.Address == "" { - err = errors.Join(err, errors.New("registration.Spec.Address is required")) - } - - if err != nil { - return err - } - return nil -} - -var validStatuses = map[string]struct{}{ - "passing": {}, - "warning": {}, - "critical": {}, -} - -func validateHealthChecks(registration *Registration) error { - if registration.Spec.HealthCheck == nil { - return nil - } - - var err error - - if registration.Spec.HealthCheck.Name == "" { - err = errors.Join(err, errors.New("registration.Spec.HealthCheck.Name is required")) - } - - // status must be one "passing", "warning", or "critical" - if _, ok := validStatuses[registration.Spec.HealthCheck.Status]; !ok { - err = errors.Join(err, fmt.Errorf("invalid registration.Spec.HealthCheck.Status value, must be 'passing', 'warning', or 'critical', actual: %q", registration.Spec.HealthCheck.Status)) - } - - // parse all durations and check for any errors - _, parseErr := time.ParseDuration(registration.Spec.HealthCheck.Definition.IntervalDuration) - if parseErr != nil { - err = errors.Join(err, fmt.Errorf("invalid registration.Spec.HealthCheck.Definition.IntervalDuration value: %q", registration.Spec.HealthCheck.Definition.IntervalDuration)) - } - - if registration.Spec.HealthCheck.Definition.TimeoutDuration != "" { - _, timeoutErr := time.ParseDuration(registration.Spec.HealthCheck.Definition.TimeoutDuration) - if timeoutErr != nil { - err = errors.Join(err, fmt.Errorf("invalid registration.Spec.HealthCheck.Definition.TimeoutDuration value: %q", registration.Spec.HealthCheck.Definition.TimeoutDuration)) - } - } - - if registration.Spec.HealthCheck.Definition.DeregisterCriticalServiceAfterDuration != "" { - _, deregCriticalErr := time.ParseDuration(registration.Spec.HealthCheck.Definition.DeregisterCriticalServiceAfterDuration) - if deregCriticalErr != nil { - err = errors.Join(err, fmt.Errorf("invalid registration.Spec.HealthCheck.Definition.DeregisterCriticalServiceAfterDuration value: %q", registration.Spec.HealthCheck.Definition.DeregisterCriticalServiceAfterDuration)) - } - } - - if err != nil { - return err - } - - return nil -} diff --git a/control-plane/api/v1alpha1/registration_webhook_test.go b/control-plane/api/v1alpha1/registration_webhook_test.go deleted file mode 100644 index 8883cbda10..0000000000 --- a/control-plane/api/v1alpha1/registration_webhook_test.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "context" - "encoding/json" - "testing" - - logrtest "github.com/go-logr/logr/testr" - "github.com/stretchr/testify/require" - admissionv1 "k8s.io/api/admission/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -func TestValidateRegistration(t *testing.T) { - cases := map[string]struct { - newResource *Registration - expectedToAllow bool - expectedErrMessage string - }{ - "valid with health check, status 'passing'": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "node-virtual", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "passing", - Definition: HealthCheckDefinition{ - IntervalDuration: "10s", - }, - }, - }, - }, - expectedToAllow: true, - }, - "valid with health check, status 'warning'": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "node-virtual", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "warning", - Definition: HealthCheckDefinition{ - IntervalDuration: "10s", - }, - }, - }, - }, - expectedToAllow: true, - }, - "valid with health check, status 'critical'": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "node-virtual", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "critical", - Definition: HealthCheckDefinition{ - IntervalDuration: "10s", - }, - }, - }, - }, - expectedToAllow: true, - }, - "valid without health check": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "node-virtual", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: nil, - }, - }, - expectedToAllow: true, - }, - "invalid, missing node field": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: nil, - }, - }, - expectedToAllow: false, - expectedErrMessage: "registration.Spec.Node is required", - }, - "invalid, missing address field": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "", - Service: Service{Name: "test-service"}, - HealthCheck: nil, - }, - }, - expectedToAllow: false, - expectedErrMessage: "registration.Spec.Address is required", - }, - "invalid, missing service.name field": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "10.2.2.1", - Service: Service{Name: ""}, - HealthCheck: nil, - }, - }, - expectedToAllow: false, - expectedErrMessage: "registration.Spec.Service.Name is required", - }, - "invalid, health check is set and name is missing": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "", - Status: "passing", - Definition: HealthCheckDefinition{ - IntervalDuration: "10s", - }, - }, - }, - }, - expectedToAllow: false, - expectedErrMessage: "registration.Spec.HealthCheck.Name is required", - }, - "invalid, health check is set and intervalDuration is missing": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "passing", - Definition: HealthCheckDefinition{ - IntervalDuration: "", - }, - }, - }, - }, - expectedToAllow: false, - expectedErrMessage: "invalid registration.Spec.HealthCheck.Definition.IntervalDuration value: \"\"", - }, - "invalid, health check is set and intervalDuration is invalid duration type": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "passing", - Definition: HealthCheckDefinition{ - IntervalDuration: "150", - }, - }, - }, - }, - expectedToAllow: false, - expectedErrMessage: "invalid registration.Spec.HealthCheck.Definition.IntervalDuration value: \"150\"", - }, - "invalid, health check is set and timeoutDuration is invalid duration type": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "passing", - Definition: HealthCheckDefinition{ - IntervalDuration: "10s", - TimeoutDuration: "150", - }, - }, - }, - }, - expectedToAllow: false, - expectedErrMessage: "invalid registration.Spec.HealthCheck.Definition.TimeoutDuration value: \"150\"", - }, - "invalid, health check is set and deregisterCriticalServiceAfterDuration is invalid duration type": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "passing", - Definition: HealthCheckDefinition{ - IntervalDuration: "10s", - TimeoutDuration: "150s", - DeregisterCriticalServiceAfterDuration: "40", - }, - }, - }, - }, - expectedToAllow: false, - expectedErrMessage: "invalid registration.Spec.HealthCheck.Definition.DeregisterCriticalServiceAfterDuration value: \"40\"", - }, - "invalid, health check is set and status is not 'passing', 'critical', or 'warning'": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "test-node", - Address: "10.2.2.1", - Service: Service{Name: "test-service"}, - HealthCheck: &HealthCheck{ - Name: "check name", - Status: "wrong", - Definition: HealthCheckDefinition{ - IntervalDuration: "10s", - }, - }, - }, - }, - expectedToAllow: false, - expectedErrMessage: "invalid registration.Spec.HealthCheck.Status value, must be 'passing', 'warning', or 'critical', actual: \"wrong\"", - }, - "everything that can go wrong has gone wrong": { - newResource: &Registration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - }, - Spec: RegistrationSpec{ - Node: "", - Address: "", - Service: Service{Name: ""}, - HealthCheck: &HealthCheck{ - Name: "", - Status: "wrong", - Definition: HealthCheckDefinition{ - IntervalDuration: "10", - TimeoutDuration: "150", - DeregisterCriticalServiceAfterDuration: "40", - }, - }, - }, - }, - expectedToAllow: false, - expectedErrMessage: "registration.Spec.Node is required\nregistration.Spec.Service.Name is required\nregistration.Spec.Address is required\nregistration.Spec.HealthCheck.Name is required\ninvalid registration.Spec.HealthCheck.Status value, must be 'passing', 'warning', or 'critical', actual: \"wrong\"\ninvalid registration.Spec.HealthCheck.Definition.IntervalDuration value: \"10\"\ninvalid registration.Spec.HealthCheck.Definition.TimeoutDuration value: \"150\"\ninvalid registration.Spec.HealthCheck.Definition.DeregisterCriticalServiceAfterDuration value: \"40\"", - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - ctx := context.Background() - marshalledRequestObject, err := json.Marshal(c.newResource) - require.NoError(t, err) - s := runtime.NewScheme() - s.AddKnownTypes(GroupVersion, &Registration{}, &RegistrationList{}) - client := fake.NewClientBuilder().WithScheme(s).Build() - decoder := admission.NewDecoder(s) - - validator := &RegistrationWebhook{ - Client: client, - Logger: logrtest.New(t), - decoder: decoder, - } - response := validator.Handle(ctx, admission.Request{ - AdmissionRequest: admissionv1.AdmissionRequest{ - Name: c.newResource.KubernetesName(), - Namespace: "default", - Operation: admissionv1.Create, - Object: runtime.RawExtension{ - Raw: marshalledRequestObject, - }, - }, - }) - - require.Equal(t, c.expectedToAllow, response.Allowed) - if c.expectedErrMessage != "" { - require.Equal(t, c.expectedErrMessage, response.AdmissionResponse.Result.Message) - } - }) - } -} diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index a8aed9b1ff..2a1854d178 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -881,52 +881,6 @@ func (in *HashPolicy) DeepCopy() *HashPolicy { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HealthCheck) DeepCopyInto(out *HealthCheck) { - *out = *in - in.Definition.DeepCopyInto(&out.Definition) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheck. -func (in *HealthCheck) DeepCopy() *HealthCheck { - if in == nil { - return nil - } - out := new(HealthCheck) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HealthCheckDefinition) DeepCopyInto(out *HealthCheckDefinition) { - *out = *in - if in.Header != nil { - in, out := &in.Header, &out.Header - *out = make(map[string][]string, len(*in)) - for key, val := range *in { - var outVal []string - if val == nil { - (*out)[key] = nil - } else { - in, out := &val, &outVal - *out = make([]string, len(*in)) - copy(*out, *in) - } - (*out)[key] = outVal - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheckDefinition. -func (in *HealthCheckDefinition) DeepCopy() *HealthCheckDefinition { - if in == nil { - return nil - } - out := new(HealthCheckDefinition) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IngressGateway) DeepCopyInto(out *IngressGateway) { *out = *in @@ -1781,21 +1735,6 @@ func (in *LocalJWKS) DeepCopy() *LocalJWKS { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Locality) DeepCopyInto(out *Locality) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Locality. -func (in *Locality) DeepCopy() *Locality { - if in == nil { - return nil - } - out := new(Locality) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Mesh) DeepCopyInto(out *Mesh) { *out = *in @@ -2544,131 +2483,6 @@ func (in *ReadWriteRatesConfig) DeepCopy() *ReadWriteRatesConfig { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Registration) DeepCopyInto(out *Registration) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Registration. -func (in *Registration) DeepCopy() *Registration { - if in == nil { - return nil - } - out := new(Registration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Registration) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RegistrationList) DeepCopyInto(out *RegistrationList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Registration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistrationList. -func (in *RegistrationList) DeepCopy() *RegistrationList { - if in == nil { - return nil - } - out := new(RegistrationList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RegistrationList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RegistrationSpec) DeepCopyInto(out *RegistrationSpec) { - *out = *in - if in.TaggedAddresses != nil { - in, out := &in.TaggedAddresses, &out.TaggedAddresses - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.NodeMeta != nil { - in, out := &in.NodeMeta, &out.NodeMeta - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - in.Service.DeepCopyInto(&out.Service) - if in.HealthCheck != nil { - in, out := &in.HealthCheck, &out.HealthCheck - *out = new(HealthCheck) - (*in).DeepCopyInto(*out) - } - if in.Locality != nil { - in, out := &in.Locality, &out.Locality - *out = new(Locality) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistrationSpec. -func (in *RegistrationSpec) DeepCopy() *RegistrationSpec { - if in == nil { - return nil - } - out := new(RegistrationSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RegistrationStatus) DeepCopyInto(out *RegistrationStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make(Conditions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.LastSyncedTime != nil { - in, out := &in.LastSyncedTime, &out.LastSyncedTime - *out = (*in).DeepCopy() - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistrationStatus. -func (in *RegistrationStatus) DeepCopy() *RegistrationStatus { - if in == nil { - return nil - } - out := new(RegistrationStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RemoteJWKS) DeepCopyInto(out *RemoteJWKS) { *out = *in @@ -3142,61 +2956,6 @@ func (in *SecretRefStatus) DeepCopy() *SecretRefStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Service) DeepCopyInto(out *Service) { - *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Meta != nil { - in, out := &in.Meta, &out.Meta - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.TaggedAddresses != nil { - in, out := &in.TaggedAddresses, &out.TaggedAddresses - *out = make(map[string]ServiceAddress, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - out.Weights = in.Weights - if in.Locality != nil { - in, out := &in.Locality, &out.Locality - *out = new(Locality) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service. -func (in *Service) DeepCopy() *Service { - if in == nil { - return nil - } - out := new(Service) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceAddress) DeepCopyInto(out *ServiceAddress) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAddress. -func (in *ServiceAddress) DeepCopy() *ServiceAddress { - if in == nil { - return nil - } - out := new(ServiceAddress) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceConsumer) DeepCopyInto(out *ServiceConsumer) { *out = *in @@ -4275,18 +4034,3 @@ func (in *Upstreams) DeepCopy() *Upstreams { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Weights) DeepCopyInto(out *Weights) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Weights. -func (in *Weights) DeepCopy() *Weights { - if in == nil { - return nil - } - out := new(Weights) - in.DeepCopyInto(out) - return out -} diff --git a/control-plane/build-support/functions/10-util.sh b/control-plane/build-support/functions/10-util.sh index 3f0a140f9c..6cc632f55c 100644 --- a/control-plane/build-support/functions/10-util.sh +++ b/control-plane/build-support/functions/10-util.sh @@ -631,8 +631,7 @@ function update_version_helm { full_consul_version="$5-$3" full_consul_dataplane_version="$7-$3" elif test "$3" == "dev"; then - full_version="${2%.*}-$3" - full_version_k8s_for_chart_version="$2-$3" + full_version="$2-$3" # strip off the last minor patch version so that the consul image can be set to something like 1.16-dev. The image # is produced by Consul every night full_consul_version="${5%.*}-$3" @@ -658,7 +657,7 @@ function update_version_helm { fi sed_i ${SED_EXT} -e "s/(imageK8S:.*\/consul-k8s-control-plane:)[^\"]*/imageK8S: $4${full_version}/g" "${vfile}" - sed_i ${SED_EXT} -e "s/(version:[[:space:]]*)[^\"]*/\1${full_version_k8s_for_chart_version}/g" "${cfile}" + sed_i ${SED_EXT} -e "s/(version:[[:space:]]*)[^\"]*/\1${full_version}/g" "${cfile}" sed_i ${SED_EXT} -e "s/(appVersion:[[:space:]]*)[^\"]*/\1${full_consul_version}/g" "${cfile}" sed_i ${SED_EXT} -e "s/(image:.*\/consul-k8s-control-plane:)[^\"]*/image: $4${full_version}/g" "${cfile}" @@ -776,8 +775,7 @@ function set_changelog { fi compatibility_note=" -> NOTE: Consul K8s ${version_short}.x is compatible with Consul ${consul_version_short}.x and Consul Dataplane ${consul_dataplane_version_short}.x. Refer to our [compatibility matrix](https://developer.hashicorp.com/consul/docs/k8s/compatibility) for more info. -" +> NOTE: Consul K8s ${version_short}.x is compatible with Consul ${consul_version_short}.x and Consul Dataplane ${consul_dataplane_version_short}.x. Refer to our [compatibility matrix](https://developer.hashicorp.com/consul/docs/k8s/compatibility) for more info." fi cat <tmp && mv tmp "${curdir}"/CHANGELOG.MD diff --git a/control-plane/catalog/registration/cache.go b/control-plane/catalog/registration/cache.go deleted file mode 100644 index e556ab7a77..0000000000 --- a/control-plane/catalog/registration/cache.go +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package registration - -import ( - "context" - "errors" - "fmt" - "slices" - "strings" - "sync" - - mapset "github.com/deckarep/golang-set/v2" - "github.com/go-logr/logr" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/consul" - capi "github.com/hashicorp/consul/api" -) - -const NotInServiceMeshFilter = "ServiceMeta[\"managed-by\"] != \"consul-k8s-endpoints-controller\"" - -type RegistrationCache struct { - ConsulClientConfig *consul.Config - ConsulServerConnMgr consul.ServerConnectionManager - serviceMtx *sync.Mutex - Services map[string]*v1alpha1.Registration - synced chan struct{} - UpdateChan chan string -} - -func NewRegistrationCache(consulClientConfig *consul.Config, consulServerConnMgr consul.ServerConnectionManager) *RegistrationCache { - return &RegistrationCache{ - ConsulClientConfig: consulClientConfig, - ConsulServerConnMgr: consulServerConnMgr, - serviceMtx: &sync.Mutex{}, - Services: make(map[string]*v1alpha1.Registration), - UpdateChan: make(chan string), - synced: make(chan struct{}), - } -} - -// waitSynced is used to coordinate with the caller when the cache is initially filled. -func (c *RegistrationCache) waitSynced(ctx context.Context) { - select { - case <-c.synced: - return - case <-ctx.Done(): - return - } -} - -func (c *RegistrationCache) run(ctx context.Context, log logr.Logger) { - once := &sync.Once{} - opts := &capi.QueryOptions{Filter: NotInServiceMeshFilter} - - for { - select { - case <-ctx.Done(): - return - default: - - client, err := consul.NewClientFromConnMgr(c.ConsulClientConfig, c.ConsulServerConnMgr) - if err != nil { - log.Error(err, "error initializing consul client") - continue - } - entries, meta, err := client.Catalog().Services(opts.WithContext(ctx)) - if err != nil { - // if we timeout we don't care about the error message because it's expected to happen on long polls - // any other error we want to alert on - if !strings.Contains(strings.ToLower(err.Error()), "timeout") && - !strings.Contains(strings.ToLower(err.Error()), "no such host") && - !strings.Contains(strings.ToLower(err.Error()), "connection refused") { - log.Error(err, "error fetching registrations") - } - continue - } - - diffs := mapset.NewSet[string]() - c.serviceMtx.Lock() - for svc := range c.Services { - if _, ok := entries[svc]; !ok { - diffs.Add(svc) - } - } - c.serviceMtx.Unlock() - - for _, svc := range diffs.ToSlice() { - log.Info("consul deregistered service", "svcName", svc) - c.UpdateChan <- svc - } - - opts.WaitIndex = meta.LastIndex - once.Do(func() { - log.Info("Initial sync complete") - c.synced <- struct{}{} - }) - } - } -} - -func (c *RegistrationCache) get(svcName string) (*v1alpha1.Registration, bool) { - c.serviceMtx.Lock() - defer c.serviceMtx.Unlock() - val, ok := c.Services[svcName] - return val, ok -} - -func (c *RegistrationCache) aclsEnabled() bool { - return c.ConsulClientConfig.APIClientConfig.Token != "" || c.ConsulClientConfig.APIClientConfig.TokenFile != "" -} - -func (c *RegistrationCache) registerService(log logr.Logger, reg *v1alpha1.Registration) error { - client, err := consul.NewClientFromConnMgr(c.ConsulClientConfig, c.ConsulServerConnMgr) - if err != nil { - return err - } - - regReq, err := reg.ToCatalogRegistration() - if err != nil { - return err - } - - _, err = client.Catalog().Register(regReq, nil) - if err != nil { - log.Error(err, "error registering service", "svcName", regReq.Service.Service) - return err - } - - c.serviceMtx.Lock() - defer c.serviceMtx.Unlock() - c.Services[reg.Spec.Service.Name] = reg - - log.Info("Successfully registered service", "svcName", regReq.Service.Service) - - return nil -} - -func (c *RegistrationCache) updateTermGWACLRole(log logr.Logger, registration *v1alpha1.Registration, termGWsToUpdate []v1alpha1.TerminatingGateway) error { - if len(termGWsToUpdate) == 0 { - log.Info("terminating gateway not found") - return nil - } - - client, err := consul.NewClientFromConnMgr(c.ConsulClientConfig, c.ConsulServerConnMgr) - if err != nil { - return err - } - - roles, _, err := client.ACL().RoleList(nil) - if err != nil { - log.Error(err, "error reading role list") - return err - } - - policy := &capi.ACLPolicy{ - Name: servicePolicyName(registration.Spec.Service.Name), - Description: "Write policy for terminating gateways for external service", - Rules: fmt.Sprintf(`service %q { policy = "write" }`, registration.Spec.Service.Name), - Datacenters: []string{registration.Spec.Datacenter}, - Namespace: registration.Spec.Service.Namespace, - Partition: registration.Spec.Service.Partition, - } - - existingPolicy, _, err := client.ACL().PolicyReadByName(policy.Name, nil) - if err != nil { - log.Error(err, "error reading policy") - return err - } - - if existingPolicy == nil { - policy, _, err = client.ACL().PolicyCreate(policy, nil) - if err != nil { - return fmt.Errorf("error creating policy: %w", err) - } - } else { - policy = existingPolicy - } - - var mErr error - for _, termGW := range termGWsToUpdate { - var role *capi.ACLRole - for _, r := range roles { - if strings.HasSuffix(r.Name, fmt.Sprintf("-%s-acl-role", termGW.Name)) { - role = r - break - } - } - - if role == nil { - log.Info("terminating gateway role not found", "terminatingGatewayName", termGW.Name) - mErr = errors.Join(mErr, fmt.Errorf("terminating gateway role not found for %q", termGW.Name)) - continue - } - - role.Policies = append(role.Policies, &capi.ACLRolePolicyLink{Name: policy.Name, ID: policy.ID}) - - _, _, err = client.ACL().RoleUpdate(role, nil) - if err != nil { - log.Error(err, "error updating role", "roleName", role.Name) - mErr = errors.Join(mErr, fmt.Errorf("error updating role %q", role.Name)) - continue - } - } - - return mErr -} - -func (c *RegistrationCache) deregisterService(log logr.Logger, reg *v1alpha1.Registration) error { - client, err := consul.NewClientFromConnMgr(c.ConsulClientConfig, c.ConsulServerConnMgr) - if err != nil { - return err - } - - deRegReq := reg.ToCatalogDeregistration() - _, err = client.Catalog().Deregister(deRegReq, nil) - if err != nil { - log.Error(err, "error deregistering service", "svcID", deRegReq.ServiceID) - return err - } - - c.serviceMtx.Lock() - defer c.serviceMtx.Unlock() - delete(c.Services, reg.Spec.Service.Name) - - log.Info("Successfully deregistered service", "svcID", deRegReq.ServiceID) - return nil -} - -func (c *RegistrationCache) removeTermGWACLRole(log logr.Logger, registration *v1alpha1.Registration, termGWsToUpdate []v1alpha1.TerminatingGateway) error { - if len(termGWsToUpdate) == 0 { - log.Info("terminating gateway not found") - return nil - } - - client, err := consul.NewClientFromConnMgr(c.ConsulClientConfig, c.ConsulServerConnMgr) - if err != nil { - return err - } - - roles, _, err := client.ACL().RoleList(nil) - if err != nil { - return err - } - - var mErr error - for _, termGW := range termGWsToUpdate { - var role *capi.ACLRole - for _, r := range roles { - if strings.HasSuffix(r.Name, fmt.Sprintf("-%s-acl-role", termGW.Name)) { - role = r - break - } - } - - if role == nil { - log.Info("terminating gateway role not found", "terminatingGatewayName", termGW.Name) - mErr = errors.Join(mErr, fmt.Errorf("terminating gateway role not found for %q", termGW.Name)) - continue - } - - var policyID string - - expectedPolicyName := servicePolicyName(registration.Spec.Service.Name) - role.Policies = slices.DeleteFunc(role.Policies, func(i *capi.ACLRolePolicyLink) bool { - if i.Name == expectedPolicyName { - policyID = i.ID - return true - } - return false - }) - - if policyID == "" { - log.Info("policy not found on terminating gateway role", "policyName", expectedPolicyName, "terminatingGatewayName", termGW.Name) - continue - } - - _, _, err = client.ACL().RoleUpdate(role, nil) - if err != nil { - log.Error(err, "error updating role", "roleName", role.Name) - mErr = errors.Join(mErr, fmt.Errorf("error updating role %q", role.Name)) - continue - } - - _, err = client.ACL().PolicyDelete(policyID, nil) - if err != nil { - log.Error(err, "error deleting service policy", "policyID", policyID, "policyName", expectedPolicyName) - mErr = errors.Join(mErr, fmt.Errorf("error deleting service ACL policy %q", policyID)) - continue - } - } - - return mErr -} - -func servicePolicyName(name string) string { - return fmt.Sprintf("%s-write-policy", name) -} diff --git a/control-plane/catalog/registration/registrations_controller.go b/control-plane/catalog/registration/registrations_controller.go deleted file mode 100644 index eabcaae979..0000000000 --- a/control-plane/catalog/registration/registrations_controller.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package registration - -import ( - "context" - "fmt" - "slices" - "time" - - "github.com/go-logr/logr" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/controllers/configentries" -) - -const ( - RegistrationFinalizer = "registration.finalizers.consul.hashicorp.com" - registrationByServiceNameIndex = "registrationName" -) - -var ( - ErrRegisteringService = fmt.Errorf("error registering service") - ErrDeregisteringService = fmt.Errorf("error deregistering service") - ErrUpdatingACLRoles = fmt.Errorf("error updating ACL roles") - ErrRemovingACLRoles = fmt.Errorf("error removing ACL roles") -) - -// RegistrationsController is the controller for Registrations resources. -type RegistrationsController struct { - client.Client - configentries.FinalizerPatcher - Scheme *runtime.Scheme - Cache *RegistrationCache - Log logr.Logger -} - -// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=servicerouters,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=servicerouters/status,verbs=get;update;patch - -func (r *RegistrationsController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := r.Log.V(1).WithValues("registration", req.NamespacedName) - log.Info("Reconciling Registaration") - - registration := &v1alpha1.Registration{} - // get the registration - if err := r.Client.Get(ctx, req.NamespacedName, registration); err != nil { - if !k8serrors.IsNotFound(err) { - log.Error(err, "unable to get registration") - } - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - cachedRegistration, ok := r.Cache.get(registration.Spec.Service.Name) - if slices.ContainsFunc(registration.Status.Conditions, func(c v1alpha1.Condition) bool { return c.Type == ConditionDeregistered }) { - if ok && registration.EqualExceptStatus(cachedRegistration) { - log.Info("Registration is in sync") - // registration is already in sync so we do nothing, this happens when consul deregisters a service - // and we update the status to show that consul deregistered it - return ctrl.Result{}, nil - } - } - - log.Info("need to reconcile") - - // deletion request - if !registration.ObjectMeta.DeletionTimestamp.IsZero() { - result := r.handleDeletion(ctx, log, registration) - - if result.hasErrors() { - err := r.UpdateStatus(ctx, log, registration, result) - if err != nil { - log.Error(err, "failed to update Registration status", "name", registration.Name, "namespace", registration.Namespace) - } - return ctrl.Result{}, result.errors() - } - return ctrl.Result{}, nil - } - - // registration request - result := r.handleRegistration(ctx, log, registration) - err := r.UpdateStatus(ctx, log, registration, result) - if err != nil { - log.Error(err, "failed to update Registration status", "name", registration.Name, "namespace", registration.Namespace) - } - if result.hasErrors() { - return ctrl.Result{}, result.errors() - } - - return ctrl.Result{}, nil -} - -func (c *RegistrationsController) watchForDeregistrations(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case svc := <-c.Cache.UpdateChan: - // get all registrations for the service - regList := &v1alpha1.RegistrationList{} - err := c.Client.List(context.Background(), regList, client.MatchingFields{registrationByServiceNameIndex: svc}) - if err != nil { - c.Log.Error(err, "error listing registrations by service name", "serviceName", svc) - continue - } - for _, reg := range regList.Items { - - err := c.UpdateStatus(context.Background(), c.Log, ®, Result{Registering: false, ConsulDeregistered: true}) - if err != nil { - c.Log.Error(err, "failed to update Registration status", "name", reg.Name, "namespace", reg.Namespace) - } - } - } - } -} - -func (r *RegistrationsController) handleRegistration(ctx context.Context, log logr.Logger, registration *v1alpha1.Registration) Result { - log.Info("Registering service") - - result := Result{Registering: true} - - patch := r.AddFinalizersPatch(registration, RegistrationFinalizer) - err := r.Patch(ctx, registration, patch) - if err != nil { - err = fmt.Errorf("error adding finalizer: %w", err) - result.Finalizer = err - return result - } - - err = r.Cache.registerService(log, registration) - if err != nil { - result.Sync = err - result.Registration = fmt.Errorf("%w: %s", ErrRegisteringService, err) - return result - } - - if r.Cache.aclsEnabled() { - termGWsToUpdate, err := r.terminatingGatewaysToUpdate(ctx, log, registration) - if err != nil { - result.Sync = err - result.ACLUpdate = fmt.Errorf("%w: %s", ErrUpdatingACLRoles, err) - return result - } - - err = r.Cache.updateTermGWACLRole(log, registration, termGWsToUpdate) - if err != nil { - result.Sync = err - result.ACLUpdate = fmt.Errorf("%w: %s", ErrUpdatingACLRoles, err) - return result - } - } - return result -} - -func (r *RegistrationsController) terminatingGatewaysToUpdate(ctx context.Context, log logr.Logger, registration *v1alpha1.Registration) ([]v1alpha1.TerminatingGateway, error) { - termGWList := &v1alpha1.TerminatingGatewayList{} - err := r.Client.List(ctx, termGWList) - if err != nil { - log.Error(err, "error listing terminating gateways") - return nil, err - } - - termGWsToUpdate := make([]v1alpha1.TerminatingGateway, 0, len(termGWList.Items)) - for _, termGW := range termGWList.Items { - if slices.ContainsFunc(termGW.Spec.Services, termGWContainsService(registration)) { - termGWsToUpdate = append(termGWsToUpdate, termGW) - } - } - - return termGWsToUpdate, nil -} - -func termGWContainsService(registration *v1alpha1.Registration) func(v1alpha1.LinkedService) bool { - return func(svc v1alpha1.LinkedService) bool { - return svc.Name == registration.Spec.Service.Name - } -} - -func (r *RegistrationsController) handleDeletion(ctx context.Context, log logr.Logger, registration *v1alpha1.Registration) Result { - log.Info("Deregistering service") - result := Result{Registering: false} - err := r.Cache.deregisterService(log, registration) - if err != nil { - result.Sync = err - result.Deregistration = fmt.Errorf("%w: %s", ErrDeregisteringService, err) - return result - } - - if r.Cache.aclsEnabled() { - termGWsToUpdate, err := r.terminatingGatewaysToUpdate(ctx, log, registration) - if err != nil { - result.Sync = err - result.ACLUpdate = fmt.Errorf("%w: %s", ErrRemovingACLRoles, err) - return result - } - - err = r.Cache.removeTermGWACLRole(log, registration, termGWsToUpdate) - if err != nil { - result.Sync = err - result.ACLUpdate = fmt.Errorf("%w: %s", ErrRemovingACLRoles, err) - return result - } - } - - patch := r.RemoveFinalizersPatch(registration, RegistrationFinalizer) - err = r.Patch(ctx, registration, patch) - if err != nil { - result.Finalizer = err - return result - } - - return result -} - -func (r *RegistrationsController) UpdateStatus(ctx context.Context, log logr.Logger, registration *v1alpha1.Registration, result Result) error { - registration.Status.LastSyncedTime = &metav1.Time{Time: time.Now()} - registration.Status.Conditions = v1alpha1.Conditions{ - syncedCondition(result), - } - - if result.Registering { - registration.Status.Conditions = append(registration.Status.Conditions, registrationCondition(result)) - } else { - registration.Status.Conditions = append(registration.Status.Conditions, deregistrationCondition(result)) - } - - if r.Cache.aclsEnabled() { - registration.Status.Conditions = append(registration.Status.Conditions, aclCondition(result)) - } - - err := r.Status().Update(ctx, registration) - if err != nil { - return err - } - return nil -} - -func (r *RegistrationsController) Logger(name types.NamespacedName) logr.Logger { - return r.Log.WithValues("request", name) -} - -func (r *RegistrationsController) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { - // setup the cache - go r.Cache.run(ctx, r.Log) - r.Cache.waitSynced(ctx) - - go r.watchForDeregistrations(ctx) - - // setup the index to lookup registrations by service name - if err := mgr.GetFieldIndexer().IndexField(ctx, &v1alpha1.Registration{}, registrationByServiceNameIndex, indexerFn); err != nil { - return err - } - - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.Registration{}). - Watches(&v1alpha1.TerminatingGateway{}, handler.EnqueueRequestsFromMapFunc(r.transformTerminatingGateways)). - Complete(r) -} - -func indexerFn(o client.Object) []string { - reg := o.(*v1alpha1.Registration) - return []string{reg.Spec.Service.Name} -} - -func (r *RegistrationsController) transformTerminatingGateways(ctx context.Context, o client.Object) []reconcile.Request { - termGW := o.(*v1alpha1.TerminatingGateway) - reqs := make([]reconcile.Request, 0, len(termGW.Spec.Services)) - for _, svc := range termGW.Spec.Services { - // lookup registrationList by service name and add it to the reconcile request - registrationList := &v1alpha1.RegistrationList{} - - err := r.Client.List(ctx, registrationList, client.MatchingFields{registrationByServiceNameIndex: svc.Name}) - if err != nil { - r.Log.Error(err, "error listing registrations by service name", "serviceName", svc.Name) - continue - } - - for _, reg := range registrationList.Items { - reqs = append(reqs, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: reg.Name, - Namespace: reg.Namespace, - }, - }) - } - } - return reqs -} diff --git a/control-plane/catalog/registration/registrations_controller_test.go b/control-plane/catalog/registration/registrations_controller_test.go deleted file mode 100644 index ccbe053d06..0000000000 --- a/control-plane/catalog/registration/registrations_controller_test.go +++ /dev/null @@ -1,1087 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package registration_test - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "strconv" - "strings" - "testing" - - logrtest "github.com/go-logr/logr/testing" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/stretchr/testify/require" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - - capi "github.com/hashicorp/consul/api" - "github.com/hashicorp/go-uuid" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/catalog/registration" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/helper/test" -) - -type serverResponseConfig struct { - registering bool - aclEnabled bool - errOnRegister bool - errOnDeregister bool - errOnPolicyRead bool - errOnPolicyWrite bool - errOnPolicyDelete bool - errOnRoleUpdate bool - policyExists bool - temGWRoleMissing bool -} - -func TestReconcile_Success(tt *testing.T) { - deletionTime := metav1.Now() - cases := map[string]struct { - registration *v1alpha1.Registration - terminatingGateways []runtime.Object - serverResponseConfig serverResponseConfig - expectedFinalizers []string - expectedConditions []v1alpha1.Condition - }{ - "registering - success on registration": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{registering: true}, - expectedFinalizers: []string{registration.RegistrationFinalizer}, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - }, - }, - "registering -- ACLs enabled and policy does not exist": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: true, - aclEnabled: true, - }, - expectedFinalizers: []string{registration.RegistrationFinalizer}, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - }, - }, - "registering -- ACLs enabled and policy does exists": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: true, - aclEnabled: true, - policyExists: true, - }, - expectedFinalizers: []string{registration.RegistrationFinalizer}, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionTrue, - Reason: "", - Message: "", - }, - }, - }, - "deregistering": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - DeletionTimestamp: &deletionTime, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: false, - aclEnabled: false, - }, - expectedConditions: []v1alpha1.Condition{}, - }, - "deregistering - ACLs enabled": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - DeletionTimestamp: &deletionTime, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: false, - aclEnabled: true, - }, - expectedConditions: []v1alpha1.Condition{}, - }, - } - - for name, tc := range cases { - tc := tc - tt.Run(name, func(t *testing.T) { - t.Parallel() - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, &v1alpha1.Registration{}, &v1alpha1.TerminatingGateway{}, &v1alpha1.TerminatingGatewayList{}) - ctx := context.Background() - - consulServer, testClient := fakeConsulServer(t, tc.serverResponseConfig, tc.registration.Spec.Service.Name) - defer consulServer.Close() - - runtimeObjs := []runtime.Object{tc.registration} - runtimeObjs = append(runtimeObjs, tc.terminatingGateways...) - fakeClient := fake.NewClientBuilder(). - WithScheme(s). - WithRuntimeObjects(runtimeObjs...). - WithStatusSubresource(&v1alpha1.Registration{}). - Build() - - controller := ®istration.RegistrationsController{ - Client: fakeClient, - Log: logrtest.NewTestLogger(t), - Scheme: s, - Cache: registration.NewRegistrationCache(testClient.Cfg, testClient.Watcher), - } - - _, err := controller.Reconcile(ctx, ctrl.Request{ - NamespacedName: types.NamespacedName{Name: tc.registration.Name, Namespace: tc.registration.Namespace}, - }) - require.NoError(t, err) - - fetchedReg := &v1alpha1.Registration{TypeMeta: metav1.TypeMeta{APIVersion: "consul.hashicorp.com/v1alpha1", Kind: "Registration"}} - fakeClient.Get(ctx, types.NamespacedName{Name: tc.registration.Name}, fetchedReg) - - require.Len(t, fetchedReg.Status.Conditions, len(tc.expectedConditions)) - - for i, c := range fetchedReg.Status.Conditions { - if diff := cmp.Diff(c, tc.expectedConditions[i], cmpopts.IgnoreFields(v1alpha1.Condition{}, "LastTransitionTime", "Message")); diff != "" { - t.Errorf("unexpected condition diff: %s", diff) - } - } - - require.ElementsMatch(t, fetchedReg.Finalizers, tc.expectedFinalizers) - }) - } -} - -func TestReconcile_Failure(tt *testing.T) { - deletionTime := metav1.Now() - cases := map[string]struct { - registration *v1alpha1.Registration - terminatingGateways []runtime.Object - serverResponseConfig serverResponseConfig - expectedConditions []v1alpha1.Condition - }{ - "registering - registration call to consul fails": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: true, - errOnRegister: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorRegistration, - }, - }, - }, - "registering - terminating gateway acl role not found": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: true, - aclEnabled: true, - temGWRoleMissing: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionTrue, - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorACL, - }, - }, - }, - "registering - error reading policy": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: true, - aclEnabled: true, - errOnPolicyRead: true, - policyExists: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionTrue, - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorACL, - }, - }, - }, - "registering - policy does not exist - error creating policy": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: true, - aclEnabled: true, - errOnPolicyWrite: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionTrue, - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorACL, - }, - }, - }, - "registering - error updating role": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - registering: true, - aclEnabled: true, - errOnRoleUpdate: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionRegistered, - Status: v1.ConditionTrue, - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorACL, - }, - }, - }, - "deregistering": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - DeletionTimestamp: &deletionTime, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - errOnDeregister: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionDeregistered, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorDeregistration, - }, - }, - }, - "deregistering - ACLs enabled - terminating-gateway error updating role": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - DeletionTimestamp: &deletionTime, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - aclEnabled: true, - errOnRoleUpdate: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionDeregistered, - Status: v1.ConditionTrue, - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorACL, - }, - }, - }, - "deregistering - ACLs enabled - terminating-gateway error deleting policy": { - registration: &v1alpha1.Registration{ - TypeMeta: metav1.TypeMeta{ - Kind: "Registration", - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test-registration", - Finalizers: []string{registration.RegistrationFinalizer}, - DeletionTimestamp: &deletionTime, - }, - Spec: v1alpha1.RegistrationSpec{ - ID: "node-id", - Node: "virtual-node", - Address: "127.0.0.1", - Datacenter: "dc1", - Service: v1alpha1.Service{ - ID: "service-id", - Name: "service-name", - Port: 8080, - Address: "127.0.0.1", - }, - }, - }, - terminatingGateways: []runtime.Object{ - &v1alpha1.TerminatingGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "terminating-gateway", - }, - Spec: v1alpha1.TerminatingGatewaySpec{ - Services: []v1alpha1.LinkedService{ - { - Name: "service-name", - }, - }, - }, - }, - }, - serverResponseConfig: serverResponseConfig{ - aclEnabled: true, - errOnPolicyDelete: true, - }, - expectedConditions: []v1alpha1.Condition{ - { - Type: v1alpha1.ConditionSynced, - Status: v1.ConditionFalse, - Reason: registration.SyncError, - }, - { - Type: registration.ConditionDeregistered, - Status: v1.ConditionTrue, - }, - { - Type: registration.ConditionACLsUpdated, - Status: v1.ConditionFalse, - Reason: registration.ConsulErrorACL, - }, - }, - }, - } - - for name, tc := range cases { - tc := tc - tt.Run(name, func(t *testing.T) { - t.Parallel() - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, &v1alpha1.Registration{}, &v1alpha1.TerminatingGateway{}, &v1alpha1.TerminatingGatewayList{}) - ctx := context.Background() - - consulServer, testClient := fakeConsulServer(t, tc.serverResponseConfig, tc.registration.Spec.Service.Name) - defer consulServer.Close() - - runtimeObjs := []runtime.Object{tc.registration} - runtimeObjs = append(runtimeObjs, tc.terminatingGateways...) - fakeClient := fake.NewClientBuilder(). - WithScheme(s). - WithRuntimeObjects(runtimeObjs...). - WithStatusSubresource(&v1alpha1.Registration{}). - Build() - - controller := ®istration.RegistrationsController{ - Client: fakeClient, - Log: logrtest.NewTestLogger(t), - Scheme: s, - Cache: registration.NewRegistrationCache(testClient.Cfg, testClient.Watcher), - } - - _, err := controller.Reconcile(ctx, ctrl.Request{ - NamespacedName: types.NamespacedName{Name: tc.registration.Name, Namespace: tc.registration.Namespace}, - }) - require.Error(t, err) - - fetchedReg := &v1alpha1.Registration{TypeMeta: metav1.TypeMeta{APIVersion: "consul.hashicorp.com/v1alpha1", Kind: "Registration"}} - fakeClient.Get(ctx, types.NamespacedName{Name: tc.registration.Name}, fetchedReg) - - require.Len(t, fetchedReg.Status.Conditions, len(tc.expectedConditions)) - - for i, c := range fetchedReg.Status.Conditions { - if diff := cmp.Diff(c, tc.expectedConditions[i], cmpopts.IgnoreFields(v1alpha1.Condition{}, "LastTransitionTime", "Message")); diff != "" { - t.Errorf("unexpected condition diff: %s", diff) - } - } - - require.ElementsMatch(t, fetchedReg.Finalizers, []string{registration.RegistrationFinalizer}) - }) - } -} - -func fakeConsulServer(t *testing.T, serverResponseConfig serverResponseConfig, serviceName string) (*httptest.Server, *test.TestServerClient) { - t.Helper() - mux := buildMux(t, serverResponseConfig, serviceName) - consulServer := httptest.NewServer(mux) - - parsedURL, err := url.Parse(consulServer.URL) - require.NoError(t, err) - host := strings.Split(parsedURL.Host, ":")[0] - - port, err := strconv.Atoi(parsedURL.Port()) - require.NoError(t, err) - - cfg := &consul.Config{APIClientConfig: &capi.Config{Address: host}, HTTPPort: port} - if serverResponseConfig.aclEnabled { - cfg.APIClientConfig.Token = "test-token" - } - - testClient := &test.TestServerClient{ - Cfg: cfg, - Watcher: test.MockConnMgrForIPAndPort(t, host, port, false), - } - - return consulServer, testClient -} - -func buildMux(t *testing.T, cfg serverResponseConfig, serviceName string) http.Handler { - t.Helper() - mux := http.NewServeMux() - mux.HandleFunc("/v1/catalog/register", func(w http.ResponseWriter, r *http.Request) { - if cfg.errOnRegister { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - }) - - mux.HandleFunc("/v1/catalog/deregister", func(w http.ResponseWriter, r *http.Request) { - if cfg.errOnDeregister { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - }) - - policyID, err := uuid.GenerateUUID() - require.NoError(t, err) - - mux.HandleFunc("/v1/acl/roles", func(w http.ResponseWriter, r *http.Request) { - entries := []*capi.ACLRole{ - { - ID: "754a8717-46e9-9f18-7f76-28dc0afafd19", - Name: "consul-consul-connect-inject-acl-role", - Description: "ACL Role for consul-consul-connect-injector", - Policies: []*capi.ACLLink{ - { - ID: "38511a9f-a309-11e2-7f67-7fea12056e7c", - Name: "connect-inject-policy", - }, - }, - }, - } - - if cfg.temGWRoleMissing { - val, err := json.Marshal(entries) - if err != nil { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - w.Write(val) - return - } - - termGWPolicies := []*capi.ACLLink{ - { - ID: "b7e377d9-5e2b-b99c-3f06-139584cf47f8", - Name: "terminating-gateway-policy", - }, - } - - if !cfg.registering { - termGWPolicies = append(termGWPolicies, &capi.ACLLink{ - ID: policyID, - Name: fmt.Sprintf("%s-write-policy", serviceName), - }) - } - - termGWRole := &capi.ACLRole{ - ID: "61fc5051-96e9-7b67-69b5-98f7f6682563", - Name: "consul-consul-terminating-gateway-acl-role", - Description: "ACL Role for consul-consul-terminating-gateway", - Policies: termGWPolicies, - } - - entries = append(entries, termGWRole) - - val, err := json.Marshal(entries) - if err != nil { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - w.Write(val) - }) - - mux.HandleFunc("/v1/acl/role/", func(w http.ResponseWriter, r *http.Request) { - if cfg.errOnRoleUpdate { - w.WriteHeader(500) - return - } - - role := &capi.ACLRole{ - ID: "61fc5051-96e9-7b67-69b5-98f7f6682563", - Name: "consul-consul-terminating-gateway-acl-role", - Description: "ACL Role for consul-consul-terminating-gateway", - Policies: []*capi.ACLLink{ - { - ID: "b7e377d9-5e2b-b99c-3f06-139584cf47f8", - Name: "terminating-gateway-policy", - }, - { - ID: policyID, - Name: fmt.Sprintf("%s-write-policy", serviceName), - }, - }, - } - val, err := json.Marshal(role) - if err != nil { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - w.Write(val) - }) - - mux.HandleFunc("/v1/acl/policy/name/", func(w http.ResponseWriter, r *http.Request) { - if cfg.errOnPolicyRead { - w.WriteHeader(500) - return - } - - if !cfg.policyExists { - w.WriteHeader(404) - return - } - - policy := &capi.ACLPolicy{ - ID: policyID, - Name: fmt.Sprintf("%s-write-policy", serviceName), - } - - val, err := json.Marshal(policy) - if err != nil { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - w.Write(val) - }) - - mux.HandleFunc("/v1/acl/policy/", func(w http.ResponseWriter, r *http.Request) { - switch r.Method { - case "GET": - if cfg.errOnPolicyWrite { - w.WriteHeader(500) - return - } - - policy := &capi.ACLPolicy{ - ID: policyID, - Name: fmt.Sprintf("%s-write-policy", serviceName), - } - - val, err := json.Marshal(policy) - if err != nil { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - w.Write(val) - case "DELETE": - if cfg.errOnPolicyDelete { - w.WriteHeader(500) - return - } - w.WriteHeader(200) - } - }) - - return mux -} diff --git a/control-plane/catalog/registration/result.go b/control-plane/catalog/registration/result.go deleted file mode 100644 index 176855c330..0000000000 --- a/control-plane/catalog/registration/result.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package registration - -import ( - "errors" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" -) - -// Conditions. -const ( - ConditionSynced = "Synced" - ConditionRegistered = "Registered" - ConditionDeregistered = "Deregistered" - ConditionACLsUpdated = "ACLsUpdated" -) - -// Status Reasons. -const ( - SyncError = "SyncError" - ConsulErrorRegistration = "ConsulErrorRegistration" - ConsulErrorDeregistration = "ConsulErrorDeregistration" - ConsulErrorACL = "ConsulErrorACL" - ConsulDeregistration = "ConsulDeregistration" -) - -type Result struct { - Registering bool - ConsulDeregistered bool - Sync error - Registration error - Deregistration error - ACLUpdate error - Finalizer error -} - -func (r Result) hasErrors() bool { - return r.Sync != nil || r.Registration != nil || r.ACLUpdate != nil || r.Finalizer != nil -} - -func (r Result) errors() error { - var err error - err = errors.Join(err, r.Sync, r.Registration, r.ACLUpdate, r.Finalizer) - return err -} - -func syncedCondition(result Result) v1alpha1.Condition { - if result.Sync != nil { - return v1alpha1.Condition{ - Type: ConditionSynced, - Status: corev1.ConditionFalse, - Reason: SyncError, - Message: result.Sync.Error(), - LastTransitionTime: metav1.Now(), - } - } - return v1alpha1.Condition{ - Type: ConditionSynced, - Status: corev1.ConditionTrue, - LastTransitionTime: metav1.Now(), - } -} - -func registrationCondition(result Result) v1alpha1.Condition { - if result.Registration != nil { - return v1alpha1.Condition{ - Type: ConditionRegistered, - Status: corev1.ConditionFalse, - Reason: ConsulErrorRegistration, - Message: result.Registration.Error(), - LastTransitionTime: metav1.Now(), - } - } - return v1alpha1.Condition{ - Type: ConditionRegistered, - Status: corev1.ConditionTrue, - LastTransitionTime: metav1.Now(), - } -} - -func deregistrationCondition(result Result) v1alpha1.Condition { - if result.Deregistration != nil { - return v1alpha1.Condition{ - Type: ConditionDeregistered, - Status: corev1.ConditionFalse, - Reason: ConsulErrorDeregistration, - Message: result.Deregistration.Error(), - LastTransitionTime: metav1.Now(), - } - } - - var ( - reason string - message string - ) - if result.ConsulDeregistered { - reason = ConsulDeregistration - message = "Consul deregistered this service" - } - return v1alpha1.Condition{ - Type: ConditionDeregistered, - Status: corev1.ConditionTrue, - Reason: reason, - Message: message, - LastTransitionTime: metav1.Now(), - } -} - -func aclCondition(result Result) v1alpha1.Condition { - if result.ACLUpdate != nil { - return v1alpha1.Condition{ - Type: ConditionACLsUpdated, - Status: corev1.ConditionFalse, - Reason: ConsulErrorACL, - Message: result.ACLUpdate.Error(), - LastTransitionTime: metav1.Now(), - } - } - - if result.ConsulDeregistered { - return v1alpha1.Condition{ - Type: ConditionACLsUpdated, - Status: corev1.ConditionFalse, - Reason: ConsulDeregistration, - Message: "Consul deregistered this service, acls were not removed", - LastTransitionTime: metav1.Now(), - } - } - - return v1alpha1.Condition{ - Type: ConditionACLsUpdated, - Status: corev1.ConditionTrue, - LastTransitionTime: metav1.Now(), - } -} diff --git a/control-plane/catalog/to-consul/resource_test.go b/control-plane/catalog/to-consul/resource_test.go index 3272849bd3..8ccc54780f 100644 --- a/control-plane/catalog/to-consul/resource_test.go +++ b/control-plane/catalog/to-consul/resource_test.go @@ -2091,6 +2091,9 @@ func createNodes(t *testing.T, client *fake.Clientset) (*corev1.Node, *corev1.No node1 := &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ Name: nodeName1, + Labels: map[string]string{ + corev1.LabelTopologyRegion: "us-west-2", + }, }, Status: corev1.NodeStatus{ @@ -2107,6 +2110,9 @@ func createNodes(t *testing.T, client *fake.Clientset) (*corev1.Node, *corev1.No node2 := &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ Name: nodeName2, + Labels: map[string]string{ + corev1.LabelTopologyRegion: "us-west-2", + }, }, Status: corev1.NodeStatus{ diff --git a/control-plane/cni/go.mod b/control-plane/cni/go.mod index e27eb9ab3f..9944d670e3 100644 --- a/control-plane/cni/go.mod +++ b/control-plane/cni/go.mod @@ -6,7 +6,7 @@ require ( github.com/containernetworking/cni v1.1.2 github.com/containernetworking/plugins v1.2.0 github.com/hashicorp/consul-k8s/version v0.0.0 - github.com/hashicorp/consul/sdk v0.16.1 + github.com/hashicorp/consul/sdk v0.16.0 github.com/hashicorp/go-hclog v1.5.0 github.com/stretchr/testify v1.8.4 k8s.io/api v0.28.9 diff --git a/control-plane/cni/go.sum b/control-plane/cni/go.sum index 25d890cdd4..cad80e31b8 100644 --- a/control-plane/cni/go.sum +++ b/control-plane/cni/go.sum @@ -59,8 +59,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= -github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= diff --git a/control-plane/cni/main.go b/control-plane/cni/main.go index 86cc211f71..b49dacd3ce 100644 --- a/control-plane/cni/main.go +++ b/control-plane/cni/main.go @@ -269,7 +269,7 @@ func main() { } // createK8sClient configures the command's Kubernetes API client if it doesn't -// already exist. +// already exist func (c *Command) createK8sClient(cfg *PluginConf) error { restConfig, err := clientcmd.BuildConfigFromFlags("", filepath.Join(cfg.CNINetDir, cfg.Kubeconfig)) if err != nil { diff --git a/control-plane/config/crd/bases/auth.consul.hashicorp.com_trafficpermissions.yaml b/control-plane/config/crd/bases/auth.consul.hashicorp.com_trafficpermissions.yaml index ca29923851..3a7699dce4 100644 --- a/control-plane/config/crd/bases/auth.consul.hashicorp.com_trafficpermissions.yaml +++ b/control-plane/config/crd/bases/auth.consul.hashicorp.com_trafficpermissions.yaml @@ -97,25 +97,23 @@ spec: when evaluating rules for the incoming connection. items: properties: - headers: - items: - properties: - exact: - type: string - invert: - type: boolean - name: - type: string - prefix: - type: string - present: - type: boolean - regex: - type: string - suffix: - type: string - type: object - type: array + header: + properties: + exact: + type: string + invert: + type: boolean + name: + type: string + prefix: + type: string + present: + type: boolean + regex: + type: string + suffix: + type: string + type: object methods: description: Methods is the list of HTTP methods. items: @@ -136,25 +134,23 @@ spec: type: array type: object type: array - headers: - items: - properties: - exact: - type: string - invert: - type: boolean - name: - type: string - prefix: - type: string - present: - type: boolean - regex: - type: string - suffix: - type: string - type: object - type: array + header: + properties: + exact: + type: string + invert: + type: boolean + name: + type: string + prefix: + type: string + present: + type: boolean + regex: + type: string + suffix: + type: string + type: object methods: description: Methods is the list of HTTP methods. If no methods are specified, this rule will apply to all methods. diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_gatewayclassconfigs.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_gatewayclassconfigs.yaml index 5f6e3a990b..c2a857db34 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_gatewayclassconfigs.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_gatewayclassconfigs.yaml @@ -118,8 +118,7 @@ spec: description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. Requests cannot exceed - Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object type: object diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_registrations.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_registrations.yaml deleted file mode 100644 index df8970512b..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_registrations.yaml +++ /dev/null @@ -1,246 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.12.1 - name: registrations.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: Registration - listKind: RegistrationList - plural: registrations - singular: registration - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Registration defines the resource for working with service registrations. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of Registration. - properties: - address: - type: string - check: - description: HealthCheck is used to represent a single check. - properties: - checkId: - type: string - definition: - description: HealthCheckDefinition is used to store the details - about a health check's execution. - properties: - body: - type: string - deregisterCriticalServiceAfterDuration: - type: string - grpc: - type: string - grpcUseTLS: - type: boolean - header: - additionalProperties: - items: - type: string - type: array - type: object - http: - type: string - intervalDuration: - type: string - method: - type: string - osService: - type: string - tcp: - type: string - tcpUseTLS: - type: boolean - timeoutDuration: - type: string - tlsServerName: - type: string - tlsSkipVerify: - type: boolean - udp: - type: string - required: - - intervalDuration - type: object - exposedPort: - type: integer - name: - type: string - namespace: - type: string - node: - type: string - notes: - type: string - output: - type: string - partition: - type: string - serviceId: - type: string - serviceName: - type: string - status: - type: string - type: - type: string - required: - - checkId - - definition - - name - - serviceId - - serviceName - - status - type: object - datacenter: - type: string - id: - type: string - locality: - properties: - region: - type: string - zone: - type: string - type: object - node: - type: string - nodeMeta: - additionalProperties: - type: string - type: object - partition: - type: string - service: - properties: - address: - type: string - enableTagOverride: - type: boolean - id: - type: string - locality: - properties: - region: - type: string - zone: - type: string - type: object - meta: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - partition: - type: string - port: - type: integer - socketPath: - type: string - taggedAddresses: - additionalProperties: - properties: - address: - type: string - port: - type: integer - required: - - address - - port - type: object - type: object - tags: - items: - type: string - type: array - weights: - properties: - passing: - type: integer - warning: - type: integer - required: - - passing - - warning - type: object - required: - - address - - name - - port - type: object - skipNodeUpdate: - type: boolean - taggedAddresses: - additionalProperties: - type: string - type: object - type: object - status: - description: RegistrationStatus defines the observed state of Registration. - properties: - conditions: - description: Conditions indicate the latest available observations - of a resource's current state. - items: - description: 'Conditions define a readiness condition for a Consul - resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' - properties: - lastTransitionTime: - description: LastTransitionTime is the last time the condition - transitioned from one status to another. - format: date-time - type: string - message: - description: A human readable message indicating details about - the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of condition. - type: string - required: - - status - - type - type: object - type: array - lastSyncedTime: - description: LastSyncedTime is the last time the resource successfully - synced with Consul. - format: date-time - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml index 7b0d2a54b9..44713c234f 100644 --- a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml +++ b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml @@ -110,6 +110,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the + resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list resources + across all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -185,110 +192,41 @@ spec: type: object status: properties: - addresses: + conditions: + description: Conditions indicate the latest available observations + of a resource's current state. items: + description: 'Conditions define a readiness condition for a Consul + resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' properties: - type: - default: IPAddress + lastTransitionTime: + description: LastTransitionTime is the last time the condition + transitioned from one status to another. + format: date-time type: string - value: + message: + description: A human readable message indicating details about + the transition. type: string - required: - - type - - value - type: object - type: array - listeners: - items: - properties: - attachedRoutes: - format: int32 - type: integer - name: + reason: + description: The reason for the condition's last transition. type: string status: - properties: - conditions: - description: Conditions indicate the latest available observations - of a resource's current state. - items: - description: 'Conditions define a readiness condition - for a Consul resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' - properties: - lastTransitionTime: - description: LastTransitionTime is the last time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: A human readable message indicating details - about the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, - False, Unknown. - type: string - type: - description: Type of condition. - type: string - required: - - status - - type - type: object - type: array - lastSyncedTime: - description: LastSyncedTime is the last time the resource - successfully synced with Consul. - format: date-time - type: string - type: object + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string required: - - attachedRoutes - - name + - status + - type type: object type: array - status: - properties: - conditions: - description: Conditions indicate the latest available observations - of a resource's current state. - items: - description: 'Conditions define a readiness condition for a - Consul resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' - properties: - lastTransitionTime: - description: LastTransitionTime is the last time the condition - transitioned from one status to another. - format: date-time - type: string - message: - description: A human readable message indicating details - about the transition. - type: string - reason: - description: The reason for the condition's last transition. - type: string - status: - description: Status of the condition, one of True, False, - Unknown. - type: string - type: - description: Type of condition. - type: string - required: - - status - - type - type: object - type: array - lastSyncedTime: - description: LastSyncedTime is the last time the resource successfully - synced with Consul. - format: date-time - type: string - type: object + lastSyncedTime: + description: LastSyncedTime is the last time the resource successfully + synced with Consul. + format: date-time + type: string type: object type: object served: true diff --git a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_gatewayclassconfigs.yaml b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_gatewayclassconfigs.yaml index cc6de192c7..e7f560861b 100644 --- a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_gatewayclassconfigs.yaml +++ b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_gatewayclassconfigs.yaml @@ -1031,7 +1031,7 @@ spec: compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. - Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object type: object @@ -1113,7 +1113,7 @@ spec: compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. - Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object type: object @@ -1265,8 +1265,7 @@ spec: in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile - location. Must be set if type is "Localhost". Must NOT - be set for any other type. + location. Must only be set if type is "Localhost". type: string type: description: "type indicates which kind of seccomp profile @@ -1331,12 +1330,15 @@ spec: type: string hostProcess: description: HostProcess determines if a container should - be run as a 'Host Process' container. All of a Pod's - containers must have the same effective HostProcess - value (it is not allowed to have a mix of HostProcess - containers and non-HostProcess containers). In addition, - if HostProcess is true then HostNetwork must also be - set to true. + be run as a 'Host Process' container. This field is + alpha-level and will only be honored by components that + enable the WindowsHostProcessContainers feature flag. + Setting this field without the feature flag will result + in errors when validating the Pod. All of a Pod's containers + must have the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, if HostProcess + is true then HostNetwork must also be set to true. type: boolean runAsUserName: description: The UserName in Windows to run the entrypoint @@ -1446,19 +1448,14 @@ spec: type: object x-kubernetes-map-type: atomic matchLabelKeys: - description: "MatchLabelKeys is a set of pod label keys - to select the pods over which spreading will be calculated. + description: MatchLabelKeys is a set of pod label keys to + select the pods over which spreading will be calculated. The keys are used to lookup values from the incoming pod labels, those key-value labels are ANDed with labelSelector to select the group of existing pods over which spreading - will be calculated for the incoming pod. The same key - is forbidden to exist in both MatchLabelKeys and LabelSelector. - MatchLabelKeys cannot be set when LabelSelector isn't - set. Keys that don't exist in the incoming pod labels - will be ignored. A null or empty list means only match - against labelSelector. \n This is a beta field and requires - the MatchLabelKeysInPodTopologySpread feature gate to - be enabled (enabled by default)." + will be calculated for the incoming pod. Keys that don't + exist in the incoming pod labels will be ignored. A null + or empty list means only match against labelSelector. items: type: string type: array diff --git a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_grpcroutes.yaml b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_grpcroutes.yaml index ff00bd86e5..fda3e4255e 100644 --- a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_grpcroutes.yaml +++ b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_grpcroutes.yaml @@ -68,10 +68,9 @@ spec: description: 'NOTE: roughly equivalent to structs.ResourceReference' properties: port: - description: "For east/west this is the name of the Consul Service + description: For east/west this is the name of the Consul Service port to direct traffic to or empty to imply all. For north/south - this is TBD. \n For more details on potential values of this - field, see documentation for Service.ServicePort." + this is TBD. type: string ref: description: For east/west configuration, this should point @@ -103,6 +102,13 @@ spec: the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the resource + is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, provide + the wildcard value \"*\" to list resources across + all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -156,9 +162,7 @@ spec: description: "For east/west this is the name of the Consul Service port to direct traffic to or empty to imply using the same value as the parent ref. - For north/south this is TBD. \n For more details - on potential values of this field, see documentation - for Service.ServicePort." + \n For north/south this is TBD." type: string ref: description: For east/west configuration, this should @@ -191,6 +195,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer + the resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list + resources across all peers." + type: string type: object type: description: Type identifies the resource's type. diff --git a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_httproutes.yaml b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_httproutes.yaml index ae41db0016..46bf7162a6 100644 --- a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_httproutes.yaml +++ b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_httproutes.yaml @@ -68,10 +68,9 @@ spec: description: 'NOTE: roughly equivalent to structs.ResourceReference' properties: port: - description: "For east/west this is the name of the Consul Service + description: For east/west this is the name of the Consul Service port to direct traffic to or empty to imply all. For north/south - this is TBD. \n For more details on potential values of this - field, see documentation for Service.ServicePort." + this is TBD. type: string ref: description: For east/west configuration, this should point @@ -103,6 +102,13 @@ spec: the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the resource + is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, provide + the wildcard value \"*\" to list resources across + all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -159,9 +165,7 @@ spec: description: "For east/west this is the name of the Consul Service port to direct traffic to or empty to imply using the same value as the parent ref. - For north/south this is TBD. \n For more details - on potential values of this field, see documentation - for Service.ServicePort." + \n For north/south this is TBD." type: string ref: description: For east/west configuration, this should @@ -194,6 +198,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer + the resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list + resources across all peers." + type: string type: object type: description: Type identifies the resource's type. diff --git a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_tcproutes.yaml b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_tcproutes.yaml index dbfb0c9b20..21a3a9c5ec 100644 --- a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_tcproutes.yaml +++ b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_tcproutes.yaml @@ -62,10 +62,9 @@ spec: description: 'NOTE: roughly equivalent to structs.ResourceReference' properties: port: - description: "For east/west this is the name of the Consul Service + description: For east/west this is the name of the Consul Service port to direct traffic to or empty to imply all. For north/south - this is TBD. \n For more details on potential values of this - field, see documentation for Service.ServicePort." + this is TBD. type: string ref: description: For east/west configuration, this should point @@ -97,6 +96,13 @@ spec: the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer the resource + is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, provide + the wildcard value \"*\" to list resources across + all peers." + type: string type: object type: description: Type identifies the resource's type. @@ -141,9 +147,7 @@ spec: description: "For east/west this is the name of the Consul Service port to direct traffic to or empty to imply using the same value as the parent ref. - For north/south this is TBD. \n For more details - on potential values of this field, see documentation - for Service.ServicePort." + \n For north/south this is TBD." type: string ref: description: For east/west configuration, this should @@ -176,6 +180,13 @@ spec: provide the wildcard value \"*\" to list resources across all partitions." type: string + peerName: + description: "PeerName identifies which peer + the resource is imported from. https://developer.hashicorp.com/consul/docs/connect/cluster-peering + \n When using the List and WatchList endpoints, + provide the wildcard value \"*\" to list + resources across all peers." + type: string type: object type: description: Type identifies the resource's type. diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index e2e4802ccc..a4b3aaadd0 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -454,24 +454,3 @@ webhooks: resources: - gatewaypolicies sideEffects: None -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /validate-v1alpha1-registration - failurePolicy: Fail - name: validate-registration.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - registrations - sideEffects: None diff --git a/control-plane/connect-inject/common/annotation_processor.go b/control-plane/connect-inject/common/annotation_processor.go index f89c6348d0..e9ef6d2eff 100644 --- a/control-plane/connect-inject/common/annotation_processor.go +++ b/control-plane/connect-inject/common/annotation_processor.go @@ -107,13 +107,13 @@ func processPodLabeledDestination(pod corev1.Pod, rawUpstream string, enablePart switch end { case "peer": // TODO: uncomment and remove error when peers supported - //peer = strings.TrimSpace(pieces[6]) + // peer = strings.TrimSpace(pieces[6]) return nil, fmt.Errorf("destination currently does not support peers: %s", rawUpstream) case "ap": partition = strings.TrimSpace(pieces[6]) case "dc": // TODO: uncomment and remove error when datacenters are supported - //datacenter = strings.TrimSpace(pieces[6]) + // datacenter = strings.TrimSpace(pieces[6]) return nil, fmt.Errorf("destination currently does not support datacenters: %s", rawUpstream) default: return nil, fmt.Errorf("destination structured incorrectly: %s", rawUpstream) @@ -147,17 +147,17 @@ func processPodLabeledDestination(pod corev1.Pod, rawUpstream string, enablePart switch end { case "peer": // TODO: uncomment and remove error when peers supported - //peer = strings.TrimSpace(pieces[4]) + // peer = strings.TrimSpace(pieces[4]) return nil, fmt.Errorf("destination currently does not support peers: %s", rawUpstream) case "dc": // TODO: uncomment and remove error when datacenter supported - //datacenter = strings.TrimSpace(pieces[4]) + // datacenter = strings.TrimSpace(pieces[4]) return nil, fmt.Errorf("destination currently does not support datacenters: %s", rawUpstream) default: return nil, fmt.Errorf("destination structured incorrectly: %s", rawUpstream) } // TODO: uncomment and remove error when datacenter and/or peers supported - //fallthrough + // fallthrough case 4: if strings.TrimSpace(pieces[3]) == "svc" { svcName = strings.TrimSpace(pieces[2]) @@ -238,7 +238,7 @@ func processPodUnlabeledDestination(pod corev1.Pod, rawUpstream string, enablePa // parse the optional datacenter if len(parts) > 2 { // TODO: uncomment and remove error when datacenters supported - //datacenter = strings.TrimSpace(parts[2]) + // datacenter = strings.TrimSpace(parts[2]) return nil, fmt.Errorf("destination currently does not support datacenters: %s", rawUpstream) } diff --git a/control-plane/connect-inject/common/annotation_processor_test.go b/control-plane/connect-inject/common/annotation_processor_test.go index 77053540e3..3757e26154 100644 --- a/control-plane/connect-inject/common/annotation_processor_test.go +++ b/control-plane/connect-inject/common/annotation_processor_test.go @@ -87,6 +87,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: constants.GetNormalizedConsulNamespace(""), + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream1", // }, @@ -123,6 +124,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: constants.GetNormalizedConsulNamespace(""), + // PeerName: "peer1", // }, // Name: "upstream1", // }, @@ -159,6 +161,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "ns1", + // PeerName: "peer1", // }, // Name: "upstream1", // }, @@ -229,6 +232,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "ns1", + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream1", // }, @@ -335,6 +339,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "ns1", + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream1", // }, @@ -353,6 +358,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: constants.GetNormalizedConsulNamespace(""), + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream2", // }, @@ -371,6 +377,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "ns1", + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream3", // }, @@ -389,6 +396,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "ns1", + // PeerName: "peer1", // }, // Name: "upstream4", // }, @@ -805,6 +813,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: constants.GetNormalizedConsulNamespace(""), + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream1", // }, @@ -823,6 +832,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "bar", + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream2", // }, @@ -841,6 +851,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: "baz", // Namespace: "foo", + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream3", // }, @@ -883,6 +894,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: constants.GetNormalizedConsulNamespace(""), + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream1", // }, @@ -901,6 +913,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "bar", + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream2", // }, @@ -919,6 +932,7 @@ func TestProcessUpstreams(t *testing.T) { // Tenancy: &pbresource.Tenancy{ // Partition: constants.GetNormalizedConsulPartition(""), // Namespace: "foo", + // PeerName: constants.GetNormalizedConsulPeer(""), // }, // Name: "upstream3", // }, diff --git a/control-plane/connect-inject/controllers/endpointsv2/endpoints_controller.go b/control-plane/connect-inject/controllers/endpointsv2/endpoints_controller.go index 82a9904201..4353590c92 100644 --- a/control-plane/connect-inject/controllers/endpointsv2/endpoints_controller.go +++ b/control-plane/connect-inject/controllers/endpointsv2/endpoints_controller.go @@ -391,7 +391,7 @@ func getServicePorts(service corev1.Service, prefixedPods selectorPodData, exact // // If we otherwise see repeat port values in a K8s service, we pass along and allow Consul to fail validation. if p.Protocol == corev1.ProtocolTCP { - //TODO(NET-5705): Error check reserved "mesh" target port + // TODO(NET-5705): Error check reserved "mesh" target port ports = append(ports, &pbcatalog.ServicePort{ VirtualPort: uint32(p.Port), TargetPort: getEffectiveTargetPort(p.TargetPort, prefixedPods, exactNamePods), @@ -436,7 +436,7 @@ func getEffectiveTargetPort(targetPort intstr.IntOrString, prefixedPods selector // very expensive operation to repeat every time endpoints change, and we don't expect the target port to change // often if ever across pod/deployment lifecycles. // - //TODO(NET-5706) in GA, we intend to change port selection to allow for Consul TargetPort to be numeric. If we + // TODO(NET-5706) in GA, we intend to change port selection to allow for Consul TargetPort to be numeric. If we // retain the port selection model used here beyond GA, we should consider updating it to also consider pod health, // s.t. when the selected port name changes between deployments of a ReplicaSet, we route traffic to ports // belonging to the set most able to serve traffic, rather than simply the largest one. diff --git a/control-plane/connect-inject/controllers/pod/pod_controller.go b/control-plane/connect-inject/controllers/pod/pod_controller.go index 12e2c2124d..febe1d6122 100644 --- a/control-plane/connect-inject/controllers/pod/pod_controller.go +++ b/control-plane/connect-inject/controllers/pod/pod_controller.go @@ -330,7 +330,7 @@ func (r *Controller) writeWorkload(ctx context.Context, pod corev1.Pod) error { // Adding a node does not currently work because the node doesn't exist so its health status will always be // unhealthy, causing any endpoints on that node to also be unhealthy. // TODO: (v2/nitya) Bring this back when node controller is built. - //NodeName: inject.ConsulNodeNameFromK8sNode(pod.Spec.NodeName), + // NodeName: inject.ConsulNodeNameFromK8sNode(pod.Spec.NodeName), Ports: workloadPorts, } data := inject.ToProtoAny(workload) diff --git a/control-plane/connect-inject/controllers/pod/pod_controller_test.go b/control-plane/connect-inject/controllers/pod/pod_controller_test.go index 489010eeb8..605d9dbce9 100644 --- a/control-plane/connect-inject/controllers/pod/pod_controller_test.go +++ b/control-plane/connect-inject/controllers/pod/pod_controller_test.go @@ -819,7 +819,7 @@ func TestDestinationsWrite(t *testing.T) { }, expErr: "error processing destination annotations: destination currently does not support peers: destination.port.upstream1.svc.ns1.ns.peer1.peer:1234", // TODO: uncomment this and remove expErr when peers is supported - //expected: &pbmesh.Destinations{ + // expected: &pbmesh.Destinations{ // Workloads: &pbcatalog.WorkloadSelector{ // Names: []string{podName}, // }, @@ -844,7 +844,7 @@ func TestDestinationsWrite(t *testing.T) { // }, // }, // }, - //}, + // }, consulNamespacesEnabled: true, consulPartitionsEnabled: false, }, @@ -1693,7 +1693,7 @@ func TestReconcileDeletePod(t *testing.T) { var token *api.ACLToken var err error if tc.aclsEnabled { - test.SetupK8sAuthMethodV2(t, testClient.APIClient, tc.podName, metav1.NamespaceDefault) //podName is a standin for the service name + test.SetupK8sAuthMethodV2(t, testClient.APIClient, tc.podName, metav1.NamespaceDefault) // podName is a standin for the service name token, _, err = testClient.APIClient.ACL().Login(&api.ACLLoginParams{ AuthMethod: test.AuthMethod, BearerToken: test.ServiceAccountJWTToken, diff --git a/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go b/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go index a9643308d8..13bf3f7bd1 100644 --- a/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go +++ b/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go @@ -97,10 +97,9 @@ func (w *MeshWebhook) consulDataplaneSidecar(namespace corev1.Namespace, pod cor } container := corev1.Container{ - Name: containerName, - Image: w.ImageConsulDataplane, - ImagePullPolicy: corev1.PullPolicy(w.GlobalImagePullPolicy), - Resources: resources, + Name: containerName, + Image: w.ImageConsulDataplane, + Resources: resources, // We need to set tmp dir to an ephemeral volume that we're mounting so that // consul-dataplane can write files to it. Otherwise, it wouldn't be able to // because we set file system to be read-only. diff --git a/control-plane/connect-inject/webhook/container_init.go b/control-plane/connect-inject/webhook/container_init.go index 49f6eda753..2626b03689 100644 --- a/control-plane/connect-inject/webhook/container_init.go +++ b/control-plane/connect-inject/webhook/container_init.go @@ -103,9 +103,8 @@ func (w *MeshWebhook) containerInit(namespace corev1.Namespace, pod corev1.Pod, initContainerName = fmt.Sprintf("%s-%s", injectInitContainerName, mpi.serviceName) } container := corev1.Container{ - Name: initContainerName, - Image: w.ImageConsulK8S, - ImagePullPolicy: corev1.PullPolicy(w.GlobalImagePullPolicy), + Name: initContainerName, + Image: w.ImageConsulK8S, Env: []corev1.EnvVar{ { Name: "POD_NAME", diff --git a/control-plane/connect-inject/webhook/mesh_webhook.go b/control-plane/connect-inject/webhook/mesh_webhook.go index f568b3a907..cdacd895f4 100644 --- a/control-plane/connect-inject/webhook/mesh_webhook.go +++ b/control-plane/connect-inject/webhook/mesh_webhook.go @@ -75,9 +75,6 @@ type MeshWebhook struct { // This image is used for the consul-sidecar container. ImageConsulK8S string - // GlobalImagePullPolicy is the pull policy for all Consul images (consul, consul-dataplane, consul-k8s) - GlobalImagePullPolicy string - // Optional: set when you need extra options to be set when running envoy // See a list of args here: https://www.envoyproxy.io/docs/envoy/latest/operations/cli EnvoyExtraArgs string diff --git a/control-plane/controllers/resources/api-gateway-controller.go b/control-plane/controllers/resources/api-gateway-controller.go deleted file mode 100644 index 87333beb6f..0000000000 --- a/control-plane/controllers/resources/api-gateway-controller.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resources - -import ( - "context" - - "github.com/go-logr/logr" - k8serr "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - "github.com/hashicorp/consul-k8s/control-plane/gateways" -) - -// APIGatewayController reconciles a APIGateway object. -type APIGatewayController struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme - Controller *ConsulResourceController - GatewayConfig gateways.GatewayConfig -} - -// +kubebuilder:rbac:groups=mesh.consul.hashicorp.com,resources=tcproute,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=mesh.consul.hashicorp.com,resources=tcproute/status,verbs=get;update;patch - -func (r *APIGatewayController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := r.Logger(req.NamespacedName) - logger.Info("Reconciling APIGateway") - - resource := &meshv2beta1.APIGateway{} - if err := r.Get(ctx, req.NamespacedName, resource); k8serr.IsNotFound(err) { - return ctrl.Result{}, client.IgnoreNotFound(err) - } else if err != nil { - logger.Error(err, "retrieving resource") - return ctrl.Result{}, err - } - - // Call hooks - if !resource.GetDeletionTimestamp().IsZero() { - logger.Info("deletion event") - - if err := onDelete(ctx, req, r.Client, resource); err != nil { - return ctrl.Result{}, err - } - } else { - // Fetch GatewayClassConfig for the gateway - if resource.Namespace == "" { - resource.Namespace = "default" - } - - gcc, err := getGatewayClassConfigByGatewayClassName(ctx, r.Client, resource.Spec.GatewayClassName) - if err != nil { - r.Log.Error(err, "unable to get gatewayclassconfig for gateway: %s gatewayclass: %s", resource.Name, resource.Spec.GatewayClassName) - return ctrl.Result{}, err - } - - if err := onCreateUpdate(ctx, r.Client, gatewayConfigs{ - gcc: gcc, - gatewayConfig: r.GatewayConfig, - }, resource, gateways.APIGatewayAnnotationKind); err != nil { - logger.Error(err, "unable to create/update gateway") - return ctrl.Result{}, err - } - } - - return r.Controller.ReconcileResource(ctx, r, req, &meshv2beta1.APIGateway{}) -} - -func (r *APIGatewayController) Logger(name types.NamespacedName) logr.Logger { - return r.Log.WithValues("request", name) -} - -func (r *APIGatewayController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { - return r.Status().Update(ctx, obj, opts...) -} - -func (r *APIGatewayController) SetupWithManager(mgr ctrl.Manager) error { - return setupGatewayControllerWithManager[*meshv2beta1.APIGatewayList](mgr, &meshv2beta1.APIGateway{}, r.Client, r, APIGateway_GatewayClassIndex) -} diff --git a/control-plane/controllers/resources/api-gateway-controller_test.go b/control-plane/controllers/resources/api-gateway-controller_test.go deleted file mode 100644 index d8e4fb3a48..0000000000 --- a/control-plane/controllers/resources/api-gateway-controller_test.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resources - -import ( - "context" - "testing" - - "github.com/google/go-cmp/cmp" - pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" - "github.com/hashicorp/consul/proto-public/pbresource" - "github.com/hashicorp/consul/sdk/testutil" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/testing/protocmp" - - "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/helper/test" - - logrtest "github.com/go-logr/logr/testr" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestAPIGatewayController_ReconcileResourceExists(t *testing.T) { - t.Parallel() - ctx := context.Background() - - s := runtime.NewScheme() - require.NoError(t, corev1.AddToScheme(s)) - require.NoError(t, appsv1.AddToScheme(s)) - require.NoError(t, rbacv1.AddToScheme(s)) - require.NoError(t, v2beta1.AddMeshToScheme(s)) - s.AddKnownTypes( - schema.GroupVersion{ - Group: "mesh.consul.hashicorp.com", - Version: pbmesh.Version, - }, - &v2beta1.APIGateway{}, - &v2beta1.GatewayClass{}, - &v2beta1.GatewayClassConfig{}, - ) - - apiGW := &v2beta1.APIGateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "api-gateway", - Namespace: metav1.NamespaceDefault, - }, - Spec: pbmesh.APIGateway{ - GatewayClassName: "consul", - Listeners: []*pbmesh.APIGatewayListener{ - { - Name: "http-listener", - Port: 9090, - Protocol: "http", - }, - }, - }, - } - - fakeClient := fake.NewClientBuilder().WithScheme(s).WithObjects(apiGW).WithStatusSubresource(apiGW).Build() - - testClient := test.TestServerWithMockConnMgrWatcher(t, func(c *testutil.TestServerConfig) { - c.Experiments = []string{"resource-apis"} - }) - - gwCtrl := APIGatewayController{ - Client: fakeClient, - Log: logrtest.New(t), - Scheme: s, - Controller: &ConsulResourceController{ - ConsulClientConfig: testClient.Cfg, - ConsulServerConnMgr: testClient.Watcher, - }, - } - - // ensure the resource is not in consul yet - { - req := &pbresource.ReadRequest{Id: apiGW.ResourceID(constants.DefaultConsulNS, constants.DefaultConsulPartition)} - _, err := testClient.ResourceClient.Read(ctx, req) - require.Error(t, err) - } - - // now reconcile the resource - { - namespacedName := types.NamespacedName{ - Namespace: metav1.NamespaceDefault, - Name: apiGW.KubernetesName(), - } - - // First get it, so we have the latest revision number. - err := fakeClient.Get(ctx, namespacedName, apiGW) - require.NoError(t, err) - - resp, err := gwCtrl.Reconcile(ctx, ctrl.Request{ - NamespacedName: namespacedName, - }) - - require.NoError(t, err) - require.False(t, resp.Requeue) - } - - // now check that the object in Consul is as expected. - { - expectedResource := &pbmesh.APIGateway{ - GatewayClassName: "consul", - Listeners: []*pbmesh.APIGatewayListener{ - { - Name: "http-listener", - Port: 9090, - Protocol: "http", - }, - }, - } - req := &pbresource.ReadRequest{Id: apiGW.ResourceID(constants.DefaultConsulNS, constants.DefaultConsulPartition)} - res, err := testClient.ResourceClient.Read(ctx, req) - require.NoError(t, err) - require.NotNil(t, res) - require.Equal(t, apiGW.GetName(), res.GetResource().GetId().GetName()) - - data := res.GetResource().Data - actual := &pbmesh.APIGateway{} - require.NoError(t, data.UnmarshalTo(actual)) - - opts := append([]cmp.Option{protocmp.IgnoreFields(&pbresource.Resource{}, "status", "generation", "version")}, test.CmpProtoIgnoreOrder()...) - diff := cmp.Diff(expectedResource, actual, opts...) - require.Equal(t, "", diff, "APIGateway does not match") - } -} - -func TestAPIGatewayController_ReconcileAPIGWDoesNotExistInK8s(t *testing.T) { - t.Parallel() - ctx := context.Background() - - s := runtime.NewScheme() - s.AddKnownTypes(schema.GroupVersion{ - Group: "mesh.consul.hashicorp.com", - Version: pbmesh.Version, - }, &v2beta1.APIGateway{}, &v2beta1.APIGatewayList{}) - - fakeClient := fake.NewClientBuilder().WithScheme(s).Build() - - testClient := test.TestServerWithMockConnMgrWatcher(t, func(c *testutil.TestServerConfig) { - c.Experiments = []string{"resource-apis"} - }) - - gwCtrl := APIGatewayController{ - Client: fakeClient, - Log: logrtest.New(t), - Scheme: s, - Controller: &ConsulResourceController{ - ConsulClientConfig: testClient.Cfg, - ConsulServerConnMgr: testClient.Watcher, - }, - } - - // now reconcile the resource - { - namespacedName := types.NamespacedName{ - Namespace: metav1.NamespaceDefault, - Name: "api-gateway", - } - - resp, err := gwCtrl.Reconcile(ctx, ctrl.Request{ - NamespacedName: namespacedName, - }) - - require.NoError(t, err) - require.False(t, resp.Requeue) - require.Equal(t, ctrl.Result{}, resp) - } - - // ensure the resource is not in consul - { - req := &pbresource.ReadRequest{Id: &pbresource.ID{ - Name: "api-gateway", - Type: pbmesh.APIGatewayType, - Tenancy: &pbresource.Tenancy{ - Namespace: constants.DefaultConsulNS, - Partition: constants.DefaultConsulPartition, - }, - }} - - _, err := testClient.ResourceClient.Read(ctx, req) - require.Error(t, err) - } -} diff --git a/control-plane/controllers/resources/gateway_controller_crud.go b/control-plane/controllers/resources/gateway_controller_crud.go deleted file mode 100644 index a2eae79811..0000000000 --- a/control-plane/controllers/resources/gateway_controller_crud.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resources - -import ( - "context" - "fmt" - - "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - "github.com/hashicorp/consul-k8s/control-plane/gateways" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - k8serr "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -type gatewayConfigs struct { - gcc *meshv2beta1.GatewayClassConfig - gatewayConfig gateways.GatewayConfig -} - -// onCreateUpdate is responsible for creating/updating all K8s resources that -// are required in order to run a meshv2beta1.XGateway. These are created/updated -// in dependency order. -// 1. ServiceAccount -// 2. Deployment -// 3. Service -// 4. Role -// 5. RoleBinding -func onCreateUpdate[T gateways.Gateway](ctx context.Context, k8sClient client.Client, cfg gatewayConfigs, resource T, gatewayKind string) error { - builder := gateways.NewGatewayBuilder[T](resource, cfg.gatewayConfig, cfg.gcc, gatewayKind) - - // Create ServiceAccount - desiredAccount := builder.ServiceAccount() - existingAccount := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: desiredAccount.Namespace, Name: desiredAccount.Name}} - - upsertOp := func(ctx context.Context, _, object client.Object) error { - _, err := controllerutil.CreateOrUpdate(ctx, k8sClient, object, func() error { return nil }) - return err - } - - err := opIfNewOrOwned(ctx, resource, k8sClient, existingAccount, desiredAccount, upsertOp) - if err != nil { - return fmt.Errorf("unable to create service account: %w", err) - } - - // Create Role - desiredRole := builder.Role() - existingRole := &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Namespace: desiredRole.Namespace, Name: desiredRole.Name}} - - err = opIfNewOrOwned(ctx, resource, k8sClient, existingRole, desiredRole, upsertOp) - if err != nil { - return fmt.Errorf("unable to create role: %w", err) - } - - // Create RoleBinding - desiredBinding := builder.RoleBinding() - existingBinding := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Namespace: desiredBinding.Namespace, Name: desiredBinding.Name}} - - err = opIfNewOrOwned(ctx, resource, k8sClient, existingBinding, desiredBinding, upsertOp) - if err != nil { - return fmt.Errorf("unable to create role binding: %w", err) - } - - // Create Service - desiredService := builder.Service() - existingService := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: desiredService.Namespace, Name: desiredService.Name}} - - mergeServiceOp := func(ctx context.Context, existingObj, desiredObj client.Object) error { - existing := existingObj.(*corev1.Service) - desired := desiredObj.(*corev1.Service) - - _, err := controllerutil.CreateOrUpdate(ctx, k8sClient, existing, func() error { - gateways.MergeService(existing, desired) - return nil - }) - return err - } - - err = opIfNewOrOwned(ctx, resource, k8sClient, existingService, desiredService, mergeServiceOp) - if err != nil { - return fmt.Errorf("unable to create service: %w", err) - } - - // Create Deployment - desiredDeployment, err := builder.Deployment() - if err != nil { - return fmt.Errorf("unable to create deployment: %w", err) - } - existingDeployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: desiredDeployment.Namespace, Name: desiredDeployment.Name}} - - mergeDeploymentOp := func(ctx context.Context, existingObj, desiredObj client.Object) error { - existing := existingObj.(*appsv1.Deployment) - desired := desiredObj.(*appsv1.Deployment) - - _, err = controllerutil.CreateOrUpdate(ctx, k8sClient, existing, func() error { - gateways.MergeDeployment(existing, desired) - return nil - }) - return err - } - - err = opIfNewOrOwned(ctx, resource, k8sClient, existingDeployment, desiredDeployment, mergeDeploymentOp) - if err != nil { - return fmt.Errorf("unable to create deployment: %w", err) - } - - return nil -} - -// onDelete is responsible for cleaning up any side effects of onCreateUpdate. -// We only clean up side effects because all resources that we create explicitly -// have an owner reference and will thus be cleaned up by the K8s garbage collector -// once the owning meshv2beta1.XGateway is deleted. -func onDelete[T gateways.Gateway](ctx context.Context, req ctrl.Request, k8sClient client.Client, resource T) error { - // TODO NET-6392 NET-6393 - return nil -} - -// ownedObjectOp represents an operation that needs to be applied -// only if the newObject does not yet exist or if the existingObject -// has an owner reference pointing to the XGateway being reconciled. -// -// The existing and new object are available in case any merging needs -// to occur, such as unknown annotations and values from the existing object -// that need to be carried forward onto the new object. -type ownedObjectOp func(ctx context.Context, existing, desired client.Object) error - -// opIfNewOrOwned runs a given ownedObjectOp to create, update, or delete a resource. -// The purpose of opIfNewOrOwned is to ensure that we aren't updating or deleting a -// resource that was not created by us. If this scenario is encountered, we error. -func opIfNewOrOwned(ctx context.Context, gateway client.Object, k8sClient client.Client, existing, desired client.Object, op ownedObjectOp) error { - // Ensure owner reference is always set on objects that we write - if err := ctrl.SetControllerReference(gateway, desired, k8sClient.Scheme()); err != nil { - return err - } - - key := client.ObjectKey{ - Namespace: existing.GetNamespace(), - Name: existing.GetName(), - } - - exists := false - if err := k8sClient.Get(ctx, key, existing); err != nil { - // We failed to fetch the object in a way that doesn't tell us about its existence - if !k8serr.IsNotFound(err) { - return err - } - } else { - // We successfully fetched the object, so it exists - exists = true - } - - // None exists, so we need only execute the operation - if !exists { - return op(ctx, existing, desired) - } - - // Ensure the existing object was put there by us so that we don't overwrite random objects - owned := false - for _, reference := range existing.GetOwnerReferences() { - if reference.UID == gateway.GetUID() && reference.Name == gateway.GetName() { - owned = true - break - } - } - if !owned { - return errResourceNotOwned - } - return op(ctx, existing, desired) -} - -func getGatewayClassConfigByGatewayClassName(ctx context.Context, k8sClient client.Client, className string) (*meshv2beta1.GatewayClassConfig, error) { - gatewayClass, err := getGatewayClassByName(ctx, k8sClient, className) - if err != nil { - return nil, err - } - - if gatewayClass == nil { - return nil, nil - } - - gatewayClassConfig := &meshv2beta1.GatewayClassConfig{} - if ref := gatewayClass.Spec.ParametersRef; ref != nil { - if ref.Group != meshv2beta1.MeshGroup || ref.Kind != v2beta1.KindGatewayClassConfig { - // TODO @Gateway-Management additionally check for controller name when available - return nil, nil - } - - if err := k8sClient.Get(ctx, types.NamespacedName{Name: ref.Name}, gatewayClassConfig); err != nil { - return nil, client.IgnoreNotFound(err) - } - } - return gatewayClassConfig, nil -} - -func getGatewayClassByName(ctx context.Context, k8sClient client.Client, className string) (*meshv2beta1.GatewayClass, error) { - var gatewayClass meshv2beta1.GatewayClass - - if err := k8sClient.Get(ctx, types.NamespacedName{Name: className}, &gatewayClass); err != nil { - return nil, client.IgnoreNotFound(err) - } - return &gatewayClass, nil -} diff --git a/control-plane/controllers/resources/gateway_controller_setup.go b/control-plane/controllers/resources/gateway_controller_setup.go deleted file mode 100644 index cd97a16ab0..0000000000 --- a/control-plane/controllers/resources/gateway_controller_setup.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resources - -import ( - "context" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - "k8s.io/apimachinery/pkg/fields" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" -) - -type gatewayList interface { - *meshv2beta1.MeshGatewayList | *meshv2beta1.APIGatewayList - client.ObjectList - ReconcileRequests() []reconcile.Request -} - -func setupGatewayControllerWithManager[L gatewayList](mgr ctrl.Manager, obj client.Object, k8sClient client.Client, gwc reconcile.Reconciler, index indexName) error { - return ctrl.NewControllerManagedBy(mgr). - For(obj). - Owns(&appsv1.Deployment{}). - Owns(&rbacv1.Role{}). - Owns(&rbacv1.RoleBinding{}). - Owns(&corev1.Service{}). - Owns(&corev1.ServiceAccount{}). - Watches( - &meshv2beta1.GatewayClass{}, - handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request { - gc := o.(*meshv2beta1.GatewayClass) - if gc == nil { - return nil - } - - gateways, err := getGatewaysReferencingGatewayClass[L](context.Background(), k8sClient, gc.Name, index) - if err != nil { - return nil - } - - return gateways.ReconcileRequests() - })). - Watches( - &meshv2beta1.GatewayClassConfig{}, - handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request { - gcc := o.(*meshv2beta1.GatewayClassConfig) - if gcc == nil { - return nil - } - - classes, err := getGatewayClassesReferencingGatewayClassConfig(ctx, k8sClient, gcc.Name) - if err != nil { - return nil - } - - var requests []reconcile.Request - for _, class := range classes.Items { - if class == nil { - continue - } - - gateways, err := getGatewaysReferencingGatewayClass[L](ctx, k8sClient, class.Name, index) - if err != nil { - continue - } - - requests = append(requests, gateways.ReconcileRequests()...) - } - - return requests - })). - Complete(gwc) -} - -// getGatewayClassesReferencingGatewayClassConfig queries all GatewayClass resources in the -// cluster and returns any that reference the given GatewayClassConfig by name. -func getGatewayClassesReferencingGatewayClassConfig(ctx context.Context, k8sClient client.Client, configName string) (*meshv2beta1.GatewayClassList, error) { - allClasses := &meshv2beta1.GatewayClassList{} - if err := k8sClient.List(ctx, allClasses, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(string(GatewayClass_GatewayClassConfigIndex), configName), - }); err != nil { - return nil, client.IgnoreNotFound(err) - } - - return allClasses, nil -} - -// getGatewaysReferencingGatewayClass queries all xGateway resources in the cluster -// and returns any that reference the given GatewayClass by name. -func getGatewaysReferencingGatewayClass[T gatewayList](ctx context.Context, k8sClient client.Client, className string, index indexName) (T, error) { - var allGateways T - if err := k8sClient.List(ctx, allGateways, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(string(index), className), - }); err != nil { - return nil, client.IgnoreNotFound(err) - } - - return allGateways, nil -} diff --git a/control-plane/controllers/resources/gateway_indices.go b/control-plane/controllers/resources/gateway_indices.go deleted file mode 100644 index 29e221d191..0000000000 --- a/control-plane/controllers/resources/gateway_indices.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resources - -import ( - "context" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" -) - -type indexName string - -const ( - // Naming convention: TARGET_REFERENCE. - GatewayClass_GatewayClassConfigIndex indexName = "__v2_gatewayclass_referencing_gatewayclassconfig" - - APIGateway_GatewayClassIndex indexName = "__v2_api_gateway_referencing_gatewayclass" - MeshGateway_GatewayClassIndex indexName = "__v2_mesh_gateway_referencing_gatewayclass" -) - -// RegisterGatewayFieldIndexes registers all of the field indexes for the xGateway controllers. -// These indexes are similar to indexes used in databases to speed up queries. -// They allow us to quickly find objects based on a field value. -func RegisterGatewayFieldIndexes(ctx context.Context, mgr ctrl.Manager) error { - for _, index := range indexes { - if err := mgr.GetFieldIndexer().IndexField(ctx, index.target, string(index.name), index.indexerFunc); err != nil { - return err - } - } - return nil -} - -type index struct { - name indexName - target client.Object - indexerFunc client.IndexerFunc -} - -var indexes = []index{ - { - name: GatewayClass_GatewayClassConfigIndex, - target: &meshv2beta1.GatewayClass{}, - indexerFunc: func(o client.Object) []string { - gc := o.(*meshv2beta1.GatewayClass) - - pr := gc.Spec.ParametersRef - if pr != nil && pr.Kind == v2beta1.KindGatewayClassConfig { - return []string{pr.Name} - } - - return []string{} - }, - }, - { - name: APIGateway_GatewayClassIndex, - target: &meshv2beta1.APIGateway{}, - indexerFunc: func(o client.Object) []string { - g := o.(*meshv2beta1.APIGateway) - return []string{string(g.Spec.GatewayClassName)} - }, - }, - { - name: MeshGateway_GatewayClassIndex, - target: &meshv2beta1.MeshGateway{}, - indexerFunc: func(o client.Object) []string { - g := o.(*meshv2beta1.MeshGateway) - return []string{string(g.Spec.GatewayClassName)} - }, - }, -} diff --git a/control-plane/controllers/resources/mesh_gateway_controller.go b/control-plane/controllers/resources/mesh_gateway_controller.go index 71bd4e3d46..3996fa4680 100644 --- a/control-plane/controllers/resources/mesh_gateway_controller.go +++ b/control-plane/controllers/resources/mesh_gateway_controller.go @@ -6,13 +6,21 @@ package resources import ( "context" "errors" + "fmt" "github.com/go-logr/logr" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" k8serr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/reconcile" meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" "github.com/hashicorp/consul-k8s/control-plane/gateways" @@ -50,21 +58,11 @@ func (r *MeshGatewayController) Reconcile(ctx context.Context, req ctrl.Request) if !resource.GetDeletionTimestamp().IsZero() { logger.Info("deletion event") - if err := onDelete(ctx, req, r.Client, resource); err != nil { + if err := r.onDelete(ctx, req, resource); err != nil { return ctrl.Result{}, err } } else { - // Fetch GatewayClassConfig for the gateway - gcc, err := getGatewayClassConfigByGatewayClassName(ctx, r.Client, resource.Spec.GatewayClassName) - if err != nil { - r.Log.Error(err, "unable to get gatewayclassconfig for gateway: %s gatewayclass: %s", resource.Name, resource.Spec.GatewayClassName) - return ctrl.Result{}, err - } - - if err := onCreateUpdate(ctx, r.Client, gatewayConfigs{ - gcc: gcc, - gatewayConfig: r.GatewayConfig, - }, resource, gateways.MeshGatewayAnnotationKind); err != nil { + if err := r.onCreateUpdate(ctx, req, resource); err != nil { return ctrl.Result{}, err } } @@ -81,5 +79,298 @@ func (r *MeshGatewayController) UpdateStatus(ctx context.Context, obj client.Obj } func (r *MeshGatewayController) SetupWithManager(mgr ctrl.Manager) error { - return setupGatewayControllerWithManager[*meshv2beta1.MeshGatewayList](mgr, &meshv2beta1.MeshGateway{}, r.Client, r, MeshGateway_GatewayClassIndex) + return ctrl.NewControllerManagedBy(mgr). + For(&meshv2beta1.MeshGateway{}). + Owns(&appsv1.Deployment{}). + Owns(&rbacv1.Role{}). + Owns(&rbacv1.RoleBinding{}). + Owns(&corev1.Service{}). + Owns(&corev1.ServiceAccount{}). + Watches( + &meshv2beta1.GatewayClass{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request { + gateways, err := r.getGatewaysReferencingGatewayClass(ctx, o.(*meshv2beta1.GatewayClass)) + if err != nil { + return nil + } + + requests := make([]reconcile.Request, 0, len(gateways.Items)) + for _, gateway := range gateways.Items { + requests = append(requests, reconcile.Request{NamespacedName: types.NamespacedName{ + Namespace: gateway.Namespace, + Name: gateway.Name, + }}) + } + + return requests + })). + Watches( + &meshv2beta1.GatewayClassConfig{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request { + classes, err := r.getGatewayClassesReferencingGatewayClassConfig(ctx, o.(*meshv2beta1.GatewayClassConfig)) + if err != nil { + return nil + } + + var requests []reconcile.Request + for _, class := range classes.Items { + gateways, err := r.getGatewaysReferencingGatewayClass(ctx, class) + if err != nil { + continue + } + + for _, gateway := range gateways.Items { + requests = append(requests, reconcile.Request{NamespacedName: types.NamespacedName{ + Namespace: gateway.Namespace, + Name: gateway.Name, + }}) + } + } + + return requests + })). + Complete(r) +} + +// onCreateUpdate is responsible for creating/updating all K8s resources that +// are required in order to run a meshv2beta1.MeshGateway. These are created/updated +// in dependency order. +// 1. ServiceAccount +// 2. Deployment +// 3. Service +// 4. Role +// 5. RoleBinding +func (r *MeshGatewayController) onCreateUpdate(ctx context.Context, req ctrl.Request, resource *meshv2beta1.MeshGateway) error { + // Fetch GatewayClassConfig for the gateway + gcc, err := r.getGatewayClassConfigForGateway(ctx, resource) + if err != nil { + r.Log.Error(err, "unable to get gatewayclassconfig for gateway: %s gatewayclass: %s", resource.Name, resource.Spec.GatewayClassName) + return err + } + + builder := gateways.NewMeshGatewayBuilder(resource, r.GatewayConfig, gcc) + + // Create ServiceAccount + desiredAccount := builder.ServiceAccount() + existingAccount := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: desiredAccount.Namespace, Name: desiredAccount.Name}} + + upsertOp := func(ctx context.Context, _, object client.Object) error { + _, err := controllerutil.CreateOrUpdate(ctx, r.Client, object, func() error { return nil }) + return err + } + + err = r.opIfNewOrOwned(ctx, resource, existingAccount, desiredAccount, upsertOp) + if err != nil { + return fmt.Errorf("unable to create service account: %w", err) + } + + // Create Role + desiredRole := builder.Role() + existingRole := &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Namespace: desiredRole.Namespace, Name: desiredRole.Name}} + + err = r.opIfNewOrOwned(ctx, resource, existingRole, desiredRole, upsertOp) + if err != nil { + return fmt.Errorf("unable to create role: %w", err) + } + + // Create RoleBinding + desiredBinding := builder.RoleBinding() + existingBinding := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Namespace: desiredBinding.Namespace, Name: desiredBinding.Name}} + + err = r.opIfNewOrOwned(ctx, resource, existingBinding, desiredBinding, upsertOp) + if err != nil { + return fmt.Errorf("unable to create role binding: %w", err) + } + + // Create Service + desiredService := builder.Service() + existingService := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: desiredService.Namespace, Name: desiredService.Name}} + + mergeServiceOp := func(ctx context.Context, existingObj, desiredObj client.Object) error { + existing := existingObj.(*corev1.Service) + desired := desiredObj.(*corev1.Service) + + _, err := controllerutil.CreateOrUpdate(ctx, r.Client, existing, func() error { + gateways.MergeService(existing, desired) + return nil + }) + return err + } + + err = r.opIfNewOrOwned(ctx, resource, existingService, desiredService, mergeServiceOp) + if err != nil { + return fmt.Errorf("unable to create service: %w", err) + } + + // Create Deployment + desiredDeployment, err := builder.Deployment() + if err != nil { + return fmt.Errorf("unable to create deployment: %w", err) + } + existingDeployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: desiredDeployment.Namespace, Name: desiredDeployment.Name}} + + mergeDeploymentOp := func(ctx context.Context, existingObj, desiredObj client.Object) error { + existing := existingObj.(*appsv1.Deployment) + desired := desiredObj.(*appsv1.Deployment) + + _, err = controllerutil.CreateOrUpdate(ctx, r.Client, existing, func() error { + gateways.MergeDeployment(existing, desired) + return nil + }) + return err + } + + err = r.opIfNewOrOwned(ctx, resource, existingDeployment, desiredDeployment, mergeDeploymentOp) + if err != nil { + return fmt.Errorf("unable to create deployment: %w", err) + } + + return nil +} + +// onDelete is responsible for cleaning up any side effects of onCreateUpdate. +// We only clean up side effects because all resources that we create explicitly +// have an owner reference and will thus be cleaned up by the K8s garbage collector +// once the owning meshv2beta1.MeshGateway is deleted. +func (r *MeshGatewayController) onDelete(ctx context.Context, req ctrl.Request, resource *meshv2beta1.MeshGateway) error { + // TODO NET-6392 NET-6393 + return nil +} + +// ownedObjectOp represents an operation that needs to be applied +// only if the newObject does not yet exist or if the existingObject +// has an owner reference pointing to the MeshGateway being reconciled. +// +// The existing and new object are available in case any merging needs +// to occur, such as unknown annotations and values from the existing object +// that need to be carried forward onto the new object. +type ownedObjectOp func(ctx context.Context, existing, desired client.Object) error + +// opIfNewOrOwned runs a given ownedObjectOp to create, update, or delete a resource. +// The purpose of opIfNewOrOwned is to ensure that we aren't updating or deleting a +// resource that was not created by us. If this scenario is encountered, we error. +func (r *MeshGatewayController) opIfNewOrOwned(ctx context.Context, gateway *meshv2beta1.MeshGateway, existing, desired client.Object, op ownedObjectOp) error { + // Ensure owner reference is always set on objects that we write + if err := ctrl.SetControllerReference(gateway, desired, r.Client.Scheme()); err != nil { + return err + } + + key := client.ObjectKey{ + Namespace: existing.GetNamespace(), + Name: existing.GetName(), + } + + exists := false + if err := r.Get(ctx, key, existing); err != nil { + // We failed to fetch the object in a way that doesn't tell us about its existence + if !k8serr.IsNotFound(err) { + return err + } + } else { + // We successfully fetched the object, so it exists + exists = true + } + + // None exists, so we need only execute the operation + if !exists { + return op(ctx, existing, desired) + } + + // Ensure the existing object was put there by us so that we don't overwrite random objects + owned := false + for _, reference := range existing.GetOwnerReferences() { + if reference.UID == gateway.GetUID() && reference.Name == gateway.GetName() { + owned = true + break + } + } + if !owned { + return errResourceNotOwned + } + return op(ctx, existing, desired) +} + +func (r *MeshGatewayController) getGatewayClassConfigForGateway(ctx context.Context, gateway *meshv2beta1.MeshGateway) (*meshv2beta1.GatewayClassConfig, error) { + gatewayClass, err := r.getGatewayClassForGateway(ctx, gateway) + if err != nil { + return nil, err + } + + gatewayClassConfig, err := r.getGatewayClassConfigForGatewayClass(ctx, gatewayClass) + if err != nil { + return nil, err + } + + return gatewayClassConfig, nil +} + +func (r *MeshGatewayController) getGatewayClassConfigForGatewayClass(ctx context.Context, gatewayClass *meshv2beta1.GatewayClass) (*meshv2beta1.GatewayClassConfig, error) { + if gatewayClass == nil { + // if we don't have a gateway class we can't fetch the corresponding config + return nil, nil + } + + config := &meshv2beta1.GatewayClassConfig{} + if ref := gatewayClass.Spec.ParametersRef; ref != nil { + if ref.Group != meshv2beta1.MeshGroup || ref.Kind != meshv2beta1.KindGatewayClassConfig { + // TODO @Gateway-Management additionally check for controller name when available + return nil, nil + } + + if err := r.Client.Get(ctx, types.NamespacedName{Name: ref.Name}, config); err != nil { + return nil, client.IgnoreNotFound(err) + } + } + return config, nil +} + +func (r *MeshGatewayController) getGatewayClassForGateway(ctx context.Context, gateway *meshv2beta1.MeshGateway) (*meshv2beta1.GatewayClass, error) { + var gatewayClass meshv2beta1.GatewayClass + + if err := r.Client.Get(ctx, types.NamespacedName{Name: string(gateway.Spec.GatewayClassName)}, &gatewayClass); err != nil { + return nil, client.IgnoreNotFound(err) + } + return &gatewayClass, nil +} + +// getGatewayClassesReferencingGatewayClassConfig queries all GatewayClass resources in the +// cluster and returns any that reference the given GatewayClassConfig. +func (r *MeshGatewayController) getGatewayClassesReferencingGatewayClassConfig(ctx context.Context, config *meshv2beta1.GatewayClassConfig) (*meshv2beta1.GatewayClassList, error) { + if config == nil { + return nil, nil + } + + allClasses := &meshv2beta1.GatewayClassList{} + if err := r.Client.List(ctx, allClasses); err != nil { + return nil, client.IgnoreNotFound(err) + } + + matchingClasses := &meshv2beta1.GatewayClassList{} + for _, class := range allClasses.Items { + if class.Spec.ParametersRef != nil && class.Spec.ParametersRef.Name == config.Name { + matchingClasses.Items = append(matchingClasses.Items, class) + } + } + return matchingClasses, nil +} + +// getGatewaysReferencingGatewayClass queries all MeshGateway resources in the cluster +// and returns any that reference the given GatewayClass. +func (r *MeshGatewayController) getGatewaysReferencingGatewayClass(ctx context.Context, class *meshv2beta1.GatewayClass) (*meshv2beta1.MeshGatewayList, error) { + if class == nil { + return nil, nil + } + + allGateways := &meshv2beta1.MeshGatewayList{} + if err := r.Client.List(ctx, allGateways); err != nil { + return nil, client.IgnoreNotFound(err) + } + + matchingGateways := &meshv2beta1.MeshGatewayList{} + for _, gateway := range allGateways.Items { + if gateway.Spec.GatewayClassName == class.Name { + matchingGateways.Items = append(matchingGateways.Items, gateway) + } + } + return matchingGateways, nil } diff --git a/control-plane/gateways/builder.go b/control-plane/gateways/builder.go index 35e8384b3f..e43e6dd890 100644 --- a/control-plane/gateways/builder.go +++ b/control-plane/gateways/builder.go @@ -5,34 +5,23 @@ package gateways import ( meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" ) -type Gateway interface { - *meshv2beta1.MeshGateway | *meshv2beta1.APIGateway - client.Object - ListenersToServicePorts(int32) []corev1.ServicePort - ListenersToContainerPorts(int32, int32) []corev1.ContainerPort -} - -// gatewayBuilder is a helper struct for building the Kubernetes resources for a mesh gateway. +// meshGatewayBuilder is a helper struct for building the Kubernetes resources for a mesh gateway. // This includes Deployment, Role, Service, and ServiceAccount resources. // Configuration is combined from the MeshGateway, GatewayConfig, and GatewayClassConfig. -type gatewayBuilder[T Gateway] struct { - gateway T - gcc *meshv2beta1.GatewayClassConfig - config GatewayConfig - gatewayKind string +type meshGatewayBuilder struct { + gateway *meshv2beta1.MeshGateway + config GatewayConfig + gcc *meshv2beta1.GatewayClassConfig } -// NewGatewayBuilder returns a new meshGatewayBuilder for the given MeshGateway, +// NewMeshGatewayBuilder returns a new meshGatewayBuilder for the given MeshGateway, // GatewayConfig, and GatewayClassConfig. -func NewGatewayBuilder[T Gateway](gateway T, gatewayConfig GatewayConfig, gatewayClassConfig *meshv2beta1.GatewayClassConfig, gatewayKind string) *gatewayBuilder[T] { - return &gatewayBuilder[T]{ - gateway: gateway, - config: gatewayConfig, - gcc: gatewayClassConfig, - gatewayKind: gatewayKind, +func NewMeshGatewayBuilder(gateway *meshv2beta1.MeshGateway, gatewayConfig GatewayConfig, gatewayClassConfig *meshv2beta1.GatewayClassConfig) *meshGatewayBuilder { + return &meshGatewayBuilder{ + gateway: gateway, + config: gatewayConfig, + gcc: gatewayClassConfig, } } diff --git a/control-plane/gateways/deployment.go b/control-plane/gateways/deployment.go index 5bab84dec8..433323489c 100644 --- a/control-plane/gateways/deployment.go +++ b/control-plane/gateways/deployment.go @@ -15,16 +15,15 @@ import ( const ( globalDefaultInstances int32 = 1 - MeshGatewayAnnotationKind = "mesh-gateway" - APIGatewayAnnotationKind = "api-gateway" + meshGatewayAnnotationKind = "mesh-gateway" ) -func (b *gatewayBuilder[T]) Deployment() (*appsv1.Deployment, error) { +func (b *meshGatewayBuilder) Deployment() (*appsv1.Deployment, error) { spec, err := b.deploymentSpec() return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: b.gateway.GetName(), - Namespace: b.gateway.GetNamespace(), + Name: b.gateway.Name, + Namespace: b.gateway.Namespace, Labels: b.labelsForDeployment(), Annotations: b.annotationsForDeployment(), }, @@ -32,7 +31,7 @@ func (b *gatewayBuilder[T]) Deployment() (*appsv1.Deployment, error) { }, err } -func (b *gatewayBuilder[T]) deploymentSpec() (*appsv1.DeploymentSpec, error) { +func (b *meshGatewayBuilder) deploymentSpec() (*appsv1.DeploymentSpec, error) { var ( deploymentConfig meshv2beta1.GatewayClassDeploymentConfig containerConfig meshv2beta1.GatewayClassContainerConfig @@ -68,18 +67,18 @@ func (b *gatewayBuilder[T]) deploymentSpec() (*appsv1.DeploymentSpec, error) { Annotations: map[string]string{ // Indicate that this pod is a mesh gateway pod so that the Pod controller, // consul-k8s CLI, etc. can key off of it - constants.AnnotationGatewayKind: b.gatewayKind, + constants.AnnotationGatewayKind: meshGatewayAnnotationKind, // It's not logical to add a proxy sidecar since our workload is itself a proxy constants.AnnotationMeshInject: "false", // This functionality only applies when proxy sidecars are used constants.AnnotationTransparentProxyOverwriteProbes: "false", // This annotation determines which source to use to set the // WAN address and WAN port for the Mesh Gateway service registration. - constants.AnnotationGatewayWANSource: b.gateway.GetAnnotations()[constants.AnnotationGatewayWANSource], + constants.AnnotationGatewayWANSource: b.gateway.Annotations[constants.AnnotationGatewayWANSource], // This annotation determines the WAN port for the Mesh Gateway service registration. - constants.AnnotationGatewayWANPort: b.gateway.GetAnnotations()[constants.AnnotationGatewayWANPort], + constants.AnnotationGatewayWANPort: b.gateway.Annotations[constants.AnnotationGatewayWANPort], // This annotation determines the address for the gateway when the source annotation is "Static". - constants.AnnotationGatewayWANAddress: b.gateway.GetAnnotations()[constants.AnnotationGatewayWANAddress], + constants.AnnotationGatewayWANAddress: b.gateway.Annotations[constants.AnnotationGatewayWANAddress], }, }, Spec: corev1.PodSpec{ diff --git a/control-plane/gateways/deployment_dataplane_container.go b/control-plane/gateways/deployment_dataplane_container.go index 630e337ad5..9dc7dad141 100644 --- a/control-plane/gateways/deployment_dataplane_container.go +++ b/control-plane/gateways/deployment_dataplane_container.go @@ -27,7 +27,7 @@ const ( volumeName = "consul-mesh-inject-data" ) -func (b *gatewayBuilder[T]) consulDataplaneContainer(containerConfig v2beta1.GatewayClassContainerConfig) (corev1.Container, error) { +func (b *meshGatewayBuilder) consulDataplaneContainer(containerConfig v2beta1.GatewayClassContainerConfig) (corev1.Container, error) { // Extract the service account token's volume mount. var ( err error @@ -56,7 +56,7 @@ func (b *gatewayBuilder[T]) consulDataplaneContainer(containerConfig v2beta1.Gat } container := corev1.Container{ - Name: b.gateway.GetName(), + Name: b.gateway.Name, Image: b.config.ImageDataplane, // We need to set tmp dir to an ephemeral volume that we're mounting so that @@ -117,7 +117,16 @@ func (b *gatewayBuilder[T]) consulDataplaneContainer(containerConfig v2beta1.Gat ContainerPort: int32(constants.ProxyDefaultHealthPort), }) - container.Ports = append(container.Ports, b.gateway.ListenersToContainerPorts(containerConfig.PortModifier, containerConfig.HostPort)...) + // Configure the wan port. + wanPort := corev1.ContainerPort{ + Name: "wan", + ContainerPort: int32(constants.DefaultWANPort), + HostPort: containerConfig.HostPort, + } + + wanPort.ContainerPort = 443 + containerConfig.PortModifier + + container.Ports = append(container.Ports, wanPort) // Configure the resource requests and limits for the proxy if they are set. if resources != nil { @@ -140,7 +149,7 @@ func (b *gatewayBuilder[T]) consulDataplaneContainer(containerConfig v2beta1.Gat return container, nil } -func (b *gatewayBuilder[T]) dataplaneArgs(bearerTokenFile string) ([]string, error) { +func (b *meshGatewayBuilder) dataplaneArgs(bearerTokenFile string) ([]string, error) { args := []string{ "-addresses", b.config.ConsulConfig.Address, "-grpc-port=" + strconv.Itoa(b.config.ConsulConfig.GRPCPort), @@ -149,14 +158,14 @@ func (b *gatewayBuilder[T]) dataplaneArgs(bearerTokenFile string) ([]string, err "-envoy-concurrency=" + defaultEnvoyProxyConcurrency, } - consulNamespace := namespaces.ConsulNamespace(b.gateway.GetNamespace(), b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.ConsulDestinationNamespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.NSMirroringPrefix) + consulNamespace := namespaces.ConsulNamespace(b.gateway.Namespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.ConsulDestinationNamespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.NSMirroringPrefix) if b.config.AuthMethod != "" { args = append(args, "-credential-type=login", "-login-auth-method="+b.config.AuthMethod, "-login-bearer-token-path="+bearerTokenFile, - "-login-meta="+fmt.Sprintf("gateway=%s/%s", b.gateway.GetNamespace(), b.gateway.GetName()), + "-login-meta="+fmt.Sprintf("gateway=%s/%s", b.gateway.Namespace, b.gateway.Name), ) if b.config.ConsulTenancyConfig.ConsulPartition != "" { args = append(args, "-login-partition="+b.config.ConsulTenancyConfig.ConsulPartition) diff --git a/control-plane/gateways/deployment_init_container.go b/control-plane/gateways/deployment_init_container.go index beb7267005..14230b98df 100644 --- a/control-plane/gateways/deployment_init_container.go +++ b/control-plane/gateways/deployment_init_container.go @@ -21,7 +21,9 @@ const ( initContainersUserAndGroupID = 5996 ) -var tpl = template.Must(template.New("root").Parse(strings.TrimSpace(initContainerCommandTpl))) +var ( + tpl = template.Must(template.New("root").Parse(strings.TrimSpace(initContainerCommandTpl))) +) type initContainerCommandData struct { ServiceName string @@ -35,12 +37,12 @@ type initContainerCommandData struct { // initContainer returns the init container spec for connect-init that polls for the service and the connect proxy service to be registered // so that it can save the proxy service id to the shared volume and boostrap Envoy with the proxy-id. -func (b *gatewayBuilder[T]) initContainer() (corev1.Container, error) { +func (b *meshGatewayBuilder) initContainer() (corev1.Container, error) { data := initContainerCommandData{ AuthMethod: b.config.AuthMethod, LogLevel: b.logLevelForInitContainer(), LogJSON: b.config.LogJSON, - ServiceName: b.gateway.GetName(), + ServiceName: b.gateway.Name, ServiceAccountName: b.serviceAccountName(), } // Render the command @@ -62,7 +64,7 @@ func (b *gatewayBuilder[T]) initContainer() (corev1.Container, error) { bearerTokenFile = defaultBearerTokenFile } - consulNamespace := namespaces.ConsulNamespace(b.gateway.GetNamespace(), b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.ConsulDestinationNamespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.NSMirroringPrefix) + consulNamespace := namespaces.ConsulNamespace(b.gateway.Namespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.ConsulDestinationNamespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.NSMirroringPrefix) initContainerName := injectInitContainerName container := corev1.Container{ diff --git a/control-plane/gateways/deployment_test.go b/control-plane/gateways/deployment_test.go index 24e5fa67a2..12fa30ee0c 100644 --- a/control-plane/gateways/deployment_test.go +++ b/control-plane/gateways/deployment_test.go @@ -42,7 +42,7 @@ RQIgXg8YtejEgGNxswtyXsvqzhLpt7k44L7TJMUhfIw0lUECIQCIxKNowmv0/XVz nRnYLmGy79EZ2Y+CZS9nSm9Es6QNwg== │ -----END CERTIFICATE-----` -func Test_gatewayBuilder_Deployment(t *testing.T) { +func Test_meshGatewayBuilder_Deployment(t *testing.T) { type fields struct { gateway *meshv2beta1.MeshGateway config GatewayConfig @@ -67,13 +67,6 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { }, Spec: pbmesh.MeshGateway{ GatewayClassName: "test-gateway-class", - Listeners: []*pbmesh.MeshGatewayListener{ - { - Name: "wan", - Port: 443, - Protocol: "tcp", - }, - }, }, }, config: GatewayConfig{}, @@ -210,7 +203,7 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { "release": "consul", }, Annotations: map[string]string{ - constants.AnnotationGatewayKind: MeshGatewayAnnotationKind, + constants.AnnotationGatewayKind: meshGatewayAnnotationKind, constants.AnnotationMeshInject: "false", constants.AnnotationTransparentProxyOverwriteProbes: "false", constants.AnnotationGatewayWANSource: "Service", @@ -334,7 +327,6 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { Name: "wan", ContainerPort: 8443, HostPort: 8080, - Protocol: "tcp", }, }, Env: []corev1.EnvVar{ @@ -483,13 +475,6 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { }, Spec: pbmesh.MeshGateway{ GatewayClassName: "test-gateway-class", - Listeners: []*pbmesh.MeshGatewayListener{ - { - Name: "wan", - Port: 443, - Protocol: "tcp", - }, - }, }, }, config: GatewayConfig{ @@ -607,7 +592,7 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { "release": "consul", }, Annotations: map[string]string{ - constants.AnnotationGatewayKind: MeshGatewayAnnotationKind, + constants.AnnotationGatewayKind: meshGatewayAnnotationKind, constants.AnnotationMeshInject: "false", constants.AnnotationTransparentProxyOverwriteProbes: "false", constants.AnnotationGatewayWANSource: "Service", @@ -743,7 +728,6 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { Name: "wan", ContainerPort: 8443, HostPort: 8080, - Protocol: "tcp", }, }, Env: []corev1.EnvVar{ @@ -892,13 +876,6 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { }, Spec: pbmesh.MeshGateway{ GatewayClassName: "test-gateway-class", - Listeners: []*pbmesh.MeshGatewayListener{ - { - Name: "wan", - Port: 443, - Protocol: "tcp", - }, - }, }, }, config: GatewayConfig{}, @@ -918,7 +895,7 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Labels: defaultLabels, Annotations: map[string]string{ - constants.AnnotationGatewayKind: MeshGatewayAnnotationKind, + constants.AnnotationGatewayKind: meshGatewayAnnotationKind, constants.AnnotationMeshInject: "false", constants.AnnotationTransparentProxyOverwriteProbes: "false", constants.AnnotationGatewayWANSource: "Service", @@ -1032,7 +1009,6 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { { Name: "wan", ContainerPort: 443, - Protocol: "tcp", }, }, Env: []corev1.EnvVar{ @@ -1139,11 +1115,10 @@ func Test_gatewayBuilder_Deployment(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - b := &gatewayBuilder[*meshv2beta1.MeshGateway]{ - gateway: tt.fields.gateway, - config: tt.fields.config, - gcc: tt.fields.gcc, - gatewayKind: MeshGatewayAnnotationKind, + b := &meshGatewayBuilder{ + gateway: tt.fields.gateway, + config: tt.fields.config, + gcc: tt.fields.gcc, } got, err := b.Deployment() if !tt.wantErr && (err != nil) { diff --git a/control-plane/gateways/metadata.go b/control-plane/gateways/metadata.go index 4581efc232..e1479ef3f2 100644 --- a/control-plane/gateways/metadata.go +++ b/control-plane/gateways/metadata.go @@ -13,54 +13,54 @@ const labelManagedBy = "mesh.consul.hashicorp.com/managed-by" var defaultLabels = map[string]string{labelManagedBy: "consul-k8s"} -func (b *gatewayBuilder[T]) annotationsForDeployment() map[string]string { +func (b *meshGatewayBuilder) annotationsForDeployment() map[string]string { if b.gcc == nil { return map[string]string{} } - return computeAnnotationsOrLabels(b.gateway.GetAnnotations(), b.gcc.Spec.Deployment.Annotations, b.gcc.Spec.Annotations) + return computeAnnotationsOrLabels(b.gateway.Annotations, b.gcc.Spec.Deployment.Annotations, b.gcc.Spec.Annotations) } -func (b *gatewayBuilder[T]) annotationsForRole() map[string]string { +func (b *meshGatewayBuilder) annotationsForRole() map[string]string { if b.gcc == nil { return map[string]string{} } - return computeAnnotationsOrLabels(b.gateway.GetAnnotations(), b.gcc.Spec.Role.Annotations, b.gcc.Spec.Annotations) + return computeAnnotationsOrLabels(b.gateway.Annotations, b.gcc.Spec.Role.Annotations, b.gcc.Spec.Annotations) } -func (b *gatewayBuilder[T]) annotationsForRoleBinding() map[string]string { +func (b *meshGatewayBuilder) annotationsForRoleBinding() map[string]string { if b.gcc == nil { return map[string]string{} } - return computeAnnotationsOrLabels(b.gateway.GetAnnotations(), b.gcc.Spec.RoleBinding.Annotations, b.gcc.Spec.Annotations) + return computeAnnotationsOrLabels(b.gateway.Annotations, b.gcc.Spec.RoleBinding.Annotations, b.gcc.Spec.Annotations) } -func (b *gatewayBuilder[T]) annotationsForService() map[string]string { +func (b *meshGatewayBuilder) annotationsForService() map[string]string { if b.gcc == nil { return map[string]string{} } - return computeAnnotationsOrLabels(b.gateway.GetAnnotations(), b.gcc.Spec.Service.Annotations, b.gcc.Spec.Annotations) + return computeAnnotationsOrLabels(b.gateway.Annotations, b.gcc.Spec.Service.Annotations, b.gcc.Spec.Annotations) } -func (b *gatewayBuilder[T]) annotationsForServiceAccount() map[string]string { +func (b *meshGatewayBuilder) annotationsForServiceAccount() map[string]string { if b.gcc == nil { return map[string]string{} } - return computeAnnotationsOrLabels(b.gateway.GetAnnotations(), b.gcc.Spec.ServiceAccount.Annotations, b.gcc.Spec.Annotations) + return computeAnnotationsOrLabels(b.gateway.Annotations, b.gcc.Spec.ServiceAccount.Annotations, b.gcc.Spec.Annotations) } -func (b *gatewayBuilder[T]) labelsForDeployment() map[string]string { +func (b *meshGatewayBuilder) labelsForDeployment() map[string]string { if b.gcc == nil { return defaultLabels } - labels := computeAnnotationsOrLabels(b.gateway.GetLabels(), b.gcc.Spec.Deployment.Labels, b.gcc.Spec.Labels) + labels := computeAnnotationsOrLabels(b.gateway.Labels, b.gcc.Spec.Deployment.Labels, b.gcc.Spec.Labels) for k, v := range defaultLabels { labels[k] = v } return labels } -func (b *gatewayBuilder[T]) logLevelForDataplaneContainer() string { +func (b *meshGatewayBuilder) logLevelForDataplaneContainer() string { if b.config.LogLevel != "" { return b.config.LogLevel } @@ -72,7 +72,7 @@ func (b *gatewayBuilder[T]) logLevelForDataplaneContainer() string { return b.gcc.Spec.Deployment.Container.Consul.Logging.Level } -func (b *gatewayBuilder[T]) logLevelForInitContainer() string { +func (b *meshGatewayBuilder) logLevelForInitContainer() string { if b.config.LogLevel != "" { return b.config.LogLevel } @@ -84,48 +84,48 @@ func (b *gatewayBuilder[T]) logLevelForInitContainer() string { return b.gcc.Spec.Deployment.InitContainer.Consul.Logging.Level } -func (b *gatewayBuilder[T]) labelsForRole() map[string]string { +func (b *meshGatewayBuilder) labelsForRole() map[string]string { if b.gcc == nil { return defaultLabels } - labels := computeAnnotationsOrLabels(b.gateway.GetLabels(), b.gcc.Spec.Role.Labels, b.gcc.Spec.Labels) + labels := computeAnnotationsOrLabels(b.gateway.Labels, b.gcc.Spec.Role.Labels, b.gcc.Spec.Labels) for k, v := range defaultLabels { labels[k] = v } return labels } -func (b *gatewayBuilder[T]) labelsForRoleBinding() map[string]string { +func (b *meshGatewayBuilder) labelsForRoleBinding() map[string]string { if b.gcc == nil { return defaultLabels } - labels := computeAnnotationsOrLabels(b.gateway.GetLabels(), b.gcc.Spec.RoleBinding.Labels, b.gcc.Spec.Labels) + labels := computeAnnotationsOrLabels(b.gateway.Labels, b.gcc.Spec.RoleBinding.Labels, b.gcc.Spec.Labels) for k, v := range defaultLabels { labels[k] = v } return labels } -func (b *gatewayBuilder[T]) labelsForService() map[string]string { +func (b *meshGatewayBuilder) labelsForService() map[string]string { if b.gcc == nil { return defaultLabels } - labels := computeAnnotationsOrLabels(b.gateway.GetLabels(), b.gcc.Spec.Service.Labels, b.gcc.Spec.Labels) + labels := computeAnnotationsOrLabels(b.gateway.Labels, b.gcc.Spec.Service.Labels, b.gcc.Spec.Labels) for k, v := range defaultLabels { labels[k] = v } return labels } -func (b *gatewayBuilder[T]) labelsForServiceAccount() map[string]string { +func (b *meshGatewayBuilder) labelsForServiceAccount() map[string]string { if b.gcc == nil { return defaultLabels } - labels := computeAnnotationsOrLabels(b.gateway.GetLabels(), b.gcc.Spec.ServiceAccount.Labels, b.gcc.Spec.Labels) + labels := computeAnnotationsOrLabels(b.gateway.Labels, b.gcc.Spec.ServiceAccount.Labels, b.gcc.Spec.Labels) for k, v := range defaultLabels { labels[k] = v } diff --git a/control-plane/gateways/metadata_test.go b/control-plane/gateways/metadata_test.go index 5b4861c1d0..7505867992 100644 --- a/control-plane/gateways/metadata_test.go +++ b/control-plane/gateways/metadata_test.go @@ -12,7 +12,7 @@ import ( meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" ) -func TestGatewayBuilder_Annotations(t *testing.T) { +func TestMeshGatewayBuilder_Annotations(t *testing.T) { gateway := &meshv2beta1.MeshGateway{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ @@ -77,7 +77,7 @@ func TestGatewayBuilder_Annotations(t *testing.T) { }, } - b := NewGatewayBuilder[*meshv2beta1.MeshGateway](gateway, GatewayConfig{}, gatewayClassConfig, MeshGatewayAnnotationKind) + b := NewMeshGatewayBuilder(gateway, GatewayConfig{}, gatewayClassConfig) for _, testCase := range []struct { Actual map[string]string @@ -133,7 +133,7 @@ func TestGatewayBuilder_Annotations(t *testing.T) { } } -func TestGatewayBuilder_Labels(t *testing.T) { +func TestNewMeshGatewayBuilder_Labels(t *testing.T) { gateway := &meshv2beta1.MeshGateway{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ @@ -198,7 +198,7 @@ func TestGatewayBuilder_Labels(t *testing.T) { }, } - b := NewGatewayBuilder[*meshv2beta1.MeshGateway](gateway, GatewayConfig{}, gatewayClassConfig, MeshGatewayAnnotationKind) + b := NewMeshGatewayBuilder(gateway, GatewayConfig{}, gatewayClassConfig) for _, testCase := range []struct { Actual map[string]string @@ -261,7 +261,7 @@ func TestGatewayBuilder_Labels(t *testing.T) { // The LogLevel for deployment containers may be set on the Gateway Class Config or the Gateway Config. // If it is set on both, the Gateway Config takes precedence. -func TestGatewayBuilder_LogLevel(t *testing.T) { +func TestMeshGatewayBuilder_LogLevel(t *testing.T) { debug := "debug" info := "info" @@ -285,6 +285,7 @@ func TestGatewayBuilder_LogLevel(t *testing.T) { for name, testCase := range testCases { t.Run(name, func(t *testing.T) { + gcc := &meshv2beta1.GatewayClassConfig{ Spec: meshv2beta1.GatewayClassConfigSpec{ Deployment: meshv2beta1.GatewayClassDeploymentConfig{ @@ -298,7 +299,7 @@ func TestGatewayBuilder_LogLevel(t *testing.T) { }, }, } - b := NewGatewayBuilder(&meshv2beta1.MeshGateway{}, GatewayConfig{LogLevel: testCase.GatewayLogLevel}, gcc, MeshGatewayAnnotationKind) + b := NewMeshGatewayBuilder(&meshv2beta1.MeshGateway{}, GatewayConfig{LogLevel: testCase.GatewayLogLevel}, gcc) assert.Equal(t, debug, b.logLevelForDataplaneContainer()) }) diff --git a/control-plane/gateways/role.go b/control-plane/gateways/role.go index 0cec287b5b..3264bb60b0 100644 --- a/control-plane/gateways/role.go +++ b/control-plane/gateways/role.go @@ -8,11 +8,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (b *gatewayBuilder[T]) Role() *rbacv1.Role { +func (b *meshGatewayBuilder) Role() *rbacv1.Role { return &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ - Name: b.gateway.GetName(), - Namespace: b.gateway.GetNamespace(), + Name: b.gateway.Name, + Namespace: b.gateway.Namespace, Labels: b.labelsForRole(), Annotations: b.annotationsForRole(), }, @@ -20,11 +20,11 @@ func (b *gatewayBuilder[T]) Role() *rbacv1.Role { } } -func (b *gatewayBuilder[T]) RoleBinding() *rbacv1.RoleBinding { +func (b *meshGatewayBuilder) RoleBinding() *rbacv1.RoleBinding { return &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: b.gateway.GetName(), - Namespace: b.gateway.GetNamespace(), + Name: b.gateway.Name, + Namespace: b.gateway.Namespace, Labels: b.labelsForRoleBinding(), Annotations: b.annotationsForRoleBinding(), }, @@ -32,8 +32,8 @@ func (b *gatewayBuilder[T]) RoleBinding() *rbacv1.RoleBinding { { APIGroup: "", Kind: rbacv1.ServiceAccountKind, - Name: b.gateway.GetName(), - Namespace: b.gateway.GetNamespace(), + Name: b.gateway.Name, + Namespace: b.gateway.Namespace, }, }, RoleRef: rbacv1.RoleRef{ diff --git a/control-plane/gateways/service.go b/control-plane/gateways/service.go index b60cc42019..c7dffdf969 100644 --- a/control-plane/gateways/service.go +++ b/control-plane/gateways/service.go @@ -6,11 +6,13 @@ package gateways import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" ) -func (b *gatewayBuilder[T]) Service() *corev1.Service { +func (b *meshGatewayBuilder) Service() *corev1.Service { var ( containerConfig *meshv2beta1.GatewayClassContainerConfig portModifier = int32(0) @@ -25,19 +27,53 @@ func (b *gatewayBuilder[T]) Service() *corev1.Service { return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: b.gateway.GetName(), - Namespace: b.gateway.GetNamespace(), + Name: b.gateway.Name, + Namespace: b.gateway.Namespace, Labels: b.labelsForService(), Annotations: b.annotationsForService(), }, Spec: corev1.ServiceSpec{ Selector: b.labelsForDeployment(), Type: serviceType, - Ports: b.gateway.ListenersToServicePorts(portModifier), + Ports: b.Ports(portModifier), }, } } +// Ports build a list of ports from the listener objects. In theory there should only ever be a WAN port on +// mesh gateway but building the ports from a list of listeners will allow for easier compatability with other +// gateway patterns in the future. +func (b *meshGatewayBuilder) Ports(portModifier int32) []corev1.ServicePort { + + ports := []corev1.ServicePort{} + + if len(b.gateway.Spec.Listeners) == 0 { + //If empty use the default value. This should always be set, but in case it's not, this check + //will prevent a panic. + return []corev1.ServicePort{ + { + Name: "wan", + Port: constants.DefaultWANPort, + TargetPort: intstr.IntOrString{ + IntVal: constants.DefaultWANPort + portModifier, + }, + }, + } + } + for _, listener := range b.gateway.Spec.Listeners { + port := int32(listener.Port) + ports = append(ports, corev1.ServicePort{ + Name: listener.Name, + Port: port, + TargetPort: intstr.IntOrString{ + IntVal: port + portModifier, + }, + Protocol: corev1.Protocol(listener.Protocol), + }) + } + return ports +} + // MergeService is used to update a corev1.Service without overwriting any // existing annotations or labels that were placed there by other vendors. // diff --git a/control-plane/gateways/service_test.go b/control-plane/gateways/service_test.go index 19e9a0e71d..f5d4beb58c 100644 --- a/control-plane/gateways/service_test.go +++ b/control-plane/gateways/service_test.go @@ -15,7 +15,7 @@ import ( meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" ) -func Test_gatewayBuilder_meshGateway_Service(t *testing.T) { +func Test_meshGatewayBuilder_Service(t *testing.T) { lbType := corev1.ServiceTypeLoadBalancer type fields struct { @@ -144,7 +144,7 @@ func Test_gatewayBuilder_meshGateway_Service(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - b := &gatewayBuilder[*meshv2beta1.MeshGateway]{ + b := &meshGatewayBuilder{ gateway: tt.fields.gateway, config: tt.fields.config, gcc: tt.fields.gcc, @@ -216,143 +216,3 @@ func Test_MergeService(t *testing.T) { }) } } - -func Test_gatewayBuilder_apiGateway_Service(t *testing.T) { - lbType := corev1.ServiceTypeLoadBalancer - - type fields struct { - gateway *meshv2beta1.APIGateway - config GatewayConfig - gcc *meshv2beta1.GatewayClassConfig - } - tests := []struct { - name string - fields fields - want *corev1.Service - }{ - { - name: "service resource crd created - happy path", - fields: fields{ - gateway: &meshv2beta1.APIGateway{ - Spec: pbmesh.APIGateway{ - GatewayClassName: "test-gateway-class", - Listeners: []*pbmesh.APIGatewayListener{ - { - Name: "http-listener", - Port: 80, - Protocol: "http", - }, - }, - }, - }, - config: GatewayConfig{}, - gcc: &meshv2beta1.GatewayClassConfig{ - Spec: meshv2beta1.GatewayClassConfigSpec{ - GatewayClassAnnotationsAndLabels: meshv2beta1.GatewayClassAnnotationsAndLabels{ - Labels: meshv2beta1.GatewayClassAnnotationsLabelsConfig{ - Set: map[string]string{ - "app": "consul", - "chart": "consul-helm", - "heritage": "Helm", - "release": "consul", - }, - }, - }, - Deployment: meshv2beta1.GatewayClassDeploymentConfig{ - Container: &meshv2beta1.GatewayClassContainerConfig{ - PortModifier: 8000, - }, - }, - Service: meshv2beta1.GatewayClassServiceConfig{ - Type: &lbType, - }, - }, - }, - }, - want: &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - labelManagedBy: "consul-k8s", - "app": "consul", - "chart": "consul-helm", - "heritage": "Helm", - "release": "consul", - }, - Annotations: map[string]string{}, - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - labelManagedBy: "consul-k8s", - "app": "consul", - "chart": "consul-helm", - "heritage": "Helm", - "release": "consul", - }, - Type: corev1.ServiceTypeLoadBalancer, - Ports: []corev1.ServicePort{ - { - Name: "http-listener", - Port: int32(80), - TargetPort: intstr.IntOrString{ - IntVal: int32(8080), - }, - Protocol: "http", - }, - }, - }, - Status: corev1.ServiceStatus{}, - }, - }, - { - name: "create service resource crd - gcc is nil", - fields: fields{ - gateway: &meshv2beta1.APIGateway{ - Spec: pbmesh.APIGateway{ - GatewayClassName: "test-gateway-class", - Listeners: []*pbmesh.APIGatewayListener{ - { - Name: "http-listener", - Port: 80, - Protocol: "http", - }, - }, - }, - }, - config: GatewayConfig{}, - gcc: nil, - }, - want: &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Labels: defaultLabels, - Annotations: map[string]string{}, - }, - Spec: corev1.ServiceSpec{ - Selector: defaultLabels, - Type: "", - Ports: []corev1.ServicePort{ - { - Name: "http-listener", - Port: int32(80), - TargetPort: intstr.IntOrString{ - IntVal: int32(80), - }, - Protocol: "http", - }, - }, - }, - Status: corev1.ServiceStatus{}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - b := &gatewayBuilder[*meshv2beta1.APIGateway]{ - gateway: tt.fields.gateway, - config: tt.fields.config, - gcc: tt.fields.gcc, - } - result := b.Service() - assert.Equalf(t, tt.want, result, "Service()") - }) - } -} diff --git a/control-plane/gateways/serviceaccount.go b/control-plane/gateways/serviceaccount.go index 8b740cbd76..1a0b32c275 100644 --- a/control-plane/gateways/serviceaccount.go +++ b/control-plane/gateways/serviceaccount.go @@ -8,17 +8,17 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (b *gatewayBuilder[T]) ServiceAccount() *corev1.ServiceAccount { +func (b *meshGatewayBuilder) ServiceAccount() *corev1.ServiceAccount { return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: b.serviceAccountName(), - Namespace: b.gateway.GetNamespace(), + Namespace: b.gateway.Namespace, Labels: b.labelsForServiceAccount(), Annotations: b.annotationsForServiceAccount(), }, } } -func (b *gatewayBuilder[T]) serviceAccountName() string { - return b.gateway.GetName() +func (b *meshGatewayBuilder) serviceAccountName() string { + return b.gateway.Name } diff --git a/control-plane/gateways/serviceaccount_test.go b/control-plane/gateways/serviceaccount_test.go index 7436beb683..ff0fb4e878 100644 --- a/control-plane/gateways/serviceaccount_test.go +++ b/control-plane/gateways/serviceaccount_test.go @@ -14,12 +14,12 @@ import ( ) func TestNewMeshGatewayBuilder_ServiceAccount(t *testing.T) { - b := NewGatewayBuilder(&meshv2beta1.MeshGateway{ + b := NewMeshGatewayBuilder(&meshv2beta1.MeshGateway{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "mesh-gateway", }, - }, GatewayConfig{}, nil, MeshGatewayAnnotationKind) + }, GatewayConfig{}, nil) expected := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ diff --git a/control-plane/go.mod b/control-plane/go.mod index 160bc748fc..bb3f10d9fe 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -1,12 +1,14 @@ module github.com/hashicorp/consul-k8s/control-plane -replace github.com/hashicorp/consul-k8s/version => ../version +replace ( + github.com/hashicorp/consul-k8s/version => ../version + github.com/hashicorp/consul/api => github.com/hashicorp/consul/api v1.10.1-0.20240312203720-262f4358003f +) require ( github.com/cenkalti/backoff v2.2.1+incompatible github.com/containernetworking/cni v1.1.2 github.com/deckarep/golang-set v1.7.1 - github.com/deckarep/golang-set/v2 v2.6.0 github.com/evanphx/json-patch v5.6.0+incompatible github.com/fsnotify/fsnotify v1.6.0 github.com/go-logr/logr v1.2.4 @@ -15,9 +17,9 @@ require ( github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20240226161840-f3842c41cb2b github.com/hashicorp/consul-k8s/version v0.0.0 github.com/hashicorp/consul-server-connection-manager v0.1.6 - github.com/hashicorp/consul/api v1.29.1 - github.com/hashicorp/consul/proto-public v0.6.1 - github.com/hashicorp/consul/sdk v0.16.1 + github.com/hashicorp/consul/api v1.28.2 + github.com/hashicorp/consul/proto-public v0.6.0 + github.com/hashicorp/consul/sdk v0.16.0 github.com/hashicorp/go-bexpr v0.1.11 github.com/hashicorp/go-discover v0.0.0-20230519164032-214571b6a530 github.com/hashicorp/go-hclog v1.5.0 @@ -129,7 +131,7 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/posener/complete v1.2.3 // indirect github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect diff --git a/control-plane/go.sum b/control-plane/go.sum index f2b4a6ad50..a406f25b8c 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -88,8 +88,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= -github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661 h1:lrWnAyy/F72MbxIxFUzKmcMCdt9Oi8RzpAxzTNQHD7o= github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -206,12 +204,12 @@ github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20240226161840-f3842c41 github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20240226161840-f3842c41cb2b/go.mod h1:9NKJHOcgmz/6P2y6MegNIOXhIKE/0ils/mHWd5sZgoU= github.com/hashicorp/consul-server-connection-manager v0.1.6 h1:ktj8Fi+dRXn9hhM+FXsfEJayhzzgTqfH08Ne5M6Fmug= github.com/hashicorp/consul-server-connection-manager v0.1.6/go.mod h1:HngMIv57MT+pqCVeRQMa1eTB5dqnyMm8uxjyv+Hn8cs= -github.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc= -github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI= -github.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg= -github.com/hashicorp/consul/proto-public v0.6.1/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg= -github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= -github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= +github.com/hashicorp/consul/api v1.10.1-0.20240312203720-262f4358003f h1:8clIrMnJtO5ab5Kd1qF19s9s581cyGYhQxfPLVRaFZs= +github.com/hashicorp/consul/api v1.10.1-0.20240312203720-262f4358003f/go.mod h1:JnWx0qZd1Ffeoa42yVAxzv7/v7eaZyptkw0dG9F/gF4= +github.com/hashicorp/consul/proto-public v0.6.0 h1:9qrBujmoTB5gQQ84kQO+YWvhjgYoYBNrOoHdo4cpHHM= +github.com/hashicorp/consul/proto-public v0.6.0/go.mod h1:JF6983XNCzvw4wDNOLEwLqOq2IPw7iyT+pkswHSz08U= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -389,8 +387,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index 96e95bfa42..db59a98d68 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -54,7 +54,6 @@ type Command struct { flagConsulImage string // Docker image for Consul flagConsulDataplaneImage string // Docker image for Envoy flagConsulK8sImage string // Docker image for consul-k8s - flagGlobalImagePullPolicy string // Pull policy for all Consul images (consul, consul-dataplane, consul-k8s) flagACLAuthMethod string // Auth Method to use for ACLs, if enabled flagEnvoyExtraArgs string // Extra envoy args when starting envoy flagEnableWebhookCAUpdate bool @@ -195,8 +194,6 @@ func (c *Command) init() { "Docker image for Consul Dataplane.") c.flagSet.StringVar(&c.flagConsulK8sImage, "consul-k8s-image", "", "Docker image for consul-k8s. Used for the connect sidecar.") - c.flagSet.StringVar(&c.flagGlobalImagePullPolicy, "global-image-pull-policy", "", - "ImagePullPolicy for all images used by Consul (consul, consul-dataplane, consul-k8s).") c.flagSet.BoolVar(&c.flagEnablePeering, "enable-peering", false, "Enable cluster peering controllers.") c.flagSet.BoolVar(&c.flagEnableFederation, "enable-federation", false, "Enable Consul WAN Federation.") c.flagSet.StringVar(&c.flagEnvoyExtraArgs, "envoy-extra-args", "", @@ -445,16 +442,6 @@ func (c *Command) validateFlags() error { return errors.New("-consul-dataplane-image must be set") } - switch corev1.PullPolicy(c.flagGlobalImagePullPolicy) { - case corev1.PullAlways: - case corev1.PullNever: - case corev1.PullIfNotPresent: - case "": - break - default: - return errors.New("-global-image-pull-policy must be `IfNotPresent`, `Always`, `Never`, or `` ") - } - // In Consul 1.17, multiport beta shipped with v2 catalog + mesh resources backed by v1 tenancy // and acls (experiments=[resource-apis]). // diff --git a/control-plane/subcommand/inject-connect/command_test.go b/control-plane/subcommand/inject-connect/command_test.go index 7f4b93f89e..e7ca3f12cd 100644 --- a/control-plane/subcommand/inject-connect/command_test.go +++ b/control-plane/subcommand/inject-connect/command_test.go @@ -133,10 +133,13 @@ func TestRun_FlagValidation(t *testing.T) { expErr: "-default-envoy-proxy-concurrency must be >= 0 if set", }, { - flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-consul-dataplane-image", "consul-dataplane:1.14.0", - "-global-image-pull-policy", "garbage", + flags: []string{ + "-consul-k8s-image", "hashicorp/consul-k8s", + "-consul-image", "hashicorp/consul", + "-consul-dataplane-image", "hashicorp/consul-dataplane", + "-enable-v2tenancy", "true", }, - expErr: "-global-image-pull-policy must be `IfNotPresent`, `Always`, `Never`, or `` ", + expErr: "-enable-resource-apis must be set to 'true' if -enable-v2tenancy is set", }, } diff --git a/control-plane/subcommand/inject-connect/v1controllers.go b/control-plane/subcommand/inject-connect/v1controllers.go index e89fd2b318..b90b220bb7 100644 --- a/control-plane/subcommand/inject-connect/v1controllers.go +++ b/control-plane/subcommand/inject-connect/v1controllers.go @@ -16,7 +16,6 @@ import ( gatewaycontrollers "github.com/hashicorp/consul-k8s/control-plane/api-gateway/controllers" apicommon "github.com/hashicorp/consul-k8s/control-plane/api/common" "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/catalog/registration" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/controllers/endpoints" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/controllers/peering" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/lifecycle" @@ -108,7 +107,7 @@ func (c *Command) configureV1Controllers(ctx context.Context, mgr manager.Manage return err } - cache, cleaner, err := gatewaycontrollers.SetupGatewayControllerWithManager(ctx, mgr, gatewaycontrollers.GatewayControllerConfig{ + cache, err := gatewaycontrollers.SetupGatewayControllerWithManager(ctx, mgr, gatewaycontrollers.GatewayControllerConfig{ HelmConfig: gatewaycommon.HelmConfig{ ConsulConfig: gatewaycommon.ConsulConfig{ Address: c.consul.Addresses, @@ -118,7 +117,6 @@ func (c *Command) configureV1Controllers(ctx context.Context, mgr manager.Manage }, ImageDataplane: c.flagConsulDataplaneImage, ImageConsulK8S: c.flagConsulK8sImage, - GlobalImagePullPolicy: c.flagGlobalImagePullPolicy, ConsulDestinationNamespace: c.flagConsulDestinationNamespace, NamespaceMirroringPrefix: c.flagK8SNSMirroringPrefix, EnableNamespaces: c.flagEnableNamespaces, @@ -152,7 +150,6 @@ func (c *Command) configureV1Controllers(ctx context.Context, mgr manager.Manage } go cache.Run(ctx) - go cleaner.Run(ctx) // wait for the cache to fill setupLog.Info("waiting for Consul cache sync") @@ -287,16 +284,6 @@ func (c *Command) configureV1Controllers(ctx context.Context, mgr manager.Manage return err } - if err := (®istration.RegistrationsController{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Cache: registration.NewRegistrationCache(consulConfig, watcher), - Log: ctrl.Log.WithName("controller").WithName(apicommon.Registration), - }).SetupWithManager(ctx, mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.Registration) - return err - } - if err := mgr.AddReadyzCheck("ready", webhook.ReadinessCheck{CertDir: c.flagCertDir}.Ready); err != nil { setupLog.Error(err, "unable to create readiness check", "controller", endpoints.Controller{}) return err @@ -340,48 +327,47 @@ func (c *Command) configureV1Controllers(ctx context.Context, mgr manager.Manage } (&webhook.MeshWebhook{ - Clientset: c.clientset, - ReleaseNamespace: c.flagReleaseNamespace, - ConsulConfig: consulConfig, - ConsulServerConnMgr: watcher, - ImageConsul: c.flagConsulImage, - ImageConsulDataplane: c.flagConsulDataplaneImage, - EnvoyExtraArgs: c.flagEnvoyExtraArgs, - ImageConsulK8S: c.flagConsulK8sImage, - GlobalImagePullPolicy: c.flagGlobalImagePullPolicy, - RequireAnnotation: !c.flagDefaultInject, - AuthMethod: c.flagACLAuthMethod, - ConsulCACert: string(c.caCertPem), - TLSEnabled: c.consul.UseTLS, - ConsulAddress: c.consul.Addresses, - SkipServerWatch: c.consul.SkipServerWatch, - ConsulTLSServerName: c.consul.TLSServerName, - DefaultProxyCPURequest: c.sidecarProxyCPURequest, - DefaultProxyCPULimit: c.sidecarProxyCPULimit, - DefaultProxyMemoryRequest: c.sidecarProxyMemoryRequest, - DefaultProxyMemoryLimit: c.sidecarProxyMemoryLimit, - DefaultEnvoyProxyConcurrency: c.flagDefaultEnvoyProxyConcurrency, - DefaultSidecarProxyStartupFailureSeconds: c.flagDefaultSidecarProxyStartupFailureSeconds, + Clientset: c.clientset, + ReleaseNamespace: c.flagReleaseNamespace, + ConsulConfig: consulConfig, + ConsulServerConnMgr: watcher, + ImageConsul: c.flagConsulImage, + ImageConsulDataplane: c.flagConsulDataplaneImage, + EnvoyExtraArgs: c.flagEnvoyExtraArgs, + ImageConsulK8S: c.flagConsulK8sImage, + RequireAnnotation: !c.flagDefaultInject, + AuthMethod: c.flagACLAuthMethod, + ConsulCACert: string(c.caCertPem), + TLSEnabled: c.consul.UseTLS, + ConsulAddress: c.consul.Addresses, + SkipServerWatch: c.consul.SkipServerWatch, + ConsulTLSServerName: c.consul.TLSServerName, + DefaultProxyCPURequest: c.sidecarProxyCPURequest, + DefaultProxyCPULimit: c.sidecarProxyCPULimit, + DefaultProxyMemoryRequest: c.sidecarProxyMemoryRequest, + DefaultProxyMemoryLimit: c.sidecarProxyMemoryLimit, + DefaultEnvoyProxyConcurrency: c.flagDefaultEnvoyProxyConcurrency, + DefaultSidecarProxyStartupFailureSeconds: c.flagDefaultSidecarProxyStartupFailureSeconds, DefaultSidecarProxyLivenessFailureSeconds: c.flagDefaultSidecarProxyLivenessFailureSeconds, - LifecycleConfig: lifecycleConfig, - MetricsConfig: metricsConfig, - InitContainerResources: c.initContainerResources, - ConsulPartition: c.consul.Partition, - AllowK8sNamespacesSet: allowK8sNamespaces, - DenyK8sNamespacesSet: denyK8sNamespaces, - EnableNamespaces: c.flagEnableNamespaces, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - EnableK8SNSMirroring: c.flagEnableK8SNSMirroring, - K8SNSMirroringPrefix: c.flagK8SNSMirroringPrefix, - CrossNamespaceACLPolicy: c.flagCrossNamespaceACLPolicy, - EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, - EnableCNI: c.flagEnableCNI, - TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, - EnableConsulDNS: c.flagEnableConsulDNS, - EnableOpenShift: c.flagEnableOpenShift, - Log: ctrl.Log.WithName("handler").WithName("connect"), - LogLevel: c.flagLogLevel, - LogJSON: c.flagLogJSON, + LifecycleConfig: lifecycleConfig, + MetricsConfig: metricsConfig, + InitContainerResources: c.initContainerResources, + ConsulPartition: c.consul.Partition, + AllowK8sNamespacesSet: allowK8sNamespaces, + DenyK8sNamespacesSet: denyK8sNamespaces, + EnableNamespaces: c.flagEnableNamespaces, + ConsulDestinationNamespace: c.flagConsulDestinationNamespace, + EnableK8SNSMirroring: c.flagEnableK8SNSMirroring, + K8SNSMirroringPrefix: c.flagK8SNSMirroringPrefix, + CrossNamespaceACLPolicy: c.flagCrossNamespaceACLPolicy, + EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, + EnableCNI: c.flagEnableCNI, + TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, + EnableConsulDNS: c.flagEnableConsulDNS, + EnableOpenShift: c.flagEnableOpenShift, + Log: ctrl.Log.WithName("handler").WithName("connect"), + LogLevel: c.flagLogLevel, + LogJSON: c.flagLogJSON, }).SetupWithManager(mgr) consulMeta := apicommon.ConsulMeta{ @@ -479,12 +465,6 @@ func (c *Command) configureV1Controllers(ctx context.Context, mgr manager.Manage ConsulMeta: consulMeta, }).SetupWithManager(mgr) - (&v1alpha1.RegistrationWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.Registration), - ConsulMeta: consulMeta, - }).SetupWithManager(mgr) - if c.flagEnableWebhookCAUpdate { err = c.updateWebhookCABundle(ctx) if err != nil { diff --git a/control-plane/subcommand/inject-connect/v2controllers.go b/control-plane/subcommand/inject-connect/v2controllers.go index 563dd79b71..480bd28cf3 100644 --- a/control-plane/subcommand/inject-connect/v2controllers.go +++ b/control-plane/subcommand/inject-connect/v2controllers.go @@ -201,11 +201,6 @@ func (c *Command) configureV2Controllers(ctx context.Context, mgr manager.Manage return err } - if err := resourceControllers.RegisterGatewayFieldIndexes(ctx, mgr); err != nil { - setupLog.Error(err, "unable to register field indexes") - return err - } - if err := (&resourceControllers.MeshConfigurationController{ Controller: consulResourceController, Client: mgr.GetClient(), @@ -216,49 +211,36 @@ func (c *Command) configureV2Controllers(ctx context.Context, mgr manager.Manage return err } - gatewayConfig := gateways.GatewayConfig{ - ConsulConfig: common.ConsulConfig{ - Address: c.consul.Addresses, - GRPCPort: consulConfig.GRPCPort, - HTTPPort: consulConfig.HTTPPort, - APITimeout: consulConfig.APITimeout, - }, - ImageDataplane: c.flagConsulDataplaneImage, - ImageConsulK8S: c.flagConsulK8sImage, - ConsulTenancyConfig: consulTenancyConfig, - PeeringEnabled: c.flagEnablePeering, - EnableOpenShift: c.flagEnableOpenShift, - AuthMethod: c.consul.ConsulLogin.AuthMethod, - LogLevel: c.flagLogLevel, - LogJSON: c.flagLogJSON, - TLSEnabled: c.consul.UseTLS, - ConsulTLSServerName: c.consul.TLSServerName, - ConsulCACert: string(c.caCertPem), - SkipServerWatch: c.consul.SkipServerWatch, - } - if err := (&resourceControllers.MeshGatewayController{ - Controller: consulResourceController, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(common.MeshGateway), - Scheme: mgr.GetScheme(), - GatewayConfig: gatewayConfig, + Controller: consulResourceController, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(common.MeshGateway), + Scheme: mgr.GetScheme(), + GatewayConfig: gateways.GatewayConfig{ + ConsulConfig: common.ConsulConfig{ + Address: c.consul.Addresses, + GRPCPort: consulConfig.GRPCPort, + HTTPPort: consulConfig.HTTPPort, + APITimeout: consulConfig.APITimeout, + }, + ImageDataplane: c.flagConsulDataplaneImage, + ImageConsulK8S: c.flagConsulK8sImage, + ConsulTenancyConfig: consulTenancyConfig, + PeeringEnabled: c.flagEnablePeering, + EnableOpenShift: c.flagEnableOpenShift, + AuthMethod: c.consul.ConsulLogin.AuthMethod, + LogLevel: c.flagLogLevel, + LogJSON: c.flagLogJSON, + TLSEnabled: c.consul.UseTLS, + ConsulTLSServerName: c.consul.TLSServerName, + ConsulCACert: string(c.caCertPem), + SkipServerWatch: c.consul.SkipServerWatch, + }, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", common.MeshGateway) return err } - if err := (&resourceControllers.APIGatewayController{ - Controller: consulResourceController, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(common.APIGateway), - Scheme: mgr.GetScheme(), - GatewayConfig: gatewayConfig, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", common.APIGateway) - return err - } - if err := (&resourceControllers.GatewayClassConfigController{ Controller: consulResourceController, Client: mgr.GetClient(), diff --git a/control-plane/subcommand/mesh-init/command_test.go b/control-plane/subcommand/mesh-init/command_test.go index 3567b36102..22184f5969 100644 --- a/control-plane/subcommand/mesh-init/command_test.go +++ b/control-plane/subcommand/mesh-init/command_test.go @@ -88,10 +88,10 @@ func TestRun_MeshServices(t *testing.T) { } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - //tokenFile := fmt.Sprintf("/tmp/%d1", rand.Int()) - //t.Cleanup(func() { + // tokenFile := fmt.Sprintf("/tmp/%d1", rand.Int()) + // t.Cleanup(func() { // _ = os.RemoveAll(tokenFile) - //}) + // }) // Create test consulServer server. var serverCfg *testutil.TestServerConfig @@ -117,11 +117,11 @@ func TestRun_MeshServices(t *testing.T) { "-http-port", strconv.Itoa(serverCfg.Ports.HTTP), "-grpc-port", strconv.Itoa(serverCfg.Ports.GRPC), } - //if tt.aclsEnabled { + // if tt.aclsEnabled { // flags = append(flags, "-auth-method-name", test.AuthMethod, // "-service-account-name", tt.serviceAccountName, // "-acl-token-sink", tokenFile) //TODO: what happens if this is unspecified? We don't need this file - //} + // } // Run the command. code := cmd.Run(flags) @@ -133,7 +133,7 @@ func TestRun_MeshServices(t *testing.T) { // TODO: Can we remove the tokenFile from this workflow? // consul-dataplane performs it's own login using the Serviceaccount bearer token - //if tt.aclsEnabled { + // if tt.aclsEnabled { // // Validate the ACL token was written. // tokenData, err := os.ReadFile(tokenFile) // require.NoError(t, err) @@ -145,7 +145,7 @@ func TestRun_MeshServices(t *testing.T) { // token, _, err := consulClient.ACL().TokenReadSelf(nil) // require.NoError(t, err) // require.Equal(t, "token created via login: {\"pod\":\"default-ns/counting-pod\"}", token.Description) - //} + // } }) } } diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index cf9283f531..3d3c28c5ae 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -68,6 +68,8 @@ type Command struct { flagIngressGatewayNames []string flagTerminatingGatewayNames []string + flagAPIGatewayController bool + // Flags to configure Consul connection. flagServerPort uint @@ -171,6 +173,8 @@ func (c *Command) init() { "Name of a terminating gateway that needs an acl token. May be specified multiple times. "+ "[Enterprise Only] If using Consul namespaces and registering the gateway outside of the "+ "default namespace, specify the value in the form ..") + c.flags.BoolVar(&c.flagAPIGatewayController, "api-gateway-controller", false, + "Toggle for configuring ACL login for the API gateway controller.") c.flags.UintVar(&c.flagServerPort, "server-port", 8500, "The HTTP or HTTPS port of the Consul server. Defaults to 8500.") @@ -585,6 +589,28 @@ func (c *Command) Run(args []string) int { } } + if c.flagAPIGatewayController { + rules, err := c.apiGatewayControllerRules() + if err != nil { + c.log.Error("Error templating api gateway rules", "err", err) + return 1 + } + serviceAccountName := c.withPrefix("api-gateway-controller") + + // API gateways require a global policy/token because they must + // create config-entry resources in the primary, even when deployed + // to a secondary datacenter + authMethodName := localComponentAuthMethodName + if !primary { + authMethodName = globalComponentAuthMethodName + } + err = c.createACLPolicyRoleAndBindingRule("api-gateway-controller", rules, consulDC, primaryDC, globalPolicy, primary, authMethodName, serviceAccountName, dynamicClient) + if err != nil { + c.log.Error(err.Error()) + return 1 + } + } + if c.flagMeshGateway { rules, err := c.meshGatewayRules() if err != nil { diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index c7bcb79384..7c3b778f5e 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -2070,6 +2070,12 @@ func TestRun_PoliciesAndBindingRulesForACLLogin_PrimaryDatacenter(t *testing.T) PolicyNames: []string{"sync-catalog-policy"}, Roles: []string{resourcePrefix + "-sync-catalog-acl-role"}, }, + { + TestName: "API Gateway Controller", + TokenFlags: []string{"-api-gateway-controller"}, + PolicyNames: []string{"api-gateway-controller-policy"}, + Roles: []string{resourcePrefix + "-api-gateway-controller-acl-role"}, + }, { TestName: "Snapshot Agent", TokenFlags: []string{"-snapshot-agent"}, @@ -2217,6 +2223,13 @@ func TestRun_PoliciesAndBindingRulesACLLogin_SecondaryDatacenter(t *testing.T) { Roles: []string{resourcePrefix + "-sync-catalog-acl-role-" + secondaryDatacenter}, GlobalAuthMethod: false, }, + { + TestName: "API Gateway Controller", + TokenFlags: []string{"-api-gateway-controller"}, + PolicyNames: []string{"api-gateway-controller-policy-" + secondaryDatacenter}, + Roles: []string{resourcePrefix + "-api-gateway-controller-acl-role-" + secondaryDatacenter}, + GlobalAuthMethod: true, + }, { TestName: "Snapshot Agent", TokenFlags: []string{"-snapshot-agent"}, @@ -2368,6 +2381,12 @@ func TestRun_ValidateLoginToken_PrimaryDatacenter(t *testing.T) { Roles: []string{resourcePrefix + "-sync-catalog-acl-role"}, GlobalToken: false, }, + { + ComponentName: "api-gateway-controller", + TokenFlags: []string{"-api-gateway-controller"}, + Roles: []string{resourcePrefix + "-api-gateway-controller-acl-role"}, + GlobalToken: false, + }, { ComponentName: "snapshot-agent", TokenFlags: []string{"-snapshot-agent"}, @@ -2499,6 +2518,13 @@ func TestRun_ValidateLoginToken_SecondaryDatacenter(t *testing.T) { GlobalAuthMethod: false, GlobalToken: false, }, + { + ComponentName: "api-gateway-controller", + TokenFlags: []string{"-api-gateway-controller"}, + Roles: []string{resourcePrefix + "-api-gateway-controller-acl-role-dc2"}, + GlobalAuthMethod: true, + GlobalToken: true, + }, { ComponentName: "snapshot-agent", TokenFlags: []string{"-snapshot-agent"}, diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 1f00e1019c..f408037157 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -145,6 +145,38 @@ partition_prefix "" { return c.renderRules(anonTokenRulesTpl) } +func (c *Command) apiGatewayControllerRules() (string, error) { + apiGatewayRulesTpl := `{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { + mesh = "write" + acl = "write" +{{- else }} +operator = "write" +acl = "write" +{{- end }} + +{{- if .EnableNamespaces }} +namespace_prefix "" { + policy = "write" +{{- end }} + service_prefix "" { + policy = "write" + intentions = "write" + } + node_prefix "" { + policy = "read" + } +{{- if .EnableNamespaces }} +} +{{- end }} +{{- if .EnablePartitions }} +} +{{- end }} +` + + return c.renderRules(apiGatewayRulesTpl) +} + // This assumes users are using the default name for the service, i.e. // "mesh-gateway". func (c *Command) meshGatewayRules() (string, error) { diff --git a/control-plane/subcommand/server-acl-init/rules_test.go b/control-plane/subcommand/server-acl-init/rules_test.go index bb727968f3..c1a02a2218 100644 --- a/control-plane/subcommand/server-acl-init/rules_test.go +++ b/control-plane/subcommand/server-acl-init/rules_test.go @@ -5,6 +5,7 @@ package serveraclinit import ( "fmt" + "strings" "testing" "github.com/stretchr/testify/require" @@ -142,6 +143,82 @@ partition_prefix "" { } } +func TestAPIGatewayControllerRules(t *testing.T) { + cases := []struct { + Name string + EnableNamespaces bool + Partition string + Expected string + }{ + { + Name: "Namespaces are disabled", + Expected: ` +operator = "write" +acl = "write" + service_prefix "" { + policy = "write" + intentions = "write" + } + node_prefix "" { + policy = "read" + }`, + }, + { + Name: "Namespaces are enabled", + EnableNamespaces: true, + Expected: ` +operator = "write" +acl = "write" +namespace_prefix "" { + policy = "write" + service_prefix "" { + policy = "write" + intentions = "write" + } + node_prefix "" { + policy = "read" + } +}`, + }, + { + Name: "Namespaces are enabled, partitions enabled", + EnableNamespaces: true, + Partition: "Default", + Expected: ` +partition "Default" { + mesh = "write" + acl = "write" +namespace_prefix "" { + policy = "write" + service_prefix "" { + policy = "write" + intentions = "write" + } + node_prefix "" { + policy = "read" + } +} +}`, + }, + } + + for _, tt := range cases { + t.Run(tt.Name, func(t *testing.T) { + cmd := Command{ + flagEnableNamespaces: tt.EnableNamespaces, + consulFlags: &flags.ConsulFlags{ + Partition: tt.Partition, + }, + } + + meshGatewayRules, err := cmd.apiGatewayControllerRules() + + require.NoError(t, err) + require.Equal(t, tt.Expected, strings.Trim(meshGatewayRules, " ")) + }) + } +} + func TestMeshGatewayRules(t *testing.T) { cases := []struct { Name string diff --git a/hack/aws-acceptance-test-cleanup/main.go b/hack/aws-acceptance-test-cleanup/main.go index 1680e9ca63..556f8420c1 100644 --- a/hack/aws-acceptance-test-cleanup/main.go +++ b/hack/aws-acceptance-test-cleanup/main.go @@ -201,7 +201,7 @@ func realMain(ctx context.Context) error { if err != nil { return err } - toDeleteVPCs = append(toDeleteVPCs, vpcsOutput.Vpcs...) + toDeleteVPCs = append(vpcsOutput.Vpcs) nextToken = vpcsOutput.NextToken if nextToken == nil { break @@ -371,11 +371,6 @@ func realMain(ctx context.Context) error { }, }, }) - - if err != nil { - return err - } - vpcPeeringConnectionsToDelete := append(vpcPeeringConnectionsWithAcceptor.VpcPeeringConnections, vpcPeeringConnectionsWithRequester.VpcPeeringConnections...) // Delete NAT gateways. @@ -387,11 +382,9 @@ func realMain(ctx context.Context) error { }, }, }) - if err != nil { return err } - for _, gateway := range natGateways.NatGateways { fmt.Printf("NAT gateway: Destroying... [id=%s]\n", *gateway.NatGatewayId) _, err = ec2Client.DeleteNatGatewayWithContext(ctx, &ec2.DeleteNatGatewayInput{ @@ -496,11 +489,6 @@ func realMain(ctx context.Context) error { }, }, }) - - if err != nil { - return err - } - for _, igw := range igws.InternetGateways { fmt.Printf("Internet gateway: Detaching from VPC... [id=%s]\n", *igw.InternetGatewayId) if err := destroyBackoff(ctx, "Internet Gateway", *igw.InternetGatewayId, func() error { @@ -528,37 +516,6 @@ func realMain(ctx context.Context) error { fmt.Printf("Internet gateway: Destroyed [id=%s]\n", *igw.InternetGatewayId) } - // Delete network interfaces - networkInterfaces, err := ec2Client.DescribeNetworkInterfacesWithContext(ctx, &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ - { - Name: aws.String("vpc-id"), - Values: []*string{vpcID}, - }, - }, - }) - - if err != nil { - return err - } - - for _, networkInterface := range networkInterfaces.NetworkInterfaces { - fmt.Printf("Network Interface: Destroying... [id=%s]\n", *networkInterface.NetworkInterfaceId) - if err := destroyBackoff(ctx, "Network Interface", *networkInterface.NetworkInterfaceId, func() error { - _, err := ec2Client.DeleteNetworkInterfaceWithContext(ctx, &ec2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: networkInterface.NetworkInterfaceId, - }) - if err != nil { - return err - } - return nil - }); err != nil { - return err - } - - fmt.Printf("Network interface: Destroyed [id=%s]\n", *networkInterface.NetworkInterfaceId) - } - // Delete subnets. subnets, err := ec2Client.DescribeSubnetsWithContext(ctx, &ec2.DescribeSubnetsInput{ Filters: []*ec2.Filter{ @@ -568,11 +525,6 @@ func realMain(ctx context.Context) error { }, }, }) - - if err != nil { - return err - } - for _, subnet := range subnets.Subnets { fmt.Printf("Subnet: Destroying... [id=%s]\n", *subnet.SubnetId) if err := destroyBackoff(ctx, "Subnet", *subnet.SubnetId, func() error { @@ -600,11 +552,6 @@ func realMain(ctx context.Context) error { }, }, }) - - if err != nil { - return err - } - for _, routeTable := range routeTables.RouteTables { // Find out if this is the main route table. var mainRouteTable bool @@ -638,11 +585,6 @@ func realMain(ctx context.Context) error { }, }, }) - - if err != nil { - return err - } - for _, sg := range sgs.SecurityGroups { if len(sg.IpPermissions) > 0 { revokeSGInput := &ec2.RevokeSecurityGroupIngressInput{GroupId: sg.GroupId} diff --git a/version/version.go b/version/version.go index e5d773c66d..4a7f924692 100644 --- a/version/version.go +++ b/version/version.go @@ -17,7 +17,7 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "1.6.0" + Version = "1.4.3" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release