diff --git a/.changelog/1914.txt b/.changelog/1914.txt deleted file mode 100644 index 3179f3b0b3..0000000000 --- a/.changelog/1914.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -control-plane: fix issue where consul-connect-injector acl token was unintentionally being deleted and not recreated when a container was restarted due to a livenessProbe failure. -``` \ No newline at end of file diff --git a/.changelog/1920.txt b/.changelog/1920.txt deleted file mode 100644 index 4b1f151fe4..0000000000 --- a/.changelog/1920.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: When the `global.acls.bootstrapToken` field is set and the content of the secret is empty, the bootstrap ACL token is written to that secret after bootstrapping ACLs. This applies to both the Vault and Consul secrets backends. -``` diff --git a/.changelog/1976.txt b/.changelog/1976.txt new file mode 100644 index 0000000000..65024aa6f9 --- /dev/null +++ b/.changelog/1976.txt @@ -0,0 +1,3 @@ +```release-note:security +upgrade to use Go 1.19.6. This resolves vulnerabilities CVE-2022-41724 in crypto/tls and CVE-2022-41723 in net/http. +``` \ No newline at end of file diff --git a/.changelog/2029.txt b/.changelog/2029.txt deleted file mode 100644 index c864419eba..0000000000 --- a/.changelog/2029.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -api-gateway: fix ACL issue where when adminPartitions and ACLs are enabled, API Gateway Controller is unable to create a new namespace in Consul -``` \ No newline at end of file diff --git a/.changelog/2030.txt b/.changelog/2030.txt deleted file mode 100644 index 46516d9513..0000000000 --- a/.changelog/2030.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: add failover policy field to service resolver and proxy default CRDs -``` \ No newline at end of file diff --git a/.changelog/2048.txt b/.changelog/2048.txt deleted file mode 100644 index 5796ce2397..0000000000 --- a/.changelog/2048.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: add samenessGroup CRD -``` \ No newline at end of file diff --git a/.changelog/2075.txt b/.changelog/2075.txt deleted file mode 100644 index 2f0f0344eb..0000000000 --- a/.changelog/2075.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: add samenessGroup field to exported services CRD -``` \ No newline at end of file diff --git a/.changelog/2086.txt b/.changelog/2086.txt deleted file mode 100644 index d4e43a630d..0000000000 --- a/.changelog/2086.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: add samenessGroup field to service resolver CRD -``` \ No newline at end of file diff --git a/.changelog/2093.txt b/.changelog/2093.txt deleted file mode 100644 index 20c657e566..0000000000 --- a/.changelog/2093.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -control-plane: set agent localities on Consul servers to the server node's `topology.kubernetes.io/region` label. -``` diff --git a/.changelog/2097.txt b/.changelog/2097.txt deleted file mode 100644 index 60e99a8515..0000000000 --- a/.changelog/2097.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: add samenessGroup field to source intention CRD -``` \ No newline at end of file diff --git a/.changelog/2100.txt b/.changelog/2100.txt deleted file mode 100644 index 4fece0991c..0000000000 --- a/.changelog/2100.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -crd: Add `mutualTLSMode` to the ProxyDefaults and ServiceDefaults CRDs and `allowEnablingPermissiveMutualTLS` to the Mesh CRD to support configuring permissive mutual TLS. -``` diff --git a/.changelog/2102.txt b/.changelog/2108.txt similarity index 76% rename from .changelog/2102.txt rename to .changelog/2108.txt index 7adf361d2d..1c10ef62d9 100644 --- a/.changelog/2102.txt +++ b/.changelog/2108.txt @@ -1,5 +1,5 @@ ```release-note:security -Upgrade to use Go 1.20.4. +Upgrade to use Go 1.19.9. This resolves vulnerabilities [CVE-2023-24537](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`go/scanner`), [CVE-2023-24538](https://github.com/advisories/GHSA-v4m2-x4rp-hv22)(`html/template`), [CVE-2023-24534](https://github.com/advisories/GHSA-8v5j-pwr7-w5f8)(`net/textproto`) and @@ -9,13 +9,4 @@ Also, `golang.org/x/net` has been updated to v0.7.0 to resolve CVEs [CVE-2022-41 ), [CVE-2022-27664](https://github.com/advisories/GHSA-69cg-p879-7622) and [CVE-2022-41723 ](https://github.com/advisories/GHSA-vvpx-j8f3-3w6h .) -``` - -```release-note:improvement -cli: update minimum go version for project to 1.20. -``` - -```release-note:improvement -control-plane: update minimum go version for project to 1.20. -``` - +``` \ No newline at end of file diff --git a/.changelog/2124.txt b/.changelog/2124.txt deleted file mode 100644 index b65c23db2e..0000000000 --- a/.changelog/2124.txt +++ /dev/null @@ -1,3 +0,0 @@ -``release-note:improvement -control-plane: Transparent proxy enhancements for failover and virtual Services -``` diff --git a/.changelog/2134.txt b/.changelog/2134.txt deleted file mode 100644 index 980e7ba666..0000000000 --- a/.changelog/2134.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -Add support for consul-telemetry-collector to forward envoy metrics to an otelhttp compatible receiver or HCP -``` \ No newline at end of file diff --git a/.changelog/2140.txt b/.changelog/2140.txt new file mode 100644 index 0000000000..d6c5efeffb --- /dev/null +++ b/.changelog/2140.txt @@ -0,0 +1,4 @@ +```release-note:improvement +helm: update `imageConsulDataplane` value to `hashicorp/consul-dataplane:1.0.2`, `image` value to `hashicorp/consul:1.14.7`, +and `imageEnvoy` to `envoyproxy/envoy:v1.24.7`. +``` diff --git a/.changelog/2143.txt b/.changelog/2143.txt deleted file mode 100644 index 8f58328f3d..0000000000 --- a/.changelog/2143.txt +++ /dev/null @@ -1,4 +0,0 @@ - -```release-note:feature -consul-telemetry-collector: Configure envoy proxy config during registration when consul-telemetry-collector is enabled. -``` diff --git a/.changelog/2152.txt b/.changelog/2152.txt deleted file mode 100644 index 2f0743a9d8..0000000000 --- a/.changelog/2152.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -api-gateway: Add API Gateway for Consul on Kubernetes leveraging Consul native API Gateway configuration. -``` diff --git a/.changelog/2159.txt b/.changelog/2159.txt new file mode 100644 index 0000000000..9b970bf3f4 --- /dev/null +++ b/.changelog/2159.txt @@ -0,0 +1,3 @@ +```release-note:bug +control-plane: fix issue with json tags of service defaults fields EnforcingConsecutive5xx, MaxEjectionPercent and BaseEjectionTime. +``` \ No newline at end of file diff --git a/.changelog/2165.txt b/.changelog/2165.txt deleted file mode 100644 index 15c4bdb1e0..0000000000 --- a/.changelog/2165.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -control-plane: add FIPS support -``` \ No newline at end of file diff --git a/.changelog/2166.txt b/.changelog/2166.txt deleted file mode 100644 index b2392bd7d5..0000000000 --- a/.changelog/2166.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -Add support for configuring Consul server-side rate limiting -``` diff --git a/.changelog/2170.txt b/.changelog/2170.txt deleted file mode 100644 index 6d10ae1097..0000000000 --- a/.changelog/2170.txt +++ /dev/null @@ -1,2 +0,0 @@ -```release-note:feature -Add support for configuring global level server rate limiting. diff --git a/.changelog/2183.txt b/.changelog/2183.txt deleted file mode 100644 index d54983a8f4..0000000000 --- a/.changelog/2183.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:security -Fix Prometheus CVEs by bumping controller-runtime. -``` diff --git a/.changelog/2184.txt b/.changelog/2184.txt deleted file mode 100644 index bdcb6039fd..0000000000 --- a/.changelog/2184.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -api-gateway: support deploying to OpenShift 4.11 -``` diff --git a/.changelog/2195.txt b/.changelog/2195.txt deleted file mode 100644 index e7475f88e0..0000000000 --- a/.changelog/2195.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -consul-telemetry-collector: add acceptance tests for consul telemetry collector component. -``` diff --git a/.changelog/2205.txt b/.changelog/2205.txt deleted file mode 100644 index 6a66970cfc..0000000000 --- a/.changelog/2205.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -cli: update cloud preset to enable telemetry collector -``` \ No newline at end of file diff --git a/.changelog/2209.txt b/.changelog/2209.txt deleted file mode 100644 index 72a59064e4..0000000000 --- a/.changelog/2209.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -helm: Add `JWTProvider` CRD for configuring the `jwt-provider` config entry. -``` diff --git a/.changelog/2213.txt b/.changelog/2213.txt deleted file mode 100644 index c09c2e0397..0000000000 --- a/.changelog/2213.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -helm: Update the ServiceIntentions CRD to support `JWT` fields. -``` diff --git a/.changelog/2225.txt b/.changelog/2225.txt new file mode 100644 index 0000000000..fcbb89a54b --- /dev/null +++ b/.changelog/2225.txt @@ -0,0 +1,3 @@ +```release-note:security +Bump `controller-runtime` to address CVEs in dependencies. +``` diff --git a/.changelog/2265.txt b/.changelog/2265.txt index 1cf6813c94..35643ce272 100644 --- a/.changelog/2265.txt +++ b/.changelog/2265.txt @@ -1,3 +1,3 @@ ```release-note:improvement (Consul Enterprise) Add support to provide inputs via helm for audit log related configuration -``` +``` \ No newline at end of file diff --git a/.changelog/2302.txt b/.changelog/2302.txt index 7bf7e6b0f6..9d36d912d3 100644 --- a/.changelog/2302.txt +++ b/.changelog/2302.txt @@ -9,5 +9,4 @@ Add support to provide the logLevel flag via helm for multiple low level compone 7. `meshGateway.logLevel` 8. `ingressGateways.logLevel` 9. `terminatingGateways.logLevel` -10. `telemetryCollector.logLevel` ``` diff --git a/.changelog/2304.txt b/.changelog/2304.txt deleted file mode 100644 index c977da5acd..0000000000 --- a/.changelog/2304.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -helm: Kubernetes v1.27 is now supported. Minimum tested version of Kubernetes is now v1.24. -``` diff --git a/.changelog/2346.txt b/.changelog/2346.txt deleted file mode 100644 index fb062ee0fb..0000000000 --- a/.changelog/2346.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -Set locality on services registered with connect-inject. -``` diff --git a/.changelog/2413.txt b/.changelog/2413.txt deleted file mode 100644 index 89755b23a7..0000000000 --- a/.changelog/2413.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -api-gateway: Fix creation of invalid Kubernetes Service when multiple Gateway listeners have the same port. -``` diff --git a/.changelog/2420.txt b/.changelog/2420.txt deleted file mode 100644 index 86776497c4..0000000000 --- a/.changelog/2420.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -api-gateway: set route condition appropriately when parent ref includes non-existent section name -``` diff --git a/.changelog/2476.txt b/.changelog/2476.txt deleted file mode 100644 index e57889cabe..0000000000 --- a/.changelog/2476.txt +++ /dev/null @@ -1,7 +0,0 @@ -```release-note:improvement -helm: update `imageConsulDataplane` value to `hashicorp/consul-dataplane:1.2.0` -``` - -```release-note:improvement -helm: update `image` value to `hashicorp/consul:1.16.0` -``` \ No newline at end of file diff --git a/.changelog/2478.txt b/.changelog/2478.txt deleted file mode 100644 index ccbbb71ec8..0000000000 --- a/.changelog/2478.txt +++ /dev/null @@ -1,5 +0,0 @@ -```release-note:bug -api-gateway: fixes bug where envoy will silently reject RSA keys less than 2048 bits in length when not in FIPS mode, and -will reject keys that are not 2048, 3072, or 4096 bits in length in FIPS mode. We now validate -and reject invalid certs earlier. -``` diff --git a/.changelog/2520.txt b/.changelog/2520.txt deleted file mode 100644 index 96d03dc093..0000000000 --- a/.changelog/2520.txt +++ /dev/null @@ -1,4 +0,0 @@ -```release-note:bug -transparent-proxy: Fix issue where connect-inject lacked sufficient `mesh:write` privileges in some deployments, -which prevented virtual IPs from persisting properly. -``` diff --git a/.changelog/2524.txt b/.changelog/2524.txt deleted file mode 100644 index 5d634e68e1..0000000000 --- a/.changelog/2524.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -(api-gateway) make API gateway controller less verbose -``` \ No newline at end of file diff --git a/.changelog/2597.txt b/.changelog/2597.txt deleted file mode 100644 index 83cc369b6d..0000000000 --- a/.changelog/2597.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -api-gateway: fix helm install when setting copyAnnotations or nodeSelector -``` diff --git a/.changelog/2642.txt b/.changelog/2650.txt similarity index 70% rename from .changelog/2642.txt rename to .changelog/2650.txt index 5278ed705c..229410a2bf 100644 --- a/.changelog/2642.txt +++ b/.changelog/2650.txt @@ -1,4 +1,4 @@ ```release-note:security -Upgrade to use Go 1.20.6 and `x/net/http` 0.12.0. +Upgrade to use Go 1.19.11 and `x/net/http` 0.12.0. This resolves [CVE-2023-29406](https://github.com/advisories/GHSA-f8f7-69v5-w4vx)(`net/http`). ``` diff --git a/.changelog/2678.txt b/.changelog/2678.txt new file mode 100644 index 0000000000..97e7707c41 --- /dev/null +++ b/.changelog/2678.txt @@ -0,0 +1,3 @@ +```release-note:improvement +helm: do not set container securityContexts by default on OpenShift < 4.11 +``` diff --git a/.changelog/2707.txt b/.changelog/2707.txt deleted file mode 100644 index 370aaa7c17..0000000000 --- a/.changelog/2707.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -api-gateway: adds ability to map privileged ports on Gateway listeners to unprivileged ports so that containers do not require additional privileges -``` diff --git a/.changelog/2711.txt b/.changelog/2711.txt deleted file mode 100644 index abb0b7e4fb..0000000000 --- a/.changelog/2711.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -api-gateway: translate and validate TLS configuration options, including min/max version and cipher suites, setting Gateway status appropriately -``` diff --git a/.changelog/2710.txt b/.changelog/2717.txt similarity index 81% rename from .changelog/2710.txt rename to .changelog/2717.txt index 1d37b32dfb..a4557ecaaf 100644 --- a/.changelog/2710.txt +++ b/.changelog/2717.txt @@ -1,5 +1,5 @@ ```release-note:security -Upgrade to use Go 1.20.7 and `x/net` 0.13.0. +Upgrade to use Go 1.19.12 and `x/net` 0.13.0. This resolves [CVE-2023-29409](https://nvd.nist.gov/vuln/detail/CVE-2023-29409)(`crypto/tls`) and [CVE-2023-3978](https://nvd.nist.gov/vuln/detail/CVE-2023-3978)(`net/html`). ``` diff --git a/.changelog/2723.txt b/.changelog/2723.txt deleted file mode 100644 index 0e46cba7a7..0000000000 --- a/.changelog/2723.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -helm: Add ability to configure resource requests and limits for Gateway API deployments. -``` diff --git a/.changelog/2735.txt b/.changelog/2735.txt deleted file mode 100644 index 8b74b5552d..0000000000 --- a/.changelog/2735.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -api-gateway: add RouteRetryFilter and RouteTimeoutFilter CRDs -``` \ No newline at end of file diff --git a/.changelog/2743.txt b/.changelog/2743.txt deleted file mode 100644 index 4e8db233b1..0000000000 --- a/.changelog/2743.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:improvement -control-plane: Changed the container ordering in connect-inject to insert consul-dataplane container first if lifecycle is enabled. Container ordering is unchanged if lifecycle is disabled. -``` diff --git a/.changelog/2748.txt b/.changelog/2748.txt deleted file mode 100644 index 2a8c922d13..0000000000 --- a/.changelog/2748.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -control-plane: Set locality on sidecar proxies in addition to services when registering with connect-inject. -``` diff --git a/.changelog/2782.txt b/.changelog/2782.txt deleted file mode 100644 index f01db6bafa..0000000000 --- a/.changelog/2782.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -helm: Update prometheus port and scheme annotations if tls is enabled -``` diff --git a/.changelog/2784.txt b/.changelog/2784.txt deleted file mode 100644 index 5b11ca3d43..0000000000 --- a/.changelog/2784.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -Add the `PrioritizeByLocality` field to the `ServiceResolver` and `ProxyDefaults` CRDs. -``` diff --git a/.copywrite.hcl b/.copywrite.hcl deleted file mode 100644 index 9c2e0c0310..0000000000 --- a/.copywrite.hcl +++ /dev/null @@ -1,16 +0,0 @@ -schema_version = 1 - -project { - license = "MPL-2.0" - copyright_year = 2018 - - # (OPTIONAL) A list of globs that should not have copyright/license headers. - # Supports doublestar glob patterns for more flexibility in defining which - # files or folders should be ignored - header_ignore = [ - - # ignoring charts templates as adding copyright headers breaks all tests - "charts/consul/templates/**", - - ] -} diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index eb998e2cd9..e22e28a48a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - blank_issues_enabled: false contact_links: - name: Consul Community Support diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f5d211b137..b615e69dd1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -9,6 +9,7 @@ How I expect reviewers to test this PR: Checklist: - [ ] Tests added -- [ ] [CHANGELOG entry added](https://github.com/hashicorp/consul-k8s/blob/main/CONTRIBUTING.md#adding-a-changelog-entry) - +- [ ] CHANGELOG entry added + > HashiCorp engineers only, community PRs should not add a changelog entry. + > Entries should use present tense (e.g. Add support for...) diff --git a/.github/workflows/backport-checker.yml b/.github/workflows/backport-checker.yml index a70790c0c0..5bcac5a38e 100644 --- a/.github/workflows/backport-checker.yml +++ b/.github/workflows/backport-checker.yml @@ -1,5 +1,3 @@ -# Copyright (c) HashiCorp, Inc. - # This workflow checks that there is either a 'pr/no-backport' label applied to a PR # or there is a backport/.txt file associated with a PR for a backport label diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index dadde6a651..48883e24fa 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -1,10 +1,8 @@ -# Copyright (c) HashiCorp, Inc. - --- name: Backport Assistant Runner on: - pull_request_target: + pull_request: types: - closed - labeled @@ -13,7 +11,7 @@ jobs: backport: if: github.event.pull_request.merged runs-on: ubuntu-latest - container: hashicorpdev/backport-assistant:0.3.4 + container: hashicorpdev/backport-assistant:0.3.3 steps: - name: Run Backport Assistant run: backport-assistant backport -merge-method=squash -gh-automerge diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 414c875b26..4fd9ae3cfd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,3 @@ -# Copyright (c) HashiCorp, Inc. - name: build on: workflow_dispatch: @@ -21,7 +19,7 @@ jobs: outputs: go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@v3 - name: Determine Go version id: get-go-version # We use .go-version as our source of truth for current Go @@ -35,7 +33,7 @@ jobs: outputs: product-version: ${{ steps.get-product-version.outputs.product-version }} steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@v3 - name: get product version id: get-product-version run: | @@ -49,7 +47,7 @@ jobs: filepath: ${{ steps.generate-metadata-file.outputs.filepath }} steps: - name: "Checkout directory" - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@v3 - name: Generate metadata file id: generate-metadata-file uses: hashicorp/actions-generate-metadata@v1 @@ -57,14 +55,14 @@ jobs: version: ${{ needs.get-product-version.outputs.product-version }} product: ${{ env.PKG_NAME }} repositoryOwner: "hashicorp" - - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + - uses: actions/upload-artifact@v3 with: name: metadata.json path: ${{ steps.generate-metadata-file.outputs.filepath }} build: needs: [get-go-version, get-product-version] - runs-on: ubuntu-20.04 # the GLIBC is too high on 22.04 + runs-on: ubuntu-latest strategy: matrix: include: @@ -79,28 +77,20 @@ jobs: - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "windows", goarch: "amd64", component: "cli", pkg_name: "consul-k8s", "bin_name": "consul-k8s.exe" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "darwin", goarch: "amd64", component: "cli", pkg_name: "consul-k8s", "bin_name": "consul-k8s" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "darwin", goarch: "arm64", component: "cli", pkg_name: "consul-k8s", "bin_name": "consul-k8s" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "amd64", component: "cli", pkg_name: "consul-k8s", "bin_name": "consul-k8s", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=boringcrypto", fips: "+fips1402", pkg_suffix: "-fips" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "arm64", component: "cli", pkg_name: "consul-k8s", "bin_name": "consul-k8s", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=boringcrypto CC=aarch64-linux-gnu-gcc", fips: "+fips1402", pkg_suffix: "-fips" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "windows", goarch: "amd64", component: "cli", pkg_name: "consul-k8s", "bin_name": "consul-k8s.exe", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=cngcrypto", fips: "+fips1402" } - - # control-plane + # control-plane - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "freebsd", goarch: "386", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "freebsd", goarch: "amd64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "386", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "amd64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "arm", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "arm64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - # solaris is only built for the control plane + # solaris is only built for the control plane - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "solaris", goarch: "amd64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "windows", goarch: "386", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane.exe" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "windows", goarch: "amd64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane.exe" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "darwin", goarch: "amd64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "darwin", goarch: "arm64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "amd64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=boringcrypto", fips: "+fips1402", pkg_suffix: "-fips" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "arm64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=boringcrypto CC=aarch64-linux-gnu-gcc", fips: "+fips1402", pkg_suffix: "-fips" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "windows", goarch: "amd64", component: "control-plane", pkg_name: "consul-k8s-control-plane", "bin_name": "consul-k8s-control-plane.exe", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=cngcrypto", fips: "+fips1402" } - - # consul-cni + # consul-cni - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "freebsd", goarch: "386", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "freebsd", goarch: "amd64", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "386", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni" } @@ -112,41 +102,18 @@ jobs: - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "windows", goarch: "amd64", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni.exe" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "darwin", goarch: "amd64", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni" } - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "darwin", goarch: "arm64", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "amd64", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=boringcrypto", fips: "+fips1402", pkg_suffix: "-fips" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "linux", goarch: "arm64", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=boringcrypto CC=aarch64-linux-gnu-gcc", fips: "+fips1402", pkg_suffix: "-fips" } - - {go: "${{ needs.get-go-version.outputs.go-version }}", goos: "windows", goarch: "amd64", component: "control-plane/cni", pkg_name: "consul-cni", "bin_name": "consul-cni.exe", gotags: "fips", env: "CGO_ENABLED=1 GOEXPERIMENT=cngcrypto", fips: "+fips1402" } - fail-fast: true - name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} ${{ matrix.component }} ${{ matrix.fips }} build + name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} ${{ matrix.component }} build steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@v3 - name: Setup go - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + uses: actions/setup-go@v3 with: go-version: ${{ matrix.go }} - - name: Replace Go for Windows FIPS with Microsoft Go - if: ${{ matrix.fips == '+fips1402' && matrix.goos == 'windows' }} - run: | - # Uninstall standard Go and use microsoft/go instead - rm -rf /home/runner/actions-runner/_work/_tool/go - curl https://aka.ms/golang/release/latest/go${{ matrix.go }}-1.linux-amd64.tar.gz -Lo go${{ matrix.go }}.linux-amd64.tar.gz - tar -C $HOME -xf go${{ matrix.go }}.linux-amd64.tar.gz - chmod +x $HOME/go/bin - export PATH=$HOME/go/bin:$PATH - if [ $(which go) != "$HOME/go/bin/go" ]; then - echo "Unable to verify microsoft/go toolchain" - exit 1 - fi - - - name: Install cross-compiler for FIPS on arm - if: ${{ matrix.fips == '+fips1402' && matrix.goarch == 'arm64' }} - run: | - sudo apt-get update --allow-releaseinfo-change-suite --allow-releaseinfo-change-version && sudo apt-get install -y gcc-aarch64-linux-gnu - - name: Build env: GOOS: ${{ matrix.goos }} @@ -161,23 +128,23 @@ jobs: export GIT_IMPORT=github.com/hashicorp/consul-k8s/${{ matrix.component }}/version export GOLDFLAGS="-X ${GIT_IMPORT}.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X ${GIT_IMPORT}.GitDescribe=${{ needs.get-product-version.outputs.product-version }}" - ${{ matrix.env }} go build -o dist/${{ matrix.bin_name }} -ldflags "${GOLDFLAGS}" -tags=${{ matrix.gotags }} . - zip -r -j out/${{ matrix.pkg_name }}_${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip dist/ + CGO_ENABLED=0 go build -o dist/${{ matrix.bin_name }} -ldflags "${GOLDFLAGS}" . + zip -r -j out/${{ matrix.pkg_name }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip dist/ - name: Upload built binaries - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@v3 with: - name: ${{ matrix.pkg_name }}_${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip - path: ${{ matrix.component}}/out/${{ matrix.pkg_name }}_${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip + name: ${{ matrix.pkg_name }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip + path: ${{ matrix.component}}/out/${{ matrix.pkg_name }}_${{ needs.get-product-version.outputs.product-version }}_${{ matrix.goos }}_${{ matrix.goarch }}.zip - name: Package rpm and deb files if: ${{ matrix.goos == 'linux' && matrix.component == 'cli' && matrix.goarch == 'amd64'}} uses: hashicorp/actions-packaging-linux@v1 with: - name: consul-k8s${{ matrix.pkg_suffix }} + name: consul-k8s description: "consul-k8s provides a cli interface to first-class integrations between Consul and Kubernetes." arch: ${{ matrix.goarch }} - version: ${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }} + version: ${{ needs.get-product-version.outputs.product-version }} maintainer: "HashiCorp" homepage: "https://github.com/hashicorp/consul-k8s" license: "MPL-2.0" @@ -193,7 +160,7 @@ jobs: - name: Test rpm package if: ${{ matrix.goos == 'linux' && matrix.component == 'cli' && matrix.goarch == 'amd64'}} - uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3 + uses: addnab/docker-run-action@v3 with: image: registry.access.redhat.com/ubi9/ubi:latest options: -v ${{ github.workspace }}:/work @@ -202,7 +169,7 @@ jobs: cd /work rpm -ivh out/${{ env.RPM_PACKAGE }} CONSUL_K8S_VERSION="$(consul-k8s version | awk '{print $2}')" - VERSION="v${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}" + VERSION="v${{ needs.get-product-version.outputs.product-version }}" if [ "${VERSION}" != "${CONSUL_K8S_VERSION}" ]; then echo "Test FAILED, expected: ${VERSION}, got: ${CONSUL_K8S_VERSION}" exit 1 @@ -210,7 +177,7 @@ jobs: echo "Test PASSED, expected: ${VERSION}, got: ${CONSUL_K8S_VERSION}" - name: Upload rpm package - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@v3 if: ${{ matrix.goos == 'linux' && matrix.component == 'cli' && matrix.goarch == 'amd64'}} with: name: ${{ env.RPM_PACKAGE }} @@ -218,7 +185,7 @@ jobs: - name: Test debian package if: ${{ matrix.goos == 'linux' && matrix.component == 'cli' && matrix.goarch == 'amd64'}} - uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3 + uses: addnab/docker-run-action@v3 with: image: ubuntu:latest options: -v ${{ github.workspace }}:/work @@ -227,7 +194,7 @@ jobs: cd /work apt install ./out/${{ env.DEB_PACKAGE }} CONSUL_K8S_VERSION="$(consul-k8s version | awk '{print $2}')" - VERSION="v${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}" + VERSION="v${{ needs.get-product-version.outputs.product-version }}" if [ "${VERSION}" != "${CONSUL_K8S_VERSION}" ]; then echo "Test FAILED, expected: ${VERSION}, got: ${CONSUL_K8S_VERSION}" exit 1 @@ -235,43 +202,36 @@ jobs: echo "Test PASSED, expected: ${VERSION}, got: ${CONSUL_K8S_VERSION}" - name: Upload debian packages - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@v3 if: ${{ matrix.goos == 'linux' && matrix.component == 'cli' && matrix.goarch == 'amd64'}} with: name: ${{ env.DEB_PACKAGE }} path: out/${{ env.DEB_PACKAGE }} build-docker: - name: Docker ${{ matrix.goarch }} ${{ matrix.fips }} default release build + name: Docker ${{ matrix.arch }} default release build needs: [get-product-version, build] runs-on: ubuntu-latest strategy: matrix: - include: - - { goos: "linux", goarch: "arm" } - - { goos: "linux", goarch: "arm64" } - - { goos: "linux", goarch: "386" } - - { goos: "linux", goarch: "amd64" } - - { goos: "linux", goarch: "amd64", fips: "+fips1402" } - - { goos: "linux", goarch: "arm64", fips: "+fips1402" } + arch: ["arm", "arm64", "386", "amd64"] env: repo: ${{ github.event.repository.name }} - version: ${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }} + version: ${{ needs.get-product-version.outputs.product-version }} steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 with: - name: consul-cni_${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}_${{ matrix.goos}}_${{ matrix.goarch }}.zip - path: control-plane/dist/cni/${{ matrix.goos}}/${{ matrix.goarch }} + name: consul-cni_${{ needs.get-product-version.outputs.product-version }}_linux_${{ matrix.arch }}.zip + path: control-plane/dist/cni/linux/${{ matrix.arch }} - name: extract consul-cni zip env: - ZIP_LOCATION: control-plane/dist/cni/${{ matrix.goos}}/${{ matrix.goarch }} + ZIP_LOCATION: control-plane/dist/cni/linux/${{ matrix.arch }} run: | cd "${ZIP_LOCATION}" unzip -j *.zip - name: Docker Build (Action) uses: hashicorp/actions-docker-build@v1 - if: ${{ !matrix.fips }} with: smoke_test: | TEST_VERSION="$(docker run "${IMAGE_NAME}" consul-k8s-control-plane version | awk '{print $2}')" @@ -282,7 +242,7 @@ jobs: echo "Test PASSED" version: ${{ env.version }} target: release-default - arch: ${{ matrix.goarch }} + arch: ${{ matrix.arch }} pkg_name: consul-k8s-control-plane_${{ env.version }} bin_name: consul-k8s-control-plane workdir: control-plane @@ -292,46 +252,21 @@ jobs: hashicorppreview/${{ env.repo }}-control-plane:${{ env.version }} docker.io/hashicorppreview/${{ env.repo }}-control-plane:${{ env.version }}-${{ github.sha }} - - name: Docker FIPS Build (Action) - uses: hashicorp/actions-docker-build@v1 - if: ${{ matrix.fips }} - with: - smoke_test: | - TEST_VERSION="$(docker run "${IMAGE_NAME}" consul-k8s-control-plane version | awk '{print $2}')" - if [ "${TEST_VERSION}" != "v${version}" ]; then - echo "Test FAILED" - exit 1 - fi - echo "Test PASSED" - version: ${{ env.version }} - target: release-default-fips # duplicate target to distinguish FIPS builds in CRT machinery - arch: ${{ matrix.goarch }} - pkg_name: consul-k8s-control-plane_${{ env.version }} - bin_name: consul-k8s-control-plane - workdir: control-plane - tags: | - docker.io/hashicorp/${{ env.repo }}-control-plane-fips:${{ env.version }} - dev_tags: | - hashicorppreview/${{ env.repo }}-control-plane-fips:${{ env.version }} - docker.io/hashicorppreview/${{ env.repo }}-control-plane-fips:${{ env.version }}-${{ github.sha }} - build-docker-ubi-redhat-registry: - name: Docker ${{ matrix.arch }} ${{ matrix.fips }} UBI build for RedHat Registry + name: Docker ${{ matrix.arch }} UBI build for RedHat Registry needs: [get-product-version, build] runs-on: ubuntu-latest strategy: matrix: - include: - - { arch: "amd64" } - - { arch: "amd64", fips: "+fips1402" } + arch: ["amd64"] env: repo: ${{ github.event.repository.name }} - version: ${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }} + version: ${{ needs.get-product-version.outputs.product-version }} steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 with: - name: consul-cni_${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}_linux_${{ matrix.arch }}.zip + name: consul-cni_${{ needs.get-product-version.outputs.product-version }}_linux_${{ matrix.arch }}.zip path: control-plane/dist/cni/linux/${{ matrix.arch }} - name: extract consul-cni zip env: @@ -342,9 +277,7 @@ jobs: - name: Copy LICENSE run: cp LICENSE ./control-plane - - name: Docker Build (Action) - if: ${{ !matrix.fips }} - uses: hashicorp/actions-docker-build@v1 + - uses: hashicorp/actions-docker-build@v1 with: smoke_test: | TEST_VERSION="$(docker run "${IMAGE_NAME}" consul-k8s-control-plane version | awk '{print $2}')" @@ -360,41 +293,22 @@ jobs: bin_name: consul-k8s-control-plane workdir: control-plane redhat_tag: quay.io/redhat-isv-containers/611ca2f89a9b407267837100:${{env.version}}-ubi - - name: Docker FIPS Build (Action) - if: ${{ matrix.fips }} - uses: hashicorp/actions-docker-build@v1 - with: - smoke_test: | - TEST_VERSION="$(docker run "${IMAGE_NAME}" consul-k8s-control-plane version | awk '{print $2}')" - if [ "${TEST_VERSION}" != "v${version}" ]; then - echo "Test FAILED" - exit 1 - fi - echo "Test PASSED" - version: ${{ env.version }} - target: ubi-fips # duplicate target to distinguish FIPS builds in CRT machinery - arch: ${{ matrix.arch }} - pkg_name: consul-k8s-control-plane_${{ env.version }} - bin_name: consul-k8s-control-plane - workdir: control-plane - redhat_tag: quay.io/redhat-isv-containers/6486b1beabfc4e51588c0416:${{env.version}}-ubi # this is different than the non-FIPS one build-docker-ubi-dockerhub: - name: Docker ${{ matrix.arch }} ${{ matrix.fips }} UBI build for DockerHub + name: Docker ${{ matrix.arch }} UBI build for DockerHub needs: [ get-product-version, build ] runs-on: ubuntu-latest strategy: matrix: arch: [ "amd64" ] - fips: [ "+fips1402", "" ] env: repo: ${{ github.event.repository.name }} - version: ${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }} + version: ${{ needs.get-product-version.outputs.product-version }} steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 with: - name: consul-cni_${{ needs.get-product-version.outputs.product-version }}${{ matrix.fips }}_linux_${{ matrix.arch }}.zip + name: consul-cni_${{ needs.get-product-version.outputs.product-version }}_linux_${{ matrix.arch }}.zip path: control-plane/dist/cni/linux/${{ matrix.arch }} - name: extract consul-cni zip env: @@ -405,9 +319,7 @@ jobs: - name: Copy LICENSE run: cp LICENSE ./control-plane - - name: Docker Build (Action) - uses: hashicorp/actions-docker-build@v1 - if: ${{ !matrix.fips }} + - uses: hashicorp/actions-docker-build@v1 with: smoke_test: | TEST_VERSION="$(docker run "${IMAGE_NAME}" consul-k8s-control-plane version | awk '{print $2}')" @@ -426,26 +338,4 @@ jobs: docker.io/hashicorp/${{ env.repo }}-control-plane:${{ env.version }}-ubi dev_tags: | hashicorppreview/${{ env.repo }}-control-plane:${{ env.version }}-ubi - docker.io/hashicorppreview/${{ env.repo }}-control-plane:${{ env.version }}-ubi-${{ github.sha }} - - name: Docker FIPS Build (Action) - uses: hashicorp/actions-docker-build@v1 - if: ${{ matrix.fips }} - with: - smoke_test: | - TEST_VERSION="$(docker run "${IMAGE_NAME}" consul-k8s-control-plane version | awk '{print $2}')" - if [ "${TEST_VERSION}" != "v${version}" ]; then - echo "Test FAILED" - exit 1 - fi - echo "Test PASSED" - version: ${{ env.version }} - target: ubi-fips # duplicate target to distinguish FIPS builds in CRT machinery - arch: ${{ matrix.arch }} - pkg_name: consul-k8s-control-plane_${{ env.version }} - bin_name: consul-k8s-control-plane - workdir: control-plane - tags: | - docker.io/hashicorp/${{ env.repo }}-control-plane-fips:${{ env.version }}-ubi - dev_tags: | - hashicorppreview/${{ env.repo }}-control-plane-fips:${{ env.version }}-ubi - docker.io/hashicorppreview/${{ env.repo }}-control-plane-fips:${{ env.version }}-ubi-${{ github.sha }} + docker.io/hashicorppreview/${{ env.repo }}-control-plane:${{ env.version }}-ubi-${{ github.sha }} diff --git a/.github/workflows/changelog-checker.yml b/.github/workflows/changelog-checker.yml index 40c9b17c68..d40bdfbd6a 100644 --- a/.github/workflows/changelog-checker.yml +++ b/.github/workflows/changelog-checker.yml @@ -1,5 +1,3 @@ -# Copyright (c) HashiCorp, Inc. - # This workflow checks that there is either a 'pr/no-changelog' label applied to a PR # or there is a .changelog/.txt file associated with a PR for a changelog entry @@ -21,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@v2 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 # by default the checkout action doesn't checkout all branches diff --git a/.github/workflows/jira-issues.yaml b/.github/workflows/jira-issues.yaml index bddc69c83f..dc743e9328 100644 --- a/.github/workflows/jira-issues.yaml +++ b/.github/workflows/jira-issues.yaml @@ -15,7 +15,7 @@ jobs: name: Jira Community Issue sync steps: - name: Login - uses: atlassian/gajira-login@ca13f8850ea309cf44a6e4e0c49d9aa48ac3ca4c # v3 + uses: atlassian/gajira-login@v3.0.0 env: JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} @@ -38,7 +38,7 @@ jobs: - name: Create ticket if an issue is filed, or if PR not by a team member is opened if: github.event.action == 'opened' - uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1 + uses: tomhjp/gh-action-jira-create@v0.2.0 with: project: NET issuetype: "${{ steps.set-ticket-type.outputs.TYPE }}" @@ -58,28 +58,28 @@ jobs: - name: Search if: github.event.action != 'opened' id: search - uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2 + uses: tomhjp/gh-action-jira-search@v0.2.1 with: # cf[10089] is Issue Link (use JIRA API to retrieve) jql: 'issuetype = "${{ steps.set-ticket-type.outputs.TYPE }}" and cf[10089] = "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"' - name: Sync comment if: github.event.action == 'created' && steps.search.outputs.issue - uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0 + uses: tomhjp/gh-action-jira-comment@v0.1.0 with: issue: ${{ steps.search.outputs.issue }} comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}" - name: Close ticket if: ( github.event.action == 'closed' || github.event.action == 'deleted' ) && steps.search.outputs.issue - uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3 + uses: atlassian/gajira-transition@v2.0.1 with: issue: ${{ steps.search.outputs.issue }} transition: "Closed" - name: Reopen ticket if: github.event.action == 'reopened' && steps.search.outputs.issue - uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3 + uses: atlassian/gajira-transition@v2.0.1 with: issue: ${{ steps.search.outputs.issue }} transition: "To Do" diff --git a/.github/workflows/jira-pr.yaml b/.github/workflows/jira-pr.yaml index 078365ac88..c07a92ee77 100644 --- a/.github/workflows/jira-pr.yaml +++ b/.github/workflows/jira-pr.yaml @@ -13,7 +13,7 @@ jobs: name: Jira sync steps: - name: Login - uses: atlassian/gajira-login@ca13f8850ea309cf44a6e4e0c49d9aa48ac3ca4c # v3 + uses: atlassian/gajira-login@v3.0.0 env: JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} @@ -52,7 +52,7 @@ jobs: - name: Create ticket if an issue is filed, or if PR not by a team member is opened if: ( github.event.action == 'opened' && steps.is-team-member.outputs.MESSAGE == 'false' ) - uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1 + uses: tomhjp/gh-action-jira-create@v0.2.0 with: project: NET issuetype: "${{ steps.set-ticket-type.outputs.TYPE }}" @@ -72,28 +72,28 @@ jobs: - name: Search if: github.event.action != 'opened' id: search - uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2 + uses: tomhjp/gh-action-jira-search@v0.2.1 with: # cf[10089] is Issue Link (use JIRA API to retrieve) jql: 'issuetype = "${{ steps.set-ticket-type.outputs.TYPE }}" and cf[10089] = "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"' - name: Sync comment if: github.event.action == 'created' && steps.search.outputs.issue - uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0 + uses: tomhjp/gh-action-jira-comment@v0.1.0 with: issue: ${{ steps.search.outputs.issue }} comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}" - name: Close ticket if: ( github.event.action == 'closed' || github.event.action == 'deleted' ) && steps.search.outputs.issue - uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3 + uses: atlassian/gajira-transition@v2.0.1 with: issue: ${{ steps.search.outputs.issue }} transition: "Closed" - name: Reopen ticket if: github.event.action == 'reopened' && steps.search.outputs.issue - uses: atlassian/gajira-transition@4749176faf14633954d72af7a44d7f2af01cc92b # v3 + uses: atlassian/gajira-transition@v2.0.1 with: issue: ${{ steps.search.outputs.issue }} transition: "To Do" diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index e95af6cdcc..2af1e46532 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -20,7 +20,7 @@ jobs: name: test runs-on: ubuntu-latest steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 + - uses: benc-uk/workflow-dispatch@v1.2.2 name: test with: workflow: test.yml diff --git a/.github/workflows/nightly-acceptance.yml b/.github/workflows/nightly-acceptance.yml index 6db7684bb8..18a8ba958d 100644 --- a/.github/workflows/nightly-acceptance.yml +++ b/.github/workflows/nightly-acceptance.yml @@ -16,7 +16,7 @@ jobs: name: cloud runs-on: ubuntu-latest steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 + - uses: benc-uk/workflow-dispatch@v1.2.2 name: cloud with: workflow: cloud.yml diff --git a/.github/workflows/nightly-api-gateway-conformance.yml b/.github/workflows/nightly-api-gateway-conformance.yml deleted file mode 100644 index abeec34659..0000000000 --- a/.github/workflows/nightly-api-gateway-conformance.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Dispatch to the consul-k8s-workflows with a nightly cron -name: nightly-api-gateway-conformance -on: - schedule: - # * is a special character in YAML so you have to quote this string - # Run nightly at 12AM UTC/8PM EST/5PM PST. - - cron: '0 0 * * *' - - -# these should be the only settings that you will ever need to change -env: - BRANCH: ${{ github.ref_name }} - CONTEXT: "nightly" - -jobs: - api-gateway-conformance: - name: api-gateway-conformance - runs-on: ubuntu-latest - steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 - name: conformance - with: - workflow: api-gateway-conformance.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/nightly-cleanup.yml b/.github/workflows/nightly-cleanup.yml deleted file mode 100644 index 83d6688ac5..0000000000 --- a/.github/workflows/nightly-cleanup.yml +++ /dev/null @@ -1,26 +0,0 @@ -# Dispatch to the consul-k8s-workflows with a nightly cron -name: nightly-cleanup -on: - schedule: - # * is a special character in YAML so you have to quote this string - # Run nightly at 12PM UTC/8AM EST/5AM PST - - cron: '0 12 * * *' - -# these should be the only settings that you will ever need to change -env: - BRANCH: ${{ github.ref_name }} - CONTEXT: "nightly" - -jobs: - cleanup: - name: cleanup - runs-on: ubuntu-latest - steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 - name: cleanup - with: - workflow: cleanup.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/pr.yml b/.github/workflows/pr.yml index 2959554e21..65f924e6d0 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -14,7 +14,7 @@ jobs: name: test runs-on: ubuntu-latest steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 + - uses: benc-uk/workflow-dispatch@v1.2.2 name: test with: workflow: test.yml diff --git a/.github/workflows/weekly-acceptance-0-49-x.yml b/.github/workflows/weekly-acceptance-0-49-x.yml index 5e1c17f3c7..691d0b6236 100644 --- a/.github/workflows/weekly-acceptance-0-49-x.yml +++ b/.github/workflows/weekly-acceptance-0-49-x.yml @@ -18,7 +18,7 @@ jobs: name: cloud runs-on: ubuntu-latest steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 + - uses: benc-uk/workflow-dispatch@v1.2.2 name: cloud with: workflow: cloud.yml diff --git a/.github/workflows/weekly-acceptance-1-0-x.yml b/.github/workflows/weekly-acceptance-1-0-x.yml index 11dda52bed..663f779bb5 100644 --- a/.github/workflows/weekly-acceptance-1-0-x.yml +++ b/.github/workflows/weekly-acceptance-1-0-x.yml @@ -19,7 +19,7 @@ jobs: name: cloud runs-on: ubuntu-latest steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 + - uses: benc-uk/workflow-dispatch@v1.2.2 name: cloud with: workflow: cloud.yml diff --git a/.github/workflows/weekly-acceptance-1-1-x.yml b/.github/workflows/weekly-acceptance-1-1-x.yml index 86153587b0..2fc21aba5b 100644 --- a/.github/workflows/weekly-acceptance-1-1-x.yml +++ b/.github/workflows/weekly-acceptance-1-1-x.yml @@ -19,7 +19,7 @@ jobs: name: cloud runs-on: ubuntu-latest steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 + - uses: benc-uk/workflow-dispatch@v1.2.2 name: cloud with: workflow: cloud.yml diff --git a/.github/workflows/weekly-acceptance-1-2-x.yml b/.github/workflows/weekly-acceptance-1-2-x.yml deleted file mode 100644 index 353a086f16..0000000000 --- a/.github/workflows/weekly-acceptance-1-2-x.yml +++ /dev/null @@ -1,30 +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-2-x -on: - schedule: - # * is a special character in YAML so you have to quote this string - # Run weekly on Wednesday at 3AM UTC/11PM EST/8PM PST - # - cron: '0 3 * * 3' - - cron: '0 0 * * *' # Temporarily nightly until 1.2.0 GA - - -# these should be the only settings that you will ever need to change -env: - BRANCH: "release/1.2.x" - CONTEXT: "weekly" - -jobs: - cloud: - name: cloud - runs-on: ubuntu-latest - steps: - - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 - 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/.go-version b/.go-version index 8909929f6e..e54f3135a7 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.20.7 +1.19.12 diff --git a/.golangci.yml b/.golangci.yml index dcad005d10..95aa25b0ff 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - linters: # enables all defaults + the below, `golangci-lint linters` to see the list of active linters. enable: diff --git a/.release/ci.hcl b/.release/ci.hcl index 5c781045e7..ffc2fd60d5 100644 --- a/.release/ci.hcl +++ b/.release/ci.hcl @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - schema = "1" project "consul-k8s" { diff --git a/.release/release-metadata.hcl b/.release/release-metadata.hcl index 10741e9c36..c053fdac2f 100644 --- a/.release/release-metadata.hcl +++ b/.release/release-metadata.hcl @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - url_docker_registry_dockerhub = "https://hub.docker.com/r/hashicorp/consul-k8s-control-plane" url_license = "https://github.com/hashicorp/consul-k8s/blob/main/LICENSE" url_project_website = "https://www.consul.io/docs/k8s" diff --git a/.release/security-scan.hcl b/.release/security-scan.hcl index 692fea1578..42576d29b2 100644 --- a/.release/security-scan.hcl +++ b/.release/security-scan.hcl @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - container { dependencies = true alpine_secdb = true diff --git a/CHANGELOG.md b/CHANGELOG.md index d9a4d76bef..1cb973e91a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,103 +1,12 @@ -## 1.2.1 (Aug 10, 2023) -BREAKING CHANGES: - -* control-plane: All policies managed by consul-k8s will now be updated on upgrade. If you previously edited the policies after install, your changes will be overwritten. [[GH-2392](https://github.com/hashicorp/consul-k8s/issues/2392)] - -SECURITY: - -* Upgrade to use Go 1.20.6 and `x/net/http` 0.12.0. - This resolves [CVE-2023-29406](https://github.com/advisories/GHSA-f8f7-69v5-w4vx)(`net/http`). [[GH-2642](https://github.com/hashicorp/consul-k8s/issues/2642)] -* Upgrade to use Go 1.20.7 and `x/net` 0.13.0. - This resolves [CVE-2023-29409](https://nvd.nist.gov/vuln/detail/CVE-2023-29409)(`crypto/tls`) - and [CVE-2023-3978](https://nvd.nist.gov/vuln/detail/CVE-2023-3978)(`net/html`). [[GH-2710](https://github.com/hashicorp/consul-k8s/issues/2710)] - -FEATURES: - -* Add support for configuring graceful shutdown proxy lifecycle management settings. [[GH-2233](https://github.com/hashicorp/consul-k8s/issues/2233)] -* api-gateway: adds ability to map privileged ports on Gateway listeners to unprivileged ports so that containers do not require additional privileges [[GH-2707](https://github.com/hashicorp/consul-k8s/issues/2707)] -* api-gateway: support deploying to OpenShift 4.11 [[GH-2184](https://github.com/hashicorp/consul-k8s/issues/2184)] -* helm: Adds `acls.resources` field which can be configured to override the `resource` settings for the `server-acl-init` and `server-acl-init-cleanup` Jobs. [[GH-2416](https://github.com/hashicorp/consul-k8s/issues/2416)] -* sync-catalog: add ability to support weighted loadbalancing by service annotation `consul.hashicorp.com/service-weight: ` [[GH-2293](https://github.com/hashicorp/consul-k8s/issues/2293)] - -IMPROVEMENTS: - -* (Consul Enterprise) Add support to provide inputs via helm for audit log related configuration [[GH-2370](https://github.com/hashicorp/consul-k8s/issues/2370)] -* (api-gateway) make API gateway controller less verbose [[GH-2524](https://github.com/hashicorp/consul-k8s/issues/2524)] -* Add support to provide the logLevel flag via helm for multiple low level components. Introduces the following fields -1. `global.acls.logLevel` -2. `global.tls.logLevel` -3. `global.federation.logLevel` -4. `global.gossipEncryption.logLevel` -5. `server.logLevel` -6. `client.logLevel` -7. `meshGateway.logLevel` -8. `ingressGateways.logLevel` -9. `terminatingGateways.logLevel` -10. `telemetryCollector.logLevel` [[GH-2302](https://github.com/hashicorp/consul-k8s/issues/2302)] -* control-plane: increase timeout after login for ACL replication to 60 seconds [[GH-2656](https://github.com/hashicorp/consul-k8s/issues/2656)] -* helm: adds values for `securityContext` and `annotations` on TLS and ACL init/cleanup jobs. [[GH-2525](https://github.com/hashicorp/consul-k8s/issues/2525)] -* helm: set container securityContexts to match the `restricted` Pod Security Standards policy to support running Consul in a namespace with restricted PSA enforcement enabled [[GH-2572](https://github.com/hashicorp/consul-k8s/issues/2572)] -* helm: update `imageConsulDataplane` value to `hashicorp/consul-dataplane:1.2.0` [[GH-2476](https://github.com/hashicorp/consul-k8s/issues/2476)] -* helm: update `image` value to `hashicorp/consul:1.16.0` [[GH-2476](https://github.com/hashicorp/consul-k8s/issues/2476)] - -BUG FIXES: - -* api-gateway: Fix creation of invalid Kubernetes Service when multiple Gateway listeners have the same port. [[GH-2413](https://github.com/hashicorp/consul-k8s/issues/2413)] -* api-gateway: fix helm install when setting copyAnnotations or nodeSelector [[GH-2597](https://github.com/hashicorp/consul-k8s/issues/2597)] -* api-gateway: fixes bug where envoy will silently reject RSA keys less than 2048 bits in length when not in FIPS mode, and - will reject keys that are not 2048, 3072, or 4096 bits in length in FIPS mode. We now validate - and reject invalid certs earlier. [[GH-2478](https://github.com/hashicorp/consul-k8s/issues/2478)] -* api-gateway: set route condition appropriately when parent ref includes non-existent section name [[GH-2420](https://github.com/hashicorp/consul-k8s/issues/2420)] -* control-plane: Always update ACL policies upon upgrade. [[GH-2392](https://github.com/hashicorp/consul-k8s/issues/2392)] -* control-plane: fix bug in endpoints controller when deregistering services from consul when a node is deleted. [[GH-2571](https://github.com/hashicorp/consul-k8s/issues/2571)] -* helm: fix CONSUL_LOGIN_DATACENTER for consul client-daemonset. [[GH-2652](https://github.com/hashicorp/consul-k8s/issues/2652)] -* helm: fix ui ingress manifest formatting, and exclude `ingressClass` when not defined. [[GH-2687](https://github.com/hashicorp/consul-k8s/issues/2687)] -* transparent-proxy: Fix issue where connect-inject lacked sufficient `mesh:write` privileges in some deployments, - which prevented virtual IPs from persisting properly. [[GH-2520](https://github.com/hashicorp/consul-k8s/issues/2520)] - -## 1.1.4 (Aug 10, 2023) - -SECURITY: - -* Upgrade to use Go 1.20.6 and `x/net/http` 0.12.0. - This resolves [CVE-2023-29406](https://github.com/advisories/GHSA-f8f7-69v5-w4vx)(`net/http`). [[GH-2642](https://github.com/hashicorp/consul-k8s/issues/2642)] -* Upgrade to use Go 1.20.7 and `x/net` 0.13.0. - This resolves [CVE-2023-29409](https://nvd.nist.gov/vuln/detail/CVE-2023-29409)(`crypto/tls`) - and [CVE-2023-3978](https://nvd.nist.gov/vuln/detail/CVE-2023-3978)(`net/html`). [[GH-2710](https://github.com/hashicorp/consul-k8s/issues/2710)] - -IMPROVEMENTS: - -* Add support to provide the logLevel flag via helm for multiple low level components. Introduces the following fields -1. `global.acls.logLevel` -2. `global.tls.logLevel` -3. `global.federation.logLevel` -4. `global.gossipEncryption.logLevel` -5. `server.logLevel` -6. `client.logLevel` -7. `meshGateway.logLevel` -8. `ingressGateways.logLevel` -9. `terminatingGateways.logLevel` -10. `telemetryCollector.logLevel` [[GH-2302](https://github.com/hashicorp/consul-k8s/issues/2302)] -* control-plane: increase timeout after login for ACL replication to 60 seconds [[GH-2656](https://github.com/hashicorp/consul-k8s/issues/2656)] -* helm: adds values for `securityContext` and `annotations` on TLS and ACL init/cleanup jobs. [[GH-2525](https://github.com/hashicorp/consul-k8s/issues/2525)] -* helm: do not set container securityContexts by default on OpenShift < 4.11 [[GH-2678](https://github.com/hashicorp/consul-k8s/issues/2678)] -* helm: set container securityContexts to match the `restricted` Pod Security Standards policy to support running Consul in a namespace with restricted PSA enforcement enabled [[GH-2572](https://github.com/hashicorp/consul-k8s/issues/2572)] - -BUG FIXES: - -* control-plane: fix bug in endpoints controller when deregistering services from consul when a node is deleted. [[GH-2571](https://github.com/hashicorp/consul-k8s/issues/2571)] -* helm: fix CONSUL_LOGIN_DATACENTER for consul client-daemonset. [[GH-2652](https://github.com/hashicorp/consul-k8s/issues/2652)] -* helm: fix ui ingress manifest formatting, and exclude `ingressClass` when not defined. [[GH-2687](https://github.com/hashicorp/consul-k8s/issues/2687)] - ## 1.0.9 (Aug 10, 2023) SECURITY: * Upgrade to use Go 1.19.11 and `x/net/http` 0.12.0. - This resolves [CVE-2023-29406](https://github.com/advisories/GHSA-f8f7-69v5-w4vx)(`net/http`). [[GH-2650](https://github.com/hashicorp/consul-k8s/issues/2650)] +This resolves [CVE-2023-29406](https://github.com/advisories/GHSA-f8f7-69v5-w4vx)(`net/http`). [[GH-2650](https://github.com/hashicorp/consul-k8s/issues/2650)] * Upgrade to use Go 1.19.12 and `x/net` 0.13.0. - This resolves [CVE-2023-29409](https://nvd.nist.gov/vuln/detail/CVE-2023-29409)(`crypto/tls`) - and [CVE-2023-3978](https://nvd.nist.gov/vuln/detail/CVE-2023-3978)(`net/html`). [[GH-2717](https://github.com/hashicorp/consul-k8s/issues/2717)] +This resolves [CVE-2023-29409](https://nvd.nist.gov/vuln/detail/CVE-2023-29409)(`crypto/tls`) +and [CVE-2023-3978](https://nvd.nist.gov/vuln/detail/CVE-2023-3978)(`net/html`). [[GH-2717](https://github.com/hashicorp/consul-k8s/issues/2717)] IMPROVEMENTS: @@ -122,86 +31,6 @@ BUG FIXES: * helm: fix CONSUL_LOGIN_DATACENTER for consul client-daemonset. [[GH-2652](https://github.com/hashicorp/consul-k8s/issues/2652)] * helm: fix ui ingress manifest formatting, and exclude `ingressClass` when not defined. [[GH-2687](https://github.com/hashicorp/consul-k8s/issues/2687)] -## 0.49.8 (July 12, 2023) - -IMPROVEMENTS: - -* helm: Add `connectInject.prepareDataplanesUpgrade` setting for help upgrading to dataplanes. This setting is required if upgrading from non-dataplanes to dataplanes when ACLs are enabled. See https://developer.hashicorp.com/consul/docs/k8s/upgrade#upgrading-to-consul-dataplane for more information. [[GH-2514](https://github.com/hashicorp/consul-k8s/issues/2514)] - -## 1.2.0 (June 28, 2023) - -FEATURES: - -* Add support for configuring Consul server-side rate limiting [[GH-2166](https://github.com/hashicorp/consul-k8s/issues/2166)] -* api-gateway: Add API Gateway for Consul on Kubernetes leveraging Consul native API Gateway configuration. [[GH-2152](https://github.com/hashicorp/consul-k8s/issues/2152)] -* crd: Add `mutualTLSMode` to the ProxyDefaults and ServiceDefaults CRDs and `allowEnablingPermissiveMutualTLS` to the Mesh CRD to support configuring permissive mutual TLS. [[GH-2100](https://github.com/hashicorp/consul-k8s/issues/2100)] -* helm: Add `JWTProvider` CRD for configuring the `jwt-provider` config entry. [[GH-2209](https://github.com/hashicorp/consul-k8s/issues/2209)] -* helm: Update the ServiceIntentions CRD to support `JWT` fields. [[GH-2213](https://github.com/hashicorp/consul-k8s/issues/2213)] - -IMPROVEMENTS: - -* cli: update minimum go version for project to 1.20. [[GH-2102](https://github.com/hashicorp/consul-k8s/issues/2102)] -* control-plane: add FIPS support [[GH-2165](https://github.com/hashicorp/consul-k8s/issues/2165)] -* control-plane: server ACL Init always appends both, the secrets from the serviceAccount's secretRefs and the one created by the Helm chart, to support Openshift secret handling. [[GH-1770](https://github.com/hashicorp/consul-k8s/issues/1770)] -* control-plane: set agent localities on Consul servers to the server node's `topology.kubernetes.io/region` label. [[GH-2093](https://github.com/hashicorp/consul-k8s/issues/2093)] -* control-plane: update alpine to 3.17 in the Docker image. [[GH-1934](https://github.com/hashicorp/consul-k8s/issues/1934)] -* control-plane: update minimum go version for project to 1.20. [[GH-2102](https://github.com/hashicorp/consul-k8s/issues/2102)] -* helm: Kubernetes v1.27 is now supported. Minimum tested version of Kubernetes is now v1.24. [[GH-2304](https://github.com/hashicorp/consul-k8s/issues/2304)] -* helm: Update the default amount of memory used by the connect-inject controller so that its less likely to get OOM killed. [[GH-2249](https://github.com/hashicorp/consul-k8s/issues/2249)] -* helm: add failover policy field to service resolver and proxy default CRDs [[GH-2030](https://github.com/hashicorp/consul-k8s/issues/2030)] -* helm: add samenessGroup CRD [[GH-2048](https://github.com/hashicorp/consul-k8s/issues/2048)] -* helm: add samenessGroup field to exported services CRD [[GH-2075](https://github.com/hashicorp/consul-k8s/issues/2075)] -* helm: add samenessGroup field to service resolver CRD [[GH-2086](https://github.com/hashicorp/consul-k8s/issues/2086)] -* helm: add samenessGroup field to source intention CRD [[GH-2097](https://github.com/hashicorp/consul-k8s/issues/2097)] -* helm: update `imageConsulDataplane` value to `hashicorp/consul-dataplane:1.1.0`. [[GH-1953](https://github.com/hashicorp/consul-k8s/issues/1953)] - -SECURITY: - -* Update [Go-Discover](https://github.com/hashicorp/go-discover) in the container has been updated to address [CVE-2020-14040](https://github.com/advisories/GHSA-5rcv-m4m3-hfh7) [[GH-2390](https://github.com/hashicorp/consul-k8s/issues/2390)] -* Bump Dockerfile base image to `alpine:3.18`. Resolves [CVE-2023-2650](https://github.com/advisories/GHSA-gqxg-9vfr-p9cg) vulnerability in openssl@3.0.8-r4 [[GH-2284](https://github.com/hashicorp/consul-k8s/issues/2284)] -* Fix Prometheus CVEs by bumping controller-runtime. [[GH-2183](https://github.com/hashicorp/consul-k8s/issues/2183)] -* Upgrade to use Go 1.20.4. - This resolves vulnerabilities [CVE-2023-24537](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`go/scanner`), - [CVE-2023-24538](https://github.com/advisories/GHSA-v4m2-x4rp-hv22)(`html/template`), - [CVE-2023-24534](https://github.com/advisories/GHSA-8v5j-pwr7-w5f8)(`net/textproto`) and - [CVE-2023-24536](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`mime/multipart`). - Also, `golang.org/x/net` has been updated to v0.7.0 to resolve CVEs [CVE-2022-41721 - ](https://github.com/advisories/GHSA-fxg5-wq6x-vr4w - ), [CVE-2022-27664](https://github.com/advisories/GHSA-69cg-p879-7622) and [CVE-2022-41723 - ](https://github.com/advisories/GHSA-vvpx-j8f3-3w6h - .) [[GH-2102](https://github.com/hashicorp/consul-k8s/issues/2102)] - -BUG FIXES: - -* control-plane: Fix casing of the Enforce Consecutive 5xx field on Service Defaults and acceptance test fixtures. [[GH-2266](https://github.com/hashicorp/consul-k8s/issues/2266)] -* control-plane: fix issue where consul-connect-injector acl token was unintentionally being deleted and not recreated when a container was restarted due to a livenessProbe failure. [[GH-1914](https://github.com/hashicorp/consul-k8s/issues/1914)] - -## 1.1.3 (June 28, 2023) -BREAKING CHANGES: - -* control-plane: All policies managed by consul-k8s will now be updated on upgrade. If you previously edited the policies after install, your changes will be overwritten. [[GH-2392](https://github.com/hashicorp/consul-k8s/issues/2392)] - -SECURITY: - -* Bump Dockerfile base image to `alpine:3.18`. Resolves [CVE-2023-2650](https://github.com/advisories/GHSA-gqxg-9vfr-p9cg) vulnerability in openssl@3.0.8-r4 [[GH-2284](https://github.com/hashicorp/consul-k8s/issues/2284)] -* Update [Go-Discover](https://github.com/hashicorp/go-discover) in the container has been updated to address [CVE-2020-14040](https://github.com/advisories/GHSA-5rcv-m4m3-hfh7) [[GH-2390](https://github.com/hashicorp/consul-k8s/issues/2390)] - -FEATURES: - -* Add support for configuring graceful shutdown proxy lifecycle management settings. [[GH-2233](https://github.com/hashicorp/consul-k8s/issues/2233)] -* helm: Adds `acls.resources` field which can be configured to override the `resource` settings for the `server-acl-init` and `server-acl-init-cleanup` Jobs. [[GH-2416](https://github.com/hashicorp/consul-k8s/issues/2416)] -* sync-catalog: add ability to support weighted loadbalancing by service annotation `consul.hashicorp.com/service-weight: ` [[GH-2293](https://github.com/hashicorp/consul-k8s/issues/2293)] - -IMPROVEMENTS: - -* (Consul Enterprise) Add support to provide inputs via helm for audit log related configuration [[GH-2369](https://github.com/hashicorp/consul-k8s/issues/2369)] -* helm: Update the default amount of memory used by the connect-inject controller so that its less likely to get OOM killed. [[GH-2249](https://github.com/hashicorp/consul-k8s/issues/2249)] - -BUG FIXES: - -* control-plane: Always update ACL policies upon upgrade. [[GH-2392](https://github.com/hashicorp/consul-k8s/issues/2392)] -* control-plane: Fix casing of the Enforce Consecutive 5xx field on Service Defaults and acceptance test fixtures. [[GH-2266](https://github.com/hashicorp/consul-k8s/issues/2266)] - ## 1.0.8 (June 28, 2023) BREAKING CHANGES: @@ -234,71 +63,6 @@ BUG FIXES: * control-plane: fix issue with multiport pods crashlooping due to dataplane port conflicts by ensuring dns redirection is disabled for non-tproxy pods [[GH-2176](https://github.com/hashicorp/consul-k8s/issues/2176)] * crd: fix bug on service intentions CRD causing some updates to be ignored. [[GH-2194](https://github.com/hashicorp/consul-k8s/issues/2194)] - -## 0.49.7 (June 28, 2023) -BREAKING CHANGES: - -* control-plane: All policies managed by consul-k8s will now be updated on upgrade. If you previously edited the policies after install, your changes will be overwritten. [[GH-2392](https://github.com/hashicorp/consul-k8s/issues/2392)] - -SECURITY: - -* Bump Dockerfile base image for RedHat UBI `consul-k8s-control-plane` image to `ubi-minimal:9.2`. [[GH-2204](https://github.com/hashicorp/consul-k8s/issues/2204)] -* Bump Dockerfile base image to `alpine:3.18`. Resolves [CVE-2023-2650](https://github.com/advisories/GHSA-gqxg-9vfr-p9cg) vulnerability in openssl@3.0.8-r4 [[GH-2284](https://github.com/hashicorp/consul-k8s/issues/2284)] - -FEATURES: - -* helm: Adds `acls.resources` field which can be configured to override the `resource` settings for the `server-acl-init` and `server-acl-init-cleanup` Jobs. [[GH-2416](https://github.com/hashicorp/consul-k8s/issues/2416)] - -IMPROVEMENTS: - -* (Consul Enterprise) Add support to provide inputs via helm for audit log related configuration [[GH-2265](https://github.com/hashicorp/consul-k8s/issues/2265)] -* helm: Update the default amount of memory used by the connect-inject controller so that its less likely to get OOM killed. [[GH-2249](https://github.com/hashicorp/consul-k8s/issues/2249)] - -BUG FIXES: - -* control-plane: Always update ACL policies upon upgrade. [[GH-2392](https://github.com/hashicorp/consul-k8s/issues/2392)] -* crd: fix bug on service intentions CRD causing some updates to be ignored. [[GH-2194](https://github.com/hashicorp/consul-k8s/issues/2194)] - -## 1.1.2 (June 5, 2023) - -SECURITY: - -* Bump Dockerfile base image for RedHat UBI `consul-k8s-control-plane` image to `ubi-minimal:9.2`. [[GH-2204](https://github.com/hashicorp/consul-k8s/issues/2204)] -* Bump `controller-runtime` to address CVEs in dependencies. [[GH-2226](https://github.com/hashicorp/consul-k8s/issues/2226)] -* Upgrade to use Go 1.20.4. -This resolves vulnerabilities [CVE-2023-24537](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`go/scanner`), -[CVE-2023-24538](https://github.com/advisories/GHSA-v4m2-x4rp-hv22)(`html/template`), -[CVE-2023-24534](https://github.com/advisories/GHSA-8v5j-pwr7-w5f8)(`net/textproto`) and -[CVE-2023-24536](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`mime/multipart`). -Also, `golang.org/x/net` has been updated to v0.7.0 to resolve CVEs [CVE-2022-41721 -](https://github.com/advisories/GHSA-fxg5-wq6x-vr4w -), [CVE-2022-27664](https://github.com/advisories/GHSA-69cg-p879-7622) and [CVE-2022-41723 -](https://github.com/advisories/GHSA-vvpx-j8f3-3w6h -.) [[GH-2104](https://github.com/hashicorp/consul-k8s/issues/2104)] - -FEATURES: - -* Add support for consul-telemetry-collector to forward envoy metrics to an otelhttp compatible receiver or HCP [[GH-2134](https://github.com/hashicorp/consul-k8s/issues/2134)] -* consul-telemetry-collector: Configure envoy proxy config during registration when consul-telemetry-collector is enabled. [[GH-2143](https://github.com/hashicorp/consul-k8s/issues/2143)] -* sync-catalog: add ability to sync hostname from a Kubernetes Ingress resource to the Consul Catalog during service registration. [[GH-2098](https://github.com/hashicorp/consul-k8s/issues/2098)] - -IMPROVEMENTS: - -* cli: Add `consul-k8s config read` command that returns the helm configuration in yaml format. [[GH-2078](https://github.com/hashicorp/consul-k8s/issues/2078)] -* cli: add consul-telemetry-gateway allow-all intention for -demo [[GH-2262](https://github.com/hashicorp/consul-k8s/issues/2262)] -* cli: update cloud preset to enable telemetry collector [[GH-2205](https://github.com/hashicorp/consul-k8s/issues/2205)] -* consul-telemetry-collector: add acceptance tests for consul telemetry collector component [[GH-2195](https://github.com/hashicorp/consul-k8s/issues/2195)] - -BUG FIXES: - -* crd: fix bug on service intentions CRD causing some updates to be ignored. [[GH-2194](https://github.com/hashicorp/consul-k8s/issues/2083)] -* api-gateway: fix issue where the API Gateway controller is unable to start up successfully when Vault is configured as the secrets backend [[GH-2083](https://github.com/hashicorp/consul-k8s/issues/2083)] -* control-plane: add support for idleTimeout in the Service Router config [[GH-2156](https://github.com/hashicorp/consul-k8s/issues/2156)] -* control-plane: fix issue with json tags of service defaults fields EnforcingConsecutive5xx, MaxEjectionPercent and BaseEjectionTime. [[GH-2160](https://github.com/hashicorp/consul-k8s/issues/2160)] -* control-plane: fix issue with multiport pods crashlooping due to dataplane port conflicts by ensuring dns redirection is disabled for non-tproxy pods [[GH-2176](https://github.com/hashicorp/consul-k8s/issues/2176)] -* helm: add missing `$HOST_IP` environment variable to to mesh gateway deployments. [[GH-1808](https://github.com/hashicorp/consul-k8s/issues/1808)] -* sync-catalog: fix issue where the sync-catalog ACL token were set with an incorrect ENV VAR. [[GH-2068](https://github.com/hashicorp/consul-k8s/issues/2068)] - ## 1.0.7 (May 17, 2023) SECURITY: @@ -330,37 +94,6 @@ BUG FIXES: * helm: add missing `$HOST_IP` environment variable to to mesh gateway deployments. [[GH-1808](https://github.com/hashicorp/consul-k8s/issues/1808)] * sync-catalog: fix issue where the sync-catalog ACL token were set with an incorrect ENV VAR. [[GH-2068](https://github.com/hashicorp/consul-k8s/issues/2068)] -## 0.49.6 (May 17, 2023) - -SECURITY: - -* Upgrade to use Go 1.19.9. -This resolves vulnerabilities [CVE-2023-24537](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`go/scanner`), -[CVE-2023-24538](https://github.com/advisories/GHSA-v4m2-x4rp-hv22)(`html/template`), -[CVE-2023-24534](https://github.com/advisories/GHSA-8v5j-pwr7-w5f8)(`net/textproto`) and -[CVE-2023-24536](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)(`mime/multipart`). -Also, `golang.org/x/net` has been updated to v0.7.0 to resolve CVEs [CVE-2022-41721 -](https://github.com/advisories/GHSA-fxg5-wq6x-vr4w -), [CVE-2022-27664](https://github.com/advisories/GHSA-69cg-p879-7622) and [CVE-2022-41723 -](https://github.com/advisories/GHSA-vvpx-j8f3-3w6h -.) [[GH-2110](https://github.com/hashicorp/consul-k8s/issues/2110)] - -IMPROVEMENTS: - -* helm: Set default `limits.cpu` resource setting to `null` for `consul-connect-inject-init` container to speed up registration times when onboarding services onto the mesh during the init container lifecycle. [[GH-2008](https://github.com/hashicorp/consul-k8s/issues/2008)] - -## 1.1.1 (March 31, 2023) - -IMPROVEMENTS: - -* helm: Set default `limits.cpu` resource setting to `null` for `consul-connect-inject-init` container to speed up registration times when onboarding services onto the mesh during the init container lifecycle. [[GH-2008](https://github.com/hashicorp/consul-k8s/issues/2008)] -* helm: When the `global.acls.bootstrapToken` field is set and the content of the secret is empty, the bootstrap ACL token is written to that secret after bootstrapping ACLs. This applies to both the Vault and Consul secrets backends. [[GH-1920](https://github.com/hashicorp/consul-k8s/issues/1920)] - -BUG FIXES: - -* api-gateway: fix ACL issue where when adminPartitions and ACLs are enabled, API Gateway Controller is unable to create a new namespace in Consul [[GH-2029](https://github.com/hashicorp/consul-k8s/issues/2029)] -* api-gateway: fix issue where specifying an external server SNI name while using client nodes resulted in a TLS verification error. [[GH-2013](https://github.com/hashicorp/consul-k8s/issues/2013)] - ## 1.0.6 (March 20, 2023) IMPROVEMENTS: @@ -383,24 +116,7 @@ IMPROVEMENTS: * control-plane: update alpine to 3.17 in the Docker image. [[GH-1934](https://github.com/hashicorp/consul-k8s/issues/1934)] * helm: update `imageConsulDataplane` value to `hashicorp/consul-dataplane:1.1.0`. [[GH-1953](https://github.com/hashicorp/consul-k8s/issues/1953)] -## 0.49.5 (March 9, 2023) - -SECURITY: - -* upgrade to use Go 1.19.6. This resolves vulnerabilities CVE-2022-41724 in crypto/tls and CVE-2022-41723 in net/http. [[GH-1975](https://github.com/hashicorp/consul-k8s/issues/1975)] - -IMPROVEMENTS: - -* cli: update minimum go version for project to 1.19. [[GH-1975](https://github.com/hashicorp/consul-k8s/issues/1975)] -* control-plane: server ACL Init always appends both, the secrets from the serviceAccount's secretRefs and the one created by the Helm chart, to support Openshift secret handling. [[GH-1770](https://github.com/hashicorp/consul-k8s/issues/1770)] -* control-plane: update alpine to 3.17 in the Docker image. [[GH-1934](https://github.com/hashicorp/consul-k8s/issues/1934)] -* control-plane: update minimum go version for project to 1.19. [[GH-1975](https://github.com/hashicorp/consul-k8s/issues/1975)] - -BUG FIXES: - -* control-plane: fix issue where consul-connect-injector acl token was unintentionally being deleted and not recreated when a container was restarted due to a livenessProbe failure. [[GH-1914](https://github.com/hashicorp/consul-k8s/issues/1914)] - -## 1.1.0 (February 27, 2023) +## 1.0.4 (February 7, 2023) BREAKING CHANGES: * Helm: @@ -416,36 +132,10 @@ BREAKING CHANGES: values: ["kube-system","local-path-storage"] ``` [[GH-1869](https://github.com/hashicorp/consul-k8s/pull/1869)] - + IMPROVEMENTS: -* Helm: - * CNI: Add `connectInject.cni.namespace` stanza which allows the CNI plugin resources to be deployed in a namespace other than the namespace that Consul is installed. [[GH-1756](https://github.com/hashicorp/consul-k8s/pull/1756)] - * Kubernetes v1.26 is now supported. Minimum tested version of Kubernetes is now v1.23. [[GH-1852](https://github.com/hashicorp/consul-k8s/pull/1852)] - * Add a `global.extraLabels` stanza to allow setting global Kubernetes labels for all components deployed by the `consul-k8s` Helm chart. [[GH-1778](https://github.com/hashicorp/consul-k8s/pull/1778)] - * Add the `accessLogs` field to the `ProxyDefaults` CRD. [[GH-1816](https://github.com/hashicorp/consul-k8s/pull/1816)] - * Add the `envoyExtensions` field to the `ProxyDefaults` and `ServiceDefaults` CRD. [[GH-1823]](https://github.com/hashicorp/consul-k8s/pull/1823) - * Add the `balanceInboundConnections` field to the `ServiceDefaults` CRD. [[GH-1823]](https://github.com/hashicorp/consul-k8s/pull/1823) - * Add the `upstreamConfig.overrides[].peer` field to the `ServiceDefaults` CRD. [[GH-1853]](https://github.com/hashicorp/consul-k8s/pull/1853) -* Control-Plane - * Update minimum go version for project to 1.20 [[GH-1908](https://github.com/hashicorp/consul-k8s/pull/1908)] - * Add support for the annotation `consul.hashicorp.com/use-proxy-health-check`. When this annotation is used by a service, it configures a readiness endpoint on Consul Dataplane and queries it instead of the proxy's inbound port which forwards requests to the application. [[GH-1824](https://github.com/hashicorp/consul-k8s/pull/1824)], [[GH-1841](https://github.com/hashicorp/consul-k8s/pull/1841)] - * Add health check for synced services based on the status of the Kubernetes readiness probe on synced pod. [[GH-1821](https://github.com/hashicorp/consul-k8s/pull/1821)] - * Remove extraneous `gnupg` dependency from `consul-k8s-control-plane` since it is no longer needed for validating binary artifacts prior to release. [[GH-1882](https://github.com/hashicorp/consul-k8s/pull/1882)] - * Server ACL Init always appends both, the secrets from the serviceAccount's secretRefs and the one created by the Helm chart, to support Openshift secret handling. [[GH-1770](https://github.com/hashicorp/consul-k8s/pull/1770)] - * Update alpine to 3.17 in the Docker image. [[GH-1934](https://github.com/hashicorp/consul-k8s/pull/1934)] -* CLI: - * Update minimum go version for project to 1.20 [[GH-1908](https://github.com/hashicorp/consul-k8s/pull/1908)] - * Add `consul-k8s proxy log podname` command for displaying and modifying Envoy log levels for a given Pod. [GH-1844](https://github.com/hashicorp/consul-k8s/pull/1844), [GH-1849](https://github.com/hashicorp/consul-k8s/pull/1849), [GH-1864](https://github.com/hashicorp/consul-k8s/pull/1864) - -BUG FIXES: -* Control Plane - * Don't incorrectly diff intention config entries when upgrading from Consul pre-1.12 to 1.12+ [[GH-1804](https://github.com/hashicorp/consul-k8s/pull/1804)] - * Add discover binary to control-plane image [[GH-1749](https://github.com/hashicorp/consul-k8s/pull/1749)] -* Helm: - * Don't pass in a CA file to the API Gateway controller when `externalServers.useSystemRoots` is `true`. [[GH-1743](https://github.com/hashicorp/consul-k8s/pull/1743)] - * Use the correct autogenerated cert for the API Gateway Controller when connecting to servers versus clients. [[GH-1753](https://github.com/hashicorp/consul-k8s/pull/1753)] -* Security: - * Upgrade to use Go 1.20.1 This resolves vulnerabilities [CVE-2022-41724](https://go.dev/issue/58001) in `crypto/tls` and [CVE-2022-41723](https://go.dev/issue/57855) in `net/http`. [[GH-1908](https://github.com/hashicorp/consul-k8s/pull/1908)] + * Control Plane + * Remove extraneous `gnupg` dependency from `consul-k8s-control-plane` since it is no longer needed for validating binary artifacts prior to release. [[GH-1882](https://github.com/hashicorp/consul-k8s/pull/1882)] ## 1.0.3 (January 30, 2023) @@ -461,42 +151,19 @@ BUG FIXES: * Control Plane * Don't incorrectly diff intention config entries when upgrading from Consul pre-1.12 to 1.12+ [[GH-1804](https://github.com/hashicorp/consul-k8s/pull/1804)] -## 0.49.3 (January 30, 2023) - -IMPROVEMENTS: -* Helm: - * Add a `global.extraLabels` stanza to allow setting global Kubernetes labels for all components deployed by the `consul-k8s` Helm chart. [[GH-1778](https://github.com/hashicorp/consul-k8s/pull/1778)] -* Control-Plane - * Add support for the annotation `consul.hashicorp.com/use-proxy-health-check`. When this annotation is used by a service, it configures a readiness endpoint on Consul Dataplane and queries it instead of the proxy's inbound port which forwards requests to the application. [[GH-1824](https://github.com/hashicorp/consul-k8s/pull/1824)], [[GH-1843](https://github.com/hashicorp/consul-k8s/pull/1843)] - * Add health check for synced services based on the status of the Kubernetes readiness probe on synced pod. [[GH-1821](https://github.com/hashicorp/consul-k8s/pull/1821)] - -BUG FIXES: -* Control Plane - * Don't incorrectly diff intention config entries when upgrading from Consul pre-1.12 to 1.12+ [[GH-1804](https://github.com/hashicorp/consul-k8s/pull/1804)] - ## 1.0.2 (December 1, 2022) IMPROVEMENTS: * Helm: * CNI: Add `connectInject.cni.namespace` stanza which allows the CNI plugin resources to be deployed in a namespace other than the namespace that Consul is installed. [[GH-1756](https://github.com/hashicorp/consul-k8s/pull/1756)] +* Control Plane: + * Server ACL Init always appends both, the secrets from the serviceAccount's secretRefs and the one created by the Helm chart, to support Openshift secret handling. [[GH-1770](https://github.com/hashicorp/consul-k8s/pull/1770)] BUG FIXES: * Helm: * Use the correct autogenerated cert for the API Gateway Controller when connecting to servers versus clients. [[GH-1753](https://github.com/hashicorp/consul-k8s/pull/1753)] * Don't mount the CA cert when `externalServers.useSystemRoots` is `true`. [[GH-1753](https://github.com/hashicorp/consul-k8s/pull/1753)] -## 0.49.2 (December 1, 2022) - -IMPROVEMENTS: -* Control Plane - * Bump Dockerfile base image for RedHat UBI `consul-k8s-control-plane` image to `ubi-minimal:9.1`. [[GH-1725](https://github.com/hashicorp/consul-k8s/pull/1725)] -* Helm - * Add fields `localConnectTimeoutMs` and `localRequestTimeoutMs` to the `ServiceDefaults` CRD. [[GH-1647](https://github.com/hashicorp/consul-k8s/pull/1647)] - -BUG FIXES: -* Helm: - * Disable PodSecurityPolicies templating for `gossip-encryption-autogenerate` and `partition-init` when `global.enablePodSecurityPolicies` is `false`. [[GH-1693](https://github.com/hashicorp/consul-k8s/pull/1693)] - ## 1.0.1 (November 21, 2022) BUG FIXES: @@ -599,6 +266,7 @@ IMPROVEMENTS: * API Gateway: Allow controller to read MeshServices for use as a route backend. [[GH-1574](https://github.com/hashicorp/consul-k8s/pull/1574)] * API Gateway: Add support for using dynamic server discovery strings when running without agents. [[GH-1732](https://github.com/hashicorp/consul-k8s/pull/1732)] + BUG FIXES: * CLI * Allow optional environment variables for use in the cloud preset to the CLI for cluster bootstrapping. [[GH-1608](https://github.com/hashicorp/consul-k8s/pull/1608)] @@ -607,24 +275,7 @@ BUG FIXES: * Peering * Add `peering:read` permissions to mesh gateway token to fix peering connections through the mesh gateways. [[GH-1685](https://github.com/hashicorp/consul-k8s/pull/1685)] * Helm: - * Disable PodSecurityPolicies in all templates when `global.enablePodSecurityPolicies` is `false`. [[GH-1693](https://github.com/hashicorp/consul-k8s/pull/1693)] - -## 0.49.1 (November 14, 2022) -BREAKING CHANGES: -* Peering: - * Rename `PeerName` to `Peer` in ExportedServices CRD. [[GH-1596](https://github.com/hashicorp/consul-k8s/pull/1596)] - -FEATURES: -* Ingress Gateway - * Add support for MaxConnections, MaxConcurrentRequests, and MaxPendingRequests to Ingress Gateway CRD. [[GH-1691](https://github.com/hashicorp/consul-k8s/pull/1691)] - -IMPROVEMENTS: -* Helm: - * Add `tolerations` and `nodeSelector` to Server ACL init jobs and `nodeSelector` to Webhook cert manager. [[GH-1581](https://github.com/hashicorp/consul-k8s/pull/1581)] - * API Gateway: Allow controller to read MeshServices for use as a route backend. [[GH-1574](https://github.com/hashicorp/consul-k8s/pull/1574)] - * API Gateway: Add `tolerations` to `apiGateway.managedGatewayClass` and `apiGateway.controller` [[GH-1650](https://github.com/hashicorp/consul-k8s/pull/1650)] - * API Gateway: Create PodSecurityPolicy for controller when `global.enablePodSecurityPolicies=true`. [[GH-1656](https://github.com/hashicorp/consul-k8s/pull/1656)] - * API Gateway: Create PodSecurityPolicy and allow controller to bind it to ServiceAccounts that it creates for Gateway Deployments when `global.enablePodSecurityPolicies=true`. [[GH-1672](https://github.com/hashicorp/consul-k8s/pull/1672)] + * Disable PodSecurityPolicies templating for `gossip-encryption-autogenerate` and `partition-init` when `global.enablePodSecurityPolicies` is `false`. [[GH-1693](https://github.com/hashicorp/consul-k8s/pull/1693)] ## 0.49.0 (September 29, 2022) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4eca76a1dd..4fb322799b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,11 +22,10 @@ 1. [Running the tests](#running-the-tests) 1. [Writing Unit tests](#writing-unit-tests) 1. [Writing Acceptance tests](#writing-acceptance-tests) -1. [Using the Acceptance Test Framework to Debug](#using-acceptance-test-framework-to-debug) 1. [Helm Reference Docs](#helm-reference-docs) -1. [Managing External CRD Dependencies](#managing-external-crd-dependencies) 1. [Adding a Changelog Entry](#adding-a-changelog-entry) + ## Contributing 101 ### Building and running `consul-k8s-control-plane` @@ -168,7 +167,7 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ```bash operator-sdk create api --group consul --version v1alpha1 --kind IngressGateway --controller --namespaced=true --make=false --resource=true ``` -1. Re-order the generated ingressgateway_types.go file, so it looks like: +1. Re-order the file so it looks like: ```go func init() { SchemeBuilder.Register(&IngressGateway{}, &IngressGatewayList{}) @@ -214,7 +213,6 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ```go // ServiceRouter is the Schema for the servicerouters API // +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" - // +kubebuilder:printcolumn:name="Last Synced",type="date",JSONPath=".status.lastSyncedTime",description="The last successful synced time of the resource with Consul" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" type ServiceRouter struct { ``` @@ -233,7 +231,7 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ``` 1. Go to the Consul `api` package for the config entry, e.g. https://github.com/hashicorp/consul/blob/main/api/config_entry_gateways.go 1. Copy the top-level fields over into the `Spec` struct except for - `Kind`, `Name`, `Namespace`, `Partition`, `Meta`, `CreateIndex` and `ModifyIndex`. In this + `Kind`, `Name`, `Namespace`, `Meta`, `CreateIndex` and `ModifyIndex`. In this example, the top-level fields remaining are `TLS` and `Listeners`: ```go @@ -322,6 +320,8 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ### Controller 1. Delete the file `control-plane/controllers/suite_test.go`. We don't write suite tests, just unit tests. +1. Move `control-plane/controllers/ingressgateway_controller.go` to `control-plane/controller` directory. +1. Delete the `control-plane/controllers` directory. 1. Rename `Reconciler` to `Controller`, e.g. `IngressGatewayReconciler` => `IngressGatewayController` 1. Use the existing controller files as a guide and make this file match. 1. Add your controller as a case in the tests in `configentry_controller_test.go`: @@ -376,7 +376,7 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ### Generating YAML 1. Run `make ctrl-manifests` to generate the CRD and webhook YAML. -1. Uncomment your CRD in `control-plane/config/crd/kustomization` under `patches:` +1. Uncomment your CRD in `control-plane/config/crd/kustomization` under `patchesStrategicMerge:` 1. Update the sample, e.g. `control-plane/config/samples/consul_v1alpha1_ingressgateway.yaml` to a valid resource that can be used for testing: ```yaml @@ -395,13 +395,13 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ``` ### Updating Helm chart -1. Update `charts/consul/templates/connect-inject-mutatingwebhookconfiguration` with the webhook for this resource +1. Update `charts/consul/templates/controller-mutatingwebhookconfiguration` with the webhook for this resource using the updated `control-plane/config/webhook/manifests.v1beta1.yaml` and replacing `clientConfig.service.name/namespace` with the templated strings shown below to match the other webhooks.: ```yaml - clientConfig: service: - name: {{ template "consul.fullname" . }}-connect-injector + name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} path: /mutate-v1alpha1-ingressgateway failurePolicy: Fail @@ -421,31 +421,24 @@ rebase the branch on main, fixing any conflicts along the way before the code ca - ingressgateways sideEffects: None ``` -1. Update `charts/consul/templates/connect-inject-clusterrole.yaml` to allow the controller to +1. Update `charts/consul/templates/controller-clusterrole.yaml` to allow the controller to manage your resource type. ### Testing A New CRD -1. Build a Docker image for consul-k8s via `make control-plane-dev-docker` and push to a docker repository: - ``` - docker tag consul-k8s-control-plane-dev /consul-k8s-control-plane-dev: - docker push /consul-k8s-control-plane-dev: - ``` +1. Build a Docker image for consul-k8s via `make dev-docker` and tagging your image appropriately. Remember to CD into the `control-plane` directory! 1. Install using the updated Helm repository, with a values like: ```yaml global: - imageK8S: lkysow/consul-k8s-control-plane-dev:nov26 + imageK8S: ghcr.io/lkysow/consul-k8s-dev:nov26 name: consul server: replicas: 1 bootstrapExpect: 1 - ui: - enabled: true - connectInject: + controller: enabled: true ``` -1. Create a sample CRD -1. Run `kubectl apply -f ` to apply your sample CRD. -1. Check its synced status (for example CRD called ingressgateway): +1. `kubectl apply` your sample CRD. +1. Check its synced status: ```bash kubectl get ingressgateway NAME SYNCED AGE @@ -941,198 +934,6 @@ Here are some things to consider before adding a test: --- -## Using Acceptance Test Framework to Debug -### Acceptance Tests - -The [consul-k8s](https://github.com/hashicorp/consul-k8s) repository has an extensive list of [acceptance](https://github.com/hashicorp/consul-k8s/tree/main/acceptance/tests) -tests that are used by CI to run per-PR and nightly acceptance tests. -It is built on its own framework that uses Helm and the consul-k8s CLI to deploy consul (and other tools) in various -configurations that provide test coverage for most features that exist and provides coverage for more advanced deployments -than are typically covered in guides. -Importantly, it is **automated**, so you are able to rapidly deploy known working -configurations in known working environments. -It can be very helpful for bootstrapping complex environments such as when using Vault as a CA for Consul or for federating test clusters. - -The tests are organized like this : -```shell -demo $ tree -L 1 -d acceptance/tests -acceptance/tests -├── basic -├── cli -├── config-entries -├── connect -├── consul-dns -├── example -├── fixtures -├── ingress-gateway -├── metrics -├── partitions -├── peering -├── snapshot-agent -├── sync -├── terminating-gateway -├── vault -└── wan-federation -``` - -### Basic Running of Tests -Any given test can be run either through GoLand or another IDE, or via command line using `go test -run`. - -To run all of the connect tests from command line: -```shell -$ cd acceptance/tests -$ go test ./connect/... -v -p 1 -timeout 2h -failfast -use-kind -no-cleanup-on-failure -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-enterprise -enable-multi-cluster -debug-directory=/tmp/debug -consul-k8s-image=kyleschochenmaier/consul-k8s-acls -``` - -When running from command line a few things are important: -* Some tests use Enterprise features, in which case you need: - * Set environment variables `CONSUL_ENT_LICENSE` and possibly `VAULT_LICENSE`. - * Use `-enable-enterprise` on command line when running the test. -* Multi-cluster tests require `-enable-multi-cluster -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2` -* Using `.//...` is required as part of the command-line to pick up necessary environmental config. - -### Using the framework to debug in an environment -=> NOTE: It is helpful to tune the docker desktop resource settings so that docker has at least 4GB memory, plenty of cpu cores and 2GB of swap. - -* If using Kind, `-use-kind` should be added, and be sure you cluster is up and running: -```shell -$ kind create cluster --name=dc1 && kind create cluster --name=dc2 -``` -* Pick a test which replicates the environment you are wanting to work with. - Ex: pick a test from `partitions/` or `vault/` or `connect/`. -* If you need the environment to persist, add a `time.Sleep(1*time.Hour)` to the end of the test in the test file. -* Use the following flags if you need to use or test out a specific consul/k8s image: - `-consul-k8s-image=` && `-consul-image=` -* You can set custom helm flags by modifying the test file directly in the respective directory. - -Finally, run the test like shown above: -```shell -$ cd acceptance/tests -$ go test -run Vault_WANFederationViaGateways ./vault/... -p 1 -timeout 2h -failfast -use-kind -no-cleanup-on-failure -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-multi-cluster -debug-directory=/tmp/debug -``` -You can interact with the running kubernetes clusters now using `kubectl [COMMAND] --context=` - -* `kind delete clusters --all` is helpful for cleanup! - -### Example Debugging session using the acceptance test framework to bootstrap and debug a Vault backed federated Consul installation: -This test utilizes the `consul-k8s` acceptance test framework, with a custom consul-k8s branch which: -* Modifies the acceptance test to use custom consul+consul-k8s images and sleeps at the end of the test to allow analysis. -* Modifies the helm chart to pass in `connect_ca.intermediate_cert_ttl` and `connect_ca.leaf_cert_ttl` in the `server-configmap` - -1. First clone the consul-k8s repo and then check out the branch locally: `git checkout origin/consul-vault-provider-wanfed-acceptance`. -2. Start the kind clusters: `kind create cluster --name=dc1 && kind create cluster --name=dc2` -3. run the `TestVault_WANFederationViaGateways` acceptance test in `acceptance/tests/vault/vault_wan_fed_test.go` - I use goland, but this command should get you most of the way: -```shell -$ cd acceptance/tests -$ go test -run Vault_WANFederationViaGateways ./vault/... -p 1 -timeout 2h -failfast -use-kind -no-cleanup-on-failure -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-multi-cluster -debug-directory=/tmp/debug -``` -NOTE: This specific acceptance test is considered FLAKY with Kind, if things don't come up it's best to run against GKE/AKS/etc, in which case you just modify the `kubecontext` command parameters to point to your clusters. It is worth noting that you will need to setup any necessary networking for non-Kind clusters manually. - -NOTE: This test requires a VAULT_LICENSE set as an environment variable in the shell where you run `go test` - -4. Wait 10-20 minutes to allow the first intermediate ca renewal, this test is particularly resource intensive so it can take time for everything to come online on a laptop, use `kubectl get pods` to validate that `static-server` and `static-client` have been deployed and are online. - -You can validate the ICA rotation by doing: -```shell -# Fetch the vault root token: -$ kubectl get secrets -root-token -o json //----> b64 decode the `data.token` field. -$ kubectl exec -it -- sh -$ export VAULT_TOKEN= -$ export VAULT_ADDR=https://-vault:8200 - -# Fetch the consul bootstrap token -$ vault kv get consul/secret/bootstrap - -# Examine the vault issuers, there should be 2 by now if ICA renewal has occured: -# NOTE: for a federated setup the issuers url for dc2 is `vault list dc2/connect_inter/issuers`! -$ vault list dc1/connect_inter/issuers - -Keys ----- -29bdffbd-87ec-cfe0-fd05-b78f99eba243 -344eea3c-f085-943a-c3ff-66721ef408f4 - -# Now login to the consul-server -$ kubectl exec -it -- sh -$ export CONSUL_HTTP_TOKEN= -$ export CONSUL_HTTP_ADDR=https://localhost:8501 -$ export CONSUL_HTTP_SSL_VERIFY=false - -# Read the `connect/ca/roots` endpoint: -# It should change + rotate with the expiration of the ICA (defined by `intermediate_cert_ttl` which is `15m` in the branch for this gist. - -$ curl -k --header "X-Consul-Token: 1428da53-5e88-db1a-6ad5-e50212b011da" https://127.0.0.1:8501/v1/agent/connect/ca/roots | jq - . - % Total % Received % Xferd Average Speed Time Time Time Current - Dload Upload Total Spent Left Speed -100 3113 100 3113 0 0 6222 0 --:--:-- --:--:-- --:--:-- 7705 -{ - "ActiveRootID": "36:be:19:0e:56:d1:c2:1a:d8:54:22:97:88:3c:91:17:1d:d2:d3:e0", - "TrustDomain": "34a76791-b9b2-b93e-b0e4-1989ed11a28e.consul", - "Roots": [ - { - "ID": "36:be:19:0e:56:d1:c2:1a:d8:54:22:97:88:3c:91:17:1d:d2:d3:e0", - "Name": "Vault CA Primary Cert", - "SerialNumber": 15998414315735550000, - "SigningKeyID": "fe:b9:d6:0b:c6:ce:2c:25:4f:d8:59:cb:11:ea:a5:42:5f:8e:41:4b", - "ExternalTrustDomain": "34a76791-b9b2-b93e-b0e4-1989ed11a28e", - "NotBefore": "2022-11-16T20:16:15Z", - "NotAfter": "2032-11-13T20:16:45Z", - "RootCert": "-----BEGIN CERTIFICATE-----\nMIICLDCCAdKgAwIBAgIUKQ9BPHF9mtC7yFPC3gXJDpLxCHIwCgYIKoZIzj0EAwIw\nLzEtMCsGA1UEAxMkcHJpLTEwOTJudTEudmF1bHQuY2EuMzRhNzY3OTEuY29uc3Vs\nMB4XDTIyMTExNjIwMTYxNVoXDTMyMTExMzIwMTY0NVowLzEtMCsGA1UEAxMkcHJp\nLTEwOTJudTEudmF1bHQuY2EuMzRhNzY3OTEuY29uc3VsMFkwEwYHKoZIzj0CAQYI\nKoZIzj0DAQcDQgAETnpGixC1kW8ep2JcGjRR2jbdESvjlEm9nSIWVAcilemUGFwi\nJ0YW0XUmJeEzRyfwLXnOw6voPzXRf1zXKjdTD6OByzCByDAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUtb6EjDxyI+myIjDc+7KbiN8u\n8XowHwYDVR0jBBgwFoAUtb6EjDxyI+myIjDc+7KbiN8u8XowZQYDVR0RBF4wXIIk\ncHJpLTEwOTJudTEudmF1bHQuY2EuMzRhNzY3OTEuY29uc3VshjRzcGlmZmU6Ly8z\nNGE3Njc5MS1iOWIyLWI5M2UtYjBlNC0xOTg5ZWQxMWEyOGUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCIHBezFSQAK5Nolf0rs3ErvlDcA8Z9esldh6gHupuGsNkAiEA\n9qL+P9PJAW4CrbTL0iF2yZUyJC2nwSSa2K0nYG8bXWQ=\n-----END CERTIFICATE-----\n", - "IntermediateCerts": [ - "-----BEGIN CERTIFICATE-----\nMIICLzCCAdSgAwIBAgIUbILCP3ODM4ScNBOm0jw59Fxju0swCgYIKoZIzj0EAwIw\nLzEtMCsGA1UEAxMkcHJpLTEwOTJudTEudmF1bHQuY2EuMzRhNzY3OTEuY29uc3Vs\nMB4XDTIyMTExNjIwMzIxNloXDTIyMTExNjIwNDc0NlowMDEuMCwGA1UEAxMlcHJp\nLTE4MThxNWlnLnZhdWx0LmNhLjM0YTc2NzkxLmNvbnN1bDBZMBMGByqGSM49AgEG\nCCqGSM49AwEHA0IABI30ikgrwTjbPaGgfNYkushvrEUUpxLzxMMEBlE82ilog1RW\nqwuEU29Qsa+N4SrfOf37xNv/Ey8SXPs5l2HmXJWjgcwwgckwDgYDVR0PAQH/BAQD\nAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCZpC/BTdaggL2kj6Dfyk3+a\nNqBvMB8GA1UdIwQYMBaAFLW+hIw8ciPpsiIw3Puym4jfLvF6MGYGA1UdEQRfMF2C\nJXByaS0xODE4cTVpZy52YXVsdC5jYS4zNGE3Njc5MS5jb25zdWyGNHNwaWZmZTov\nLzM0YTc2NzkxLWI5YjItYjkzZS1iMGU0LTE5ODllZDExYTI4ZS5jb25zdWwwCgYI\nKoZIzj0EAwIDSQAwRgIhAJ8RHgR5qkyW2q866vGYJy+7BJ4zUXs3OJ76QLmxxU3K\nAiEA70S7wBEm1ZduTAk1ZfZPJEUGxvAXAcgy7EWeO/6MJ5o=\n-----END CERTIFICATE-----\n", - "-----BEGIN CERTIFICATE-----\nMIICLTCCAdKgAwIBAgIUU3qwESuhh4PgW3/tnHDn3qnBMrAwCgYIKoZIzj0EAwIw\nLzEtMCsGA1UEAxMkcHJpLTEwOTJudTEudmF1bHQuY2EuMzRhNzY3OTEuY29uc3Vs\nMB4XDTIyMTExNjIwNDAxNloXDTIyMTExNjIwNTU0NlowLzEtMCsGA1UEAxMkcHJp\nLTFkY2hkbGkudmF1bHQuY2EuMzRhNzY3OTEuY29uc3VsMFkwEwYHKoZIzj0CAQYI\nKoZIzj0DAQcDQgAEpj0BWPkcH82su9XGOo9rN5Zr5+Jyp68LiHy+qlIgH3L+OAir\nYgmXmJfuNwI8S2BB8cu0Gk3w5cTF7O0p/qAghaOByzCByDAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU/rnWC8bOLCVP2FnLEeqlQl+O\nQUswHwYDVR0jBBgwFoAUtb6EjDxyI+myIjDc+7KbiN8u8XowZQYDVR0RBF4wXIIk\ncHJpLTFkY2hkbGkudmF1bHQuY2EuMzRhNzY3OTEuY29uc3VshjRzcGlmZmU6Ly8z\nNGE3Njc5MS1iOWIyLWI5M2UtYjBlNC0xOTg5ZWQxMWEyOGUuY29uc3VsMAoGCCqG\nSM49BAMCA0kAMEYCIQCtq4LiZzkiIKUES9MrzUEflg7wcwQf7Km+8RcOGQbz9QIh\nANWHWt1fe8Hl1wQ55qxsV5lSfOpGAox5WHpgnsBC7cwU\n-----END CERTIFICATE-----\n" - ], - "Active": true, - "PrivateKeyType": "ec", - "PrivateKeyBits": 256, - "CreateIndex": 11, - "ModifyIndex": 797 - } - ] -} - -# You can x509 decode the ICA certs to verify they have been updated and have correct expiry: -$ openssl x509 -in cert.crt -text -noout -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 53:7a:b0:11:2b:a1:87:83:e0:5b:7f:ed:9c:70:e7:de:a9:c1:32:b0 - Signature Algorithm: ecdsa-with-SHA256 - Issuer: CN=pri-1092nu1.vault.ca.34a76791.consul - Validity - Not Before: Nov 16 20:40:16 2022 GMT - Not After : Nov 16 20:55:46 2022 GMT - Subject: CN=pri-1dchdli.vault.ca.34a76791.consul - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:a6:3d:01:58:f9:1c:1f:cd:ac:bb:d5:c6:3a:8f: - 6b:37:96:6b:e7:e2:72:a7:af:0b:88:7c:be:aa:52: - 20:1f:72:fe:38:08:ab:62:09:97:98:97:ee:37:02: - 3c:4b:60:41:f1:cb:b4:1a:4d:f0:e5:c4:c5:ec:ed: - 29:fe:a0:20:85 - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - FE:B9:D6:0B:C6:CE:2C:25:4F:D8:59:CB:11:EA:A5:42:5F:8E:41:4B - X509v3 Authority Key Identifier: - keyid:B5:BE:84:8C:3C:72:23:E9:B2:22:30:DC:FB:B2:9B:88:DF:2E:F1:7A - - X509v3 Subject Alternative Name: - DNS:pri-1dchdli.vault.ca.34a76791.consul, URI:spiffe://34a76791-b9b2-b93e-b0e4-1989ed11a28e.consul - -``` - ---- - ## Helm Reference Docs The Helm reference docs (https://www.consul.io/docs/k8s/helm) are automatically @@ -1209,26 +1010,6 @@ So that the documentation can look like: - `ports` ((#v-ingressgateways-defaults-service-ports)) (`array: [{port: 8080, port: 8443}]`) - Port docs ``` -## Managing External CRD Dependencies - -Some of the features of Consul on Kubernetes make use of CustomResourceDefinitions (CRDs) that we don't directly -manage. One such example is the Gateway API CRDs which we use to configure API Gateways, but are managed by SIG -Networking. - -To pull external CRDs into our Helm chart and make sure they get installed, we generate their configuration using -[Kustomize](https://kustomize.io/) which can pull in Kubernetes config from external sources. We split these -generated CRDs into individual files and store them in the `charts/consul/templates` directory. - -If you need to update the external CRDs we depend on, or add to them, you can do this by editing the -[control-plane/config/crd/external/kustomization.yaml](/control-plane/config/crd/external/kustomization.yaml) file. -Once modified, running - -```bash -make generate-external-crds -``` - -will update the CRDs in the `/templates` directory. - ## Adding a Changelog Entry Any change that a Consul-K8s user might need to know about should have a changelog entry. diff --git a/Makefile b/Makefile index 866a37fbfc..44a0a6a7f2 100644 --- a/Makefile +++ b/Makefile @@ -14,10 +14,6 @@ gen-helm-docs: ## Generate Helm reference docs from values.yaml and update Consu copy-crds-to-chart: ## Copy generated CRD YAML into charts/consul. Usage: make copy-crds-to-chart @cd hack/copy-crds-to-chart; go run ./... -generate-external-crds: ## Generate CRDs for externally defined CRDs and copy them to charts/consul. Usage: make generate-external-crds - @cd ./control-plane/config/crd/external; \ - kustomize build | yq --split-exp '.metadata.name + ".yaml"' --no-doc - bats-tests: ## Run Helm chart bats tests. bats --jobs 4 charts/consul/test/unit @@ -53,17 +49,6 @@ control-plane-dev-docker-multi-arch: check-remote-dev-image-env ## Build consul- --push \ -f $(CURDIR)/control-plane/Dockerfile $(CURDIR)/control-plane -control-plane-fips-dev-docker: ## Build consul-k8s-control-plane FIPS dev Docker image. - @$(SHELL) $(CURDIR)/control-plane/build-support/scripts/build-local.sh -o linux -a $(GOARCH) --fips - @docker build -t '$(DEV_IMAGE)' \ - --target=dev \ - --build-arg 'TARGETARCH=$(GOARCH)' \ - --build-arg 'GIT_COMMIT=$(GIT_COMMIT)' \ - --build-arg 'GIT_DIRTY=$(GIT_DIRTY)' \ - --build-arg 'GIT_DESCRIBE=$(GIT_DESCRIBE)' \ - --push \ - -f $(CURDIR)/control-plane/Dockerfile $(CURDIR)/control-plane - control-plane-test: ## Run go test for the control plane. cd control-plane; go test ./... @@ -85,7 +70,7 @@ cni-plugin-lint: cd control-plane/cni; golangci-lint run -c ../../.golangci.yml ctrl-generate: get-controller-gen ## Run CRD code generation. - cd control-plane; $(CONTROLLER_GEN) object paths="./..." + cd control-plane; $(CONTROLLER_GEN) object:headerFile="build-support/controller/boilerplate.go.txt" paths="./..." # Perform a terraform fmt check but don't change anything terraform-fmt-check: @@ -107,10 +92,6 @@ cli-dev: @echo "==> Installing consul-k8s CLI tool for ${GOOS}/${GOARCH}" @cd cli; go build -o ./bin/consul-k8s; cp ./bin/consul-k8s ${GOPATH}/bin/ -cli-fips-dev: - @echo "==> Installing consul-k8s CLI tool for ${GOOS}/${GOARCH}" - @cd cli; CGO_ENABLED=1 GOEXPERIMENT=boringcrypto go build -o ./bin/consul-k8s -tags "fips"; cp ./bin/consul-k8s ${GOPATH}/bin/ - cli-lint: ## Run linter in the control-plane directory. cd cli; golangci-lint run -c ../.golangci.yml @@ -130,30 +111,22 @@ kind-cni-calico: kubectl create -f $(CURDIR)/acceptance/framework/environment/cni-kind/custom-resources.yaml @sleep 20 -kind-delete: +# Helper target for doing local cni acceptance testing +kind-cni: kind delete cluster --name dc1 kind delete cluster --name dc2 - kind delete cluster --name dc3 - kind delete cluster --name dc4 - - -# Helper target for doing local cni acceptance testing -kind-cni: kind-delete kind create cluster --config=$(CURDIR)/acceptance/framework/environment/cni-kind/kind.config --name dc1 --image $(KIND_NODE_IMAGE) make kind-cni-calico kind create cluster --config=$(CURDIR)/acceptance/framework/environment/cni-kind/kind.config --name dc2 --image $(KIND_NODE_IMAGE) make kind-cni-calico - kind create cluster --config=$(CURDIR)/acceptance/framework/environment/cni-kind/kind.config --name dc3 --image $(KIND_NODE_IMAGE) - make kind-cni-calico - kind create cluster --config=$(CURDIR)/acceptance/framework/environment/cni-kind/kind.config --name dc4 --image $(KIND_NODE_IMAGE) - make kind-cni-calico # Helper target for doing local acceptance testing -kind: kind-delete +kind: + kind delete cluster --name dc1 + kind delete cluster --name dc2 kind create cluster --name dc1 --image $(KIND_NODE_IMAGE) kind create cluster --name dc2 --image $(KIND_NODE_IMAGE) - kind create cluster --name dc3 --image $(KIND_NODE_IMAGE) - kind create cluster --name dc4 --image $(KIND_NODE_IMAGE) + # Helper target for loading local dev images (run with `DEV_IMAGE=...` to load non-k8s images) kind-load: @@ -173,8 +146,6 @@ lint: cni-plugin-lint ## Run linter in the control-plane, cli, and acceptance di ctrl-manifests: get-controller-gen ## Generate CRD manifests. cd control-plane; $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases make copy-crds-to-chart - make generate-external-crds - make add-copyright-header get-controller-gen: ## Download controller-gen program needed for operator SDK. ifeq (, $(shell which controller-gen)) @@ -191,13 +162,6 @@ else CONTROLLER_GEN=$(shell which controller-gen) endif -add-copyright-header: ## Add copyright header to all files in the project -ifeq (, $(shell which copywrite)) - @echo "Installing copywrite" - @go install github.com/hashicorp/copywrite@latest -endif - @copywrite headers --spdx "MPL-2.0" - # ===========> CI Targets ci.aws-acceptance-test-cleanup: ## Deletes AWS resources left behind after failed acceptance tests. @@ -277,7 +241,7 @@ endif # ===========> Makefile config .DEFAULT_GOAL := help -.PHONY: gen-helm-docs copy-crds-to-chart generate-external-crds bats-tests help ci.aws-acceptance-test-cleanup version cli-dev prepare-dev prepare-release +.PHONY: gen-helm-docs copy-crds-to-chart bats-tests help ci.aws-acceptance-test-cleanup version cli-dev prepare-dev prepare-release SHELL = bash GOOS?=$(shell go env GOOS) GOARCH?=$(shell go env GOARCH) diff --git a/README.md b/README.md index d43a12b455..1d3a3733ab 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ by contacting us at [security@hashicorp.com](mailto:security@hashicorp.com). The following pre-requisites must be met before installing Consul on Kubernetes. - * **Kubernetes 1.24.x - 1.27.x** - This represents the earliest versions of Kubernetes tested. + * **Kubernetes 1.23.x - 1.26.x** - This represents the earliest versions of Kubernetes tested. It is possible that this chart works with earlier versions, but it is untested. * Helm install diff --git a/acceptance/ci-inputs/aks_acceptance_test_packages.yaml b/acceptance/ci-inputs/aks_acceptance_test_packages.yaml index c1f1093200..cef04a3205 100644 --- a/acceptance/ci-inputs/aks_acceptance_test_packages.yaml +++ b/acceptance/ci-inputs/aks_acceptance_test_packages.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - - {runner: 0, test-packages: "connect peering snapshot-agent wan-federation"} - {runner: 1, test-packages: "consul-dns example partitions metrics sync"} - {runner: 2, test-packages: "basic cli config-entries api-gateway ingress-gateway terminating-gateway vault"} \ No newline at end of file diff --git a/acceptance/ci-inputs/eks_acceptance_test_packages.yaml b/acceptance/ci-inputs/eks_acceptance_test_packages.yaml index c1f1093200..cef04a3205 100644 --- a/acceptance/ci-inputs/eks_acceptance_test_packages.yaml +++ b/acceptance/ci-inputs/eks_acceptance_test_packages.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - - {runner: 0, test-packages: "connect peering snapshot-agent wan-federation"} - {runner: 1, test-packages: "consul-dns example partitions metrics sync"} - {runner: 2, test-packages: "basic cli config-entries api-gateway ingress-gateway terminating-gateway vault"} \ No newline at end of file diff --git a/acceptance/ci-inputs/gke_acceptance_test_packages.yaml b/acceptance/ci-inputs/gke_acceptance_test_packages.yaml index c1f1093200..cef04a3205 100644 --- a/acceptance/ci-inputs/gke_acceptance_test_packages.yaml +++ b/acceptance/ci-inputs/gke_acceptance_test_packages.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - - {runner: 0, test-packages: "connect peering snapshot-agent wan-federation"} - {runner: 1, test-packages: "consul-dns example partitions metrics sync"} - {runner: 2, test-packages: "basic cli config-entries api-gateway ingress-gateway terminating-gateway vault"} \ No newline at end of file diff --git a/acceptance/ci-inputs/kind-inputs.yaml b/acceptance/ci-inputs/kind-inputs.yaml index ba21d2cdaf..70dc2f0974 100644 --- a/acceptance/ci-inputs/kind-inputs.yaml +++ b/acceptance/ci-inputs/kind-inputs.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - kindVersion: v0.19.0 -kindNodeImage: kindest/node:v1.27.1 +kindNodeImage: kindest/node:v1.25.9 kubectlVersion: v1.27.1 diff --git a/acceptance/ci-inputs/kind_acceptance_test_packages.yaml b/acceptance/ci-inputs/kind_acceptance_test_packages.yaml index e0e126bbda..74991abd76 100644 --- a/acceptance/ci-inputs/kind_acceptance_test_packages.yaml +++ b/acceptance/ci-inputs/kind_acceptance_test_packages.yaml @@ -1,10 +1,6 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - - {runner: 0, test-packages: "partitions"} - {runner: 1, test-packages: "peering"} -- {runner: 2, test-packages: "sameness"} -- {runner: 3, test-packages: "connect snapshot-agent wan-federation"} -- {runner: 4, test-packages: "cli vault metrics"} -- {runner: 5, test-packages: "api-gateway ingress-gateway sync example consul-dns"} -- {runner: 6, test-packages: "config-entries terminating-gateway basic"} +- {runner: 2, test-packages: "connect snapshot-agent wan-federation"} +- {runner: 3, test-packages: "cli vault metrics"} +- {runner: 4, test-packages: "api-gateway ingress-gateway sync example consul-dns"} +- {runner: 5, test-packages: "config-entries terminating-gateway basic"} \ No newline at end of file diff --git a/acceptance/framework/cli/cli.go b/acceptance/framework/cli/cli.go index 11a158269f..5297382d94 100644 --- a/acceptance/framework/cli/cli.go +++ b/acceptance/framework/cli/cli.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cli import ( diff --git a/acceptance/framework/config/config.go b/acceptance/framework/config/config.go index a638732c37..cba72db125 100644 --- a/acceptance/framework/config/config.go +++ b/acceptance/framework/config/config.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config import ( @@ -88,15 +85,8 @@ type TestConfig struct { ConsulVersion *version.Version ConsulDataplaneVersion *version.Version EnvoyImage string - ConsulCollectorImage string - - HCPResourceID string - - VaultHelmChartVersion string - VaultServerVersion string NoCleanupOnFailure bool - NoCleanup bool DebugDirectory string UseAKS bool diff --git a/acceptance/framework/config/config_test.go b/acceptance/framework/config/config_test.go index 4d432da3b0..124bfe65f5 100644 --- a/acceptance/framework/config/config_test.go +++ b/acceptance/framework/config/config_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config import ( diff --git a/acceptance/framework/connhelper/connect_helper.go b/acceptance/framework/connhelper/connect_helper.go index 5f140c3368..dc0bf9d402 100644 --- a/acceptance/framework/connhelper/connect_helper.go +++ b/acceptance/framework/connhelper/connect_helper.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connhelper import ( @@ -11,25 +8,21 @@ import ( "time" terratestK8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/hashicorp/consul-k8s/acceptance/framework/config" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/environment" "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" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( StaticClientName = "static-client" StaticServerName = "static-server" - JobName = "job-client" - - retryTimeout = 120 * time.Second ) // ConnectHelper configures a Consul cluster for connect injection tests. @@ -52,7 +45,6 @@ type ConnectHelper struct { // Ctx is used to deploy Consul Ctx environment.TestContext - // UseAppNamespace is used top optionally deploy applications into a separate namespace. // If unset, the namespace associated with Ctx is used. UseAppNamespace bool @@ -66,13 +58,6 @@ type ConnectHelper struct { ConsulClient *api.Client } -// ConnHelperOpts allows for configuring optional parameters to be passed into the -// conn helper methods. This provides added flexibility, although not every value will be used -// by every method. See documentation for more details. -type ConnHelperOpts struct { - ClientType string -} - // Setup creates a new cluster using the New*Cluster function and assigns it // to the consulCluster field. func (c *ConnectHelper) Setup(t *testing.T) { @@ -101,8 +86,6 @@ func (c *ConnectHelper) Upgrade(t *testing.T) { c.consulCluster.Upgrade(t, c.helmValues()) } -// KubectlOptsForApp returns options using the -apps appended namespace if -// UseAppNamespace is enabled. Otherwise, it returns the ctx options. func (c *ConnectHelper) KubectlOptsForApp(t *testing.T) *terratestK8s.KubectlOptions { opts := c.Ctx.KubectlOptions(t) if !c.UseAppNamespace { @@ -123,7 +106,7 @@ func (c *ConnectHelper) DeployClientAndServer(t *testing.T) { // deployments because golang will execute them in reverse order // (i.e. the last registered cleanup function will be executed first). t.Cleanup(func() { - retrier := &retry.Timer{Timeout: retryTimeout, Wait: 100 * time.Millisecond} + retrier := &retry.Timer{Timeout: 30 * time.Second, Wait: 100 * time.Millisecond} retry.RunWith(retrier, t, func(r *retry.R) { tokens, _, err := c.ConsulClient.ACL().TokenList(nil) require.NoError(r, err) @@ -147,28 +130,28 @@ func (c *ConnectHelper) DeployClientAndServer(t *testing.T) { // TODO: A base fixture is the wrong place for these files k8s.KubectlApply(t, opts, "../fixtures/bases/openshift/") - helpers.Cleanup(t, c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, func() { + helpers.Cleanup(t, c.Cfg.NoCleanupOnFailure, func() { k8s.KubectlDelete(t, opts, "../fixtures/bases/openshift/") }) - k8s.DeployKustomize(t, opts, c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, "../fixtures/cases/static-server-openshift") + k8s.DeployKustomize(t, opts, c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-server-openshift") if c.Cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, opts, c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-openshift-tproxy") + k8s.DeployKustomize(t, opts, c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-openshift-tproxy") } else { - k8s.DeployKustomize(t, opts, c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-openshift-inject") + k8s.DeployKustomize(t, opts, c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-openshift-inject") } } else { - k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if c.Cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } } // Check that both static-server and static-client have been injected and // now have 2 containers. retry.RunWith( - &retry.Timer{Timeout: retryTimeout, Wait: 100 * time.Millisecond}, t, + &retry.Timer{Timeout: 30 * time.Second, Wait: 100 * time.Millisecond}, t, func(r *retry.R) { for _, labelSelector := range []string{"app=static-server", "app=static-client"} { podList, err := c.Ctx.KubernetesClient(t).CoreV1(). @@ -184,94 +167,6 @@ func (c *ConnectHelper) DeployClientAndServer(t *testing.T) { }) } -func (c *ConnectHelper) CreateNamespace(t *testing.T, namespace string) { - opts := c.Ctx.KubectlOptions(t) - _, err := k8s.RunKubectlAndGetOutputE(t, opts, "create", "ns", namespace) - if err != nil && strings.Contains(err.Error(), "AlreadyExists") { - return - } - require.NoError(t, err) - helpers.Cleanup(t, c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, func() { - k8s.RunKubectl(t, opts, "delete", "ns", namespace) - }) -} - -// DeployJob deploys a job pod to the Kubernetes -// cluster which will be used to test service mesh connectivity. If the Secure -// flag is true, a pre-check is done to ensure that the ACL tokens for the test -// are deleted. The status of the deployment and injection is checked after the -// deployment is complete to ensure success. -func (c *ConnectHelper) DeployJob(t *testing.T, path string) { - // Check that the ACL token is deleted. - if c.Secure { - // We need to register the cleanup function before we create the - // deployments because golang will execute them in reverse order - // (i.e. the last registered cleanup function will be executed first). - t.Cleanup(func() { - retrier := &retry.Timer{Timeout: 30 * time.Second, Wait: 100 * time.Millisecond} - retry.RunWith(retrier, t, func(r *retry.R) { - tokens, _, err := c.ConsulClient.ACL().TokenList(nil) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, JobName) - } - }) - }) - } - - logger.Log(t, "creating job-client deployment") - k8s.DeployJob(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, path) - - // Check that job-client has been injected and - // now have 2 containers. - for _, labelSelector := range []string{"app=job-client"} { - podList, err := c.Ctx.KubernetesClient(t).CoreV1().Pods(c.Ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } -} - -// DeployServer deploys a server pod to the Kubernetes -// cluster which will be used to test service mesh connectivity. If the Secure -// flag is true, a pre-check is done to ensure that the ACL tokens for the test -// are deleted. The status of the deployment and injection is checked after the -// deployment is complete to ensure success. -func (c *ConnectHelper) DeployServer(t *testing.T) { - // Check that the ACL token is deleted. - if c.Secure { - // We need to register the cleanup function before we create the - // deployments because golang will execute them in reverse order - // (i.e. the last registered cleanup function will be executed first). - t.Cleanup(func() { - retrier := &retry.Timer{Timeout: 30 * time.Second, Wait: 100 * time.Millisecond} - retry.RunWith(retrier, t, func(r *retry.R) { - tokens, _, err := c.ConsulClient.ACL().TokenList(nil) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, StaticServerName) - } - }) - }) - } - - logger.Log(t, "creating static-server deployment") - k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, c.Cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - // Check that static-server has been injected and - // now have 2 containers. - for _, labelSelector := range []string{"app=static-server"} { - podList, err := c.Ctx.KubernetesClient(t).CoreV1().Pods(c.Ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } -} - // SetupAppNamespace creates a namespace where applications are deployed. This // does nothing if UseAppNamespace is not set. The app namespace is relevant // when testing with restricted PSA enforcement enabled. @@ -282,7 +177,14 @@ func (c *ConnectHelper) SetupAppNamespace(t *testing.T) { opts := c.KubectlOptsForApp(t) // If we are deploying apps in another namespace, create the namespace. - c.CreateNamespace(t, opts.Namespace) + _, err := k8s.RunKubectlAndGetOutputE(t, opts, "create", "ns", opts.Namespace) + if err != nil && strings.Contains(err.Error(), "AlreadyExists") { + return + } + require.NoError(t, err) + helpers.Cleanup(t, c.Cfg.NoCleanupOnFailure, func() { + k8s.RunKubectl(t, opts, "delete", "ns", opts.Namespace) + }) if c.Cfg.EnableRestrictedPSAEnforcement { // Allow anything to run in the app namespace. @@ -291,103 +193,48 @@ func (c *ConnectHelper) SetupAppNamespace(t *testing.T) { "pod-security.kubernetes.io/enforce-version=v1.24", ) } -} -// CreateResolverRedirect creates a resolver that redirects to a static-server, a corresponding k8s service, -// 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) - c.SetupAppNamespace(t) - kustomizeDir := "../fixtures/cases/resolver-redirect-virtualip" - k8s.KubectlApplyK(t, opts, kustomizeDir) - - helpers.Cleanup(t, c.Cfg.NoCleanupOnFailure, c.Cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, opts, kustomizeDir) - }) } // TestConnectionFailureWithoutIntention ensures the connection to the static -// server fails when no intentions are configured. When provided with a ClientType option -// the client is overridden, otherwise a default will be used. -func (c *ConnectHelper) TestConnectionFailureWithoutIntention(t *testing.T, connHelperOpts ConnHelperOpts) { +// server fails when no intentions are configured. +func (c *ConnectHelper) TestConnectionFailureWithoutIntention(t *testing.T) { logger.Log(t, "checking that the connection is not successful because there's no intention") opts := c.KubectlOptsForApp(t) - //Default to deploying static-client. If a client type is passed in (ex. job-client), use that instead. - client := StaticClientName - if connHelperOpts.ClientType != "" { - client = connHelperOpts.ClientType - } - if c.Cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionFailing(t, opts, client, "http://static-server") + k8s.CheckStaticServerConnectionFailing(t, opts, StaticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionFailing(t, opts, client, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, opts, StaticClientName, "http://localhost:1234") } } -type IntentionOpts struct { - ConnHelperOpts - SourceNamespace string - DestinationNamespace string -} - // CreateIntention creates an intention for the static-server pod to connect to -// the static-client pod. opts parameter allows for overriding of some fields. If opts is empty -// then all namespaces and clients use defaults. -func (c *ConnectHelper) CreateIntention(t *testing.T, opts IntentionOpts) { +// the static-client pod. +func (c *ConnectHelper) CreateIntention(t *testing.T) { logger.Log(t, "creating intention") - //Default to deploying static-client. If a client type is passed in (ex. job-client), use that instead. - client := StaticClientName - if opts.ClientType != "" { - client = opts.ClientType - } - - sourceNamespace := c.KubectlOptsForApp(t).Namespace - if opts.SourceNamespace != "" { - sourceNamespace = opts.SourceNamespace - } - - destinationNamespace := c.KubectlOptsForApp(t).Namespace - if opts.DestinationNamespace != "" { - destinationNamespace = opts.DestinationNamespace - } - - retrier := &retry.Timer{Timeout: retryTimeout, Wait: 100 * time.Millisecond} - retry.RunWith(retrier, t, func(r *retry.R) { - _, _, err := c.ConsulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: StaticServerName, - Namespace: destinationNamespace, - Sources: []*api.SourceIntention{ - { - Namespace: sourceNamespace, - Name: client, - Action: api.IntentionActionAllow, - }, + _, _, err := c.ConsulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: StaticServerName, + Sources: []*api.SourceIntention{ + { + Name: StaticClientName, + Action: api.IntentionActionAllow, }, - }, nil) - require.NoError(r, err) - }) + }, + }, nil) + require.NoError(t, err) } // TestConnectionSuccess ensures the static-server pod can connect to the -// static-client pod once the intention is set. When provided with a ClientType option -// the client is overridden, otherwise a default will be used. -func (c *ConnectHelper) TestConnectionSuccess(t *testing.T, connHelperOpts ConnHelperOpts) { +// static-client pod once the intention is set. +func (c *ConnectHelper) TestConnectionSuccess(t *testing.T) { logger.Log(t, "checking that connection is successful") opts := c.KubectlOptsForApp(t) - //Default to deploying static-client. If a client type is passed in (ex. job-client), use that instead. - client := StaticClientName - if connHelperOpts.ClientType != "" { - client = connHelperOpts.ClientType - } - if c.Cfg.EnableTransparentProxy { // todo: add an assertion that the traffic is going through the proxy - k8s.CheckStaticServerConnectionSuccessful(t, opts, client, "http://static-server") + k8s.CheckStaticServerConnectionSuccessful(t, opts, StaticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionSuccessful(t, opts, client, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, opts, StaticClientName, "http://localhost:1234") } } @@ -401,7 +248,7 @@ func (c *ConnectHelper) TestConnectionFailureWhenUnhealthy(t *testing.T) { opts := c.KubectlOptsForApp(t) logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, opts, "exec", "deploy/"+StaticServerName, "-c", "static-server", "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, opts, "exec", "deploy/"+StaticServerName, "--", "touch", "/tmp/unhealthy") // The readiness probe should take a moment to be reflected in Consul, // CheckStaticServerConnection will retry until Consul marks the service @@ -426,7 +273,7 @@ func (c *ConnectHelper) TestConnectionFailureWhenUnhealthy(t *testing.T) { } // Return the static-server to a "healthy state". - k8s.RunKubectl(t, opts, "exec", "deploy/"+StaticServerName, "-c", "static-server", "--", "rm", "/tmp/unhealthy") + k8s.RunKubectl(t, opts, "exec", "deploy/"+StaticServerName, "--", "rm", "/tmp/unhealthy") } // helmValues uses the Secure and AutoEncrypt fields to set values for the Helm diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go index a45bcc665c..b90e3134bd 100644 --- a/acceptance/framework/consul/cli_cluster.go +++ b/acceptance/framework/consul/cli_cluster.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consul import ( @@ -45,7 +42,6 @@ type CLICluster struct { kubeConfig string kubeContext string noCleanupOnFailure bool - noCleanup bool debugDirectory string logger terratestLogger.TestLogger cli cli.CLI @@ -110,7 +106,6 @@ func NewCLICluster( kubeConfig: cfg.GetPrimaryKubeEnv().KubeConfig, kubeContext: cfg.GetPrimaryKubeEnv().KubeContext, noCleanupOnFailure: cfg.NoCleanupOnFailure, - noCleanup: cfg.NoCleanup, debugDirectory: cfg.DebugDirectory, logger: logger, cli: *cli, @@ -124,7 +119,7 @@ func (c *CLICluster) Create(t *testing.T) { // Make sure we delete the cluster if we receive an interrupt signal and // register cleanup so that we delete the cluster when test finishes. - helpers.Cleanup(t, c.noCleanupOnFailure, c.noCleanup, func() { + helpers.Cleanup(t, c.noCleanupOnFailure, func() { c.Destroy(t) }) @@ -203,14 +198,9 @@ func (c *CLICluster) Destroy(t *testing.T) { require.NoError(t, err) } -func (c *CLICluster) SetupConsulClient(t *testing.T, secure bool, release ...string) (*api.Client, string) { +func (c *CLICluster) SetupConsulClient(t *testing.T, secure bool) (*api.Client, string) { t.Helper() - releaseName := c.releaseName - if len(release) > 0 { - releaseName = release[0] - } - namespace := c.kubectlOptions.Namespace config := api.DefaultConfig() localPort := terratestk8s.GetAvailablePort(t) @@ -230,13 +220,13 @@ func (c *CLICluster) SetupConsulClient(t *testing.T, secure bool, release ...str // In secondary servers, we don't create a bootstrap token since ACLs are only bootstrapped in the primary. // Instead, we provide a replication token that serves the role of the bootstrap token. - aclSecretName := fmt.Sprintf("%s-consul-bootstrap-acl-token", releaseName) + aclSecretName := fmt.Sprintf("%s-consul-bootstrap-acl-token", c.releaseName) if c.releaseName == CLIReleaseName { aclSecretName = "consul-bootstrap-acl-token" } aclSecret, err := c.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), aclSecretName, metav1.GetOptions{}) if err != nil && errors.IsNotFound(err) { - federationSecret := fmt.Sprintf("%s-consul-federation", releaseName) + federationSecret := fmt.Sprintf("%s-consul-federation", c.releaseName) if c.releaseName == CLIReleaseName { federationSecret = "consul-federation" } @@ -250,8 +240,8 @@ func (c *CLICluster) SetupConsulClient(t *testing.T, secure bool, release ...str } } - serverPod := fmt.Sprintf("%s-consul-server-0", releaseName) - if releaseName == CLIReleaseName { + serverPod := fmt.Sprintf("%s-consul-server-0", c.releaseName) + if c.releaseName == CLIReleaseName { serverPod = "consul-server-0" } tunnel := terratestk8s.NewTunnelWithLogger( diff --git a/acceptance/framework/consul/cluster.go b/acceptance/framework/consul/cluster.go index 1b9a543245..41dbec86f8 100644 --- a/acceptance/framework/consul/cluster.go +++ b/acceptance/framework/consul/cluster.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consul import ( @@ -12,7 +9,7 @@ import ( // Cluster represents a consul cluster object. type Cluster interface { // SetupConsulClient returns a new Consul client. - SetupConsulClient(t *testing.T, secure bool, release ...string) (*api.Client, string) + SetupConsulClient(t *testing.T, secure bool) (*api.Client, string) // Create creates a new Consul Cluster. Create(t *testing.T) diff --git a/acceptance/framework/consul/helm_cluster.go b/acceptance/framework/consul/helm_cluster.go index 81787ebfc3..3f4d31173d 100644 --- a/acceptance/framework/consul/helm_cluster.go +++ b/acceptance/framework/consul/helm_cluster.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consul import ( @@ -18,7 +15,6 @@ import ( "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/portforward" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" @@ -27,11 +23,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" "k8s.io/client-go/kubernetes" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) // HelmCluster implements Cluster and uses Helm @@ -49,10 +41,8 @@ type HelmCluster struct { ctx environment.TestContext helmOptions *helm.Options releaseName string - runtimeClient client.Client kubernetesClient kubernetes.Interface noCleanupOnFailure bool - noCleanup bool debugDirectory string logger terratestLogger.TestLogger } @@ -105,10 +95,8 @@ func NewHelmCluster( ctx: ctx, helmOptions: opts, releaseName: releaseName, - runtimeClient: ctx.ControllerRuntimeClient(t), kubernetesClient: ctx.KubernetesClient(t), noCleanupOnFailure: cfg.NoCleanupOnFailure, - noCleanup: cfg.NoCleanup, debugDirectory: cfg.DebugDirectory, logger: logger, } @@ -119,7 +107,7 @@ func (h *HelmCluster) Create(t *testing.T) { // Make sure we delete the cluster if we receive an interrupt signal and // register cleanup so that we delete the cluster when test finishes. - helpers.Cleanup(t, h.noCleanupOnFailure, h.noCleanup, func() { + helpers.Cleanup(t, h.noCleanupOnFailure, func() { h.Destroy(t) }) @@ -155,47 +143,14 @@ func (h *HelmCluster) Destroy(t *testing.T) { "--wait": nil, } - // Clean up any stuck gateway resources, note that we swallow all errors from - // here down since the terratest helm installation may actually already be - // deleted at this point, in which case these operations will fail on non-existent - // CRD cleanups. - requirement, err := labels.NewRequirement("release", selection.Equals, []string{h.releaseName}) - require.NoError(t, err) - - // Forcibly delete all gateway classes and remove their finalizers. - _ = h.runtimeClient.DeleteAllOf(context.Background(), &gwv1beta1.GatewayClass{}, client.HasLabels{"release=" + h.releaseName}) - - var gatewayClassList gwv1beta1.GatewayClassList - if h.runtimeClient.List(context.Background(), &gatewayClassList, &client.ListOptions{ - LabelSelector: labels.NewSelector().Add(*requirement), - }) == nil { - for _, item := range gatewayClassList.Items { - item.SetFinalizers([]string{}) - _ = h.runtimeClient.Update(context.Background(), &item) - } - } - - // Forcibly delete all gateway class configs and remove their finalizers. - _ = h.runtimeClient.DeleteAllOf(context.Background(), &v1alpha1.GatewayClassConfig{}, client.HasLabels{"release=" + h.releaseName}) - - var gatewayClassConfigList v1alpha1.GatewayClassConfigList - if h.runtimeClient.List(context.Background(), &gatewayClassConfigList, &client.ListOptions{ - LabelSelector: labels.NewSelector().Add(*requirement), - }) == nil { - for _, item := range gatewayClassConfigList.Items { - item.SetFinalizers([]string{}) - _ = h.runtimeClient.Update(context.Background(), &item) - } - } - - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 30}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 15}, t, func(r *retry.R) { err := helm.DeleteE(t, h.helmOptions, h.releaseName, false) require.NoError(r, err) }) // Retry because sometimes certain resources (like PVC) take time to delete // in cloud providers. - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 600}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 600}, t, func(r *retry.R) { // Force delete any pods that have h.releaseName in their name because sometimes // graceful termination takes a long time and since this is an uninstall // we don't care that they're stopped gracefully. @@ -348,23 +303,14 @@ func (h *HelmCluster) Upgrade(t *testing.T, helmValues map[string]string) { k8s.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) } -func (h *HelmCluster) CreatePortForwardTunnel(t *testing.T, remotePort int, release ...string) string { - releaseName := h.releaseName - if len(release) > 0 { - releaseName = release[0] - } - serverPod := fmt.Sprintf("%s-consul-server-0", releaseName) +func (h *HelmCluster) CreatePortForwardTunnel(t *testing.T, remotePort int) string { + serverPod := fmt.Sprintf("%s-consul-server-0", h.releaseName) return portforward.CreateTunnelToResourcePort(t, serverPod, remotePort, h.helmOptions.KubectlOptions, h.logger) } -func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool, release ...string) (client *api.Client, configAddress string) { +func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool) (client *api.Client, configAddress string) { t.Helper() - releaseName := h.releaseName - if len(release) > 0 { - releaseName = release[0] - } - namespace := h.helmOptions.KubectlOptions.Namespace config := api.DefaultConfig() remotePort := 8500 // use non-secure by default @@ -381,15 +327,15 @@ func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool, release ...st if h.ACLToken != "" { config.Token = h.ACLToken } else { - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 600}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 600}, t, func(r *retry.R) { // Get the ACL token. First, attempt to read it from the bootstrap token (this will be true in primary Consul servers). // If the bootstrap token doesn't exist, it means we are running against a secondary cluster // and will try to read the replication token from the federation secret. // In secondary servers, we don't create a bootstrap token since ACLs are only bootstrapped in the primary. // Instead, we provide a replication token that serves the role of the bootstrap token. - aclSecret, err := h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), releaseName+"-consul-bootstrap-acl-token", metav1.GetOptions{}) + aclSecret, err := h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), h.releaseName+"-consul-bootstrap-acl-token", metav1.GetOptions{}) if err != nil && errors.IsNotFound(err) { - federationSecret := fmt.Sprintf("%s-consul-federation", releaseName) + federationSecret := fmt.Sprintf("%s-consul-federation", h.releaseName) aclSecret, err = h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), federationSecret, metav1.GetOptions{}) require.NoError(r, err) config.Token = string(aclSecret.Data["replicationToken"]) @@ -403,7 +349,7 @@ func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool, release ...st } } - config.Address = h.CreatePortForwardTunnel(t, remotePort, release...) + config.Address = h.CreatePortForwardTunnel(t, remotePort) consulClient, err := api.NewClient(config) require.NoError(t, err) @@ -510,7 +456,7 @@ func configurePodSecurityPolicies(t *testing.T, client kubernetes.Interface, cfg } } - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { _ = client.PolicyV1beta1().PodSecurityPolicies().Delete(context.Background(), pspName, metav1.DeleteOptions{}) _ = client.RbacV1().ClusterRoles().Delete(context.Background(), pspName, metav1.DeleteOptions{}) _ = client.RbacV1().RoleBindings(namespace).Delete(context.Background(), pspName, metav1.DeleteOptions{}) @@ -561,7 +507,7 @@ func configureSCCs(t *testing.T, client kubernetes.Interface, cfg *config.TestCo } } - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { _ = client.RbacV1().RoleBindings(namespace).Delete(context.Background(), anyuidRoleBinding, metav1.DeleteOptions{}) _ = client.RbacV1().RoleBindings(namespace).Delete(context.Background(), privilegedRoleBinding, metav1.DeleteOptions{}) }) @@ -585,7 +531,7 @@ func defaultValues() map[string]string { func CreateK8sSecret(t *testing.T, client kubernetes.Interface, cfg *config.TestConfig, namespace, secretName, secretKey, secret string) { - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 15}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * 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{ @@ -603,7 +549,7 @@ func CreateK8sSecret(t *testing.T, client kubernetes.Interface, cfg *config.Test } }) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { _ = client.CoreV1().Secrets(namespace).Delete(context.Background(), secretName, metav1.DeleteOptions{}) }) } diff --git a/acceptance/framework/consul/helm_cluster_test.go b/acceptance/framework/consul/helm_cluster_test.go index 011ca23e0f..1f7b8b7d58 100644 --- a/acceptance/framework/consul/helm_cluster_test.go +++ b/acceptance/framework/consul/helm_cluster_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consul import ( @@ -12,8 +9,6 @@ import ( "github.com/stretchr/testify/require" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/client" - runtimefake "sigs.k8s.io/controller-runtime/pkg/client/fake" ) // Test that if TestConfig has values that need to be provided @@ -87,8 +82,5 @@ func (c *ctx) KubectlOptionsForNamespace(ns string) *k8s.KubectlOptions { func (c *ctx) KubernetesClient(_ *testing.T) kubernetes.Interface { return fake.NewSimpleClientset() } -func (c *ctx) ControllerRuntimeClient(_ *testing.T) client.Client { - return runtimefake.NewClientBuilder().Build() -} var _ environment.TestContext = (*ctx)(nil) diff --git a/acceptance/framework/environment/cni-kind/custom-resources.yaml b/acceptance/framework/environment/cni-kind/custom-resources.yaml index 9a87195041..1d2e08da56 100644 --- a/acceptance/framework/environment/cni-kind/custom-resources.yaml +++ b/acceptance/framework/environment/cni-kind/custom-resources.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # This section includes base Calico installation configuration. # For more information, see: https://projectcalico.docs.tigera.io/master/reference/installation/api#operator.tigera.io/v1.Installation apiVersion: operator.tigera.io/v1 diff --git a/acceptance/framework/environment/cni-kind/tigera-operator.yaml b/acceptance/framework/environment/cni-kind/tigera-operator.yaml index 8114b6f596..f13e65ceb0 100644 --- a/acceptance/framework/environment/cni-kind/tigera-operator.yaml +++ b/acceptance/framework/environment/cni-kind/tigera-operator.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Namespace metadata: diff --git a/acceptance/framework/environment/environment.go b/acceptance/framework/environment/environment.go index 7014a3c05f..96245cfde3 100644 --- a/acceptance/framework/environment/environment.go +++ b/acceptance/framework/environment/environment.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package environment import ( @@ -9,15 +6,9 @@ import ( "github.com/gruntwork-io/terratest/modules/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) const ( @@ -38,7 +29,6 @@ type TestContext interface { // TODO: I don't love this. KubectlOptionsForNamespace(ns string) *k8s.KubectlOptions KubernetesClient(t *testing.T) kubernetes.Interface - ControllerRuntimeClient(t *testing.T) client.Client } type KubernetesEnvironment struct { @@ -83,9 +73,7 @@ type kubernetesContext struct { kubeContextName string namespace string - client kubernetes.Interface - runtimeClient client.Client - + client kubernetes.Interface options *k8s.KubectlOptions } @@ -172,31 +160,6 @@ func (k kubernetesContext) KubernetesClient(t *testing.T) kubernetes.Interface { return k.client } -func (k kubernetesContext) ControllerRuntimeClient(t *testing.T) client.Client { - if k.runtimeClient != nil { - return k.runtimeClient - } - - options := k.KubectlOptions(t) - configPath, err := options.GetConfigPath(t) - require.NoError(t, err) - config, err := k8s.LoadApiClientConfigE(configPath, options.ContextName) - require.NoError(t, err) - - s := runtime.NewScheme() - require.NoError(t, clientgoscheme.AddToScheme(s)) - require.NoError(t, gwv1alpha2.Install(s)) - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - client, err := client.New(config, client.Options{Scheme: s}) - require.NoError(t, err) - - k.runtimeClient = client - - return k.runtimeClient -} - func NewContext(namespace, pathToKubeConfig, kubeContextName string) *kubernetesContext { return &kubernetesContext{ namespace: namespace, diff --git a/acceptance/framework/flags/flags.go b/acceptance/framework/flags/flags.go index ce8e1ea726..3e9b733047 100644 --- a/acceptance/framework/flags/flags.go +++ b/acceptance/framework/flags/flags.go @@ -39,14 +39,8 @@ type TestFlags struct { flagConsulVersion string flagConsulDataplaneVersion string flagEnvoyImage string - flagConsulCollectorImage string - flagVaultHelmChartVersion string - flagVaultServerVersion string - - flagHCPResourceID string flagNoCleanupOnFailure bool - flagNoCleanup bool flagDebugDirectory string @@ -87,16 +81,12 @@ func (t *TestFlags) init() { flag.StringVar(&t.flagConsulDataplaneVersion, "consul-dataplane-version", "", "The consul-dataplane version used for all tests.") flag.StringVar(&t.flagHelmChartVersion, "helm-chart-version", config.HelmChartPath, "The helm chart used for all tests.") flag.StringVar(&t.flagEnvoyImage, "envoy-image", "", "The Envoy image to use for all tests.") - flag.StringVar(&t.flagConsulCollectorImage, "consul-collector-image", "", "The consul collector image to use for all tests.") - flag.StringVar(&t.flagVaultServerVersion, "vault-server-version", "", "The vault serverversion used for all tests.") - flag.StringVar(&t.flagVaultHelmChartVersion, "vault-helm-chart-version", "", "The Vault helm chart used for all tests.") flag.Var(&t.flagKubeconfigs, "kubeconfigs", "The list of paths to a kubeconfig files. If this is blank, "+ "the default kubeconfig path (~/.kube/config) will be used.") flag.Var(&t.flagKubecontexts, "kube-contexts", "The list of names of the Kubernetes contexts to use. If this is blank, "+ "the context set as the current context will be used by default.") flag.Var(&t.flagKubeNamespaces, "kube-namespaces", "The list of Kubernetes namespaces to use for tests.") - flag.StringVar(&t.flagHCPResourceID, "hcp-resource-id", "", "The hcp resource id to use for all tests.") flag.BoolVar(&t.flagEnableMultiCluster, "enable-multi-cluster", false, "If true, the tests that require multiple Kubernetes clusters will be run. "+ @@ -133,9 +123,6 @@ func (t *TestFlags) init() { "If true, the tests will not cleanup Kubernetes resources they create when they finish running."+ "Note this flag must be run with -failfast flag, otherwise subsequent tests will fail.") - flag.BoolVar(&t.flagNoCleanup, "no-cleanup", false, - "If true, the tests will not cleanup Kubernetes resources for Vault test") - flag.StringVar(&t.flagDebugDirectory, "debug-directory", "", "The directory where to write debug information about failed test runs, "+ "such as logs and pod definitions. If not provided, a temporary directory will be created by the tests.") @@ -198,7 +185,6 @@ func (t *TestFlags) TestConfigFromFlags() *config.TestConfig { kubeEnvs := config.NewKubeTestConfigList(t.flagKubeconfigs, t.flagKubecontexts, t.flagKubeNamespaces) c := &config.TestConfig{ - EnableEnterprise: t.flagEnableEnterprise, EnterpriseLicense: t.flagEnterpriseLicense, @@ -223,14 +209,8 @@ func (t *TestFlags) TestConfigFromFlags() *config.TestConfig { ConsulVersion: consulVersion, ConsulDataplaneVersion: consulDataplaneVersion, EnvoyImage: t.flagEnvoyImage, - ConsulCollectorImage: t.flagConsulCollectorImage, - VaultHelmChartVersion: t.flagVaultHelmChartVersion, - VaultServerVersion: t.flagVaultServerVersion, - - HCPResourceID: t.flagHCPResourceID, NoCleanupOnFailure: t.flagNoCleanupOnFailure, - NoCleanup: t.flagNoCleanup, DebugDirectory: tempDir, UseAKS: t.flagUseAKS, UseEKS: t.flagUseEKS, diff --git a/acceptance/framework/flags/flags_test.go b/acceptance/framework/flags/flags_test.go index 1e2bf0a039..05e9ab19c0 100644 --- a/acceptance/framework/flags/flags_test.go +++ b/acceptance/framework/flags/flags_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index f8b1d2f15d..5f99a682ae 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helpers import ( @@ -38,7 +35,7 @@ func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, optio // Check if there's an existing cluster and fail if there is one. // We may need to retry since this is the first command run once the Kube // cluster is created and sometimes the API server returns errors. - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 15}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 15}, t, func(r *retry.R) { var err error // NOTE: It's okay to pass in `t` to RunHelmCommandAndGetOutputE despite being in a retry // because we're using RunHelmCommandAndGetOutputE (not RunHelmCommandAndGetOutput) so the `t` won't @@ -58,7 +55,7 @@ func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, optio // Wait for all pods in the "default" namespace to exit. A previous // release may not be listed by Helm but its pods may still be terminating. - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 60}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(options.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: labelSelector}) require.NoError(r, err) if len(pods.Items) > 0 { @@ -87,7 +84,7 @@ func SetupInterruptHandler(cleanup func()) { // Cleanup will both register a cleanup function with t // and SetupInterruptHandler to make sure resources get cleaned up // if an interrupt signal is caught. -func Cleanup(t *testing.T, noCleanupOnFailure bool, noCleanup bool, cleanup func()) { +func Cleanup(t *testing.T, noCleanupOnFailure bool, cleanup func()) { t.Helper() // Always clean up when an interrupt signal is caught. @@ -97,7 +94,7 @@ func Cleanup(t *testing.T, noCleanupOnFailure bool, noCleanup bool, cleanup func // We need to wrap the cleanup function because t that is passed in to this function // might not have the information on whether the test has failed yet. wrappedCleanupFunc := func() { - if !((noCleanupOnFailure && t.Failed()) || noCleanup) { + if !(noCleanupOnFailure && t.Failed()) { logger.Logf(t, "cleaning up resources for %s", t.Name()) cleanup() } else { diff --git a/acceptance/framework/helpers/helpers_test.go b/acceptance/framework/helpers/helpers_test.go index 2a994d7f9f..c1b4a916e2 100644 --- a/acceptance/framework/helpers/helpers_test.go +++ b/acceptance/framework/helpers/helpers_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helpers import ( diff --git a/acceptance/framework/k8s/debug.go b/acceptance/framework/k8s/debug.go index 773769fced..5bf588f959 100644 --- a/acceptance/framework/k8s/debug.go +++ b/acceptance/framework/k8s/debug.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package k8s import ( diff --git a/acceptance/framework/k8s/deploy.go b/acceptance/framework/k8s/deploy.go index e60f4c4730..869ebdd804 100644 --- a/acceptance/framework/k8s/deploy.go +++ b/acceptance/framework/k8s/deploy.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package k8s import ( @@ -16,13 +13,12 @@ import ( "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" v1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" "k8s.io/apimachinery/pkg/util/yaml" ) // Deploy creates a Kubernetes deployment by applying configuration stored at filepath, // sets up a cleanup function and waits for the deployment to become available. -func Deploy(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, noCleanup bool, debugDirectory string, filepath string) { +func Deploy(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, debugDirectory string, filepath string) { t.Helper() KubectlApply(t, options, filepath) @@ -34,7 +30,7 @@ func Deploy(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, err = yaml.NewYAMLOrJSONDecoder(file, 1024).Decode(&deployment) require.NoError(t, err) - helpers.Cleanup(t, noCleanupOnFailure, noCleanup, func() { + helpers.Cleanup(t, noCleanupOnFailure, func() { // Note: this delete command won't wait for pods to be fully terminated. // This shouldn't cause any test pollution because the underlying // objects are deployments, and so when other tests create these @@ -48,7 +44,7 @@ func Deploy(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, // DeployKustomize creates a Kubernetes deployment by applying the kustomize directory stored at kustomizeDir, // sets up a cleanup function and waits for the deployment to become available. -func DeployKustomize(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, noCleanup bool, debugDirectory string, kustomizeDir string) { +func DeployKustomize(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, debugDirectory string, kustomizeDir string) { t.Helper() KubectlApplyK(t, options, kustomizeDir) @@ -60,7 +56,7 @@ func DeployKustomize(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailu err = yaml.NewYAMLOrJSONDecoder(strings.NewReader(output), 1024).Decode(&deployment) require.NoError(t, err) - helpers.Cleanup(t, noCleanupOnFailure, noCleanup, func() { + helpers.Cleanup(t, noCleanupOnFailure, func() { // Note: this delete command won't wait for pods to be fully terminated. // This shouldn't cause any test pollution because the underlying // objects are deployments, and so when other tests create these @@ -73,32 +69,6 @@ func DeployKustomize(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailu RunKubectl(t, options, "wait", "--for=condition=available", "--timeout=5m", fmt.Sprintf("deploy/%s", deployment.Name)) } -func DeployJob(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, noCleanup bool, debugDirectory, kustomizeDir string) { - t.Helper() - - KubectlApplyK(t, options, kustomizeDir) - - output, err := RunKubectlAndGetOutputE(t, options, "kustomize", kustomizeDir) - require.NoError(t, err) - - job := batchv1.Job{} - err = yaml.NewYAMLOrJSONDecoder(strings.NewReader(output), 1024).Decode(&job) - require.NoError(t, err) - - helpers.Cleanup(t, noCleanupOnFailure, noCleanup, func() { - // Note: this delete command won't wait for pods to be fully terminated. - // This shouldn't cause any test pollution because the underlying - // objects are deployments, and so when other tests create these - // they should have different pod names. - WritePodsDebugInfoIfFailed(t, options, debugDirectory, labelMapToString(job.GetLabels())) - KubectlDeleteK(t, options, kustomizeDir) - }) - logger.Log(t, "job deployed") - - // Because Jobs don't have a "started" condition, we have to check the status of the Pods they create. - RunKubectl(t, options, "wait", "--for=condition=Ready", "--timeout=5m", "pods", "--selector", fmt.Sprintf("job-name=%s", job.Name)) -} - // CheckStaticServerConnection execs into a pod of sourceApp // and runs a curl command with the provided curlArgs. // This function assumes that the connection is made to the static-server and expects the output @@ -120,10 +90,7 @@ func CheckStaticServerConnection(t *testing.T, options *k8s.KubectlOptions, sour // on the existence of any of them. func CheckStaticServerConnectionMultipleFailureMessages(t *testing.T, options *k8s.KubectlOptions, sourceApp string, expectSuccess bool, failureMessages []string, expectedSuccessOutput string, curlArgs ...string) { t.Helper() - resourceType := "deploy/" - if sourceApp == "job-client" { - resourceType = "jobs/" - } + expectedOutput := "hello world" if expectedSuccessOutput != "" { expectedOutput = expectedSuccessOutput @@ -131,7 +98,7 @@ func CheckStaticServerConnectionMultipleFailureMessages(t *testing.T, options *k retrier := &retry.Timer{Timeout: 320 * time.Second, Wait: 2 * time.Second} - args := []string{"exec", resourceType + sourceApp, "-c", sourceApp, "--", "curl", "-vvvsSf"} + args := []string{"exec", "deploy/" + sourceApp, "-c", sourceApp, "--", "curl", "-vvvsSf"} args = append(args, curlArgs...) retry.RunWith(retrier, t, func(r *retry.R) { @@ -183,15 +150,6 @@ func CheckStaticServerConnectionFailing(t *testing.T, options *k8s.KubectlOption }, "", curlArgs...) } -// CheckStaticServerHTTPConnectionFailing is just like CheckStaticServerConnectionFailing -// except with HTTP-based intentions. -func CheckStaticServerHTTPConnectionFailing(t *testing.T, options *k8s.KubectlOptions, sourceApp string, curlArgs ...string) { - t.Helper() - CheckStaticServerConnection(t, options, sourceApp, false, []string{ - "curl: (22) The requested URL returned error: 403", - }, "", curlArgs...) -} - // labelMapToString takes a label map[string]string // and returns the string-ified version of, e.g app=foo,env=dev. func labelMapToString(labelMap map[string]string) string { diff --git a/acceptance/framework/k8s/helpers.go b/acceptance/framework/k8s/helpers.go index a6b4d1ca7c..7c3205928f 100644 --- a/acceptance/framework/k8s/helpers.go +++ b/acceptance/framework/k8s/helpers.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package k8s import ( @@ -43,10 +40,10 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac logger.Logf(t, "Waiting for pods with label %q to be ready.", podLabelSelector) - // Wait up to 20m. + // Wait up to 11m. // On Azure, volume provisioning can sometimes take close to 5 min, // so we need to give a bit more time for pods to become healthy. - counter := &retry.Counter{Count: 20 * 60, Wait: 2 * time.Second} + counter := &retry.Counter{Count: 11 * 60, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) @@ -113,7 +110,7 @@ func ServiceHost(t *testing.T, cfg *config.TestConfig, ctx environment.TestConte var host string // It can take some time for the load balancers to be ready and have an IP/Hostname. // Wait for 5 minutes before failing. - retry.RunWith(&retry.Counter{Wait: 2 * time.Second, Count: 600}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 600}, t, func(r *retry.R) { svc, err := ctx.KubernetesClient(t).CoreV1().Services(ctx.KubectlOptions(t).Namespace).Get(context.Background(), serviceName, metav1.GetOptions{}) require.NoError(t, err) require.NotEmpty(r, svc.Status.LoadBalancer.Ingress) diff --git a/acceptance/framework/k8s/kubectl.go b/acceptance/framework/k8s/kubectl.go index 2e37b9bd0a..e766395f47 100644 --- a/acceptance/framework/k8s/kubectl.go +++ b/acceptance/framework/k8s/kubectl.go @@ -1,10 +1,6 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package k8s import ( - "fmt" "strings" "testing" "time" @@ -17,10 +13,6 @@ import ( "github.com/stretchr/testify/require" ) -const ( - kubectlTimeout = "--timeout=120s" -) - // kubeAPIConnectErrs are errors that sometimes occur when talking to the // Kubernetes API related to connection issues. var kubeAPIConnectErrs = []string{ @@ -61,7 +53,7 @@ func RunKubectlAndGetOutputWithLoggerE(t *testing.T, options *k8s.KubectlOptions } counter := &retry.Counter{ - Count: 10, + Count: 3, Wait: 1 * time.Second, } var output string @@ -102,7 +94,7 @@ func KubectlApplyK(t *testing.T, options *k8s.KubectlOptions, kustomizeDir strin // deletes it from the cluster by running 'kubectl delete -f'. // If there's an error deleting the file, fail the test. func KubectlDelete(t *testing.T, options *k8s.KubectlOptions, configPath string) { - _, err := RunKubectlAndGetOutputE(t, options, "delete", kubectlTimeout, "-f", configPath) + _, err := RunKubectlAndGetOutputE(t, options, "delete", "--timeout=60s", "-f", configPath) require.NoError(t, err) } @@ -112,21 +104,7 @@ func KubectlDelete(t *testing.T, options *k8s.KubectlOptions, configPath string) func KubectlDeleteK(t *testing.T, options *k8s.KubectlOptions, kustomizeDir string) { // Ignore not found errors because Kubernetes automatically cleans up the kube secrets that we deployed // referencing the ServiceAccount when it is deleted. - _, err := RunKubectlAndGetOutputE(t, options, "delete", kubectlTimeout, "--ignore-not-found", "-k", kustomizeDir) - require.NoError(t, err) -} - -// KubectlScale takes a deployment and scales it to the provided number of replicas. -func KubectlScale(t *testing.T, options *k8s.KubectlOptions, deployment string, replicas int) { - _, err := RunKubectlAndGetOutputE(t, options, "scale", kubectlTimeout, fmt.Sprintf("--replicas=%d", replicas), deployment) - require.NoError(t, err) -} - -// KubectlLabel takes an object and applies the given label to it. -// Example: `KubectlLabel(t, options, "node", nodeId, corev1.LabelTopologyRegion, "us-east-1")`. -func KubectlLabel(t *testing.T, options *k8s.KubectlOptions, objectType string, objectId string, key string, value string) { - // `kubectl label` doesn't support timeouts - _, err := RunKubectlAndGetOutputE(t, options, "label", objectType, objectId, "--overwrite", fmt.Sprintf("%s=%s", key, value)) + _, err := RunKubectlAndGetOutputE(t, options, "delete", "--timeout=60s", "--ignore-not-found", "-k", kustomizeDir) require.NoError(t, err) } diff --git a/acceptance/framework/logger/logger.go b/acceptance/framework/logger/logger.go index 26777c4e22..c186e77436 100644 --- a/acceptance/framework/logger/logger.go +++ b/acceptance/framework/logger/logger.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package logger import ( diff --git a/acceptance/framework/portforward/port_forward.go b/acceptance/framework/portforward/port_forward.go index 3242541cc5..30f4aed157 100644 --- a/acceptance/framework/portforward/port_forward.go +++ b/acceptance/framework/portforward/port_forward.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package portforward import ( @@ -27,7 +24,7 @@ func CreateTunnelToResourcePort(t *testing.T, resourceName string, remotePort in logger) // Retry creating the port forward since it can fail occasionally. - retry.RunWith(&retry.Counter{Wait: 5 * time.Second, Count: 60}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 3 * time.Second, Count: 60}, t, func(r *retry.R) { // NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry // because we're using ForwardPortE (not ForwardPort) so the `t` won't // get used to fail the test, just for logging. diff --git a/acceptance/framework/suite/suite.go b/acceptance/framework/suite/suite.go index 5d93d2c23f..67dff4f587 100644 --- a/acceptance/framework/suite/suite.go +++ b/acceptance/framework/suite/suite.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package suite import ( diff --git a/acceptance/framework/vault/helpers.go b/acceptance/framework/vault/helpers.go index d086e10391..4726e246ae 100644 --- a/acceptance/framework/vault/helpers.go +++ b/acceptance/framework/vault/helpers.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( @@ -170,20 +167,6 @@ func (config *KV2Secret) SaveSecretAndAddReadPolicy(t *testing.T, vaultClient *v path "%s" { capabilities = ["read"] }`, config.Path) - config.saveSecretAndAddPolicy(t, vaultClient, policy) -} - -// SaveSecretAndAddUpdatePolicy will create an update policy for the PolicyName -// on the KV2Secret and then will save the secret in the KV2 store. -func (config *KV2Secret) SaveSecretAndAddUpdatePolicy(t *testing.T, vaultClient *vapi.Client) { - policy := fmt.Sprintf(` - path "%s" { - capabilities = ["read", "update"] - }`, config.Path) - config.saveSecretAndAddPolicy(t, vaultClient, policy) -} - -func (config *KV2Secret) saveSecretAndAddPolicy(t *testing.T, vaultClient *vapi.Client, policy string) { // Create the Vault Policy for the secret. logger.Log(t, "Creating policy") err := vaultClient.Sys().PutPolicy(config.PolicyName, policy) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index 8b82e41841..dd6cbe4a68 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -1,13 +1,8 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( "context" "fmt" - "os" - "strings" "testing" "time" @@ -15,7 +10,6 @@ import ( terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" terratestLogger "github.com/gruntwork-io/terratest/modules/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/environment" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" @@ -47,7 +41,6 @@ type VaultCluster struct { kubernetesClient kubernetes.Interface noCleanupOnFailure bool - noCleanup bool debugDirectory string logger terratestLogger.TestLogger } @@ -58,45 +51,18 @@ func NewVaultCluster(t *testing.T, ctx environment.TestContext, cfg *config.Test logger := terratestLogger.New(logger.TestLogger{}) kopts := ctx.KubectlOptions(t) - ns := ctx.KubectlOptions(t).Namespace - - entstr := "-ent" values := defaultHelmValues(releaseName) if cfg.EnablePodSecurityPolicies { values["global.psp.enable"] = "true" } - vaultReleaseName := helpers.RandomName() - k8sClient := environment.KubernetesClientFromOptions(t, ctx.KubectlOptions(t)) - vaultLicenseSecretName := fmt.Sprintf("%s-enterprise-license", vaultReleaseName) - vaultLicenseSecretKey := "license" - - vaultEnterpriseLicense := os.Getenv("VAULT_LICENSE") - - if cfg.VaultServerVersion != "" { - - if strings.Contains(cfg.VaultServerVersion, entstr) { - - logger.Logf(t, "Creating secret for Vault license") - consul.CreateK8sSecret(t, k8sClient, cfg, ns, vaultLicenseSecretName, vaultLicenseSecretKey, vaultEnterpriseLicense) - - values["server.image.repository"] = "docker.mirror.hashicorp.services/hashicorp/vault-enterprise" - values["server.enterpriseLicense.secretName"] = vaultLicenseSecretName - values["server.enterpriseLicense.secretKey"] = vaultLicenseSecretKey - } - values["server.image.tag"] = cfg.VaultServerVersion - } - vaultHelmChartVersion := defaultVaultHelmChartVersion - if cfg.VaultHelmChartVersion != "" { - vaultHelmChartVersion = cfg.VaultHelmChartVersion - } helpers.MergeMaps(values, helmValues) vaultHelmOpts := &helm.Options{ SetValues: values, KubectlOptions: kopts, Logger: logger, - Version: vaultHelmChartVersion, + Version: defaultVaultHelmChartVersion, } helm.AddRepo(t, vaultHelmOpts, "hashicorp", "https://helm.releases.hashicorp.com") @@ -113,7 +79,6 @@ func NewVaultCluster(t *testing.T, ctx environment.TestContext, cfg *config.Test kubectlOptions: kopts, kubernetesClient: ctx.KubernetesClient(t), noCleanupOnFailure: cfg.NoCleanupOnFailure, - noCleanup: cfg.NoCleanup, debugDirectory: cfg.DebugDirectory, logger: logger, releaseName: releaseName, @@ -145,7 +110,7 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { v.logger) // Retry creating the port forward since it can fail occasionally. - retry.RunWith(&retry.Counter{Wait: 5 * time.Second, Count: 60}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { // NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry // because we're using ForwardPortE (not ForwardPort) so the `t` won't // get used to fail the test, just for logging. @@ -249,7 +214,7 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext, vaultNa // Make sure we delete the cluster if we receive an interrupt signal and // register cleanup so that we delete the cluster when test finishes. - helpers.Cleanup(t, v.noCleanupOnFailure, v.noCleanup, func() { + helpers.Cleanup(t, v.noCleanupOnFailure, func() { v.Destroy(t) }) @@ -371,7 +336,7 @@ func (v *VaultCluster) createTLSCerts(t *testing.T) { require.NoError(t, err) t.Cleanup(func() { - if !(v.noCleanupOnFailure || v.noCleanup) { + if !v.noCleanupOnFailure { // We're ignoring error here because secret deletion is best-effort. _ = v.kubernetesClient.CoreV1().Secrets(namespace).Delete(context.Background(), certSecretName(v.releaseName), metav1.DeleteOptions{}) _ = v.kubernetesClient.CoreV1().Secrets(namespace).Delete(context.Background(), CASecretName(v.releaseName), metav1.DeleteOptions{}) @@ -444,7 +409,7 @@ func (v *VaultCluster) initAndUnseal(t *testing.T) { rootTokenSecret := fmt.Sprintf("%s-vault-root-token", v.releaseName) v.logger.Logf(t, "saving Vault root token to %q Kubernetes secret", rootTokenSecret) - helpers.Cleanup(t, v.noCleanupOnFailure, v.noCleanup, func() { + helpers.Cleanup(t, v.noCleanupOnFailure, func() { _ = v.kubernetesClient.CoreV1().Secrets(namespace).Delete(context.Background(), rootTokenSecret, metav1.DeleteOptions{}) }) _, err := v.kubernetesClient.CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{ diff --git a/acceptance/go.mod b/acceptance/go.mod index 1dd344a5c8..501d7e0a7b 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -1,145 +1,104 @@ module github.com/hashicorp/consul-k8s/acceptance -go 1.20 +go 1.19 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul-k8s/control-plane v0.0.0-20230609143603-198c4433d892 - github.com/hashicorp/consul/api v1.22.0-rc1 - github.com/hashicorp/consul/sdk v0.14.0-rc1 + github.com/hashicorp/consul-k8s/control-plane v0.0.0-20221117191905-0b1cc2b631e3 + github.com/hashicorp/consul/api v1.17.0 + github.com/hashicorp/consul/sdk v0.13.0 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 - github.com/hashicorp/hcp-sdk-go v0.50.0 - github.com/hashicorp/serf v0.10.1 - github.com/hashicorp/vault/api v1.8.3 - github.com/stretchr/testify v1.8.3 + github.com/hashicorp/vault/api v1.2.0 + github.com/stretchr/testify v1.7.2 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.26.3 - k8s.io/apimachinery v0.26.3 - k8s.io/client-go v0.26.3 - k8s.io/utils v0.0.0-20230209194617-a36077c30491 - sigs.k8s.io/controller-runtime v0.14.6 - sigs.k8s.io/gateway-api v0.7.1 + k8s.io/api v0.22.2 + k8s.io/apimachinery v0.22.2 + k8s.io/client-go v0.22.2 ) require ( + cloud.google.com/go v0.81.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/armon/go-radix v1.0.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect - github.com/aws/aws-sdk-go v1.44.262 // indirect - github.com/beorn7/perks v1.0.1 // indirect + github.com/aws/aws-sdk-go v1.30.27 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/deckarep/golang-set v1.7.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fatih/color v1.14.1 // indirect + github.com/fatih/color v1.13.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-logr/logr v1.2.3 // indirect - github.com/go-logr/stdr v1.2.2 // 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 - github.com/go-openapi/jsonreference v0.20.1 // indirect - github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/runtime v0.25.0 // indirect - github.com/go-openapi/spec v0.20.8 // indirect - github.com/go-openapi/strfmt v0.21.3 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-openapi/validate v0.22.1 // indirect - github.com/go-ozzo/ozzo-validation v3.6.0+incompatible // indirect + github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect + github.com/go-logr/logr v0.4.0 // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/google/go-cmp v0.5.7 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect github.com/gruntwork-io/gruntwork-cli v0.7.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-bexpr v0.1.11 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-hclog v1.2.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.4.5 // indirect + github.com/hashicorp/go-plugin v1.0.1 // indirect github.com/hashicorp/go-retryablehttp v0.6.6 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect - github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/vault/sdk v0.7.0 // indirect + github.com/hashicorp/serf v0.10.1 // indirect + github.com/hashicorp/vault/sdk v0.2.1 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.3.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect - github.com/miekg/dns v1.1.50 // indirect - github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/pointerstructure v1.2.1 // indirect + github.com/mitchellh/mapstructure v1.4.2 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/run v1.0.0 // indirect - github.com/oklog/ulid v1.3.1 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect + github.com/onsi/gomega v1.15.0 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pquerna/otp v1.2.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/urfave/cli v1.22.2 // indirect - go.mongodb.org/mongo-driver v1.11.0 // indirect - go.opentelemetry.io/otel v1.11.1 // indirect - go.opentelemetry.io/otel/trace v1.11.1 // indirect - go.uber.org/atomic v1.9.0 // indirect + go.uber.org/atomic v1.7.0 // indirect golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect - golang.org/x/mod v0.9.0 // indirect golang.org/x/net v0.13.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.7.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect - google.golang.org/grpc v1.49.0 // indirect + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect + google.golang.org/grpc v1.48.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + k8s.io/klog/v2 v2.9.0 // indirect + k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect + k8s.io/utils v0.0.0-20220812165043-ad590609e2e5 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect ) diff --git a/acceptance/go.sum b/acceptance/go.sum index 7361efbbb6..ed575b5e09 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -14,6 +15,12 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -42,12 +49,14 @@ github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8 github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -64,6 +73,7 @@ github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQ github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -71,6 +81,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -80,28 +92,26 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= +github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -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/aws/aws-sdk-go v1.30.27 h1:9gPjZWVDSoQrBO2AvqrWObS6KAZByfEJxQoCYo4ZfK0= +github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= 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= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= @@ -111,8 +121,6 @@ github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3 github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -120,13 +128,24 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200709052629-daa8e1ccc0bc/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= @@ -144,11 +163,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= @@ -157,6 +173,7 @@ github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20200319182547-c7ad2b866182/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -172,133 +189,73 @@ github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/El github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.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.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= +github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU= github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= +github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= -github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= -github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc= -github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= -github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= -github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE= -github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -310,7 +267,7 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -318,6 +275,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -334,17 +292,15 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -353,11 +309,12 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -365,6 +322,7 @@ github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -372,19 +330,26 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -397,55 +362,62 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul-k8s/control-plane v0.0.0-20230609143603-198c4433d892 h1:4iI0ztWbVPTSDax+m1/XDs4jIRorxY4kSMyuM0fX+Dc= -github.com/hashicorp/consul-k8s/control-plane v0.0.0-20230609143603-198c4433d892/go.mod h1:iZ8BJGSnY52wnxJTo2VIfGX63CPjqiNzbuqdOtJCKnI= -github.com/hashicorp/consul/api v1.22.0-rc1 h1:ePmGqndeMgaI38KUbSA/CqTzeEAIogXyWnfNJzglo70= -github.com/hashicorp/consul/api v1.22.0-rc1/go.mod h1:wtduXtbAqSGtBdi3tyA5SSAYGAG51rBejV9SEUBciMY= -github.com/hashicorp/consul/sdk v0.14.0-rc1 h1:PuETOfN0uxl28i0Pq6rK7TBCrIl7psMbL0YTSje4KvM= -github.com/hashicorp/consul/sdk v0.14.0-rc1/go.mod h1:gHYeuDa0+0qRAD6Wwr6yznMBvBwHKoxSBoW5l73+saE= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20221117191905-0b1cc2b631e3 h1:4wROIZB8Y4cN/wPILChc2zQ/q00z1VyJitdgyLbITdU= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20221117191905-0b1cc2b631e3/go.mod h1:j9Db/whkzvNC+KP2GftY0HxxleLm9swxXjlu3tYaOAw= +github.com/hashicorp/consul/api v1.17.0 h1:aqytbw31uCPNn37ST+717IyGod+P1eTgSGu3yjRo4bs= +github.com/hashicorp/consul/api v1.17.0/go.mod h1:ZNwemOPAdgtV4cCx9fqxNmw+PI3vliW6gYin2WD+F2g= +github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= +github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= 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= -github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubCI7dY= -github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U+N8T+6Kz1AE= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -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/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.2 h1:ihRI7YFwcZdiSD7SIenIhHfQH3OuDvWerAUBZbeQS3M= +github.com/hashicorp/go-hclog v1.2.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 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-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= -github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE= +github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= 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= +github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -455,41 +427,34 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcp-sdk-go v0.50.0 h1:vOUpVf4MQF/gtoBukuoYKs/i6KinTSpP5jhKCvsZ2bc= -github.com/hashicorp/hcp-sdk-go v0.50.0/go.mod h1:hZqky4HEzsKwvLOt4QJlZUrjeQmb4UCZUhDP2HyQFfc= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hashicorp/vault/api v1.8.3 h1:cHQOLcMhBR+aVI0HzhPxO62w2+gJhIrKguQNONPzu6o= -github.com/hashicorp/vault/api v1.8.3/go.mod h1:4g/9lj9lmuJQMtT6CmVMHC5FW1yENaVv+Nv4ZfG8fAg= -github.com/hashicorp/vault/sdk v0.7.0 h1:2pQRO40R1etpKkia5fb4kjrdYMx3BHklPxl1pxpxDHg= -github.com/hashicorp/vault/sdk v0.7.0/go.mod h1:KyfArJkhooyba7gYCKSq8v66QdqJmnbAxtV/OX1+JTs= +github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f/go.mod h1:euTFbi2YJgwcju3imEt919lhJKF68nN1cQPq3aA+kBE= +github.com/hashicorp/vault/api v1.2.0 h1:ysGFc6XRGbv05NsWPzuO5VTv68Lj8jtwATxRLFOpP9s= +github.com/hashicorp/vault/api v1.2.0/go.mod h1:dAjw0T5shMnrfH7Q/Mst+LrcTKvStZBVs1PICEDpUqY= +github.com/hashicorp/vault/sdk v0.1.14-0.20200519221530-14615acda45f/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10= +github.com/hashicorp/vault/sdk v0.2.1 h1:S4O6Iv/dyKlE9AUTXGa7VOvZmsCvg36toPKgV4f2P4M= +github.com/hashicorp/vault/sdk v0.2.1/go.mod h1:WfUiO1vYzfBkz1TmoE4ZGU7HD0T0Cl/rZwaxjBkgN4U= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -502,22 +467,17 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -528,58 +488,46 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI= github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= -github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= @@ -592,99 +540,89 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= 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.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= @@ -693,22 +631,22 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -717,10 +655,8 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -728,67 +664,47 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= -go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= -go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= -go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= -go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= -go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -796,10 +712,10 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -814,8 +730,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= -golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -828,6 +742,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -836,15 +752,15 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -871,22 +787,24 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -894,15 +812,18 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -910,8 +831,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -920,32 +839,35 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -958,37 +880,37 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -997,18 +919,19 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1019,16 +942,13 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-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= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1036,6 +956,7 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1065,17 +986,20 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= -gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= @@ -1096,6 +1020,11 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1134,12 +1063,24 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 h1:hrbNEivu7Zn1pxvHk6MBrq9iE22woVILTHqexqBxe6I= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= @@ -1151,11 +1092,16 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1169,27 +1115,29 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -1203,12 +1151,12 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1218,22 +1166,20 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= -k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU= -k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE= -k8s.io/apiextensions-apiserver v0.26.3 h1:5PGMm3oEzdB1W/FTMgGIDmm100vn7IaUP5er36dB+YE= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= -k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= -k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= -k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= -k8s.io/component-base v0.26.1 h1:4ahudpeQXHZL5kko+iDHqLj/FSGAEUnSVO0EBbgDd+4= k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= @@ -1243,17 +1189,18 @@ k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220812165043-ad590609e2e5 h1:XmRqFcQlCy/lKRZ39j+RVpokYNroHPqV3mcBRfnhT5o= +k8s.io/utils v0.0.0-20220812165043-ad590609e2e5/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -1262,18 +1209,12 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA= -sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= -sigs.k8s.io/gateway-api v0.7.1 h1:Tts2jeepVkPA5rVG/iO+S43s9n7Vp7jCDhZDQYtPigQ= -sigs.k8s.io/gateway-api v0.7.1/go.mod h1:Xv0+ZMxX0lu1nSSDIIPEfbVztgNZ+3cfiYrJsa2Ooso= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/acceptance/tests/api-gateway/api_gateway_external_servers_test.go b/acceptance/tests/api-gateway/api_gateway_external_servers_test.go deleted file mode 100644 index aa0934dc65..0000000000 --- a/acceptance/tests/api-gateway/api_gateway_external_servers_test.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigateway - -import ( - "context" - "fmt" - "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/api" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/types" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -// TestAPIGateway_ExternalServers tests that connect works when using external servers. -// It sets up an external Consul server in the same cluster but a different Helm installation -// and then treats this server as external. -func TestAPIGateway_ExternalServers(t *testing.T) { - cfg := suite.Config() - ctx := suite.Environment().DefaultContext(t) - - serverHelmValues := map[string]string{ - "global.acls.manageSystemACLs": "true", - "global.tls.enabled": "true", - - // Don't install injector, controller and cni on this cluster so that it's not installed twice. - "connectInject.enabled": "false", - "connectInject.cni.enabled": "false", - } - serverReleaseName := helpers.RandomName() - consulServerCluster := consul.NewHelmCluster(t, serverHelmValues, ctx, cfg, serverReleaseName) - - consulServerCluster.Create(t) - - helmValues := map[string]string{ - "server.enabled": "false", - "global.acls.manageSystemACLs": "true", - "global.tls.enabled": "true", - "connectInject.enabled": "true", - "externalServers.enabled": "true", - "externalServers.hosts[0]": fmt.Sprintf("%s-consul-server", serverReleaseName), - "externalServers.httpsPort": "8501", - "global.tls.caCert.secretName": fmt.Sprintf("%s-consul-ca-cert", serverReleaseName), - "global.tls.caCert.secretKey": "tls.crt", - "global.acls.bootstrapToken.secretName": fmt.Sprintf("%s-consul-bootstrap-acl-token", serverReleaseName), - "global.acls.bootstrapToken.secretKey": "token", - } - - releaseName := helpers.RandomName() - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - consulCluster.SkipCheckForPreviousInstallations = true - - consulCluster.Create(t) - - logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") - - // Override the default proxy config settings for this test - consulClient, _ := consulCluster.SetupConsulClient(t, true, serverReleaseName) - logger.Log(t, "have consul client") - _, _, 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, "set consul config entry") - - logger.Log(t, "creating api-gateway resources") - 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 - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-k", "../fixtures/bases/api-gateway") - }) - - logger.Log(t, "patching route to target server") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"name":"static-server","port":80}]}]}}`, "--type=merge") - - // 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 a ~1m timeout here). - var gatewayAddress string - retryCheck(t, 60, func(r *retry.R) { - var gateway gwv1beta1.Gateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: "default"}, &gateway) - require.NoError(r, err) - - // check that we have an address to use - require.Len(r, gateway.Status.Addresses, 1) - // now we know we have an address, set it so we can use it - gatewayAddress = gateway.Status.Addresses[0].Value - }) - - k8sOptions := ctx.KubectlOptions(t) - targetAddress := fmt.Sprintf("http://%s/", gatewayAddress) - - // check that intentions keep our connection from happening - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, targetAddress) - - // Now we create the allow intention. - _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: "static-server", - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Action: api.IntentionActionAllow, - }, - }, - }, nil) - require.NoError(t, err) - - // 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") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, targetAddress) -} diff --git a/acceptance/tests/api-gateway/api_gateway_gatewayclassconfig_test.go b/acceptance/tests/api-gateway/api_gateway_gatewayclassconfig_test.go deleted file mode 100644 index 89ba07a1e7..0000000000 --- a/acceptance/tests/api-gateway/api_gateway_gatewayclassconfig_test.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigateway - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/logger" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/stretchr/testify/require" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -// GatewayClassConfig tests the creation of a gatewayclassconfig object and makes sure that its configuration -// is properly applied to any child gateway objects, namely that the number of gateway instances match the defined -// minInstances,maxInstances and defaultInstances parameters, and that changing the parent gateway does not affect -// the child gateways. -func TestAPIGateway_GatewayClassConfig(t *testing.T) { - var ( - defaultInstances = pointer.Int32(2) - maxInstances = pointer.Int32(3) - minInstances = pointer.Int32(1) - - namespace = "default" - gatewayClassName = "gateway-class" - ) - - ctx := suite.Environment().DefaultContext(t) - cfg := suite.Config() - helmValues := map[string]string{ - "global.logLevel": "trace", - "connectInject.enabled": "true", - } - 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, false) - _, _, err := consulClient.ConfigEntries().Set(&api.ProxyConfigEntry{ - Kind: api.ProxyDefaults, - Name: api.ProxyConfigGlobal, - Config: map[string]interface{}{ - "protocol": "http", - }, - }, nil) - require.NoError(t, err) - - k8sClient := ctx.ControllerRuntimeClient(t) - - // create a GatewayClassConfig with configuration set - gatewayClassConfigName := "gateway-class-config" - gatewayClassConfig := &v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: gatewayClassConfigName, - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - DeploymentSpec: v1alpha1.DeploymentSpec{ - DefaultInstances: defaultInstances, - MaxInstances: maxInstances, - MinInstances: minInstances, - }, - }, - } - logger.Log(t, "creating gateway class config") - err = k8sClient.Create(context.Background(), gatewayClassConfig) - require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - logger.Log(t, "deleting all gateway class configs") - k8sClient.DeleteAllOf(context.Background(), &v1alpha1.GatewayClassConfig{}) - }) - - gatewayParametersRef := &gwv1beta1.ParametersReference{ - Group: gwv1beta1.Group(v1alpha1.ConsulHashicorpGroup), - Kind: gwv1beta1.Kind(v1alpha1.GatewayClassConfigKind), - Name: gatewayClassConfigName, - } - - // Create gateway class referencing gateway-class-config. - logger.Log(t, "creating controlled gateway class") - createGatewayClass(t, k8sClient, gatewayClassName, gatewayClassControllerName, gatewayParametersRef) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - logger.Log(t, "deleting all gateway classes") - k8sClient.DeleteAllOf(context.Background(), &gwv1beta1.GatewayClass{}) - }) - - // Create a certificate to reference in listeners. - certificateInfo := generateCertificate(t, nil, "certificate.consul.local") - certificateName := "certificate" - certificate := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: certificateName, - Namespace: namespace, - Labels: map[string]string{ - "test-certificate": "true", - }, - }, - Type: corev1.SecretTypeTLS, - Data: map[string][]byte{ - corev1.TLSCertKey: certificateInfo.CertPEM, - corev1.TLSPrivateKeyKey: certificateInfo.PrivateKeyPEM, - }, - } - logger.Log(t, "creating certificate") - err = k8sClient.Create(context.Background(), certificate) - require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8sClient.Delete(context.Background(), certificate) - }) - - // Create gateway referencing gateway class. - gatewayName := "gcctestgateway" + namespace - logger.Log(t, "creating controlled gateway") - gateway := createGateway(t, k8sClient, gatewayName, namespace, gatewayClassName, certificateName) - - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - logger.Log(t, "deleting all gateways") - k8sClient.DeleteAllOf(context.Background(), &gwv1beta1.Gateway{}, client.InNamespace(namespace)) - }) - - // Ensure it exists. - logger.Log(t, "checking that gateway is synchronized to Consul") - checkConsulExists(t, consulClient, api.APIGateway, gatewayName) - - // Scenario: Gateway deployment should match the default instances defined on the gateway class config - logger.Log(t, "checking that gateway instances match defined gateway class config") - checkNumberOfInstances(t, k8sClient, consulClient, gateway.Name, gateway.Namespace, defaultInstances, gateway) - - // Scenario: Updating the GatewayClassConfig should not affect gateways that have already been created - logger.Log(t, "updating gatewayclassconfig values") - err = k8sClient.Get(context.Background(), types.NamespacedName{Name: gatewayClassConfigName, Namespace: namespace}, gatewayClassConfig) - require.NoError(t, err) - gatewayClassConfig.Spec.DeploymentSpec.DefaultInstances = pointer.Int32(8) - gatewayClassConfig.Spec.DeploymentSpec.MinInstances = pointer.Int32(5) - err = k8sClient.Update(context.Background(), gatewayClassConfig) - require.NoError(t, err) - checkNumberOfInstances(t, k8sClient, consulClient, gateway.Name, gateway.Namespace, defaultInstances, gateway) - - // Scenario: gateways should be able to scale independently and not get overridden by the controller unless it's above the max - scale(t, k8sClient, gateway.Name, gateway.Namespace, pointer.Int32(*maxInstances+1)) - checkNumberOfInstances(t, k8sClient, consulClient, gateway.Name, gateway.Namespace, maxInstances, gateway) - scale(t, k8sClient, gateway.Name, gateway.Namespace, pointer.Int32(0)) - checkNumberOfInstances(t, k8sClient, consulClient, gateway.Name, gateway.Namespace, minInstances, gateway) - -} - -func scale(t *testing.T, client client.Client, name, namespace string, scaleTo *int32) { - t.Helper() - - var deployment appsv1.Deployment - err := client.Get(context.Background(), types.NamespacedName{Name: name, Namespace: namespace}, &deployment) - require.NoError(t, err) - - logger.Log(t, fmt.Sprintf("scaling gateway from %d to %d", *deployment.Spec.Replicas, *scaleTo)) - - deployment.Spec.Replicas = scaleTo - err = client.Update(context.Background(), &deployment) - require.NoError(t, err) - -} - -func checkNumberOfInstances(t *testing.T, k8client client.Client, consulClient *api.Client, name, namespace string, wantNumber *int32, gateway *gwv1beta1.Gateway) { - t.Helper() - - retryCheckWithWait(t, 30, 10*time.Second, func(r *retry.R) { - logger.Log(t, "checking that gateway instances match defined gateway class config") - logger.Log(t, fmt.Sprintf("want: %d", *wantNumber)) - - // Ensure the number of replicas has been set properly. - var deployment appsv1.Deployment - err := k8client.Get(context.Background(), types.NamespacedName{Name: name, Namespace: namespace}, &deployment) - require.NoError(r, err) - logger.Log(t, fmt.Sprintf("deployment replicas: %d", *deployment.Spec.Replicas)) - require.EqualValues(r, *wantNumber, *deployment.Spec.Replicas, "deployment replicas should match the number of instances defined on the gateway class config") - - // Ensure the number of gateway pods matches the replicas generated. - podList := corev1.PodList{} - labels := common.LabelsForGateway(gateway) - err = k8client.List(context.Background(), &podList, client.InNamespace(namespace), client.MatchingLabels(labels)) - require.NoError(r, err) - logger.Log(t, fmt.Sprintf("number of pods: %d", len(podList.Items))) - require.EqualValues(r, *wantNumber, len(podList.Items), "number of pods should match the number of instances defined on the gateway class config") - - // Ensure the number of services matches the replicas generated. - services, _, err := consulClient.Catalog().Service(name, "", nil) - seenServices := map[string]interface{}{} - require.NoError(r, err) - logger.Log(t, fmt.Sprintf("number of services: %d", len(services))) - //we need to double check that we aren't double counting services with the same ID - for _, s := range services { - seenServices[s.ServiceID] = true - logger.Log(t, fmt.Sprintf("service info: id: %s, name: %s, namespace: %s", s.ServiceID, s.ServiceName, s.Namespace)) - } - - logger.Log(t, fmt.Sprintf("number of services: %d", len(services))) - require.EqualValues(r, int(*wantNumber), len(seenServices), "number of services should match the number of instances defined on the gateway class config") - }) -} diff --git a/acceptance/tests/api-gateway/api_gateway_lifecycle_test.go b/acceptance/tests/api-gateway/api_gateway_lifecycle_test.go deleted file mode 100644 index f6f66ed995..0000000000 --- a/acceptance/tests/api-gateway/api_gateway_lifecycle_test.go +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigateway - -import ( - "context" - "fmt" - "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/control-plane/api/v1alpha1" - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestAPIGateway_Lifecycle(t *testing.T) { - ctx := suite.Environment().DefaultContext(t) - cfg := suite.Config() - helmValues := map[string]string{ - "global.logLevel": "trace", - "connectInject.enabled": "true", - } - - releaseName := helpers.RandomName() - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - - consulCluster.Create(t) - - k8sClient := ctx.ControllerRuntimeClient(t) - consulClient, _ := consulCluster.SetupConsulClient(t, false) - - defaultNamespace := "default" - - // create a service to target - targetName := "static-server" - logger.Log(t, "creating target server") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - // create a basic GatewayClassConfig - gatewayClassConfigName := "controlled-gateway-class-config" - gatewayClassConfig := &v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: gatewayClassConfigName, - }, - } - logger.Log(t, "creating gateway class config") - err := k8sClient.Create(context.Background(), gatewayClassConfig) - require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - logger.Log(t, "deleting all gateway class configs") - k8sClient.DeleteAllOf(context.Background(), &v1alpha1.GatewayClassConfig{}) - }) - - gatewayParametersRef := &gwv1beta1.ParametersReference{ - Group: gwv1beta1.Group(v1alpha1.ConsulHashicorpGroup), - Kind: gwv1beta1.Kind(v1alpha1.GatewayClassConfigKind), - Name: gatewayClassConfigName, - } - - // create three gateway classes, two we control, one we don't - controlledGatewayClassOneName := "controlled-gateway-class-one" - logger.Log(t, "creating controlled gateway class one") - createGatewayClass(t, k8sClient, controlledGatewayClassOneName, gatewayClassControllerName, gatewayParametersRef) - - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - logger.Log(t, "deleting all gateway classes") - k8sClient.DeleteAllOf(context.Background(), &gwv1beta1.GatewayClass{}) - }) - - controlledGatewayClassTwoName := "controlled-gateway-class-two" - logger.Log(t, "creating controlled gateway class two") - createGatewayClass(t, k8sClient, controlledGatewayClassTwoName, gatewayClassControllerName, gatewayParametersRef) - - uncontrolledGatewayClassName := "uncontrolled-gateway-class" - logger.Log(t, "creating uncontrolled gateway class") - createGatewayClass(t, k8sClient, uncontrolledGatewayClassName, "example.com/some-controller", nil) - - // Create a certificate to reference in listeners - certificateInfo := generateCertificate(t, nil, "certificate.consul.local") - certificateName := "certificate" - certificate := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: certificateName, - Namespace: defaultNamespace, - Labels: map[string]string{ - "test-certificate": "true", - }, - }, - Type: corev1.SecretTypeTLS, - Data: map[string][]byte{ - corev1.TLSCertKey: certificateInfo.CertPEM, - corev1.TLSPrivateKeyKey: certificateInfo.PrivateKeyPEM, - }, - } - logger.Log(t, "creating certificate") - err = k8sClient.Create(context.Background(), certificate) - require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8sClient.Delete(context.Background(), certificate) - }) - - // Create three gateways with a basic HTTPS listener to correspond to the three classes - controlledGatewayOneName := "controlled-gateway-one" - logger.Log(t, "creating controlled gateway one") - controlledGatewayOne := createGateway(t, k8sClient, controlledGatewayOneName, defaultNamespace, controlledGatewayClassOneName, certificateName) - - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - logger.Log(t, "deleting all gateways") - k8sClient.DeleteAllOf(context.Background(), &gwv1beta1.Gateway{}, client.InNamespace(defaultNamespace)) - }) - - controlledGatewayTwoName := "controlled-gateway-two" - logger.Log(t, "creating controlled gateway two") - controlledGatewayTwo := createGateway(t, k8sClient, controlledGatewayTwoName, defaultNamespace, controlledGatewayClassTwoName, certificateName) - - uncontrolledGatewayName := "uncontrolled-gateway" - logger.Log(t, "creating uncontrolled gateway") - _ = createGateway(t, k8sClient, uncontrolledGatewayName, defaultNamespace, uncontrolledGatewayClassName, certificateName) - - // create two http routes associated with the first controlled gateway - routeOneName := "route-one" - logger.Log(t, "creating route one") - routeOne := createRoute(t, k8sClient, routeOneName, defaultNamespace, controlledGatewayOneName, targetName) - - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - logger.Log(t, "deleting all http routes") - k8sClient.DeleteAllOf(context.Background(), &gwv1beta1.HTTPRoute{}, client.InNamespace(defaultNamespace)) - }) - - routeTwoName := "route-two" - logger.Log(t, "creating route two") - routeTwo := createRoute(t, k8sClient, routeTwoName, defaultNamespace, controlledGatewayTwoName, targetName) - - // Scenario: Swapping a route to another controlled gateway should clean up the old parent statuses and references on Consul resources - - // check that the route is bound properly and objects are reflected in Consul - logger.Log(t, "checking that http route one is bound to gateway one") - checkRouteBound(t, k8sClient, routeOneName, defaultNamespace, controlledGatewayOneName) - - logger.Log(t, "checking that http route one is synchronized to Consul") - checkConsulRouteParent(t, consulClient, routeOneName, controlledGatewayOneName) - - // update the route to point to the other controlled gateway - logger.Log(t, "updating route one to be bound to gateway two") - updateKubernetes(t, k8sClient, routeOne, func(r *gwv1beta1.HTTPRoute) { - r.Spec.ParentRefs[0].Name = gwv1beta1.ObjectName(controlledGatewayTwoName) - }) - - // check that the route is bound properly and objects are reflected in Consul - logger.Log(t, "checking that http route one is bound to gateway two") - checkRouteBound(t, k8sClient, routeOneName, defaultNamespace, controlledGatewayTwoName) - - logger.Log(t, "checking that http route one is synchronized to Consul") - checkConsulRouteParent(t, consulClient, routeOneName, controlledGatewayTwoName) - - // Scenario: Binding a route to a controlled gateway and then associating it with another gateway we don’t control should clean up Consul resources, route statuses, and finalizers - // check that the route is bound properly and objects are reflected in Consul - - // check that our second http route is bound properly - logger.Log(t, "checking that http route two is bound to gateway two") - checkRouteBound(t, k8sClient, routeTwoName, defaultNamespace, controlledGatewayTwoName) - - logger.Log(t, "checking that http route two is synchronized to Consul") - checkConsulRouteParent(t, consulClient, routeTwoName, controlledGatewayTwoName) - - // update the route to point to the uncontrolled gateway - logger.Log(t, "updating route two to be bound to an uncontrolled gateway") - updateKubernetes(t, k8sClient, routeTwo, func(r *gwv1beta1.HTTPRoute) { - r.Spec.ParentRefs[0].Name = gwv1beta1.ObjectName(uncontrolledGatewayName) - }) - - // check that the route is unbound and all Consul objects and Kubernetes statuses are cleaned up - logger.Log(t, "checking that http route two is cleaned up because we no longer control it") - checkEmptyRoute(t, k8sClient, routeTwoName, defaultNamespace) - - logger.Log(t, "checking that http route two is deleted from Consul") - checkConsulNotExists(t, consulClient, api.HTTPRoute, routeTwoName) - - // Scenario: Switching a controlled gateway’s protocol that causes a route to unbind should cause the route to drop the parent ref in Consul and result in proper statuses set in Kubernetes - - // swap the gateway's protocol and see the route unbind - logger.Log(t, "marking gateway two as using TCP") - updateKubernetes(t, k8sClient, controlledGatewayTwo, func(g *gwv1beta1.Gateway) { - g.Spec.Listeners[0].Protocol = gwv1beta1.TCPProtocolType - }) - - // check that the route is unbound and all Consul objects and Kubernetes statuses are cleaned up - logger.Log(t, "checking that http route one is not bound to gateway two") - retryCheck(t, 60, func(r *retry.R) { - var route gwv1beta1.HTTPRoute - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: routeOneName, Namespace: defaultNamespace}, &route) - require.NoError(r, err) - - require.Len(r, route.Status.Parents, 1) - require.EqualValues(r, controlledGatewayTwoName, route.Status.Parents[0].ParentRef.Name) - checkStatusCondition(r, route.Status.Parents[0].Conditions, falseCondition("Accepted", "NotAllowedByListeners")) - }) - - logger.Log(t, "checking that route one is deleted from Consul") - checkConsulNotExists(t, consulClient, api.HTTPRoute, routeOneName) - - // Scenario: Deleting a gateway should result in routes only referencing it to get cleaned up from Consul and their statuses/finalizers cleared, but routes referencing another controlled gateway should still exist in Consul and only have their statuses cleaned up from referencing the gateway we previously controlled. Any referenced certificates should also get cleaned up. - - // delete gateway two - logger.Log(t, "deleting gateway two in Kubernetes") - err = k8sClient.Delete(context.Background(), controlledGatewayTwo) - require.NoError(t, err) - - // check that the gateway is deleted from Consul - logger.Log(t, "checking that gateway two is deleted from Consul") - checkConsulNotExists(t, consulClient, api.APIGateway, controlledGatewayTwoName) - - // check that the Kubernetes route is cleaned up and the entries deleted from Consul - logger.Log(t, "checking that http route one is cleaned up in Kubernetes") - checkEmptyRoute(t, k8sClient, routeOneName, defaultNamespace) - - // Scenario: Changing a gateway class name on a gateway to something we don’t control should have the same affect as deleting it with the addition of cleaning up our finalizer from the gateway. - - // reset route one to point to our first gateway and check that it's bound properly - logger.Log(t, "remarking route one as bound to gateway one") - updateKubernetes(t, k8sClient, routeOne, func(r *gwv1beta1.HTTPRoute) { - r.Spec.ParentRefs[0].Name = gwv1beta1.ObjectName(controlledGatewayOneName) - }) - - logger.Log(t, "checking that http route one is bound to gateway one") - checkRouteBound(t, k8sClient, routeOneName, defaultNamespace, controlledGatewayOneName) - - logger.Log(t, "checking that http route one is synchronized to Consul") - checkConsulRouteParent(t, consulClient, routeOneName, controlledGatewayOneName) - - // make the gateway uncontrolled by pointing to a non-existent gateway class - logger.Log(t, "marking gateway one as not controlled by our controller") - updateKubernetes(t, k8sClient, controlledGatewayOne, func(g *gwv1beta1.Gateway) { - g.Spec.GatewayClassName = "non-existent" - }) - - // check that the Kubernetes gateway is cleaned up - logger.Log(t, "checking that gateway one is cleaned up in Kubernetes") - retryCheck(t, 60, func(r *retry.R) { - var route gwv1beta1.Gateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: controlledGatewayOneName, Namespace: defaultNamespace}, &route) - require.NoError(r, err) - - require.Len(r, route.Finalizers, 0) - }) - - // check that the gateway is deleted from Consul - logger.Log(t, "checking that gateway one is deleted from Consul") - checkConsulNotExists(t, consulClient, api.APIGateway, controlledGatewayOneName) - - // check that the Kubernetes route is cleaned up and the entries deleted from Consul - logger.Log(t, "checking that http route one is cleaned up in Kubernetes") - checkEmptyRoute(t, k8sClient, routeOneName, defaultNamespace) - - logger.Log(t, "checking that http route one is deleted from Consul") - checkConsulNotExists(t, consulClient, api.HTTPRoute, routeOneName) - - // Scenario: Deleting a certificate referenced by a gateway’s listener should make the listener invalid and drop it from Consul. - - // reset the gateway - logger.Log(t, "remarking gateway one as controlled by our controller") - updateKubernetes(t, k8sClient, controlledGatewayOne, func(g *gwv1beta1.Gateway) { - g.Spec.GatewayClassName = gwv1beta1.ObjectName(controlledGatewayClassOneName) - }) - - // make sure it exists - logger.Log(t, "checking that gateway one is synchronized to Consul") - checkConsulExists(t, consulClient, api.APIGateway, controlledGatewayOneName) - - // make sure our certificate exists - logger.Log(t, "checking that the certificate is synchronized to Consul") - checkConsulExists(t, consulClient, api.InlineCertificate, certificateName) - - // delete the certificate in Kubernetes - logger.Log(t, "deleting the certificate in Kubernetes") - err = k8sClient.Delete(context.Background(), certificate) - require.NoError(t, err) - - // make sure the certificate no longer exists in Consul - logger.Log(t, "checking that the certificate is deleted from Consul") - checkConsulNotExists(t, consulClient, api.InlineCertificate, certificateName) -} - -func checkConsulNotExists(t *testing.T, client *api.Client, kind, name string, namespace ...string) { - t.Helper() - - opts := &api.QueryOptions{} - if len(namespace) != 0 { - opts.Namespace = namespace[0] - } - - retryCheck(t, 60, func(r *retry.R) { - _, _, err := client.ConfigEntries().Get(kind, name, opts) - require.Error(r, err) - require.EqualError(r, err, fmt.Sprintf("Unexpected response code: 404 (Config entry not found for %q / %q)", kind, name)) - }) -} - -func checkConsulExists(t *testing.T, client *api.Client, kind, name string) { - t.Helper() - - retryCheck(t, 60, func(r *retry.R) { - _, _, err := client.ConfigEntries().Get(kind, name, nil) - require.NoError(r, err) - }) -} - -func checkConsulRouteParent(t *testing.T, client *api.Client, name, parent string) { - t.Helper() - - retryCheck(t, 60, func(r *retry.R) { - entry, _, err := client.ConfigEntries().Get(api.HTTPRoute, name, nil) - require.NoError(r, err) - route := entry.(*api.HTTPRouteConfigEntry) - - require.Len(r, route.Parents, 1) - require.Equal(r, parent, route.Parents[0].Name) - }) -} - -func checkEmptyRoute(t *testing.T, client client.Client, name, namespace string) { - t.Helper() - - retryCheck(t, 60, func(r *retry.R) { - var route gwv1beta1.HTTPRoute - err := client.Get(context.Background(), types.NamespacedName{Name: name, Namespace: namespace}, &route) - require.NoError(r, err) - - require.Len(r, route.Status.Parents, 0) - require.Len(r, route.Finalizers, 0) - }) -} - -func checkRouteBound(t *testing.T, client client.Client, name, namespace, parent string) { - t.Helper() - - retryCheck(t, 60, func(r *retry.R) { - var route gwv1beta1.HTTPRoute - err := client.Get(context.Background(), types.NamespacedName{Name: name, Namespace: namespace}, &route) - require.NoError(r, err) - - require.Len(r, route.Status.Parents, 1) - require.EqualValues(r, gatewayClassControllerName, route.Status.Parents[0].ControllerName) - require.EqualValues(r, parent, route.Status.Parents[0].ParentRef.Name) - checkStatusCondition(r, route.Status.Parents[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, route.Status.Parents[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - checkStatusCondition(r, route.Status.Parents[0].Conditions, trueCondition("Synced", "Synced")) - }) -} - -func updateKubernetes[T client.Object](t *testing.T, k8sClient client.Client, o T, fn func(o T)) { - t.Helper() - - err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(o), o) - require.NoError(t, err) - fn(o) - err = k8sClient.Update(context.Background(), o) - require.NoError(t, err) -} - -func createRoute(t *testing.T, client client.Client, name, namespace, parent, target string) *gwv1beta1.HTTPRoute { - t.Helper() - - route := &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: gwv1beta1.ObjectName(parent)}, - }, - }, - Rules: []gwv1beta1.HTTPRouteRule{ - {BackendRefs: []gwv1beta1.HTTPBackendRef{ - {BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{Name: gwv1beta1.ObjectName(target)}, - }}, - }}, - }, - }, - } - - err := client.Create(context.Background(), route) - require.NoError(t, err) - return route -} - -func createGateway(t *testing.T, client client.Client, name, namespace, gatewayClass, certificate string) *gwv1beta1.Gateway { - t.Helper() - - gateway := &gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: gwv1beta1.ObjectName(gatewayClass), - Listeners: []gwv1beta1.Listener{{ - Name: gwv1beta1.SectionName("listener"), - Protocol: gwv1beta1.HTTPSProtocolType, - Port: 8443, - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{{ - Name: gwv1beta1.ObjectName(certificate), - }}, - }, - }}, - }, - } - - err := client.Create(context.Background(), gateway) - require.NoError(t, err) - - return gateway -} - -func createGatewayClass(t *testing.T, client client.Client, name, controllerName string, parameters *gwv1beta1.ParametersReference) { - t.Helper() - - gatewayClass := &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: gwv1beta1.GatewayController(controllerName), - ParametersRef: parameters, - }, - } - - err := client.Create(context.Background(), gatewayClass) - require.NoError(t, err) -} diff --git a/acceptance/tests/api-gateway/api_gateway_tenancy_test.go b/acceptance/tests/api-gateway/api_gateway_tenancy_test.go deleted file mode 100644 index f7b0ac6d79..0000000000 --- a/acceptance/tests/api-gateway/api_gateway_tenancy_test.go +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigateway - -import ( - "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/base64" - "encoding/pem" - "fmt" - "math/big" - "path" - "strconv" - "testing" - "time" - - terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "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/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/environment" - "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/control-plane/api/v1alpha1" - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/testutil/retry" -) - -var ( - gatewayGroup = gwv1beta1.Group(gwv1beta1.GroupVersion.Group) - consulGroup = gwv1beta1.Group(v1alpha1.GroupVersion.Group) - gatewayKind = gwv1beta1.Kind("Gateway") - serviceKind = gwv1beta1.Kind("Service") - secretKind = gwv1beta1.Kind("Secret") - meshServiceKind = gwv1beta1.Kind("MeshService") - httpRouteKind = gwv1beta1.Kind("HTTPRoute") - tcpRouteKind = gwv1beta1.Kind("TCPRoute") -) - -func TestAPIGateway_Tenancy(t *testing.T) { - cases := []struct { - secure bool - namespaceMirroring bool - }{ - { - secure: false, - namespaceMirroring: false, - }, - { - secure: true, - namespaceMirroring: false, - }, - { - secure: false, - namespaceMirroring: true, - }, - { - secure: true, - namespaceMirroring: true, - }, - } - for _, c := range cases { - name := fmt.Sprintf("secure: %t, namespaces: %t", c.secure, c.namespaceMirroring) - t.Run(name, func(t *testing.T) { - cfg := suite.Config() - - if !cfg.EnableEnterprise && c.namespaceMirroring { - t.Skipf("skipping this test because -enable-enterprise is not set") - } - - ctx := suite.Environment().DefaultContext(t) - - helmValues := map[string]string{ - "global.enableConsulNamespaces": strconv.FormatBool(c.namespaceMirroring), - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - "global.tls.enabled": strconv.FormatBool(c.secure), - "global.logLevel": "trace", - "connectInject.enabled": "true", - "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.namespaceMirroring), - } - - releaseName := helpers.RandomName() - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - - consulCluster.Create(t) - - serviceNamespace, serviceK8SOptions := createNamespace(t, ctx, cfg) - certificateNamespace, certificateK8SOptions := createNamespace(t, ctx, cfg) - gatewayNamespace, gatewayK8SOptions := createNamespace(t, ctx, cfg) - routeNamespace, routeK8SOptions := createNamespace(t, ctx, cfg) - - logger.Logf(t, "creating target server in %s namespace", serviceNamespace) - k8s.DeployKustomize(t, serviceK8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - logger.Logf(t, "creating certificate resources in %s namespace", certificateNamespace) - applyFixture(t, cfg, certificateK8SOptions, "cases/api-gateways/certificate") - - logger.Logf(t, "creating gateway in %s namespace", gatewayNamespace) - applyFixture(t, cfg, gatewayK8SOptions, "cases/api-gateways/gateway") - - logger.Logf(t, "creating route resources in %s namespace", routeNamespace) - applyFixture(t, cfg, routeK8SOptions, "cases/api-gateways/httproute") - - // patch certificate with data - logger.Log(t, "patching certificate with generated data") - certificate := generateCertificate(t, nil, "gateway.test.local") - k8s.RunKubectl(t, certificateK8SOptions, "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") - - // patch the resources to reference each other - logger.Log(t, "patching gateway to certificate") - k8s.RunKubectl(t, gatewayK8SOptions, "patch", "gateway", "gateway", "-p", fmt.Sprintf(`{"spec":{"listeners":[{"protocol":"HTTPS","port":8082,"name":"https","tls":{"certificateRefs":[{"name":"certificate","namespace":"%s"}]},"allowedRoutes":{"namespaces":{"from":"All"}}}]}}`, certificateNamespace), "--type=merge") - - logger.Log(t, "patching route to target server") - k8s.RunKubectl(t, routeK8SOptions, "patch", "httproute", "route", "-p", fmt.Sprintf(`{"spec":{"rules":[{"backendRefs":[{"name":"static-server","namespace":"%s","port":80}]}]}}`, serviceNamespace), "--type=merge") - - logger.Log(t, "patching route to gateway") - k8s.RunKubectl(t, routeK8SOptions, "patch", "httproute", "route", "-p", fmt.Sprintf(`{"spec":{"parentRefs":[{"name":"gateway","namespace":"%s"}]}}`, gatewayNamespace), "--type=merge") - - // Grab a kubernetes and consul client so that we can verify binding - // behavior prior to issuing requests through the gateway. - k8sClient := ctx.ControllerRuntimeClient(t) - consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) - - retryCheck(t, 120, func(r *retry.R) { - var gateway gwv1beta1.Gateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: gatewayNamespace}, &gateway) - require.NoError(r, err) - - // check our statuses - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Conditions, falseCondition("Programmed", "Pending")) - // we expect a sync error here since dropping the listener means the gateway is now invalid - checkStatusCondition(r, gateway.Status.Conditions, falseCondition("Synced", "SyncError")) - - require.Len(r, gateway.Status.Listeners, 1) - require.EqualValues(r, 1, gateway.Status.Listeners[0].AttachedRoutes) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, falseCondition("Conflicted", "NoConflicts")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, falseCondition("ResolvedRefs", "RefNotPermitted")) - }) - - // since the sync operation should fail above, check that we don't have the entry in Consul. - checkConsulNotExists(t, consulClient, api.APIGateway, "gateway", namespaceForConsul(c.namespaceMirroring, gatewayNamespace)) - - // route failure - retryCheck(t, 60, func(r *retry.R) { - var httproute gwv1beta1.HTTPRoute - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "route", Namespace: routeNamespace}, &httproute) - require.NoError(r, err) - - require.Len(r, httproute.Status.Parents, 1) - require.EqualValues(r, gatewayClassControllerName, httproute.Status.Parents[0].ControllerName) - require.EqualValues(r, "gateway", httproute.Status.Parents[0].ParentRef.Name) - require.NotNil(r, httproute.Status.Parents[0].ParentRef.Namespace) - require.EqualValues(r, gatewayNamespace, *httproute.Status.Parents[0].ParentRef.Namespace) - checkStatusCondition(r, httproute.Status.Parents[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, httproute.Status.Parents[0].Conditions, falseCondition("ResolvedRefs", "RefNotPermitted")) - }) - - // we only sync validly referenced certificates over, so check to make sure it is not created. - checkConsulNotExists(t, consulClient, api.InlineCertificate, "certificate", namespaceForConsul(c.namespaceMirroring, certificateNamespace)) - - // now create reference grants - createReferenceGrant(t, k8sClient, "gateway-certificate", gatewayNamespace, certificateNamespace) - createReferenceGrant(t, k8sClient, "route-service", routeNamespace, serviceNamespace) - - // gateway updated with references allowed - retryCheck(t, 60, func(r *retry.R) { - var gateway gwv1beta1.Gateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: gatewayNamespace}, &gateway) - require.NoError(r, err) - - // check our statuses - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("Programmed", "Programmed")) - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("Synced", "Synced")) - require.Len(r, gateway.Status.Listeners, 1) - require.EqualValues(r, 1, gateway.Status.Listeners[0].AttachedRoutes) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, falseCondition("Conflicted", "NoConflicts")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - }) - - // check the Consul gateway is updated, with the listener. - retryCheck(t, 30, func(r *retry.R) { - entry, _, err := consulClient.ConfigEntries().Get(api.APIGateway, "gateway", &api.QueryOptions{ - Namespace: namespaceForConsul(c.namespaceMirroring, gatewayNamespace), - }) - require.NoError(r, err) - gateway := entry.(*api.APIGatewayConfigEntry) - - require.EqualValues(r, "gateway", gateway.Meta["k8s-name"]) - require.EqualValues(r, gatewayNamespace, gateway.Meta["k8s-namespace"]) - require.Len(r, gateway.Listeners, 1) - checkConsulStatusCondition(t, gateway.Status.Conditions, trueConsulCondition("Accepted", "Accepted")) - checkConsulStatusCondition(t, gateway.Status.Conditions, trueConsulCondition("ResolvedRefs", "ResolvedRefs")) - }) - - // route updated with gateway and services allowed - retryCheck(t, 30, func(r *retry.R) { - var httproute gwv1beta1.HTTPRoute - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "route", Namespace: routeNamespace}, &httproute) - require.NoError(r, err) - - require.Len(r, httproute.Status.Parents, 1) - require.EqualValues(r, gatewayClassControllerName, httproute.Status.Parents[0].ControllerName) - require.EqualValues(r, "gateway", httproute.Status.Parents[0].ParentRef.Name) - require.NotNil(r, httproute.Status.Parents[0].ParentRef.Namespace) - require.EqualValues(r, gatewayNamespace, *httproute.Status.Parents[0].ParentRef.Namespace) - checkStatusCondition(r, httproute.Status.Parents[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, httproute.Status.Parents[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - }) - - // now check to make sure that the route is updated and valid - retryCheck(t, 30, func(r *retry.R) { - // since we're not bound, check to make sure that the route doesn't target the gateway in Consul. - entry, _, err := consulClient.ConfigEntries().Get(api.HTTPRoute, "route", &api.QueryOptions{ - Namespace: namespaceForConsul(c.namespaceMirroring, routeNamespace), - }) - require.NoError(r, err) - route := entry.(*api.HTTPRouteConfigEntry) - - require.EqualValues(r, "route", route.Meta["k8s-name"]) - require.EqualValues(r, routeNamespace, route.Meta["k8s-namespace"]) - require.Len(r, route.Parents, 1) - }) - - // and check to make sure that the certificate exists - retryCheck(t, 30, func(r *retry.R) { - entry, _, err := consulClient.ConfigEntries().Get(api.InlineCertificate, "certificate", &api.QueryOptions{ - Namespace: namespaceForConsul(c.namespaceMirroring, certificateNamespace), - }) - require.NoError(r, err) - certificate := entry.(*api.InlineCertificateConfigEntry) - - require.EqualValues(r, "certificate", certificate.Meta["k8s-name"]) - require.EqualValues(r, certificateNamespace, certificate.Meta["k8s-namespace"]) - }) - }) - } -} - -func applyFixture(t *testing.T, cfg *config.TestConfig, k8sOptions *terratestk8s.KubectlOptions, fixture string) { - t.Helper() - - out, err := k8s.RunKubectlAndGetOutputE(t, k8sOptions, "apply", "-k", path.Join("../fixtures", fixture)) - require.NoError(t, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectlAndGetOutputE(t, k8sOptions, "delete", "-k", path.Join("../fixtures", fixture)) - }) -} - -func createNamespace(t *testing.T, ctx environment.TestContext, cfg *config.TestConfig) (string, *terratestk8s.KubectlOptions) { - t.Helper() - - namespace := helpers.RandomName() - - logger.Logf(t, "creating Kubernetes namespace %s", namespace) - k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", namespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", namespace) - }) - - return namespace, &terratestk8s.KubectlOptions{ - ContextName: ctx.KubectlOptions(t).ContextName, - ConfigPath: ctx.KubectlOptions(t).ConfigPath, - Namespace: namespace, - } -} - -type certificateInfo struct { - Cert *x509.Certificate - PrivateKey *rsa.PrivateKey - CertPEM []byte - PrivateKeyPEM []byte -} - -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, - } -} - -func retryCheck(t *testing.T, count int, fn func(r *retry.R)) { - retryCheckWithWait(t, count, 2*time.Second, fn) -} - -func retryCheckWithWait(t *testing.T, count int, wait time.Duration, fn func(r *retry.R)) { - t.Helper() - - counter := &retry.Counter{Count: count, Wait: wait} - retry.RunWith(counter, t, fn) -} - -func createReferenceGrant(t *testing.T, client client.Client, name, from, to string) { - t.Helper() - - // we just create a reference grant for all combinations in the given namespaces - - require.NoError(t, client.Create(context.Background(), &gwv1beta1.ReferenceGrant{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: to, - }, - Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{{ - Group: gatewayGroup, - Kind: gatewayKind, - Namespace: gwv1beta1.Namespace(from), - }, { - Group: gatewayGroup, - Kind: httpRouteKind, - Namespace: gwv1beta1.Namespace(from), - }, { - Group: gatewayGroup, - Kind: tcpRouteKind, - Namespace: gwv1beta1.Namespace(from), - }}, - To: []gwv1beta1.ReferenceGrantTo{{ - Group: gatewayGroup, - Kind: gatewayKind, - }, { - Kind: serviceKind, - }, { - Group: consulGroup, - Kind: meshServiceKind, - }, { - Kind: secretKind, - }}, - }, - })) -} - -func namespaceForConsul(namespaceMirroringEnabled bool, namespace string) string { - if namespaceMirroringEnabled { - return namespace - } - return "" -} diff --git a/acceptance/tests/api-gateway/api_gateway_test.go b/acceptance/tests/api-gateway/api_gateway_test.go deleted file mode 100644 index df4a097b7e..0000000000 --- a/acceptance/tests/api-gateway/api_gateway_test.go +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package apigateway - -import ( - "context" - "encoding/base64" - "fmt" - "strconv" - "testing" - "time" - - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - - "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" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -const ( - StaticClientName = "static-client" - gatewayClassControllerName = "consul.hashicorp.com/gateway-controller" - gatewayClassFinalizer = "gateway-exists-finalizer.consul.hashicorp.com" - gatewayFinalizer = "gateway-finalizer.consul.hashicorp.com" -) - -// Test that api gateway basic functionality works in a default installation and a secure installation. -func TestAPIGateway_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", - } - - 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") - 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") - }) - - // 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") - }) - - // 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") - - logger.Log(t, "creating target http server") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - // 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, "patching route to target http server") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"name":"static-server","port":80}]}]}}`, "--type=merge") - - 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/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/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 gwv1beta1.Gateway - 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 - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("ConsulAccepted", "Accepted")) - require.Len(r, gateway.Status.Listeners, 3) - - require.EqualValues(r, 1, gateway.Status.Listeners[0].AttachedRoutes) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, falseCondition("Conflicted", "NoConflicts")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - require.EqualValues(r, 1, gateway.Status.Listeners[1].AttachedRoutes) - checkStatusCondition(r, gateway.Status.Listeners[1].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Listeners[1].Conditions, falseCondition("Conflicted", "NoConflicts")) - checkStatusCondition(r, gateway.Status.Listeners[1].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - require.EqualValues(r, 1, gateway.Status.Listeners[2].AttachedRoutes) - checkStatusCondition(r, gateway.Status.Listeners[2].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Listeners[2].Conditions, falseCondition("Conflicted", "NoConflicts")) - checkStatusCondition(r, gateway.Status.Listeners[2].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - - // check that we have an address to use - require.Len(r, gateway.Status.Addresses, 1) - // now we know we have an address, set it so we can use it - gatewayAddress = gateway.Status.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 gwv1beta1.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]) - - // http route checks - var httproute gwv1beta1.HTTPRoute - err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "http-route", Namespace: "default"}, &httproute) - require.NoError(t, err) - - // check our finalizers - require.Len(t, httproute.Finalizers, 1) - require.EqualValues(t, gatewayFinalizer, httproute.Finalizers[0]) - - // check parent status - require.Len(t, httproute.Status.Parents, 1) - require.EqualValues(t, gatewayClassControllerName, httproute.Status.Parents[0].ControllerName) - require.EqualValues(t, "gateway", httproute.Status.Parents[0].ParentRef.Name) - checkStatusCondition(t, httproute.Status.Parents[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(t, httproute.Status.Parents[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - checkStatusCondition(t, httproute.Status.Parents[0].Conditions, trueCondition("ConsulAccepted", "Accepted")) - - // tcp route checks - var tcpRoute gwv1alpha2.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]) - - // check parent status - require.Len(t, tcpRoute.Status.Parents, 1) - require.EqualValues(t, gatewayClassControllerName, tcpRoute.Status.Parents[0].ControllerName) - require.EqualValues(t, "gateway", tcpRoute.Status.Parents[0].ParentRef.Name) - checkStatusCondition(t, tcpRoute.Status.Parents[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(t, tcpRoute.Status.Parents[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - checkStatusCondition(t, tcpRoute.Status.Parents[0].Conditions, trueCondition("ConsulAccepted", "Accepted")) - - // check that the Consul entries were created - var gateway *api.APIGatewayConfigEntry - var httpRoute *api.HTTPRouteConfigEntry - var route *api.TCPRouteConfigEntry - retry.RunWith(counter, t, func(r *retry.R) { - entry, _, err := consulClient.ConfigEntries().Get(api.APIGateway, "gateway", nil) - require.NoError(r, err) - gateway = entry.(*api.APIGatewayConfigEntry) - - entry, _, err = consulClient.ConfigEntries().Get(api.HTTPRoute, "http-route", nil) - require.NoError(r, err) - httpRoute = entry.(*api.HTTPRouteConfigEntry) - - entry, _, err = consulClient.ConfigEntries().Get(api.TCPRoute, "tcp-route", nil) - require.NoError(r, err) - route = entry.(*api.TCPRouteConfigEntry) - }) - - // now check the gateway status conditions - checkConsulStatusCondition(t, gateway.Status.Conditions, trueConsulCondition("Accepted", "Accepted")) - - // and the route status conditions - checkConsulStatusCondition(t, httpRoute.Status.Conditions, trueConsulCondition("Bound", "Bound")) - checkConsulStatusCondition(t, route.Status.Conditions, trueConsulCondition("Bound", "Bound")) - - // finally we check that we can actually route to the service via the gateway - k8sOptions := ctx.KubectlOptions(t) - targetHTTPAddress := fmt.Sprintf("http://%s", gatewayAddress) - targetHTTPSAddress := fmt.Sprintf("https://%s", gatewayAddress) - targetTCPAddress := fmt.Sprintf("http://%s:81", gatewayAddress) - - if c.secure { - // check that intentions keep our connection from happening - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, targetHTTPAddress) - - k8s.CheckStaticServerConnectionFailing(t, k8sOptions, StaticClientName, targetTCPAddress) - - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, "-k", targetHTTPSAddress) - - // Now we create the allow intention. - _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: "static-server", - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Action: api.IntentionActionAllow, - }, - }, - }, nil) - require.NoError(t, err) - - // Now we create the allow intention tcp. - _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: "static-server-tcp", - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Action: api.IntentionActionAllow, - }, - }, - }, nil) - require.NoError(t, err) - } - - // 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 http") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, targetHTTPAddress) - - logger.Log(t, "trying calls to api gateway tcp") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, targetTCPAddress) - - logger.Log(t, "trying calls to api gateway https") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, targetHTTPSAddress, "-k") - }) - } -} - -func TestAPIGateway_JWTAuth_Basic(t *testing.T) { - t.Skip("skipping this test until GW JWT auth is complete") - ctx := suite.Environment().DefaultContext(t) - cfg := suite.Config() - - if !cfg.EnableEnterprise { - t.Skipf("skipping this test because -enable-enterprise is not set") - } - - helmValues := map[string]string{ - "connectInject.enabled": "true", - "connectInject.consulNamespaces.mirroringK8S": "true", - "global.acls.manageSystemACLs": "true", // acls must be enabled for JWT auth to take place - "global.tls.enabled": "true", - "global.logLevel": "trace", - } - - 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, true) - _, _, 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/cases/api-gateways/jwt-auth") - 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/cases/api-gateways/jwt-auth") - }) - - // 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") - }) - - // 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") - - k8s.RunKubectl(t, ctx.KubectlOptions(t), "wait", "--for=condition=available", "--timeout=5m", fmt.Sprintf("deploy/%s", "static-server")) - // 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 2m timeout here). - var ( - gatewayAddress string - gatewayClass gwv1beta1.GatewayClass - httpRoute gwv1beta1.HTTPRoute - httpRouteAuth gwv1beta1.HTTPRoute - ) - - counter := &retry.Counter{Count: 60, Wait: 2 * time.Second} - retry.RunWith(counter, t, func(r *retry.R) { - var gateway gwv1beta1.Gateway - 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 - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Conditions, trueCondition("ConsulAccepted", "Accepted")) - require.Len(r, gateway.Status.Listeners, 4) - - require.EqualValues(r, 1, gateway.Status.Listeners[0].AttachedRoutes) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, falseCondition("Conflicted", "NoConflicts")) - checkStatusCondition(r, gateway.Status.Listeners[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - require.EqualValues(r, 1, gateway.Status.Listeners[1].AttachedRoutes) - checkStatusCondition(r, gateway.Status.Listeners[1].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, gateway.Status.Listeners[1].Conditions, falseCondition("Conflicted", "NoConflicts")) - checkStatusCondition(r, gateway.Status.Listeners[1].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - - // check that we have an address to use - require.Len(r, gateway.Status.Addresses, 1) - // now we know we have an address, set it so we can use it - gatewayAddress = gateway.Status.Addresses[0].Value - - // gateway class checks - err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway-class"}, &gatewayClass) - require.NoError(r, err) - - // check our finalizers - require.Len(r, gatewayClass.Finalizers, 1) - require.EqualValues(r, gatewayClassFinalizer, gatewayClass.Finalizers[0]) - - // http route checks - err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "http-route", Namespace: "default"}, &httpRoute) - require.NoError(r, err) - - // http route checks - err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "http-route-auth", Namespace: "default"}, &httpRouteAuth) - require.NoError(r, err) - - // check our finalizers - require.Len(r, httpRoute.Finalizers, 1) - require.EqualValues(r, gatewayFinalizer, httpRoute.Finalizers[0]) - - // check parent status - require.Len(r, httpRoute.Status.Parents, 1) - require.EqualValues(r, gatewayClassControllerName, httpRoute.Status.Parents[0].ControllerName) - require.EqualValues(r, "gateway", httpRoute.Status.Parents[0].ParentRef.Name) - checkStatusCondition(r, httpRoute.Status.Parents[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, httpRoute.Status.Parents[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - checkStatusCondition(r, httpRoute.Status.Parents[0].Conditions, trueCondition("ConsulAccepted", "Accepted")) - - // check our finalizers - require.Len(r, httpRouteAuth.Finalizers, 1) - require.EqualValues(r, gatewayFinalizer, httpRouteAuth.Finalizers[0]) - - // check parent status - require.Len(r, httpRouteAuth.Status.Parents, 1) - require.EqualValues(r, gatewayClassControllerName, httpRouteAuth.Status.Parents[0].ControllerName) - require.EqualValues(r, "gateway", httpRouteAuth.Status.Parents[0].ParentRef.Name) - checkStatusCondition(r, httpRouteAuth.Status.Parents[0].Conditions, trueCondition("Accepted", "Accepted")) - checkStatusCondition(r, httpRouteAuth.Status.Parents[0].Conditions, trueCondition("ResolvedRefs", "ResolvedRefs")) - checkStatusCondition(r, httpRouteAuth.Status.Parents[0].Conditions, trueCondition("ConsulAccepted", "Accepted")) - }) - - // check that the Consul entries were created - entry, _, err := consulClient.ConfigEntries().Get(api.APIGateway, "gateway", nil) - require.NoError(t, err) - gateway := entry.(*api.APIGatewayConfigEntry) - - entry, _, err = consulClient.ConfigEntries().Get(api.HTTPRoute, "http-route", nil) - require.NoError(t, err) - consulHTTPRoute := entry.(*api.HTTPRouteConfigEntry) - - entry, _, err = consulClient.ConfigEntries().Get(api.HTTPRoute, "http-route-auth", nil) - require.NoError(t, err) - consulHTTPRouteAuth := entry.(*api.HTTPRouteConfigEntry) - - // now check the gateway status conditions - checkConsulStatusCondition(t, gateway.Status.Conditions, trueConsulCondition("Accepted", "Accepted")) - - // and the route status conditions - checkConsulStatusCondition(t, consulHTTPRoute.Status.Conditions, trueConsulCondition("Bound", "Bound")) - checkConsulStatusCondition(t, consulHTTPRouteAuth.Status.Conditions, trueConsulCondition("Bound", "Bound")) - - // finally we check that we can actually route to the service(s) via the gateway - k8sOptions := ctx.KubectlOptions(t) - targetHTTPAddress := fmt.Sprintf("http://%s/v1", gatewayAddress) - targetHTTPAddressAdmin := fmt.Sprintf("http://%s:8080/admin", gatewayAddress) - targetHTTPAddressPet := fmt.Sprintf("http://%s:8080/pet", gatewayAddress) - // valid JWT token with role of "doctor" - doctorToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiIsImtpZCI6IkMtRTFuQ2p3Z0JDLVB1R00yTzQ2N0ZSRGhLeDhBa1ZjdElTQWJvM3JpZXcifQ.eyJpc3MiOiJsb2NhbCIsInJvbGUiOiJkb2N0b3IifQ.FfgpzjMf8Evh6K-fJ1cLXklfIXOm-vojVbWlPPbGVFtzxZ9hxMxoyAY_G8i36SfGrpUlp-RJ6ohMvprMrEgyRgbenu7u5kkm5iGHW-zpMus4izXRxPELBcpWOGF105HIssT2NYRstXieNR8EVzvGfLdvR0GW8ttEERgseqGvuAfdb4-aNYsysGwUUHbsZjazA6H1rZmWqHdCLOJ2ZwFsIdckO9CadnkyTILpcPUmLYyUVJdtlLGOySb0GG8c_dPML_IR5jSXCSUZt6S2JBNBNBdqukrlqpA-fIaaWft0dbWVMhv8DqPC8znult8dKvLZ1qXeU0itsqqJUyE16ihJjw" - // valid JWT token with role of "pet" - petToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiIsImtpZCI6IkMtRTFuQ2p3Z0JDLVB1R00yTzQ2N0ZSRGhLeDhBa1ZjdElTQWJvM3JpZXcifQ.eyJpc3MiOiJsb2NhbCIsInJvbGUiOiJwZXQifQ.l94rJayGGTMB426HwEw5ipSjaIHjm-UWDHiBAlB_Slmi814AxAfl_0AdRwSz67UDnkoygKbvPpR5xUB03JCXNshLZuKLegWsBeQg_OJYvZGmFagl5NglBFvH7Jbta4e1eQoAxZI6Xyy1jHbu7jFBjQPVnK8EaRvWoW8Pe8a8rp_5xhub0pomhvRF6Pm5kAS4cMnxvqpVc5Oo5nO7ws_SmoNnbt2Ok14k23Zx5E2EWmGStOfbgFsdbhVbepB2DMzqv1j8jvBbwa_OxCwc_7pEOthOOxRV6L3ZjgbRSB4GumlXAOCBYXD1cRLgrMSrWB1GkefAKu8PV0Ho1px6sI9Evg" - - // check that intentions keep our connection from happening - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, targetHTTPAddress) - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, targetHTTPAddressAdmin) - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, "-H", doctorToken, targetHTTPAddressAdmin) - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, "-H", petToken, targetHTTPAddressAdmin) - - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, targetHTTPAddressPet) - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, "-H", doctorToken, targetHTTPAddressPet) - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, "-H", petToken, targetHTTPAddressPet) - - // Now we create the allow intention. - _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: "static-server", - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Action: api.IntentionActionAllow, - }, - }, - }, nil) - require.NoError(t, err) - - _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: "static-server-protected", - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Action: api.IntentionActionAllow, - }, - }, - }, nil) - require.NoError(t, err) - - // Test that we can make a call to the api gateway - logger.Log(t, "trying calls to api gateway http") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, targetHTTPAddress) - - // ensure that overrides -> route extension -> default by making a request to the admin route with a JWT that has an issuer of "local" and a "role" of "doctor" - // we can see that: - // * the "iss" verification in the gateway override takes precedence over the "iss" verification in the route filter - // * the "role" verification in the route extension takes precedence over the "role" verification in the gateway default - // should fail because we're missing JWT - logger.Log(t, "trying calls to api gateway /admin should fail without JWT token") - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, targetHTTPAddressAdmin) - - // should fail because we use the token with the wrong role and correct issuer - logger.Log(t, "trying calls to api gateway /admin should fail with wrong role") - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, "-H", petToken, targetHTTPAddressAdmin) - - // will succeed because we use the token with the correct role and the correct issuer - logger.Log(t, "trying calls to api gateway /admin should succeed with JWT token with correct role") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, "-H", doctorToken, targetHTTPAddressAdmin) - - // ensure that overrides -> route extension -> default by making a request to the admin route with a JWT that has an issuer of "local" and a "role" of "pet" - // the route does not define - // we can see that: - // * the "iss" verification in the gateway override takes precedence over the "iss" verification in the route filter - // * the "role" verification in the route extension takes precedence over the "role" verification in the gateway default - // should fail because we're missing JWT - logger.Log(t, "trying calls to api gateway /pet should fail without JWT token") - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, targetHTTPAddressPet) - - // should fail because we use the token with the wrong role and correct issuer - logger.Log(t, "trying calls to api gateway /pet should fail with wrong role") - k8s.CheckStaticServerHTTPConnectionFailing(t, k8sOptions, StaticClientName, "-H", doctorToken, targetHTTPAddressPet) - - // will succeed because we use the token with the correct role and the correct issuer - logger.Log(t, "trying calls to api gateway /pet should succeed with JWT token with correct role") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, "-H", petToken, targetHTTPAddressPet) -} - -func checkStatusCondition(t require.TestingT, conditions []metav1.Condition, toCheck metav1.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 trueCondition(conditionType, reason string) metav1.Condition { - return metav1.Condition{ - Type: conditionType, - Reason: reason, - Status: metav1.ConditionTrue, - } -} - -func falseCondition(conditionType, reason string) metav1.Condition { - return metav1.Condition{ - Type: conditionType, - Reason: reason, - Status: metav1.ConditionFalse, - } -} - -func checkConsulStatusCondition(t require.TestingT, conditions []api.Condition, toCheck api.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 trueConsulCondition(conditionType, reason string) api.Condition { - return api.Condition{ - Type: conditionType, - Reason: reason, - Status: "True", - } -} diff --git a/acceptance/tests/api-gateway/example_test.go b/acceptance/tests/api-gateway/example_test.go new file mode 100644 index 0000000000..b324ac31fe --- /dev/null +++ b/acceptance/tests/api-gateway/example_test.go @@ -0,0 +1,64 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Rename package to your test package. +package example + +import ( + "context" + "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/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestExample(t *testing.T) { + // Get test configuration. + cfg := suite.Config() + + // Get the default context. + ctx := suite.Environment().DefaultContext(t) + + // Create Helm values for the Helm install. + helmValues := map[string]string{ + "exampleFeature.enabled": "true", + } + + // Generate a random name for this test. + releaseName := helpers.RandomName() + + // Create a new Consul cluster object. + consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) + + // Create the Consul cluster with Helm. + consulCluster.Create(t) + + // Make test assertions. + + // To run kubectl commands, you need to get KubectlOptions from the test context. + // There are a number of kubectl commands available in the helpers/kubectl.go file. + // For example, to call 'kubectl apply' from the test write the following: + k8s.KubectlApply(t, ctx.KubectlOptions(t), "path/to/config") + + // Clean up any Kubernetes resources you have created + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDelete(t, ctx.KubectlOptions(t), "path/to/config") + }) + + // Similarly, you can obtain Kubernetes client from your test context. + // You can use it to, for example, read all services in a namespace: + k8sClient := ctx.KubernetesClient(t) + services, err := k8sClient.CoreV1().Services(ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.NotNil(t, services.Items) + + // To make Consul API calls, you can get the Consul client from the consulCluster object, + // indicating whether the client needs to be secure or not (i.e. whether TLS and ACLs are enabled on the Consul cluster): + consulClient, _ := consulCluster.SetupConsulClient(t, true) + consulServices, _, err := consulClient.Catalog().Services(nil) + require.NoError(t, err) + require.NotNil(t, consulServices) +} diff --git a/acceptance/tests/api-gateway/main_test.go b/acceptance/tests/api-gateway/main_test.go index f408845b3e..f92fff8a59 100644 --- a/acceptance/tests/api-gateway/main_test.go +++ b/acceptance/tests/api-gateway/main_test.go @@ -1,10 +1,10 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package apigateway +// Rename package to your test package. +package example import ( - "os" "testing" testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" @@ -13,6 +13,25 @@ import ( var suite testsuite.Suite func TestMain(m *testing.M) { - suite = testsuite.NewSuite(m) - os.Exit(suite.Run()) + // First, uncomment the line below to create a new suite so that all flags are parsed. + /* + suite = framework.NewSuite(m) + */ + + // If the test suite needs to run only when certain test flags are passed, + // you need to handle that in the TestMain function. + // Uncomment and modify example code below if that is the case. + /* + if suite.Config().EnableExampleFeature { + os.Exit(suite.Run()) + } else { + fmt.Println("Skipping example feature tests because -enable-example-feature is not set") + os.Exit(0) + } + */ + + // If the test suite should run in every case, uncomment the line below. + /* + os.Exit(suite.Run()) + */ } diff --git a/acceptance/tests/basic/basic_test.go b/acceptance/tests/basic/basic_test.go index 4727b53495..91047711a1 100644 --- a/acceptance/tests/basic/basic_test.go +++ b/acceptance/tests/basic/basic_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package basic import ( diff --git a/acceptance/tests/basic/main_test.go b/acceptance/tests/basic/main_test.go index 0e400ef870..fa858ee4ae 100644 --- a/acceptance/tests/basic/main_test.go +++ b/acceptance/tests/basic/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package basic import ( diff --git a/acceptance/tests/cli/cli_install_test.go b/acceptance/tests/cli/cli_install_test.go index c8b66ff451..1af26d62c7 100644 --- a/acceptance/tests/cli/cli_install_test.go +++ b/acceptance/tests/cli/cli_install_test.go @@ -1,10 +1,6 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cli import ( - "context" "fmt" "strings" "testing" @@ -16,7 +12,6 @@ import ( "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 ipv4RegEx = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" @@ -52,8 +47,8 @@ func TestInstall(t *testing.T) { connHelper.Install(t) connHelper.DeployClientAndServer(t) if c.secure { - connHelper.TestConnectionFailureWithoutIntention(t, connhelper.ConnHelperOpts{}) - connHelper.CreateIntention(t, connhelper.IntentionOpts{}) + connHelper.TestConnectionFailureWithoutIntention(t) + connHelper.CreateIntention(t) } // Run proxy list and get the two results. @@ -88,40 +83,7 @@ func TestInstall(t *testing.T) { } }) - // Troubleshoot: Get the client pod so we can portForward to it and get the 'troubleshoot upstreams' output - clientPod, err := connHelper.Ctx.KubernetesClient(t).CoreV1().Pods(connHelper.Ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ - LabelSelector: "app=static-client", - }) - require.NoError(t, err) - - clientPodName := clientPod.Items[0].Name - upstreamsOut, err := cli.Run(t, ctx.KubectlOptions(t), "troubleshoot", "upstreams", "-pod", clientPodName) - logger.Log(t, string(upstreamsOut)) - require.NoError(t, err) - - if cfg.EnableTransparentProxy { - // If tproxy is enabled we are looking for the upstream ip which is the ClusterIP of the Kubernetes Service - serverService, err := connHelper.Ctx.KubernetesClient(t).CoreV1().Services(connHelper.Ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ - FieldSelector: "metadata.name=static-server", - }) - require.NoError(t, err) - serverIP := serverService.Items[0].Spec.ClusterIP - - proxyOut, err := cli.Run(t, ctx.KubectlOptions(t), "troubleshoot", "proxy", "-pod", clientPodName, "-upstream-ip", serverIP) - require.NoError(t, err) - require.Regexp(t, "Upstream resources are valid", string(proxyOut)) - logger.Log(t, string(proxyOut)) - } else { - // With tproxy disabled and explicit upstreams we need the envoy-id of the server - require.Regexp(t, "static-server", string(upstreamsOut)) - - proxyOut, err := cli.Run(t, ctx.KubectlOptions(t), "troubleshoot", "proxy", "-pod", clientPodName, "-upstream-envoy-id", "static-server") - require.NoError(t, err) - require.Regexp(t, "Upstream resources are valid", string(proxyOut)) - logger.Log(t, string(proxyOut)) - } - - connHelper.TestConnectionSuccess(t, connhelper.ConnHelperOpts{}) + connHelper.TestConnectionSuccess(t) connHelper.TestConnectionFailureWhenUnhealthy(t) }) } diff --git a/acceptance/tests/cli/cli_upgrade_test.go b/acceptance/tests/cli/cli_upgrade_test.go index 8c8970d88a..6fcf82f738 100644 --- a/acceptance/tests/cli/cli_upgrade_test.go +++ b/acceptance/tests/cli/cli_upgrade_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cli import ( diff --git a/acceptance/tests/cli/main_test.go b/acceptance/tests/cli/main_test.go index 2e66d89543..85cef25abe 100644 --- a/acceptance/tests/cli/main_test.go +++ b/acceptance/tests/cli/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cli import ( diff --git a/acceptance/tests/cloud/basic_test.go b/acceptance/tests/cloud/basic_test.go deleted file mode 100644 index e17169700a..0000000000 --- a/acceptance/tests/cloud/basic_test.go +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cloud - -import ( - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "strings" - "testing" - "time" - - terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/environment" - "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/serf/testutil/retry" - "github.com/stretchr/testify/require" -) - -type TokenResponse struct { - Token string `json:"token"` -} - -var ( - resourceSecretName = "resource-sec-name" - resourceSecretKey = "resource-sec-key" - resourceSecretKeyValue = "organization/11eb1a35-aac0-f7c7-8fe1-0242ac110008/project/11eb1a35-ab64-d576-8fe1-0242ac110008/hashicorp.consul.global-network-manager.cluster/TEST" - - clientIDSecretName = "clientid-sec-name" - clientIDSecretKey = "clientid-sec-key" - clientIDSecretKeyValue = "clientid" - - clientSecretName = "client-sec-name" - clientSecretKey = "client-sec-key" - clientSecretKeyValue = "client-secret" - - apiHostSecretName = "apihost-sec-name" - apiHostSecretKey = "apihost-sec-key" - apiHostSecretKeyValue = "fake-server:443" - - authUrlSecretName = "authurl-sec-name" - authUrlSecretKey = "authurl-sec-key" - authUrlSecretKeyValue = "https://fake-server:443" - - scadaAddressSecretName = "scadaaddress-sec-name" - scadaAddressSecretKey = "scadaaddress-sec-key" - scadaAddressSecretKeyValue = "fake-server:443" -) - -// The fake-server has a requestToken endpoint to retrieve the token. -func requestToken(endpoint string) (string, error) { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - - client := &http.Client{Transport: tr} - url := fmt.Sprintf("https://%s/token", endpoint) - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return "", errors.New("error creating request") - } - - // Perform the request - resp, err := client.Do(req) - if err != nil { - fmt.Println("Error sending request:", err) - return "", errors.New("error making request") - } - defer resp.Body.Close() - - // Read the response body - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Println("Error reading response:", err) - return "", errors.New("error reading body") - } - - var tokenResponse TokenResponse - err = json.Unmarshal(body, &tokenResponse) - if err != nil { - fmt.Println("Error parsing response:", err) - return "", errors.New("error parsing body") - } - - return tokenResponse.Token, nil - -} - -func TestBasicCloud(t *testing.T) { - ctx := suite.Environment().DefaultContext(t) - - kubectlOptions := ctx.KubectlOptions(t) - ns := kubectlOptions.Namespace - k8sClient := environment.KubernetesClientFromOptions(t, kubectlOptions) - - cfg := suite.Config() - - if cfg.HCPResourceID != "" { - resourceSecretKeyValue = cfg.HCPResourceID - } - consul.CreateK8sSecret(t, k8sClient, cfg, ns, resourceSecretName, resourceSecretKey, resourceSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, clientIDSecretName, clientIDSecretKey, clientIDSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, clientSecretName, clientSecretKey, clientSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, apiHostSecretName, apiHostSecretKey, apiHostSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, authUrlSecretName, authUrlSecretKey, authUrlSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, scadaAddressSecretName, scadaAddressSecretKey, scadaAddressSecretKeyValue) - - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/cloud/hcp-mock") - podName, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "get", "pod", "-l", "app=fake-server", "-o", `jsonpath="{.items[0].metadata.name}"`) - podName = strings.ReplaceAll(podName, "\"", "") - if err != nil { - logger.Log(t, "error finding pod name") - return - } - logger.Log(t, "fake-server pod name:"+podName) - localPort := terratestk8s.GetAvailablePort(t) - tunnel := terratestk8s.NewTunnelWithLogger( - ctx.KubectlOptions(t), - terratestk8s.ResourceTypePod, - podName, - localPort, - 443, - logger.TestLogger{}) - defer tunnel.Close() - // Retry creating the port forward since it can fail occasionally. - retry.RunWith(&retry.Counter{Wait: 5 * time.Second, Count: 60}, t, func(r *retry.R) { - // NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry - // because we're using ForwardPortE (not ForwardPort) so the `t` won't - // get used to fail the test, just for logging. - require.NoError(r, tunnel.ForwardPortE(t)) - }) - - logger.Log(t, "fake-server addr:"+tunnel.Endpoint()) - consulToken, err := requestToken(tunnel.Endpoint()) - if err != nil { - logger.Log(t, "error finding consul token") - return - } - - logger.Log(t, "consul test token :"+consulToken) - - releaseName := helpers.RandomName() - - helmValues := map[string]string{ - "global.imagePullPolicy": "IfNotPresent", - "global.cloud.enabled": "true", - "global.cloud.resourceId.secretName": resourceSecretName, - "global.cloud.resourceId.secretKey": resourceSecretKey, - - "global.cloud.clientId.secretName": clientIDSecretName, - "global.cloud.clientId.secretKey": clientIDSecretKey, - - "global.cloud.clientSecret.secretName": clientSecretName, - "global.cloud.clientSecret.secretKey": clientSecretKey, - - "global.cloud.apiHost.secretName": apiHostSecretName, - "global.cloud.apiHost.secretKey": apiHostSecretKey, - - "global.cloud.authUrl.secretName": authUrlSecretName, - "global.cloud.authUrl.secretKey": authUrlSecretKey, - - "global.cloud.scadaAddress.secretName": scadaAddressSecretName, - "global.cloud.scadaAddress.secretKey": scadaAddressSecretKey, - "connectInject.default": "true", - - // TODO: Follow up with this bug - "global.acls.manageSystemACLs": "false", - "global.gossipEncryption.autoGenerate": "false", - "global.tls.enabled": "true", - "global.tls.enableAutoEncrypt": "true", - // TODO: Take this out - - "telemetryCollector.enabled": "true", - "telemetryCollector.image": cfg.ConsulCollectorImage, - "telemetryCollector.cloud.clientId.secretName": clientIDSecretName, - "telemetryCollector.cloud.clientId.secretKey": clientIDSecretKey, - - "telemetryCollector.cloud.clientSecret.secretName": clientSecretName, - "telemetryCollector.cloud.clientSecret.secretKey": clientSecretKey, - // Either we set the global.trustedCAs (make sure it's idented exactly) or we - // set TLS to insecure - - "telemetryCollector.extraEnvironmentVars.HCP_API_TLS": "insecure", - "telemetryCollector.extraEnvironmentVars.HCP_AUTH_TLS": "insecure", - "telemetryCollector.extraEnvironmentVars.HCP_SCADA_TLS": "insecure", - "telemetryCollector.extraEnvironmentVars.OTLP_EXPORTER_TLS": "insecure", - - "server.extraEnvironmentVars.HCP_API_TLS": "insecure", - "server.extraEnvironmentVars.HCP_AUTH_TLS": "insecure", - "server.extraEnvironmentVars.HCP_SCADA_TLS": "insecure", - - // This is pregenerated CA used for testing. It can be replaced at any time and isn't - // meant for anything other than testing - // "global.trustedCAs[0]": `-----BEGIN CERTIFICATE----- - // MIICrjCCAZYCCQD5LxMcnMY8rDANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDDA5m - // YWtlLXNlcnZlci1jYTAeFw0yMzA1MTkxMjIwMzhaFw0zMzA1MTYxMjIwMzhaMBkx - // FzAVBgNVBAMMDmZha2Utc2VydmVyLWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A - // MIIBCgKCAQEAwhbiII7sMultedFzQVhVZz5Ti+9lWrpZb8y0ZR6NaNvoxDPX151t - // Adh5NegSeH/+351iDBGZHhmKECtBuk8FJgk88O7y8A7Yg+/lyeZd0SJTEeiYUe7d - // sSaBTYSmixyn6s15Y5MVp9gM7t2YXrocRkFxDtdhLMWf0zwzJEwDouFMMiFZw5II - // yDbI6UfwKyB8C8ln10+TcczbheaOMQ1jGn35YWAG/LEdutU6DO2Y/GZYQ41nyLF1 - // klqh34USQPVQSQW7R7GiDxyhh1fGaDF6RAzH4RerzQSNvvTHmBXIGurB/Hnu1n3p - // CwWeatWMU5POy1es73S/EPM0NpWD5RabSwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB - // AQBayoTltSW55PvKVp9cmqGOBMlkIMKPd6Ny4bCb/3UF+3bzQmIblh3O3kEt7WoY - // fA9vp+6cSRGVqgBfR2bi40RrerLNA79yywIZjfBMteNuRoul5VeD+mLyFCo4197r - // Atl2TEx2kl2V8rjCsEBcTqKqetVOMLYEZ2tbCeUt1A/K7OzaJfHgelEYcsVt68Q9 - // /BLoo2UXfOpRrcsx7u7s5HPVbG3bx+1MvGJZ2C3i0B6agnkGDzEpoM4KZGxEefB9 - // DOHIJfie9d9BQD52nZh3SGHz0b3vfJ430XrQmaNZ26fuIEyIYrpvyAhBXckj2iTD - // 1TXpqr/1D7EUbddktyhXTK9e - // -----END CERTIFICATE-----`, - } - if cfg.ConsulImage != "" { - helmValues["global.image"] = cfg.ConsulImage - } - if cfg.ConsulCollectorImage != "" { - helmValues["telemetryCollector.image"] = cfg.ConsulCollectorImage - } - - consulCluster := consul.NewHelmCluster(t, helmValues, suite.Environment().DefaultContext(t), suite.Config(), releaseName) - consulCluster.Create(t) - - logger.Log(t, "creating static-server deployment") - - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") - t.Log("Finished deployment. Validating expected conditions now") - // Give some time for collector send metrics - time.Sleep(5 * time.Second) - err = validate(tunnel.Endpoint()) - logger.Log(t, fmt.Sprintf("result: %v", err)) - require.NoError(t, err) - -} - -func validate(endpoint string) error { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - - client := &http.Client{Transport: tr} - url := fmt.Sprintf("https://%s/validation", endpoint) - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return errors.New("error creating validation request") - } - - // Perform the request - resp, err := client.Do(req) - if err != nil { - fmt.Println("Error sending request:", err) - return errors.New("error making validation request") - } - if resp.StatusCode == http.StatusExpectationFailed { - // Read the response body - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Println("Error reading response:", err) - return errors.New("error reading body") - } - var message errMsg - err = json.Unmarshal(body, &message) - if err != nil { - fmt.Println("Error parsing response:", err) - return errors.New("error parsing body") - } - - return fmt.Errorf("Failed validation: %s", message) - } else if resp.StatusCode != http.StatusOK { - return errors.New("unexpected status code response from failure") - } - - return nil - -} - -type errMsg struct { - Error string `json:"error"` -} diff --git a/acceptance/tests/cloud/main_test.go b/acceptance/tests/cloud/main_test.go deleted file mode 100644 index 85d1867933..0000000000 --- a/acceptance/tests/cloud/main_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cloud - -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/cloud/remote_dev_test.go b/acceptance/tests/cloud/remote_dev_test.go deleted file mode 100644 index 457dc4f269..0000000000 --- a/acceptance/tests/cloud/remote_dev_test.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cloud - -import ( - "crypto/tls" - "encoding/json" - "os" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/environment" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/acceptance/framework/logger" - - hcpgnm "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/client/global_network_manager_service" - "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models" - hcpcfg "github.com/hashicorp/hcp-sdk-go/config" - "github.com/hashicorp/hcp-sdk-go/httpclient" - "github.com/hashicorp/hcp-sdk-go/resource" -) - -type DevTokenResponse struct { - Token string `json:"token"` -} - -type hcp struct { - ResourceID string - ClientID string - ClientSecret string - AuthURL string - APIHostname string - ScadaAddress string -} - -func TestRemoteDevCloud(t *testing.T) { - _, rIDok := os.LookupEnv("HCP_RESOURCE_ID") - _, cIDok := os.LookupEnv("HCP_CLIENT_ID") - _, cSECok := os.LookupEnv("HCP_CLIENT_SECRET") - - if !rIDok || !cIDok || !cSECok { - t.Log("Must set HCP_RESOURCE_ID, HCP_CLIENT_ID and HCP_CLIENT_SECRET") - t.FailNow() - } - - apiHost := os.Getenv("HCP_AUTH_URL") - if apiHost == "" { - apiHost = "https://api.hcp.dev" - } - authURL := os.Getenv("HCP_API_HOST") - if authURL == "" { - authURL = "https://auth.idp.hcp.dev" - } - scadaAddr := os.Getenv("HCP_SCADA_ADDRESS") - if scadaAddr == "" { - scadaAddr = "scada.internal.hcp.dev:7224" - } - - ctx := suite.Environment().DefaultContext(t) - - kubectlOptions := ctx.KubectlOptions(t) - ns := kubectlOptions.Namespace - k8sClient := environment.KubernetesClientFromOptions(t, kubectlOptions) - - var ( - resourceSecretName = "resource-sec-name" - resourceSecretKey = "resource-sec-key" - resourceSecretKeyValue = os.Getenv("HCP_RESOURCE_ID") - - clientIDSecretName = "clientid-sec-name" - clientIDSecretKey = "clientid-sec-key" - clientIDSecretKeyValue = os.Getenv("HCP_CLIENT_ID") - - clientSecretName = "client-sec-name" - clientSecretKey = "client-sec-key" - clientSecretKeyValue = os.Getenv("HCP_CLIENT_SECRET") - - apiHostSecretName = "apihost-sec-name" - apiHostSecretKey = "apihost-sec-key" - apiHostSecretKeyValue = apiHost - - authUrlSecretName = "authurl-sec-name" - authUrlSecretKey = "authurl-sec-key" - authUrlSecretKeyValue = authURL - - scadaAddressSecretName = "scadaaddress-sec-name" - scadaAddressSecretKey = "scadaaddress-sec-key" - scadaAddressSecretKeyValue = scadaAddr - - bootstrapTokenSecretName = "bootstrap-token" - bootstrapTokenSecretKey = "token" - ) - - hcpCfg := hcp{ - ResourceID: resourceSecretKeyValue, - ClientID: clientIDSecretKeyValue, - ClientSecret: clientSecretKeyValue, - AuthURL: authUrlSecretKeyValue, - APIHostname: apiHostSecretKeyValue, - ScadaAddress: scadaAddressSecretKeyValue, - } - - aclToken := hcpCfg.fetchAgentBootstrapConfig(t) - - cfg := suite.Config() - consul.CreateK8sSecret(t, k8sClient, cfg, ns, resourceSecretName, resourceSecretKey, resourceSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, clientIDSecretName, clientIDSecretKey, clientIDSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, clientSecretName, clientSecretKey, clientSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, apiHostSecretName, apiHostSecretKey, apiHostSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, authUrlSecretName, authUrlSecretKey, authUrlSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, scadaAddressSecretName, scadaAddressSecretKey, scadaAddressSecretKeyValue) - consul.CreateK8sSecret(t, k8sClient, cfg, ns, bootstrapTokenSecretName, bootstrapTokenSecretKey, aclToken) - - releaseName := helpers.RandomName() - - helmValues := map[string]string{ - "global.imagePullPolicy": "IfNotPresent", - "global.cloud.enabled": "true", - "global.cloud.resourceId.secretName": resourceSecretName, - "global.cloud.resourceId.secretKey": resourceSecretKey, - - "global.cloud.clientId.secretName": clientIDSecretName, - "global.cloud.clientId.secretKey": clientIDSecretKey, - - "global.cloud.clientSecret.secretName": clientSecretName, - "global.cloud.clientSecret.secretKey": clientSecretKey, - - "global.cloud.apiHost.secretName": apiHostSecretName, - "global.cloud.apiHost.secretKey": apiHostSecretKey, - - "global.cloud.authUrl.secretName": authUrlSecretName, - "global.cloud.authUrl.secretKey": authUrlSecretKey, - - "global.cloud.scadaAddress.secretName": scadaAddressSecretName, - "global.cloud.scadaAddress.secretKey": scadaAddressSecretKey, - "connectInject.default": "true", - - "global.acls.manageSystemACLs": "true", - "global.acls.bootstrapToken.secretName": bootstrapTokenSecretName, - "global.acls.bootstrapToken.secretKey": bootstrapTokenSecretKey, - - "global.gossipEncryption.autoGenerate": "false", - "global.tls.enabled": "true", - "global.tls.enableAutoEncrypt": "true", - - "telemetryCollector.enabled": "true", - "telemetryCollector.cloud.clientId.secretName": clientIDSecretName, - "telemetryCollector.cloud.clientId.secretKey": clientIDSecretKey, - - "telemetryCollector.cloud.clientSecret.secretName": clientSecretName, - "telemetryCollector.cloud.clientSecret.secretKey": clientSecretKey, - // Either we set the global.trustedCAs (make sure it's idented exactly) or we - // set TLS to insecure - - "telemetryCollector.extraEnvironmentVars.HCP_API_ADDRESS": apiHostSecretKeyValue, - } - - if cfg.ConsulImage != "" { - helmValues["global.image"] = cfg.ConsulImage - } - if cfg.ConsulCollectorImage != "" { - helmValues["telemetryCollector.image"] = cfg.ConsulCollectorImage - } - - consulCluster := consul.NewHelmCluster(t, helmValues, suite.Environment().DefaultContext(t), cfg, releaseName) - consulCluster.Create(t) - - logger.Log(t, "setting acl permissions for collector and services") - aclDir := "../fixtures/bases/cloud/service-intentions" - k8s.KubectlApplyK(t, ctx.KubectlOptions(t), aclDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, ctx.KubectlOptions(t), aclDir) - }) - - logger.Log(t, "creating static-server deployment") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") - time.Sleep(1 * time.Hour) - - // TODO: add in test assertions here - -} - -// fetchAgentBootstrapConfig use the resource-id, client-id, and client-secret -// to call to the agent bootstrap config endpoint and parse the response into a -// CloudBootstrapConfig struct. -func (c *hcp) fetchAgentBootstrapConfig(t *testing.T) string { - cfg, err := c.HCPConfig() - require.NoError(t, err) - logger.Log(t, "Fetching Consul cluster configuration from HCP") - httpClientCfg := httpclient.Config{ - HCPConfig: cfg, - } - clientRuntime, err := httpclient.New(httpClientCfg) - require.NoError(t, err) - - hcpgnmClient := hcpgnm.New(clientRuntime, nil) - clusterResource, err := resource.FromString(c.ResourceID) - require.NoError(t, err) - - params := hcpgnm.NewAgentBootstrapConfigParams(). - WithID(clusterResource.ID). - WithLocationOrganizationID(clusterResource.Organization). - WithLocationProjectID(clusterResource.Project) - - resp, err := hcpgnmClient.AgentBootstrapConfig(params, nil) - require.NoError(t, err) - - bootstrapConfig := resp.GetPayload() - logger.Log(t, "HCP configuration successfully fetched.") - - return c.parseBootstrapConfigResponse(t, bootstrapConfig) -} - -// ConsulConfig represents 'cluster.consul_config' in the response -// fetched from the agent bootstrap config endpoint in HCP. -type ConsulConfig struct { - ACL ACL `json:"acl"` -} - -// ACL represents 'cluster.consul_config.acl' in the response -// fetched from the agent bootstrap config endpoint in HCP. -type ACL struct { - Tokens Tokens `json:"tokens"` -} - -// Tokens represents 'cluster.consul_config.acl.tokens' in the -// response fetched from the agent bootstrap config endpoint in HCP. -type Tokens struct { - Agent string `json:"agent"` - InitialManagement string `json:"initial_management"` -} - -// parseBootstrapConfigResponse unmarshals the boostrap parseBootstrapConfigResponse -// and also sets the HCPConfig values to return CloudBootstrapConfig struct. -func (c *hcp) parseBootstrapConfigResponse(t *testing.T, bootstrapRepsonse *models.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse) string { - - var consulConfig ConsulConfig - err := json.Unmarshal([]byte(bootstrapRepsonse.Bootstrap.ConsulConfig), &consulConfig) - require.NoError(t, err) - - return consulConfig.ACL.Tokens.InitialManagement -} - -func (c *hcp) HCPConfig(opts ...hcpcfg.HCPConfigOption) (hcpcfg.HCPConfig, error) { - if c.ClientID != "" && c.ClientSecret != "" { - opts = append(opts, hcpcfg.WithClientCredentials(c.ClientID, c.ClientSecret)) - } - if c.AuthURL != "" { - opts = append(opts, hcpcfg.WithAuth(c.AuthURL, &tls.Config{})) - } - if c.APIHostname != "" { - opts = append(opts, hcpcfg.WithAPI(c.APIHostname, &tls.Config{})) - } - if c.ScadaAddress != "" { - opts = append(opts, hcpcfg.WithSCADA(c.ScadaAddress, &tls.Config{})) - } - opts = append(opts, hcpcfg.FromEnv(), hcpcfg.WithoutBrowserLogin()) - return hcpcfg.NewHCPConfig(opts...) -} diff --git a/acceptance/tests/config-entries/config_entries_namespaces_test.go b/acceptance/tests/config-entries/config_entries_namespaces_test.go index a013c99e09..a2580069a8 100644 --- a/acceptance/tests/config-entries/config_entries_namespaces_test.go +++ b/acceptance/tests/config-entries/config_entries_namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config_entries import ( @@ -102,7 +99,7 @@ func TestControllerNamespaces(t *testing.T) { if err != nil && !strings.Contains(out, "(AlreadyExists)") { require.NoError(t, err) } - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", KubeNS) }) @@ -136,7 +133,7 @@ func TestControllerNamespaces(t *testing.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 1m timeout here). - counter := &retry.Counter{Count: 60, Wait: 2 * time.Second} + counter := &retry.Counter{Count: 60, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { // service-defaults entry, _, err := consulClient.ConfigEntries().Get(api.ServiceDefaults, "defaults", queryOpts) @@ -159,6 +156,13 @@ func TestControllerNamespaces(t *testing.T) { require.True(r, ok, "could not cast to ProxyConfigEntry") require.Equal(r, api.MeshGatewayModeLocal, proxyDefaultEntry.MeshGateway.Mode) + // exported-services + entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) + require.NoError(r, err) + exportedServicesEntry, ok := entry.(*api.ExportedServicesConfigEntry) + require.True(r, ok, "could not cast to ExportedServicesConfigEntry") + require.Equal(r, "frontend", exportedServicesEntry.Services[0].Name) + // mesh entry, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) require.NoError(r, err) @@ -209,68 +213,6 @@ func TestControllerNamespaces(t *testing.T) { require.Equal(r, "certFile", terminatingGatewayEntry.Services[0].CertFile) require.Equal(r, "keyFile", terminatingGatewayEntry.Services[0].KeyFile) require.Equal(r, "sni", terminatingGatewayEntry.Services[0].SNI) - - // jwt-provider - entry, _, err = consulClient.ConfigEntries().Get(api.JWTProvider, "jwt-provider", defaultOpts) - require.NoError(r, err) - jwtProviderConfigEntry, ok := entry.(*api.JWTProviderConfigEntry) - require.True(r, ok, "could not cast to JWTProviderConfigEntry") - require.Equal(r, "jwks.txt", jwtProviderConfigEntry.JSONWebKeySet.Local.Filename) - require.Equal(r, "test-issuer", jwtProviderConfigEntry.Issuer) - require.ElementsMatch(r, []string{"aud1", "aud2"}, jwtProviderConfigEntry.Audiences) - require.Equal(r, "x-jwt-header", jwtProviderConfigEntry.Locations[0].Header.Name) - require.Equal(r, "x-query-param", jwtProviderConfigEntry.Locations[1].QueryParam.Name) - require.Equal(r, "session-id", jwtProviderConfigEntry.Locations[2].Cookie.Name) - require.Equal(r, "x-forwarded-jwt", jwtProviderConfigEntry.Forwarding.HeaderName) - require.True(r, jwtProviderConfigEntry.Forwarding.PadForwardPayloadHeader) - require.Equal(r, 45, jwtProviderConfigEntry.ClockSkewSeconds) - require.Equal(r, 15, jwtProviderConfigEntry.CacheConfig.Size) - - // exported-services - entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) - require.NoError(r, err) - exportedServicesConfigEntry, ok := entry.(*api.ExportedServicesConfigEntry) - require.True(r, ok, "could not cast to ExportedServicesConfigEntry") - require.Equal(r, "frontend", exportedServicesConfigEntry.Services[0].Name) - require.Equal(r, "frontend", exportedServicesConfigEntry.Services[0].Namespace) - require.Equal(r, "partitionName", exportedServicesConfigEntry.Services[0].Consumers[0].Partition) - require.Equal(r, "peerName", exportedServicesConfigEntry.Services[0].Consumers[1].Peer) - require.Equal(r, "groupName", exportedServicesConfigEntry.Services[0].Consumers[2].SamenessGroup) - - // control-plane-request-limit - entry, _, err = consulClient.ConfigEntries().Get(api.RateLimitIPConfig, "controlplanerequestlimit", defaultOpts) - require.NoError(r, err) - rateLimitIPConfigEntry, ok := entry.(*api.RateLimitIPConfigEntry) - require.True(r, ok, "could not cast to RateLimitIPConfigEntry") - require.Equal(r, "permissive", rateLimitIPConfigEntry.Mode) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ACL.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ACL.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Catalog.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Catalog.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConfigEntry.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConfigEntry.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConnectCA.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConnectCA.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Coordinate.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Coordinate.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.DiscoveryChain.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.DiscoveryChain.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Health.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Health.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Intention.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Intention.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.KV.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.KV.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Tenancy.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Tenancy.WriteRate) - //require.Equal(r, 100.0, rateLimitIPConfigEntry.PreparedQuery.ReadRate) - //require.Equal(r, 100.0, rateLimitIPConfigEntry.PreparedQuery.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Session.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Session.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Txn.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Txn.WriteRate) }) } @@ -288,6 +230,10 @@ func TestControllerNamespaces(t *testing.T) { patchMeshGatewayMode := "remote" k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "proxydefaults", "global", "-p", fmt.Sprintf(`{"spec":{"meshGateway":{"mode": "%s"}}}`, patchMeshGatewayMode), "--type=merge") + logger.Log(t, "patching partition-exports custom resource") + patchServiceName := "backend" + k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "exportedservices", "default", "-p", fmt.Sprintf(`{"spec":{"services":[{"name": "%s", "namespace": "front", "consumers":[{"partition": "foo"}]}]}}`, patchServiceName), "--type=merge") + logger.Log(t, "patching mesh custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "mesh", "mesh", "-p", fmt.Sprintf(`{"spec":{"transparentProxy":{"meshDestinationsOnly": %t}}}`, false), "--type=merge") @@ -309,18 +255,7 @@ func TestControllerNamespaces(t *testing.T) { patchSNI := "patch-sni" k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "terminatinggateway", "terminating-gateway", "-p", fmt.Sprintf(`{"spec": {"services": [{"name":"name","caFile":"caFile","certFile":"certFile","keyFile":"keyFile","sni":"%s"}]}}`, patchSNI), "--type=merge") - logger.Log(t, "patching jwt-provider custom resource") - patchIssuer := "other-issuer" - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "jwtprovider", "jwt-provider", "-p", fmt.Sprintf(`{"spec": {"issuer": "%s"}}`, patchIssuer), "--type=merge") - - logger.Log(t, "patching exported-services custom resource") - patchPartition := "destination" - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "exportedservices", "default", "-p", fmt.Sprintf(`{"spec": {"services": [{"name": "frontend", "namespace": "frontend", "consumers": [{"partition": "%s"}, {"peer": "peerName"}, {"samenessGroup": "groupName"}]}]}}`, patchPartition), "--type=merge") - - logger.Log(t, "patching control-plane-request-limit custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "controlplanerequestlimit", "controlplanerequestlimit", "-p", `{"spec": {"mode": "disabled"}}`, "--type=merge") - - counter := &retry.Counter{Count: 20, Wait: 2 * time.Second} + counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond} retry.RunWith(counter, t, func(r *retry.R) { // service-defaults entry, _, err := consulClient.ConfigEntries().Get(api.ServiceDefaults, "defaults", queryOpts) @@ -343,6 +278,13 @@ func TestControllerNamespaces(t *testing.T) { require.True(r, ok, "could not cast to ProxyConfigEntry") require.Equal(r, api.MeshGatewayModeRemote, proxyDefaultsEntry.MeshGateway.Mode) + // partition-exports + entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) + require.NoError(r, err) + exportedServicesEntry, ok := entry.(*api.ExportedServicesConfigEntry) + require.True(r, ok, "could not cast to ExportedServicesConfigEntry") + require.Equal(r, "backend", exportedServicesEntry.Services[0].Name) + // mesh entry, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) require.NoError(r, err) @@ -386,27 +328,6 @@ func TestControllerNamespaces(t *testing.T) { terminatingGatewayEntry, ok := entry.(*api.TerminatingGatewayConfigEntry) require.True(r, ok, "could not cast to TerminatingGatewayConfigEntry") require.Equal(r, patchSNI, terminatingGatewayEntry.Services[0].SNI) - - // jwt-Provider - entry, _, err = consulClient.ConfigEntries().Get(api.JWTProvider, "jwt-provider", defaultOpts) - require.NoError(r, err) - jwtProviderConfigEntry, ok := entry.(*api.JWTProviderConfigEntry) - require.True(r, ok, "could not cast to JWTProviderConfigEntry") - require.Equal(r, patchIssuer, jwtProviderConfigEntry.Issuer) - - // exported-services - entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) - require.NoError(r, err) - exportedServicesConfigEntry, ok := entry.(*api.ExportedServicesConfigEntry) - require.True(r, ok, "could not cast to ExportedServicesConfigEntry") - require.Equal(r, patchPartition, exportedServicesConfigEntry.Services[0].Consumers[0].Partition) - - // control-plane-request-limit - entry, _, err = consulClient.ConfigEntries().Get(api.RateLimitIPConfig, "controlplanerequestlimit", defaultOpts) - require.NoError(r, err) - rateLimitIPConfigEntry, ok := entry.(*api.RateLimitIPConfigEntry) - require.True(r, ok, "could not cast to RateLimitIPConfigEntry") - require.Equal(r, rateLimitIPConfigEntry.Mode, "disabled") }) } @@ -421,6 +342,9 @@ func TestControllerNamespaces(t *testing.T) { logger.Log(t, "deleting proxy-defaults custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "proxydefaults", "global") + logger.Log(t, "deleting partition-exports custom resource") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "exportedservices", "default") + logger.Log(t, "deleting mesh custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "mesh", "mesh") @@ -439,16 +363,7 @@ func TestControllerNamespaces(t *testing.T) { logger.Log(t, "deleting terminating-gateway custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "terminatinggateway", "terminating-gateway") - logger.Log(t, "deleting jwt-provider custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "jwtprovider", "jwt-provider") - - logger.Log(t, "deleting exported-services custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "exportedservices", "default") - - logger.Log(t, "deleting control-plane-request-limit custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "controlplanerequestlimit", "controlplanerequestlimit") - - counter := &retry.Counter{Count: 20, Wait: 2 * time.Second} + counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond} retry.RunWith(counter, t, func(r *retry.R) { // service-defaults _, _, err := consulClient.ConfigEntries().Get(api.ServiceDefaults, "defaults", queryOpts) @@ -465,6 +380,11 @@ func TestControllerNamespaces(t *testing.T) { require.Error(r, err) require.Contains(r, err.Error(), "404 (Config entry not found") + // partition-exports + _, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) + require.Error(r, err) + require.Contains(r, err.Error(), "404 (Config entry not found") + // mesh _, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) require.Error(r, err) @@ -494,21 +414,6 @@ func TestControllerNamespaces(t *testing.T) { _, _, err = consulClient.ConfigEntries().Get(api.IngressGateway, "terminating-gateway", queryOpts) require.Error(r, err) require.Contains(r, err.Error(), "404 (Config entry not found") - - // jwt-provider - _, _, err = consulClient.ConfigEntries().Get(api.JWTProvider, "jwt-provider", defaultOpts) - require.Error(r, err) - require.Contains(r, err.Error(), "404 (Config entry not found") - - // exported-services - _, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) - require.Error(r, err) - require.Contains(r, err.Error(), "404 (Config entry not found") - - // control-plane-request-limit - _, _, err = consulClient.ConfigEntries().Get(api.RateLimitIPConfig, "controlplanerequestlimit", defaultOpts) - require.Error(r, err) - require.Contains(r, err.Error(), "404 (Config entry not found") }) } }) diff --git a/acceptance/tests/config-entries/config_entries_test.go b/acceptance/tests/config-entries/config_entries_test.go index a36e9baaf5..035edf6a8f 100644 --- a/acceptance/tests/config-entries/config_entries_test.go +++ b/acceptance/tests/config-entries/config_entries_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config_entries import ( @@ -86,7 +83,7 @@ func TestController(t *testing.T) { // endpoint fails initially. out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/crds-oss") require.NoError(r, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, 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/crds-oss") @@ -95,8 +92,8 @@ func TestController(t *testing.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 2m timeout here). - counter := &retry.Counter{Count: 60, Wait: 2 * time.Second} + // the reconcile loop to run (hence the 1m timeout here). + counter := &retry.Counter{Count: 60, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { // service-defaults entry, _, err := consulClient.ConfigEntries().Get(api.ServiceDefaults, "defaults", nil) @@ -178,67 +175,6 @@ func TestController(t *testing.T) { require.Equal(r, "certFile", terminatingGatewayEntry.Services[0].CertFile) require.Equal(r, "keyFile", terminatingGatewayEntry.Services[0].KeyFile) require.Equal(r, "sni", terminatingGatewayEntry.Services[0].SNI) - - // jwt-provider - entry, _, err = consulClient.ConfigEntries().Get(api.JWTProvider, "jwt-provider", nil) - require.NoError(r, err) - jwtProviderConfigEntry, ok := entry.(*api.JWTProviderConfigEntry) - require.True(r, ok, "could not cast to JWTProviderConfigEntry") - require.Equal(r, "jwks.txt", jwtProviderConfigEntry.JSONWebKeySet.Local.Filename) - require.Equal(r, "test-issuer", jwtProviderConfigEntry.Issuer) - require.ElementsMatch(r, []string{"aud1", "aud2"}, jwtProviderConfigEntry.Audiences) - require.Equal(r, "x-jwt-header", jwtProviderConfigEntry.Locations[0].Header.Name) - require.Equal(r, "x-query-param", jwtProviderConfigEntry.Locations[1].QueryParam.Name) - require.Equal(r, "session-id", jwtProviderConfigEntry.Locations[2].Cookie.Name) - require.Equal(r, "x-forwarded-jwt", jwtProviderConfigEntry.Forwarding.HeaderName) - require.True(r, jwtProviderConfigEntry.Forwarding.PadForwardPayloadHeader) - require.Equal(r, 45, jwtProviderConfigEntry.ClockSkewSeconds) - require.Equal(r, 15, jwtProviderConfigEntry.CacheConfig.Size) - - // exported-services - entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", nil) - require.NoError(r, err) - exportedServicesConfigEntry, ok := entry.(*api.ExportedServicesConfigEntry) - require.True(r, ok, "could not cast to ExportedServicesConfigEntry") - require.Equal(r, "frontend", exportedServicesConfigEntry.Services[0].Name) - require.Equal(r, "peerName", exportedServicesConfigEntry.Services[0].Consumers[0].Peer) - require.Equal(r, "groupName", exportedServicesConfigEntry.Services[0].Consumers[1].SamenessGroup) - - // control-plane-request-limit - entry, _, err = consulClient.ConfigEntries().Get(api.RateLimitIPConfig, "controlplanerequestlimit", nil) - require.NoError(r, err) - rateLimitIPConfigEntry, ok := entry.(*api.RateLimitIPConfigEntry) - require.True(r, ok, "could not cast to RateLimitIPConfigEntry") - require.Equal(r, "permissive", rateLimitIPConfigEntry.Mode) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ACL.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ACL.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Catalog.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Catalog.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConfigEntry.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConfigEntry.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConnectCA.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.ConnectCA.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Coordinate.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Coordinate.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.DiscoveryChain.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.DiscoveryChain.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Health.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Health.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Intention.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Intention.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.KV.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.KV.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Tenancy.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Tenancy.WriteRate) - //require.Equal(r, 100.0, rateLimitIPConfigEntry.PreparedQuery.ReadRate) - //require.Equal(r, 100.0, rateLimitIPConfigEntry.PreparedQuery.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Session.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Session.WriteRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Txn.ReadRate) - require.Equal(r, 100.0, rateLimitIPConfigEntry.Txn.WriteRate) - }) } @@ -277,17 +213,6 @@ func TestController(t *testing.T) { patchSNI := "patch-sni" k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "terminatinggateway", "terminating-gateway", "-p", fmt.Sprintf(`{"spec": {"services": [{"name":"name","caFile":"caFile","certFile":"certFile","keyFile":"keyFile","sni":"%s"}]}}`, patchSNI), "--type=merge") - logger.Log(t, "patching JWTProvider custom resource") - patchIssuer := "other-issuer" - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "jwtprovider", "jwt-provider", "-p", fmt.Sprintf(`{"spec": {"issuer": "%s"}}`, patchIssuer), "--type=merge") - - logger.Log(t, "patching ExportedServices custom resource") - patchPeer := "destination" - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "exportedservices", "default", "-p", fmt.Sprintf(`{"spec": {"services": [{"name": "frontend", "consumers": [{"peer": "%s"}, {"samenessGroup": "groupName"}]}]}}`, patchPeer), "--type=merge") - - logger.Log(t, "patching control-plane-request-limit custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "controlplanerequestlimit", "controlplanerequestlimit", "-p", `{"spec": {"mode": "disabled"}}`, "--type=merge") - counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond} retry.RunWith(counter, t, func(r *retry.R) { // service-defaults @@ -355,27 +280,6 @@ func TestController(t *testing.T) { terminatingGatewayEntry, ok := entry.(*api.TerminatingGatewayConfigEntry) require.True(r, ok, "could not cast to TerminatingGatewayConfigEntry") require.Equal(r, patchSNI, terminatingGatewayEntry.Services[0].SNI) - - // jwt-provider - entry, _, err = consulClient.ConfigEntries().Get(api.JWTProvider, "jwt-provider", nil) - require.NoError(r, err) - jwtProviderConfigEntry, ok := entry.(*api.JWTProviderConfigEntry) - require.True(r, ok, "could not cast to JWTProviderConfigEntry") - require.Equal(r, patchIssuer, jwtProviderConfigEntry.Issuer) - - // exported-services - entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", nil) - require.NoError(r, err) - exportedServicesConfigEntry, ok := entry.(*api.ExportedServicesConfigEntry) - require.True(r, ok, "could not cast to ExportedServicesConfigEntry") - require.Equal(r, patchPeer, exportedServicesConfigEntry.Services[0].Consumers[0].Peer) - - // control-plane-request-limit - entry, _, err = consulClient.ConfigEntries().Get(api.RateLimitIPConfig, "controlplanerequestlimit", nil) - require.NoError(r, err) - rateLimitIPConfigEntry, ok := entry.(*api.RateLimitIPConfigEntry) - require.True(r, ok, "could not cast to RateLimitIPConfigEntry") - require.Equal(r, rateLimitIPConfigEntry.Mode, "disabled") }) } @@ -408,15 +312,6 @@ func TestController(t *testing.T) { logger.Log(t, "deleting terminating-gateway custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "terminatinggateway", "terminating-gateway") - logger.Log(t, "deleting jwt-provider custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "jwtprovider", "jwt-provider") - - logger.Log(t, "deleting exported-services custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "exportedservices", "default") - - logger.Log(t, "deleting control-plane-request-limit custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "controlplanerequestlimit", "controlplanerequestlimit") - counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond} retry.RunWith(counter, t, func(r *retry.R) { // service-defaults @@ -460,22 +355,7 @@ func TestController(t *testing.T) { require.Contains(r, err.Error(), "404 (Config entry not found") // terminating-gateway - _, _, err = consulClient.ConfigEntries().Get(api.TerminatingGateway, "terminating-gateway", nil) - require.Error(r, err) - require.Contains(r, err.Error(), "404 (Config entry not found") - - // jwt-provider - _, _, err = consulClient.ConfigEntries().Get(api.JWTProvider, "jwt-provider", nil) - require.Error(r, err) - require.Contains(r, err.Error(), "404 (Config entry not found") - - // exported-services - _, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", nil) - require.Error(r, err) - require.Contains(r, err.Error(), "404 (Config entry not found") - - // control-plane-request-limit - _, _, err = consulClient.ConfigEntries().Get(api.RateLimitIPConfig, "controlplanerequestlimit", nil) + _, _, err = consulClient.ConfigEntries().Get(api.IngressGateway, "terminating-gateway", nil) require.Error(r, err) require.Contains(r, err.Error(), "404 (Config entry not found") }) diff --git a/acceptance/tests/config-entries/main_test.go b/acceptance/tests/config-entries/main_test.go index 805045dcef..64034f7663 100644 --- a/acceptance/tests/config-entries/main_test.go +++ b/acceptance/tests/config-entries/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config_entries import ( diff --git a/acceptance/tests/connect/connect_external_servers_test.go b/acceptance/tests/connect/connect_external_servers_test.go index c0a61f160f..56d7b16bc0 100644 --- a/acceptance/tests/connect/connect_external_servers_test.go +++ b/acceptance/tests/connect/connect_external_servers_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connect import ( @@ -75,11 +72,11 @@ func TestConnectInject_ExternalServers(t *testing.T) { consulCluster.Create(t) logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } // Check that both static-server and static-client have been injected and now have 2 containers. @@ -128,7 +125,7 @@ func TestConnectInject_ExternalServers(t *testing.T) { // Test that kubernetes readiness status is synced to Consul. // Create the file so that the readiness probe of the static-server pod fails. logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+connhelper.StaticServerName, "-c", "static-server", "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+connhelper.StaticServerName, "--", "touch", "/tmp/unhealthy") // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. diff --git a/acceptance/tests/connect/connect_inject_namespaces_test.go b/acceptance/tests/connect/connect_inject_namespaces_test.go index 03200cc75b..dbfc4725e4 100644 --- a/acceptance/tests/connect/connect_inject_namespaces_test.go +++ b/acceptance/tests/connect/connect_inject_namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connect import ( @@ -101,12 +98,12 @@ func TestConnectInjectNamespaces(t *testing.T) { logger.Logf(t, "creating namespaces %s and %s", staticServerNamespace, StaticClientNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", staticServerNamespace) }) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", StaticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { // Note: this deletion will take longer in cases when the static-client deployment // hasn't yet fully terminated. k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", StaticClientNamespace) @@ -147,11 +144,11 @@ func TestConnectInjectNamespaces(t *testing.T) { } logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") } // Check that both static-server and static-client have been injected and now have 2 containers. @@ -221,7 +218,7 @@ func TestConnectInjectNamespaces(t *testing.T) { // Test that kubernetes readiness status is synced to Consul. // Create the file so that the readiness probe of the static-server pod fails. logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, staticServerOpts, "exec", "deploy/"+connhelper.StaticServerName, "-c", "static-server", "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, staticServerOpts, "exec", "deploy/"+connhelper.StaticServerName, "--", "touch", "/tmp/unhealthy") // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. @@ -305,7 +302,7 @@ func TestConnectInjectNamespaces_CleanupController(t *testing.T) { logger.Logf(t, "creating namespace %s", StaticClientNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", StaticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", StaticClientNamespace) }) @@ -315,7 +312,7 @@ func TestConnectInjectNamespaces_CleanupController(t *testing.T) { ConfigPath: ctx.KubectlOptions(t).ConfigPath, Namespace: StaticClientNamespace, } - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") logger.Log(t, "waiting for static-client to be registered with Consul") consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) diff --git a/acceptance/tests/connect/connect_inject_test.go b/acceptance/tests/connect/connect_inject_test.go index b44523235c..2909f8e5d0 100644 --- a/acceptance/tests/connect/connect_inject_test.go +++ b/acceptance/tests/connect/connect_inject_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connect import ( @@ -51,45 +48,16 @@ func TestConnectInject(t *testing.T) { connHelper.Install(t) connHelper.DeployClientAndServer(t) if c.secure { - connHelper.TestConnectionFailureWithoutIntention(t, connhelper.ConnHelperOpts{}) - connHelper.CreateIntention(t, connhelper.IntentionOpts{}) + connHelper.TestConnectionFailureWithoutIntention(t) + connHelper.CreateIntention(t) } - connHelper.TestConnectionSuccess(t, connhelper.ConnHelperOpts{}) + connHelper.TestConnectionSuccess(t) connHelper.TestConnectionFailureWhenUnhealthy(t) }) } } -// TestConnectInject_VirtualIPFailover ensures that KubeDNS entries are saved to the virtual IP address table in Consul. -func TestConnectInject_VirtualIPFailover(t *testing.T) { - cfg := suite.Config() - if !cfg.EnableTransparentProxy { - // This can only be tested in transparent proxy mode. - t.SkipNow() - } - ctx := suite.Environment().DefaultContext(t) - - releaseName := helpers.RandomName() - connHelper := connhelper.ConnectHelper{ - ClusterKind: consul.Helm, - Secure: true, - ReleaseName: releaseName, - Ctx: ctx, - UseAppNamespace: cfg.EnableRestrictedPSAEnforcement, - Cfg: cfg, - } - - connHelper.Setup(t) - - connHelper.Install(t) - connHelper.CreateResolverRedirect(t) - connHelper.DeployClientAndServer(t) - - opts := connHelper.KubectlOptsForApp(t) - k8s.CheckStaticServerConnectionSuccessful(t, opts, "static-client", "http://resolver-redirect") -} - // Test the endpoints controller cleans up force-killed pods. func TestConnectInject_CleanupKilledPods(t *testing.T) { for _, secure := range []bool{false, true} { @@ -113,7 +81,7 @@ func TestConnectInject_CleanupKilledPods(t *testing.T) { consulCluster.Create(t) logger.Log(t, "creating static-client deployment") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") logger.Log(t, "waiting for static-client to be registered with Consul") consulClient, _ := consulCluster.SetupConsulClient(t, secure) @@ -220,8 +188,8 @@ func TestConnectInject_MultiportServices(t *testing.T) { } logger.Log(t, "creating multiport static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/multiport-app") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject-multiport") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/multiport-app") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject-multiport") // Check that static-client has been injected and now has 2 containers. podList, err := ctx.KubernetesClient(t).CoreV1().Pods(ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ @@ -280,7 +248,7 @@ func TestConnectInject_MultiportServices(t *testing.T) { // pod to static-server. // Deploy static-server. - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") // For outbound connections from the multi port pod, only intentions from the first service in the multiport // pod need to be created, since all upstream connections are made through the first service's envoy proxy. @@ -310,9 +278,9 @@ func TestConnectInject_MultiportServices(t *testing.T) { // and check inbound connections to the multi port pods' services. // Create the files so that the readiness probes of the multi port pod fails. logger.Log(t, "testing k8s -> consul health checks sync by making the multiport unhealthy") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+multiport, "-c", "multiport", "--", "touch", "/tmp/unhealthy-multiport") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+multiport, "--", "touch", "/tmp/unhealthy-multiport") logger.Log(t, "testing k8s -> consul health checks sync by making the multiport-admin unhealthy") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+multiport, "-c", "multiport-admin", "--", "touch", "/tmp/unhealthy-multiport-admin") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+multiport, "--", "touch", "/tmp/unhealthy-multiport-admin") // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. diff --git a/acceptance/tests/connect/connect_proxy_lifecycle_test.go b/acceptance/tests/connect/connect_proxy_lifecycle_test.go index a94175270e..ae70a0fdeb 100644 --- a/acceptance/tests/connect/connect_proxy_lifecycle_test.go +++ b/acceptance/tests/connect/connect_proxy_lifecycle_test.go @@ -11,10 +11,10 @@ import ( "testing" "time" + "github.com/gruntwork-io/terratest/modules/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/connhelper" "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/sdk/testutil/retry" "github.com/stretchr/testify/require" @@ -33,6 +33,7 @@ const ( // Test the endpoints controller cleans up force-killed pods. func TestConnectInject_ProxyLifecycleShutdown(t *testing.T) { + t.Skipf("skiping this test, will be re-added in a future commit") cfg := suite.Config() cfg.SkipWhenOpenshiftAndCNI(t) @@ -120,11 +121,11 @@ func TestConnectInject_ProxyLifecycleShutdown(t *testing.T) { }) if testCfg.secure { - connHelper.TestConnectionFailureWithoutIntention(t, connhelper.ConnHelperOpts{}) - connHelper.CreateIntention(t, connhelper.IntentionOpts{}) + connHelper.TestConnectionFailureWithoutIntention(t) + connHelper.CreateIntention(t) } - connHelper.TestConnectionSuccess(t, connhelper.ConnHelperOpts{}) + connHelper.TestConnectionSuccess(t) // Get static-client pod name ns := ctx.KubectlOptions(t).Namespace @@ -205,172 +206,3 @@ func TestConnectInject_ProxyLifecycleShutdown(t *testing.T) { }) } } - -func TestConnectInject_ProxyLifecycleShutdownJob(t *testing.T) { - cfg := suite.Config() - - if cfg.EnableTransparentProxy { - // TODO t-eckert: Come back and review this with wise counsel. - t.Skip("Skipping test because transparent proxy is enabled") - } - - defaultGracePeriod := 5 - - cases := map[string]int{ - "../fixtures/cases/jobs/job-client-inject": defaultGracePeriod, - "../fixtures/cases/jobs/job-client-inject-grace-period-0s": 0, - "../fixtures/cases/jobs/job-client-inject-grace-period-10s": 10, - } - - // Set up the installation and static-server once. - ctx := suite.Environment().DefaultContext(t) - releaseName := helpers.RandomName() - - connHelper := connhelper.ConnectHelper{ - ClusterKind: consul.Helm, - ReleaseName: releaseName, - Ctx: ctx, - Cfg: cfg, - HelmValues: map[string]string{ - "connectInject.sidecarProxy.lifecycle.defaultShutdownGracePeriodSeconds": strconv.FormatInt(int64(defaultGracePeriod), 10), - "connectInject.sidecarProxy.lifecycle.defaultEnabled": strconv.FormatBool(true), - }, - } - - connHelper.Setup(t) - connHelper.Install(t) - connHelper.DeployServer(t) - - logger.Log(t, "waiting for static-server to be registered with Consul") - retry.RunWith(&retry.Timer{Timeout: 3 * time.Minute, Wait: 5 * time.Second}, t, func(r *retry.R) { - for _, name := range []string{ - "static-server", - "static-server-sidecar-proxy", - } { - logger.Logf(t, "checking for %s service in Consul catalog", name) - instances, _, err := connHelper.ConsulClient.Catalog().Service(name, "", nil) - r.Check(err) - - if len(instances) != 1 { - r.Errorf("expected 1 instance of %s", name) - - } - } - }) - - // Iterate over the Job cases and test connection. - for path, gracePeriod := range cases { - connHelper.DeployJob(t, path) // Default case. - - logger.Log(t, "waiting for job-client to be registered with Consul") - retry.RunWith(&retry.Timer{Timeout: 300 * time.Second, Wait: 5 * time.Second}, t, func(r *retry.R) { - for _, name := range []string{ - "job-client", - "job-client-sidecar-proxy", - } { - logger.Logf(t, "checking for %s service in Consul catalog", name) - instances, _, err := connHelper.ConsulClient.Catalog().Service(name, "", nil) - r.Check(err) - - if len(instances) != 1 { - r.Errorf("expected 1 instance of %s", name) - } - } - }) - - connHelper.TestConnectionSuccess(t, connhelper.ConnHelperOpts{ClientType: connhelper.JobName}) - - // Get job-client pod name - ns := ctx.KubectlOptions(t).Namespace - pods, err := ctx.KubernetesClient(t).CoreV1().Pods(ns).List( - context.Background(), - metav1.ListOptions{ - LabelSelector: "app=job-client", - }, - ) - require.NoError(t, err) - require.Len(t, pods.Items, 1) - jobName := pods.Items[0].Name - - // Exec into job and send shutdown request to running proxy. - // curl --max-time 2 -s -f -XPOST http://127.0.0.1:20600/graceful_shutdown - sendProxyShutdownArgs := []string{"exec", jobName, "-c", connhelper.JobName, "--", "curl", "--max-time", "2", "-s", "-f", "-XPOST", "http://127.0.0.1:20600/graceful_shutdown"} - _, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), sendProxyShutdownArgs...) - require.NoError(t, err) - - logger.Log(t, "Proxy killed...") - - args := []string{"exec", jobName, "-c", connhelper.JobName, "--", "curl", "-vvvsSf"} - if cfg.EnableTransparentProxy { - args = append(args, "http://static-server") - } else { - args = append(args, "http://localhost:1234") - } - - if gracePeriod > 0 { - logger.Log(t, "Checking if connection successful within grace period...") - retry.RunWith(&retry.Timer{Timeout: time.Duration(gracePeriod) * time.Second, Wait: 2 * time.Second}, t, func(r *retry.R) { - output, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), args...) - require.NoError(r, err) - require.True(r, !strings.Contains(output, "curl: (7) Failed to connect")) - }) - //wait for the grace period to end after successful request - time.Sleep(time.Duration(gracePeriod) * time.Second) - } - - // Test that requests fail once grace period has ended, or there was no grace period set. - logger.Log(t, "Checking that requests fail now that proxy is killed...") - retry.RunWith(&retry.Timer{Timeout: 2 * time.Minute, Wait: 2 * time.Second}, t, func(r *retry.R) { - output, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), args...) - require.Error(r, err) - require.True(r, strings.Contains(output, "curl: (7) Failed to connect")) - }) - - // Wait for the job to complete. - retry.RunWith(&retry.Timer{Timeout: 4 * time.Minute, Wait: 30 * time.Second}, t, func(r *retry.R) { - logger.Log(t, "Checking if job completed...") - jobs, err := ctx.KubernetesClient(t).BatchV1().Jobs(ns).List( - context.Background(), - metav1.ListOptions{ - LabelSelector: "app=job-client", - }, - ) - require.NoError(r, err) - require.True(r, jobs.Items[0].Status.Succeeded == 1) - }) - - // Delete the job and its associated Pod. - pods, err = ctx.KubernetesClient(t).CoreV1().Pods(ns).List( - context.Background(), - metav1.ListOptions{ - LabelSelector: "app=job-client", - }, - ) - require.NoError(t, err) - podName := pods.Items[0].Name - - err = ctx.KubernetesClient(t).BatchV1().Jobs(ns).Delete(context.Background(), "job-client", metav1.DeleteOptions{}) - require.NoError(t, err) - - err = ctx.KubernetesClient(t).CoreV1().Pods(ns).Delete(context.Background(), podName, metav1.DeleteOptions{}) - require.NoError(t, err) - - logger.Log(t, "ensuring job is deregistered after termination") - retry.RunWith(&retry.Timer{Timeout: 4 * time.Minute, Wait: 30 * time.Second}, t, func(r *retry.R) { - for _, name := range []string{ - "job-client", - "job-client-sidecar-proxy", - } { - logger.Logf(t, "checking for %s service in Consul catalog", name) - instances, _, err := connHelper.ConsulClient.Catalog().Service(name, "", nil) - r.Check(err) - - for _, instance := range instances { - if strings.Contains(instance.ServiceID, jobName) { - r.Errorf("%s is still registered", instance.ServiceID) - } - } - } - }) - } -} diff --git a/acceptance/tests/connect/main_test.go b/acceptance/tests/connect/main_test.go index e44c75e519..a2b5925bed 100644 --- a/acceptance/tests/connect/main_test.go +++ b/acceptance/tests/connect/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connect import ( diff --git a/acceptance/tests/connect/permissive_mtls_test.go b/acceptance/tests/connect/permissive_mtls_test.go deleted file mode 100644 index 929d56acfd..0000000000 --- a/acceptance/tests/connect/permissive_mtls_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package connect - -import ( - "context" - "testing" - - "github.com/hashicorp/consul-k8s/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/acceptance/framework/connhelper" - "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/sdk/testutil/retry" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestConnectInject_PermissiveMTLS(t *testing.T) { - cfg := suite.Config() - if !cfg.EnableTransparentProxy { - t.Skipf("skipping this because -enable-transparent-proxy is not set") - } - cfg.SkipWhenOpenshiftAndCNI(t) - - ctx := suite.Environment().DefaultContext(t) - - releaseName := helpers.RandomName() - connHelper := connhelper.ConnectHelper{ - ClusterKind: consul.Helm, - Secure: true, - ReleaseName: releaseName, - Ctx: ctx, - Cfg: cfg, - } - connHelper.Setup(t) - connHelper.Install(t) - - deployNonMeshClient(t, connHelper) - deployStaticServer(t, cfg, connHelper) - - kubectlOpts := connHelper.Ctx.KubectlOptions(t) - logger.Logf(t, "Check that incoming non-mTLS connection fails in MutualTLSMode = strict") - k8s.CheckStaticServerConnectionFailing(t, kubectlOpts, "static-client", "http://static-server") - - logger.Log(t, "Set allowEnablingPermissiveMutualTLS = true") - writeCrd(t, connHelper, "../fixtures/cases/permissive-mtls/mesh-config-permissive-allowed.yaml") - - logger.Log(t, "Set mutualTLSMode = permissive for static-server") - writeCrd(t, connHelper, "../fixtures/cases/permissive-mtls/service-defaults-static-server-permissive.yaml") - - logger.Log(t, "Check that incoming mTLS connection is successful in MutualTLSMode = permissive") - k8s.CheckStaticServerConnectionSuccessful(t, kubectlOpts, "static-client", "http://static-server") -} - -func deployNonMeshClient(t *testing.T, ch connhelper.ConnectHelper) { - t.Helper() - - logger.Log(t, "Creating static-client deployment with connect-inject=false") - k8s.DeployKustomize(t, ch.Ctx.KubectlOptions(t), ch.Cfg.NoCleanupOnFailure, ch.Cfg.NoCleanup, ch.Cfg.DebugDirectory, "../fixtures/bases/static-client") - requirePodContainers(t, ch, "app=static-client", 1) -} - -func deployStaticServer(t *testing.T, cfg *config.TestConfig, ch connhelper.ConnectHelper) { - t.Helper() - - logger.Log(t, "Creating static-server deployment with connect-inject=true") - k8s.DeployKustomize(t, ch.Ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - requirePodContainers(t, ch, "app=static-server", 2) -} - -func writeCrd(t *testing.T, ch connhelper.ConnectHelper, path string) { - t.Helper() - - t.Cleanup(func() { - _, _ = k8s.RunKubectlAndGetOutputE(t, ch.Ctx.KubectlOptions(t), "delete", "-f", path) - }) - - _, err := k8s.RunKubectlAndGetOutputE(t, ch.Ctx.KubectlOptions(t), "apply", "-f", path) - require.NoError(t, err) -} - -func requirePodContainers(t *testing.T, ch connhelper.ConnectHelper, selector string, nContainers int) { - t.Helper() - - opts := ch.Ctx.KubectlOptions(t) - client := ch.Ctx.KubernetesClient(t) - retry.Run(t, func(r *retry.R) { - podList, err := client.CoreV1(). - Pods(opts.Namespace). - List(context.Background(), metav1.ListOptions{LabelSelector: selector}) - require.NoError(r, err) - require.Len(r, podList.Items, 1) - require.Len(r, podList.Items[0].Spec.Containers, nContainers) - }) -} diff --git a/acceptance/tests/consul-dns/consul_dns_test.go b/acceptance/tests/consul-dns/consul_dns_test.go index 84741175af..47cfb4af07 100644 --- a/acceptance/tests/consul-dns/consul_dns_test.go +++ b/acceptance/tests/consul-dns/consul_dns_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consuldns import ( @@ -62,10 +59,10 @@ func TestConsulDNS(t *testing.T) { dnsPodName := fmt.Sprintf("%s-dns-pod", releaseName) dnsTestPodArgs := []string{ - "run", "-it", dnsPodName, "--restart", "Never", "--image", "anubhavmishra/tiny-tools", "--", "dig", fmt.Sprintf("@%s-consul-dns", releaseName), "consul.service.consul", + "run", "-i", dnsPodName, "--restart", "Never", "--image", "anubhavmishra/tiny-tools", "--", "dig", fmt.Sprintf("@%s-consul-dns", releaseName), "consul.service.consul", } - helpers.Cleanup(t, suite.Config().NoCleanupOnFailure, suite.Config().NoCleanup, func() { + helpers.Cleanup(t, suite.Config().NoCleanupOnFailure, func() { // Note: this delete command won't wait for pods to be fully terminated. // This shouldn't cause any test pollution because the underlying // objects are deployments, and so when other tests create these diff --git a/acceptance/tests/consul-dns/main_test.go b/acceptance/tests/consul-dns/main_test.go index 1a17337d0a..848f30ad8f 100644 --- a/acceptance/tests/consul-dns/main_test.go +++ b/acceptance/tests/consul-dns/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consuldns import ( diff --git a/acceptance/tests/example/example_test.go b/acceptance/tests/example/example_test.go index 07b04d6097..9c6457f906 100644 --- a/acceptance/tests/example/example_test.go +++ b/acceptance/tests/example/example_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Rename package to your test package. package example @@ -44,7 +41,7 @@ func TestExample(t *testing.T) { k8s.KubectlApply(t, ctx.KubectlOptions(t), "path/to/config") // Clean up any Kubernetes resources you have created - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDelete(t, ctx.KubectlOptions(t), "path/to/config") }) diff --git a/acceptance/tests/example/main_test.go b/acceptance/tests/example/main_test.go index f92fff8a59..323f421d32 100644 --- a/acceptance/tests/example/main_test.go +++ b/acceptance/tests/example/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Rename package to your test package. package example diff --git a/acceptance/tests/fixtures/bases/api-gateway/apigateway.yaml b/acceptance/tests/fixtures/bases/api-gateway/apigateway.yaml deleted file mode 100644 index 2a355e1b2f..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway/apigateway.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: Gateway -metadata: - name: gateway -spec: - gatewayClassName: gateway-class - listeners: - - protocol: HTTP - port: 80 - name: http - allowedRoutes: - namespaces: - from: "All" - - protocol: TCP - port: 81 - name: tcp - allowedRoutes: - namespaces: - from: "All" - - protocol: HTTPS - port: 443 - name: https - tls: - certificateRefs: - - name: "certificate" - allowedRoutes: - namespaces: - from: "All" diff --git a/acceptance/tests/fixtures/bases/api-gateway/certificate.yaml b/acceptance/tests/fixtures/bases/api-gateway/certificate.yaml deleted file mode 100644 index d35dc559e2..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway/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/gatewayclass.yaml b/acceptance/tests/fixtures/bases/api-gateway/gatewayclass.yaml deleted file mode 100644 index 9ff985fd49..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway/gatewayclass.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -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/gatewayclassconfig.yaml b/acceptance/tests/fixtures/bases/api-gateway/gatewayclassconfig.yaml deleted file mode 100644 index b8dfae7aa5..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway/gatewayclassconfig.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: GatewayClassConfig -metadata: - name: gateway-class-config \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway/httproute.yaml b/acceptance/tests/fixtures/bases/api-gateway/httproute.yaml deleted file mode 100644 index d59c4e067e..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway/httproute.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: http-route -spec: - parentRefs: - - name: gateway \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway/kustomization.yaml b/acceptance/tests/fixtures/bases/api-gateway/kustomization.yaml deleted file mode 100644 index e2125414d9..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - gatewayclassconfig.yaml - - gatewayclass.yaml - - apigateway.yaml - - httproute.yaml - - meshservice.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway/meshservice.yaml b/acceptance/tests/fixtures/bases/api-gateway/meshservice.yaml deleted file mode 100644 index 4c32452bc3..0000000000 --- a/acceptance/tests/fixtures/bases/api-gateway/meshservice.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: MeshService -metadata: - name: mesh-service -spec: - name: static-server \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/cloud/hcp-mock/deployment.yaml b/acceptance/tests/fixtures/bases/cloud/hcp-mock/deployment.yaml deleted file mode 100644 index 7278557cdb..0000000000 --- a/acceptance/tests/fixtures/bases/cloud/hcp-mock/deployment.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: fake-server -spec: - replicas: 1 - selector: - matchLabels: - app: fake-server - template: - metadata: - name: fake-server - labels: - app: fake-server - spec: - containers: - - name: fake-server - # TODO: move this to a hashicorp mirror - image: docker.io/chaapppie/fakeserver:latest - ports: - - containerPort: 443 - name: https - - containerPort: 8080 - name: http - serviceAccountName: fake-server - terminationGracePeriodSeconds: 0 # so deletion is quick diff --git a/acceptance/tests/fixtures/bases/cloud/hcp-mock/kustomization.yaml b/acceptance/tests/fixtures/bases/cloud/hcp-mock/kustomization.yaml deleted file mode 100644 index dc9c951ab2..0000000000 --- a/acceptance/tests/fixtures/bases/cloud/hcp-mock/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ - - -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - deployment.yaml - - service.yaml - - serviceaccount.yaml - diff --git a/acceptance/tests/fixtures/bases/cloud/hcp-mock/service.yaml b/acceptance/tests/fixtures/bases/cloud/hcp-mock/service.yaml deleted file mode 100644 index 0cc6f1b9ce..0000000000 --- a/acceptance/tests/fixtures/bases/cloud/hcp-mock/service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: v1 -kind: Service -metadata: - name: fake-server -spec: - selector: - app: fake-server - ports: - - name: https - port: 443 - targetPort: 443 - - name: http - port: 8080 - targetPort: 8080 diff --git a/acceptance/tests/fixtures/bases/cloud/hcp-mock/serviceaccount.yaml b/acceptance/tests/fixtures/bases/cloud/hcp-mock/serviceaccount.yaml deleted file mode 100644 index f52d9640cd..0000000000 --- a/acceptance/tests/fixtures/bases/cloud/hcp-mock/serviceaccount.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: v1 -kind: ServiceAccount -metadata: - name: fake-server diff --git a/acceptance/tests/fixtures/bases/cloud/service-intentions/acl.yaml b/acceptance/tests/fixtures/bases/cloud/service-intentions/acl.yaml deleted file mode 100644 index fb3f77f496..0000000000 --- a/acceptance/tests/fixtures/bases/cloud/service-intentions/acl.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceIntentions -metadata: - name: consul-telemetry-collector -spec: - destination: - name: 'consul-telemetry-collector' - sources: - - name: '*' - action: allow - - - \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/cloud/service-intentions/kustomization.yaml b/acceptance/tests/fixtures/bases/cloud/service-intentions/kustomization.yaml deleted file mode 100644 index 9c19bf4ca3..0000000000 --- a/acceptance/tests/fixtures/bases/cloud/service-intentions/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - acl.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/crds-oss/controlplanerequestlimit.yaml b/acceptance/tests/fixtures/bases/crds-oss/controlplanerequestlimit.yaml deleted file mode 100644 index 5e8e32dbb5..0000000000 --- a/acceptance/tests/fixtures/bases/crds-oss/controlplanerequestlimit.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ControlPlaneRequestLimit -metadata: - name: controlplanerequestlimit -spec: - mode: "permissive" - readRate: 100.0 - writeRate: 100.0 - acl: - readRate: 100.0 - writeRate: 100.0 - catalog: - readRate: 100.0 - writeRate: 100.0 - configEntry: - readRate: 100.0 - writeRate: 100.0 - connectCA: - readRate: 100.0 - writeRate: 100.0 - coordinate: - readRate: 100.0 - writeRate: 100.0 - discoveryChain: - readRate: 100.0 - writeRate: 100.0 - health: - readRate: 100.0 - writeRate: 100.0 - intention: - readRate: 100.0 - writeRate: 100.0 - kv: - readRate: 100.0 - writeRate: 100.0 - tenancy: - readRate: 100.0 - writeRate: 100.0 -# preparedQuery: -# readRate: 100.0 -# writeRate: 100.0 - session: - readRate: 100.0 - writeRate: 100.0 - txn: - readRate: 100.0 - writeRate: 100.0 diff --git a/acceptance/tests/fixtures/bases/crds-oss/exportedservices.yaml b/acceptance/tests/fixtures/bases/crds-oss/exportedservices.yaml deleted file mode 100644 index 51d69ae709..0000000000 --- a/acceptance/tests/fixtures/bases/crds-oss/exportedservices.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ExportedServices -metadata: - name: default -spec: - services: - - name: frontend - consumers: - - peer: peerName - - samenessGroup: groupName \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/crds-oss/ingressgateway.yaml b/acceptance/tests/fixtures/bases/crds-oss/ingressgateway.yaml index 79b5b194bc..d613dc217c 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/ingressgateway.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/ingressgateway.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: IngressGateway metadata: diff --git a/acceptance/tests/fixtures/bases/crds-oss/jwtprovider.yaml b/acceptance/tests/fixtures/bases/crds-oss/jwtprovider.yaml deleted file mode 100644 index d35e532bf2..0000000000 --- a/acceptance/tests/fixtures/bases/crds-oss/jwtprovider.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: JWTProvider -metadata: - name: jwt-provider -spec: - jsonWebKeySet: - local: - filename: "jwks.txt" - issuer: "test-issuer" - audiences: - - "aud1" - - "aud2" - locations: - - header: - name: "x-jwt-header" - valuePrefix: "bearer" - forward: true - - queryParam: - name: "x-query-param" - - cookie: - name: "session-id" - forwarding: - headerName: "x-forwarded-jwt" - padForwardPayloadHeader: true - clockSkewSeconds: 45 - cacheConfig: - size: 15 \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml b/acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml index 77afbc9522..040b64f155 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml @@ -1,16 +1,10 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: -- ingressgateway.yaml -- mesh.yaml -- proxydefaults.yaml -- servicedefaults.yaml -- serviceintentions.yaml -- serviceresolver.yaml -- servicerouter.yaml -- servicesplitter.yaml -- terminatinggateway.yaml -- jwtprovider.yaml -- exportedservices.yaml -- controlplanerequestlimit.yaml \ No newline at end of file + - ingressgateway.yaml + - mesh.yaml + - proxydefaults.yaml + - servicedefaults.yaml + - serviceintentions.yaml + - serviceresolver.yaml + - servicerouter.yaml + - servicesplitter.yaml + - terminatinggateway.yaml diff --git a/acceptance/tests/fixtures/bases/crds-oss/mesh.yaml b/acceptance/tests/fixtures/bases/crds-oss/mesh.yaml index 9af8106b27..85474c1db6 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/mesh.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/mesh.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: Mesh metadata: diff --git a/acceptance/tests/fixtures/bases/crds-oss/proxydefaults.yaml b/acceptance/tests/fixtures/bases/crds-oss/proxydefaults.yaml index af4d7c30c2..040da247f8 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/proxydefaults.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/proxydefaults.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ProxyDefaults metadata: @@ -22,14 +19,3 @@ spec: - path: /health listenerPort: 22000 localPathPort: 8080 - envoyExtensions: - - name: builtin/aws/lambda - required: false - arguments: - payloadPassthrough: false - arn: arn:aws:lambda:us-west-2:111111111111:function:lambda-1234 - - name: builtin/aws/lambda - required: false - arguments: - payloadPassthrough: false - arn: arn:aws:lambda:us-east-1:111111111111:function:lambda-1234 diff --git a/acceptance/tests/fixtures/bases/crds-oss/servicedefaults.yaml b/acceptance/tests/fixtures/bases/crds-oss/servicedefaults.yaml index cd9c35fa39..825c0484d8 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/servicedefaults.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/servicedefaults.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceDefaults metadata: @@ -22,23 +19,9 @@ spec: interval: 1s maxFailures: 10 enforcingConsecutive5xx: 60 - maxEjectionPercent: 100 - baseEjectionTime: 20s - name: "bar" limits: maxConnections: 5 passiveHealthCheck: interval: 10s - maxFailures: 2 - balanceInboundConnections: "exact_balance" - envoyExtensions: - - name: builtin/aws/lambda - required: false - arguments: - payloadPassthrough: false - arn: arn:aws:lambda:us-west-2:111111111111:function:lambda-1234 - - name: builtin/aws/lambda - required: false - arguments: - payloadPassthrough: false - arn: arn:aws:lambda:us-east-1:111111111111:function:lambda-1234 \ No newline at end of file + maxFailures: 2 \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/crds-oss/serviceexports.yaml b/acceptance/tests/fixtures/bases/crds-oss/serviceexports.yaml new file mode 100644 index 0000000000..8ae095cd8e --- /dev/null +++ b/acceptance/tests/fixtures/bases/crds-oss/serviceexports.yaml @@ -0,0 +1,10 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceExports +metadata: + name: exports +spec: + services: + - name: frontend + namespace: frontend + consumers: + - partition: other \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/crds-oss/serviceintentions.yaml b/acceptance/tests/fixtures/bases/crds-oss/serviceintentions.yaml index fe3408cbd5..6b86312a78 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/serviceintentions.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/serviceintentions.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceDefaults metadata: diff --git a/acceptance/tests/fixtures/bases/crds-oss/serviceresolver.yaml b/acceptance/tests/fixtures/bases/crds-oss/serviceresolver.yaml index fc236966d6..05dee04184 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/serviceresolver.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/serviceresolver.yaml @@ -1,10 +1,7 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceResolver metadata: name: resolver spec: redirect: - service: bar \ No newline at end of file + service: bar diff --git a/acceptance/tests/fixtures/bases/crds-oss/servicerouter.yaml b/acceptance/tests/fixtures/bases/crds-oss/servicerouter.yaml index 0f04cd4cd4..8526f1202d 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/servicerouter.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/servicerouter.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceDefaults metadata: diff --git a/acceptance/tests/fixtures/bases/crds-oss/servicesplitter.yaml b/acceptance/tests/fixtures/bases/crds-oss/servicesplitter.yaml index 2eb9c3fccc..f0e8d74fe4 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/servicesplitter.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/servicesplitter.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceDefaults metadata: diff --git a/acceptance/tests/fixtures/bases/crds-oss/terminatinggateway.yaml b/acceptance/tests/fixtures/bases/crds-oss/terminatinggateway.yaml index 23daa6da20..77333b2011 100644 --- a/acceptance/tests/fixtures/bases/crds-oss/terminatinggateway.yaml +++ b/acceptance/tests/fixtures/bases/crds-oss/terminatinggateway.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: TerminatingGateway metadata: diff --git a/acceptance/tests/fixtures/bases/exportedservices-default/exportedservices-default.yaml b/acceptance/tests/fixtures/bases/exportedservices-default/exportedservices-default.yaml index 0e523bdd7e..a260602109 100644 --- a/acceptance/tests/fixtures/bases/exportedservices-default/exportedservices-default.yaml +++ b/acceptance/tests/fixtures/bases/exportedservices-default/exportedservices-default.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml b/acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml index 59527a69fb..e540a4def1 100644 --- a/acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml @@ -1,5 +1,2 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - exportedservices-default.yaml diff --git a/acceptance/tests/fixtures/bases/exportedservices-secondary/exportedservices-secondary.yaml b/acceptance/tests/fixtures/bases/exportedservices-secondary/exportedservices-secondary.yaml index 69151577f9..a514ed50d9 100644 --- a/acceptance/tests/fixtures/bases/exportedservices-secondary/exportedservices-secondary.yaml +++ b/acceptance/tests/fixtures/bases/exportedservices-secondary/exportedservices-secondary.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml b/acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml index e1781d47c1..10af8e20c5 100644 --- a/acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml @@ -1,5 +1,2 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - exportedservices-secondary.yaml diff --git a/acceptance/tests/fixtures/bases/intention/intention.yaml b/acceptance/tests/fixtures/bases/intention/intention.yaml index 973866be03..c7bf26dac2 100644 --- a/acceptance/tests/fixtures/bases/intention/intention.yaml +++ b/acceptance/tests/fixtures/bases/intention/intention.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceIntentions metadata: diff --git a/acceptance/tests/fixtures/bases/intention/kustomization.yaml b/acceptance/tests/fixtures/bases/intention/kustomization.yaml index 572e7727a4..8d15c05511 100644 --- a/acceptance/tests/fixtures/bases/intention/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/intention/kustomization.yaml @@ -1,5 +1,2 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - intention.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/job-client/job.yaml b/acceptance/tests/fixtures/bases/job-client/job.yaml deleted file mode 100644 index cc5f2f2896..0000000000 --- a/acceptance/tests/fixtures/bases/job-client/job.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: job-client - namespace: default - labels: - app: job-client -spec: - template: - metadata: - labels: - app: job-client - spec: - containers: - - name: job-client - image: alpine/curl:3.14 - ports: - - containerPort: 80 - command: - - /bin/sh - - -c - - | - echo "Started test job" - sleep 120 - echo "Ended test job" - serviceAccountName: job-client - restartPolicy: Never diff --git a/acceptance/tests/fixtures/bases/job-client/kustomization.yaml b/acceptance/tests/fixtures/bases/job-client/kustomization.yaml deleted file mode 100644 index 390d19c859..0000000000 --- a/acceptance/tests/fixtures/bases/job-client/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ./job.yaml - - service.yaml - - serviceaccount.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/job-client/service.yaml b/acceptance/tests/fixtures/bases/job-client/service.yaml deleted file mode 100644 index 36ec16133a..0000000000 --- a/acceptance/tests/fixtures/bases/job-client/service.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: job-client - namespace: default -spec: - selector: - app: job-client - ports: - - port: 80 \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/job-client/serviceaccount.yaml b/acceptance/tests/fixtures/bases/job-client/serviceaccount.yaml deleted file mode 100644 index b4637d4d55..0000000000 --- a/acceptance/tests/fixtures/bases/job-client/serviceaccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: job-client - namespace: default \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml b/acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml index c271e6af8b..6a913f2c44 100644 --- a/acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml @@ -1,5 +1,2 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - proxydefaults.yaml diff --git a/acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml b/acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml index 1560f6c640..2d28036fe5 100644 --- a/acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml +++ b/acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ProxyDefaults metadata: diff --git a/acceptance/tests/fixtures/bases/mesh-peering/kustomization.yaml b/acceptance/tests/fixtures/bases/mesh-peering/kustomization.yaml index e964c5ab05..b48237763e 100644 --- a/acceptance/tests/fixtures/bases/mesh-peering/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/mesh-peering/kustomization.yaml @@ -1,5 +1,2 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - meshpeering.yaml diff --git a/acceptance/tests/fixtures/bases/mesh-peering/meshpeering.yaml b/acceptance/tests/fixtures/bases/mesh-peering/meshpeering.yaml index 2fb6a04bb6..de84382d3e 100644 --- a/acceptance/tests/fixtures/bases/mesh-peering/meshpeering.yaml +++ b/acceptance/tests/fixtures/bases/mesh-peering/meshpeering.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: Mesh metadata: diff --git a/acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml index 5c2e0dcfa2..f80bd41d81 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/multiport-app/deployment.yaml b/acceptance/tests/fixtures/bases/multiport-app/deployment.yaml index f345b27c5e..a99d415d80 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/deployment.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/deployment.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml b/acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml index fb792d63a7..ead8b3afe5 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - deployment.yaml - service.yaml diff --git a/acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml index d0910816ed..f909785b36 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml index f321858164..fce63f0076 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/multiport-app/secret.yaml b/acceptance/tests/fixtures/bases/multiport-app/secret.yaml index bc8d931f1b..cb3fa957e2 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/secret.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/secret.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Secret metadata: diff --git a/acceptance/tests/fixtures/bases/multiport-app/service.yaml b/acceptance/tests/fixtures/bases/multiport-app/service.yaml index 8684c75f21..d18da258a3 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/service.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/service.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Service metadata: diff --git a/acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml b/acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml index 87b33476f4..2293c2e173 100644 --- a/acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml +++ b/acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: ServiceAccount metadata: diff --git a/acceptance/tests/fixtures/bases/openshift/network-attachment.yaml b/acceptance/tests/fixtures/bases/openshift/network-attachment.yaml index c2f36c5e1a..4b3f7948ee 100644 --- a/acceptance/tests/fixtures/bases/openshift/network-attachment.yaml +++ b/acceptance/tests/fixtures/bases/openshift/network-attachment.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: diff --git a/acceptance/tests/fixtures/bases/peering/peering-acceptor.yaml b/acceptance/tests/fixtures/bases/peering/peering-acceptor.yaml index 1b3ea3956b..3eff952833 100644 --- a/acceptance/tests/fixtures/bases/peering/peering-acceptor.yaml +++ b/acceptance/tests/fixtures/bases/peering/peering-acceptor.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: PeeringAcceptor metadata: diff --git a/acceptance/tests/fixtures/bases/peering/peering-dialer.yaml b/acceptance/tests/fixtures/bases/peering/peering-dialer.yaml index 9bf9f03819..ec125d7bb6 100644 --- a/acceptance/tests/fixtures/bases/peering/peering-dialer.yaml +++ b/acceptance/tests/fixtures/bases/peering/peering-dialer.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: PeeringDialer metadata: diff --git a/acceptance/tests/fixtures/bases/resolver-redirect/intention.yaml b/acceptance/tests/fixtures/bases/resolver-redirect/intention.yaml deleted file mode 100644 index faff0cd251..0000000000 --- a/acceptance/tests/fixtures/bases/resolver-redirect/intention.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceIntentions -metadata: - name: client-to-server -spec: - destination: - name: static-server - sources: - - name: static-client - action: allow ---- -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceIntentions -metadata: - name: client-to-redirect -spec: - destination: - name: resolver-redirect - sources: - - name: static-client - action: allow \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/resolver-redirect/kustomization.yaml b/acceptance/tests/fixtures/bases/resolver-redirect/kustomization.yaml deleted file mode 100644 index 323957ad53..0000000000 --- a/acceptance/tests/fixtures/bases/resolver-redirect/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - intention.yaml - - service.yaml - - serviceaccount.yaml - - resolver.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/resolver-redirect/resolver.yaml b/acceptance/tests/fixtures/bases/resolver-redirect/resolver.yaml deleted file mode 100644 index 9adbcc9fb4..0000000000 --- a/acceptance/tests/fixtures/bases/resolver-redirect/resolver.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: resolver-redirect -spec: - redirect: - service: static-server \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/resolver-redirect/service.yaml b/acceptance/tests/fixtures/bases/resolver-redirect/service.yaml deleted file mode 100644 index e63ae97cca..0000000000 --- a/acceptance/tests/fixtures/bases/resolver-redirect/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: v1 -kind: Service -metadata: - name: resolver-redirect -spec: - selector: - # Nothing needs to be selected. We only utilize this service so that KubeDNS has a ClusterIP to resolve. - app: idonotexist - ports: - - name: http - port: 80 - targetPort: 8080 diff --git a/acceptance/tests/fixtures/bases/resolver-redirect/serviceaccount.yaml b/acceptance/tests/fixtures/bases/resolver-redirect/serviceaccount.yaml deleted file mode 100644 index c74ecd667b..0000000000 --- a/acceptance/tests/fixtures/bases/resolver-redirect/serviceaccount.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: v1 -kind: ServiceAccount -metadata: - name: resolver-redirect diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-01-a-default-ns/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-01-a-default-ns/kustomization.yaml deleted file mode 100644 index 3f9d23c28a..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-01-a-default-ns/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - sameness.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-01-a-default-ns/sameness.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-01-a-default-ns/sameness.yaml deleted file mode 100644 index 9c43bb505f..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-01-a-default-ns/sameness.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: SamenessGroup -metadata: - name: group-01 -spec: - defaultForFailover: true - members: - - partition: default - - partition: ap1 - - peer: cluster-02-a - - peer: cluster-03-a \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-01-b-default-ns/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-01-b-default-ns/kustomization.yaml deleted file mode 100644 index 3f9d23c28a..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-01-b-default-ns/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - sameness.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-01-b-default-ns/sameness.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-01-b-default-ns/sameness.yaml deleted file mode 100644 index bf83338243..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-01-b-default-ns/sameness.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: SamenessGroup -metadata: - name: group-01 -spec: - defaultForFailover: true - members: - - partition: ap1 - - partition: default - - peer: cluster-02-a - - peer: cluster-03-a \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-02-a-default-ns/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-02-a-default-ns/kustomization.yaml deleted file mode 100644 index 3f9d23c28a..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-02-a-default-ns/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - sameness.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-02-a-default-ns/sameness.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-02-a-default-ns/sameness.yaml deleted file mode 100644 index 2ed466585b..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-02-a-default-ns/sameness.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: SamenessGroup -metadata: - name: group-01 -spec: - defaultForFailover: true - members: - - partition: default - - peer: cluster-01-a - - peer: cluster-01-b - - peer: cluster-03-a \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-03-a-default-ns/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-03-a-default-ns/kustomization.yaml deleted file mode 100644 index 3f9d23c28a..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-03-a-default-ns/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - sameness.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/cluster-03-a-default-ns/sameness.yaml b/acceptance/tests/fixtures/bases/sameness/cluster-03-a-default-ns/sameness.yaml deleted file mode 100644 index 83a3c1e71a..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/cluster-03-a-default-ns/sameness.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: SamenessGroup -metadata: - name: group-01 -spec: - defaultForFailover: true - members: - - partition: default - - peer: cluster-01-a - - peer: cluster-01-b - - peer: cluster-02-a \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/exportedservices-ap1/exportedservices-ap1.yaml b/acceptance/tests/fixtures/bases/sameness/exportedservices-ap1/exportedservices-ap1.yaml deleted file mode 100644 index 3dc494dd43..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/exportedservices-ap1/exportedservices-ap1.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ExportedServices -metadata: - name: ap1 -spec: - services: [] diff --git a/acceptance/tests/fixtures/bases/sameness/exportedservices-ap1/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/exportedservices-ap1/kustomization.yaml deleted file mode 100644 index 1793fa6db7..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/exportedservices-ap1/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - exportedservices-ap1.yaml diff --git a/acceptance/tests/fixtures/bases/sameness/override-ns/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/override-ns/kustomization.yaml deleted file mode 100644 index 0646179949..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/override-ns/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - service-defaults.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/override-ns/service-defaults.yaml b/acceptance/tests/fixtures/bases/sameness/override-ns/service-defaults.yaml deleted file mode 100644 index 87f6a71f32..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/override-ns/service-defaults.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceDefaults -metadata: - name: static-server -spec: - protocol: http \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/kustomization.yaml deleted file mode 100644 index cf214eac6c..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - peering-dialer-cluster-02-a.yaml - - peering-dialer-cluster-03-a.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/peering-dialer-cluster-02-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/peering-dialer-cluster-02-a.yaml deleted file mode 100644 index d4c51553f3..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/peering-dialer-cluster-02-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringDialer -metadata: - name: cluster-02-a -spec: - peer: - secret: - name: "cluster-02-a-cluster-01-a-peering-token" - key: "data" - backend: "kubernetes" diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/peering-dialer-cluster-03-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/peering-dialer-cluster-03-a.yaml deleted file mode 100644 index e6f9f9a6c9..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-a-dialer/peering-dialer-cluster-03-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringDialer -metadata: - name: cluster-03-a -spec: - peer: - secret: - name: "cluster-03-a-cluster-01-a-peering-token" - key: "data" - backend: "kubernetes" diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/kustomization.yaml deleted file mode 100644 index cf214eac6c..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - peering-dialer-cluster-02-a.yaml - - peering-dialer-cluster-03-a.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/peering-dialer-cluster-02-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/peering-dialer-cluster-02-a.yaml deleted file mode 100644 index 8f0f7064df..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/peering-dialer-cluster-02-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringDialer -metadata: - name: cluster-02-a -spec: - peer: - secret: - name: "cluster-02-a-cluster-01-b-peering-token" - key: "data" - backend: "kubernetes" diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/peering-dialer-cluster-03-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/peering-dialer-cluster-03-a.yaml deleted file mode 100644 index 27cdd27ff8..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-01-b-dialer/peering-dialer-cluster-03-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringDialer -metadata: - name: cluster-03-a -spec: - peer: - secret: - name: "cluster-03-a-cluster-01-b-peering-token" - key: "data" - backend: "kubernetes" diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/kustomization.yaml deleted file mode 100644 index 4c485ee633..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - peering-acceptor-cluster-01-a.yaml - - peering-acceptor-cluster-01-b.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/peering-acceptor-cluster-01-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/peering-acceptor-cluster-01-a.yaml deleted file mode 100644 index b20b61328f..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/peering-acceptor-cluster-01-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: cluster-01-a -spec: - peer: - secret: - name: "cluster-02-a-cluster-01-a-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/peering-acceptor-cluster-01-b.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/peering-acceptor-cluster-01-b.yaml deleted file mode 100644 index c2d5c21b37..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-acceptor/peering-acceptor-cluster-01-b.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: cluster-01-b -spec: - peer: - secret: - name: "cluster-02-a-cluster-01-b-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-dialer/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-dialer/kustomization.yaml deleted file mode 100644 index c90eab30cc..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-dialer/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - peering-dialer-cluster-03-a.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-dialer/peering-dialer-cluster-03-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-dialer/peering-dialer-cluster-03-a.yaml deleted file mode 100644 index 80518a04c2..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-02-a-dialer/peering-dialer-cluster-03-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringDialer -metadata: - name: cluster-03-a -spec: - peer: - secret: - name: "cluster-03-a-cluster-02-a-peering-token" - key: "data" - backend: "kubernetes" diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/kustomization.yaml deleted file mode 100644 index 543a846805..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - peering-acceptor-cluster-01-a.yaml - - peering-acceptor-cluster-01-b.yaml - - peering-acceptor-cluster-02-a.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-01-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-01-a.yaml deleted file mode 100644 index 06c87e15a6..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-01-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: cluster-01-a -spec: - peer: - secret: - name: "cluster-03-a-cluster-01-a-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-01-b.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-01-b.yaml deleted file mode 100644 index 0a835ecef5..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-01-b.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: cluster-01-b -spec: - peer: - secret: - name: "cluster-03-a-cluster-01-b-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-02-a.yaml b/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-02-a.yaml deleted file mode 100644 index e60ea8b083..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/cluster-03-a-acceptor/peering-acceptor-cluster-02-a.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: cluster-02-a -spec: - peer: - secret: - name: "cluster-03-a-cluster-02-a-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/mesh/kustomization.yaml b/acceptance/tests/fixtures/bases/sameness/peering/mesh/kustomization.yaml deleted file mode 100644 index 926e91236d..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/mesh/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - mesh.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/sameness/peering/mesh/mesh.yaml b/acceptance/tests/fixtures/bases/sameness/peering/mesh/mesh.yaml deleted file mode 100644 index 2fb6a04bb6..0000000000 --- a/acceptance/tests/fixtures/bases/sameness/peering/mesh/mesh.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: Mesh -metadata: - name: mesh -spec: - peering: - peerThroughMeshGateways: true diff --git a/acceptance/tests/fixtures/bases/service-resolver/kustomization.yaml b/acceptance/tests/fixtures/bases/service-resolver/kustomization.yaml deleted file mode 100644 index 8e36fe276e..0000000000 --- a/acceptance/tests/fixtures/bases/service-resolver/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - service-resolver.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/service-resolver/service-resolver.yaml b/acceptance/tests/fixtures/bases/service-resolver/service-resolver.yaml deleted file mode 100644 index 2e0459e381..0000000000 --- a/acceptance/tests/fixtures/bases/service-resolver/service-resolver.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: static-server diff --git a/acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml index b80bc5c562..be44c13e0a 100644 --- a/acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-client/deployment.yaml b/acceptance/tests/fixtures/bases/static-client/deployment.yaml index ff29f1b03a..66bb771f6f 100644 --- a/acceptance/tests/fixtures/bases/static-client/deployment.yaml +++ b/acceptance/tests/fixtures/bases/static-client/deployment.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/bases/static-client/kustomization.yaml b/acceptance/tests/fixtures/bases/static-client/kustomization.yaml index 9aa0009dc4..b9d8e11f73 100644 --- a/acceptance/tests/fixtures/bases/static-client/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/static-client/kustomization.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - deployment.yaml - service.yaml diff --git a/acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml index 36f6652e65..b8e097c3d8 100644 --- a/acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml index e516e57f7c..a377c8038d 100644 --- a/acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-client/service.yaml b/acceptance/tests/fixtures/bases/static-client/service.yaml index abd6ee4faf..16fbee0463 100644 --- a/acceptance/tests/fixtures/bases/static-client/service.yaml +++ b/acceptance/tests/fixtures/bases/static-client/service.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Service metadata: diff --git a/acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml b/acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml index 23578e5ead..b9bf136862 100644 --- a/acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml +++ b/acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: ServiceAccount metadata: diff --git a/acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml b/acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml index 21852487e3..a3020ddb47 100644 --- a/acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml +++ b/acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml b/acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml index ccc066e0a8..6d1374a18e 100644 --- a/acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - deployment.yaml - service.yaml diff --git a/acceptance/tests/fixtures/bases/static-metrics-app/service.yaml b/acceptance/tests/fixtures/bases/static-metrics-app/service.yaml index 2e553f7e83..a37db26875 100644 --- a/acceptance/tests/fixtures/bases/static-metrics-app/service.yaml +++ b/acceptance/tests/fixtures/bases/static-metrics-app/service.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Service metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-https/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server-https/anyuid-scc-rolebinding.yaml index 2be7cf13db..d224a082da 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/anyuid-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/anyuid-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-https/configmap.yaml b/acceptance/tests/fixtures/bases/static-server-https/configmap.yaml index 5a037ecdc6..dcb975978e 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/configmap.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/configmap.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: ConfigMap metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-https/deployment.yaml b/acceptance/tests/fixtures/bases/static-server-https/deployment.yaml index c95bdb4289..3071162c15 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/deployment.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/deployment.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-https/kustomization.yaml b/acceptance/tests/fixtures/bases/static-server-https/kustomization.yaml index da166af201..78508b7938 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/kustomization.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - deployment.yaml - configmap.yaml diff --git a/acceptance/tests/fixtures/bases/static-server-https/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server-https/privileged-scc-rolebinding.yaml index bed477ed26..1b9fe13789 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/privileged-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/privileged-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-https/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server-https/psp-rolebinding.yaml index 3c6cfad8f1..acccd2fcec 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/psp-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/psp-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-https/service.yaml b/acceptance/tests/fixtures/bases/static-server-https/service.yaml index 7f4f930c0a..168c90d3d0 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/service.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/service.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Service metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-https/serviceaccount.yaml b/acceptance/tests/fixtures/bases/static-server-https/serviceaccount.yaml index ced9002d6b..f4267a573e 100644 --- a/acceptance/tests/fixtures/bases/static-server-https/serviceaccount.yaml +++ b/acceptance/tests/fixtures/bases/static-server-https/serviceaccount.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: ServiceAccount metadata: diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/anyuid-scc-rolebinding.yaml deleted file mode 100644 index eb86dc8bae..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/anyuid-scc-rolebinding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: static-server-tcp-openshift-anyuid -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:openshift:scc:anyuid -subjects: - - kind: ServiceAccount - name: static-server-tcp \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/deployment.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/deployment.yaml deleted file mode 100644 index 9aa5177e9e..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/deployment.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: static-server-tcp - name: static-server-tcp -spec: - replicas: 1 - selector: - matchLabels: - app: static-server-tcp - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - labels: - app: static-server-tcp - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/kschoche/http-echo:latest - args: - - -text="hello world" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - livenessProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - startupProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 30 - periodSeconds: 1 - readinessProbe: - exec: - command: ['sh', '-c', 'test ! -f /tmp/unhealthy'] - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - serviceAccountName: static-server-tcp diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/kustomization.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/kustomization.yaml deleted file mode 100644 index 2180aa94e1..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - deployment.yaml - - service.yaml - - serviceaccount.yaml - - servicedefaults.yaml - - psp-rolebinding.yaml - - anyuid-scc-rolebinding.yaml - - privileged-scc-rolebinding.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/privileged-scc-rolebinding.yaml deleted file mode 100644 index ac28006765..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/privileged-scc-rolebinding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: static-server-tcp-openshift-privileged -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:openshift:scc:privileged -subjects: - - kind: ServiceAccount - name: static-server-tcp \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/psp-rolebinding.yaml deleted file mode 100644 index f4f008dbea..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/psp-rolebinding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: static-server-tcp -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: test-psp -subjects: - - kind: ServiceAccount - name: static-server-tcp \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/service.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/service.yaml deleted file mode 100644 index 6ceccf940a..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: v1 -kind: Service -metadata: - name: static-server-tcp - labels: - app: static-server-tcp -spec: - ports: - - name: http - port: 8080 - selector: - app: static-server-tcp diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/serviceaccount.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/serviceaccount.yaml deleted file mode 100644 index af2247af8e..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/serviceaccount.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: v1 -kind: ServiceAccount -metadata: - name: static-server-tcp diff --git a/acceptance/tests/fixtures/bases/static-server-tcp/servicedefaults.yaml b/acceptance/tests/fixtures/bases/static-server-tcp/servicedefaults.yaml deleted file mode 100644 index f89765cf6d..0000000000 --- a/acceptance/tests/fixtures/bases/static-server-tcp/servicedefaults.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceDefaults -metadata: - name: static-server-tcp - namespace: default -spec: - protocol: tcp \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml index 2be7cf13db..d224a082da 100644 --- a/acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-server/deployment.yaml b/acceptance/tests/fixtures/bases/static-server/deployment.yaml index 9f5776c9ca..1c724b0d37 100644 --- a/acceptance/tests/fixtures/bases/static-server/deployment.yaml +++ b/acceptance/tests/fixtures/bases/static-server/deployment.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: @@ -18,9 +15,7 @@ spec: spec: containers: - name: static-server - # Using alpine vs latest as there is a build issue with M1s. Also other tests in multiport-app reference - # alpine so standardizing this. - image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine + image: docker.mirror.hashicorp.services/hashicorp/http-echo:latest args: - -text="hello world" - -listen=:8080 diff --git a/acceptance/tests/fixtures/bases/static-server/kustomization.yaml b/acceptance/tests/fixtures/bases/static-server/kustomization.yaml index 9aa0009dc4..b9d8e11f73 100644 --- a/acceptance/tests/fixtures/bases/static-server/kustomization.yaml +++ b/acceptance/tests/fixtures/bases/static-server/kustomization.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resources: - deployment.yaml - service.yaml diff --git a/acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml index bed477ed26..1b9fe13789 100644 --- a/acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml index 3c6cfad8f1..acccd2fcec 100644 --- a/acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml +++ b/acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/acceptance/tests/fixtures/bases/static-server/service.yaml b/acceptance/tests/fixtures/bases/static-server/service.yaml index 6d8d54acc2..4776c07239 100644 --- a/acceptance/tests/fixtures/bases/static-server/service.yaml +++ b/acceptance/tests/fixtures/bases/static-server/service.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Service metadata: diff --git a/acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml b/acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml index ced9002d6b..f4267a573e 100644 --- a/acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml +++ b/acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: ServiceAccount metadata: diff --git a/acceptance/tests/fixtures/cases/api-gateways/certificate/certificate.yaml b/acceptance/tests/fixtures/cases/api-gateways/certificate/certificate.yaml deleted file mode 100644 index d35dc559e2..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/certificate/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/cases/api-gateways/certificate/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/certificate/kustomization.yaml deleted file mode 100644 index 42b7526335..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/certificate/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - certificate.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/dc1-to-dc2-resolver/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/dc1-to-dc2-resolver/kustomization.yaml deleted file mode 100644 index cdbcd688c0..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/dc1-to-dc2-resolver/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - serviceresolver.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/dc1-to-dc2-resolver/serviceresolver.yaml b/acceptance/tests/fixtures/cases/api-gateways/dc1-to-dc2-resolver/serviceresolver.yaml deleted file mode 100644 index ca009754b4..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/dc1-to-dc2-resolver/serviceresolver.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: static-server -spec: - redirect: - service: static-server - datacenter: dc2 \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/api-gateways/dc2-to-dc1-resolver/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/dc2-to-dc1-resolver/kustomization.yaml deleted file mode 100644 index cdbcd688c0..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/dc2-to-dc1-resolver/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - serviceresolver.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/dc2-to-dc1-resolver/serviceresolver.yaml b/acceptance/tests/fixtures/cases/api-gateways/dc2-to-dc1-resolver/serviceresolver.yaml deleted file mode 100644 index af8cdb72ed..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/dc2-to-dc1-resolver/serviceresolver.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: static-server -spec: - redirect: - service: static-server - datacenter: dc1 \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/api-gateways/gateway/gateway.yaml b/acceptance/tests/fixtures/cases/api-gateways/gateway/gateway.yaml deleted file mode 100644 index 7f0428b039..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/gateway/gateway.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: Gateway -metadata: - name: gateway -spec: - gatewayClassName: consul - listeners: - - protocol: HTTPS - port: 8080 - name: https - tls: - certificateRefs: - - name: "certificate" - namespace: "default" - allowedRoutes: - namespaces: - from: "All" diff --git a/acceptance/tests/fixtures/cases/api-gateways/gateway/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/gateway/kustomization.yaml deleted file mode 100644 index 8efac31693..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/gateway/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - gateway.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/httproute/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/httproute/kustomization.yaml deleted file mode 100644 index 7a6713835c..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/httproute/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - route.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/httproute/route.yaml b/acceptance/tests/fixtures/cases/api-gateways/httproute/route.yaml deleted file mode 100644 index 9f7f66b433..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/httproute/route.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: route -spec: {} \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/api-gateway.yaml b/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/api-gateway.yaml deleted file mode 100644 index bef7e96f12..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/api-gateway.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: Gateway -metadata: - name: gateway -spec: - gatewayClassName: gateway-class - listeners: - - protocol: HTTP - port: 8080 - name: http-auth - allowedRoutes: - namespaces: - from: "All" - - protocol: HTTP - port: 80 - name: http - allowedRoutes: - namespaces: - from: "All" - - protocol: TCP - port: 81 - name: tcp - allowedRoutes: - namespaces: - from: "All" - - protocol: HTTPS - port: 443 - name: https - tls: - certificateRefs: - - name: "certificate" - allowedRoutes: - namespaces: - from: "All" diff --git a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/gateway-policy.yaml b/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/gateway-policy.yaml deleted file mode 100644 index 6c58632d87..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/gateway-policy.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ConsulGatewayPolicy -metadata: - name: my-policy -spec: - targetRef: - name: gateway - kind: Gateway - group: gateway.networking.kuberenetes.io - sectionName: http - override: - Providers: - - Provider: "local" - VerifyClaims: - - Path: - - "iss" - Value: "local" - default: - Providers: - - Provider: "local" - VerifyClaims: - - Path: - - "iss" - Value: "local" diff --git a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/httproute-auth.yaml b/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/httproute-auth.yaml deleted file mode 100644 index 4963277c55..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/httproute-auth.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: http-route-auth -spec: - parentRefs: - - name: gateway - sectionName: http-auth - rules: - - matches: - - path: - type: PathPrefix - value: "/admin" - backendRefs: - - name: static-server - port: 80 - filters: - - type: ExtensionRef - extensionRef: - group: consul.hashicorp.com - kind: HTTPRouteAuthFilter - name: route-jwt-auth-filter - - matches: - - path: - type: PathPrefix - value: "/pet" - backendRefs: - - name: static-server - port: 80 diff --git a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/httproute.yaml b/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/httproute.yaml deleted file mode 100644 index 52e206a91e..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/httproute.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: http-route -spec: - parentRefs: - - name: gateway - sectionName: http - rules: - - matches: - - path: - type: PathPrefix - value: "/v1" - backendRefs: - - name: static-server - port: 80 diff --git a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/jwt-provider.yaml b/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/jwt-provider.yaml deleted file mode 100644 index 1e5cbf35d6..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/jwt-provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: JWTProvider -metadata: - name: local -spec: - issuer: local - jsonWebKeySet: - local: - jwks: "ewogICAgImtleXMiOiBbCiAgICAgICAgewogICAgICAgICAgICAicCI6ICI5TTlWSVhJR0hpR3FlTnhseEJ2V0xFV09oUFh3dXhXZUpod01uM3dGdG9STEtfZmF6VWxjWEc1cUViLTdpMXo3VmlPUWVZRnh6WUZYTS1pbVU3OVFRa1dTVUVSazR2dHZuc2R5UnpUSnVPc3A0ZUhuWFVMSHJPOU51NkJ5bC1VeVprMzFvSnFGeGllM0pHQXlRLUM2OVF2NVFkVjFZV0hfVDkyTzk4d1hYZGMiLAogICAgICAgICAgICAia3R5IjogIlJTQSIsCiAgICAgICAgICAgICJxIjogInFIVnZBb3h0ckgxUTVza25veXNMMkhvbC1ubnU3ZlM3Mjg4clRGdE9jeG9Jb29nWXBKVTljemxwcjctSlo2bjc0TUViVHBBMHRkSUR5TEtQQ0xIN3JKTFRrZzBDZVZNQWpmY01zdkRUcWdFOHNBWE42bzd2ZjYya2hwcExYOHVCU3JxSHkyV1JhZXJsbDROU09hcmRGSkQ2MWhHSVF2cEpXRk4xazFTV3pWcyIsCiAgICAgICAgICAgICJkIjogIlp3elJsVklRZkg5ekZ6d1hOZ2hEMHhkZVctalBCbmRkWnJNZ0wwQ2JjeXZZYlg2X1c0ajlhM1dmYWpobmI2bTFILW9CWjRMczVmNXNRVTB2ZFJ2ZG1laFItUG43aWNRcUdURFNKUTYtdWVtNm15UVRWaEo2UmZiM0lINVJ2VDJTOXUzcVFDZWFadWN3aXFoZ1RCbFhnOWFfV0pwVHJYNFhPQ3JCR1ZsTng3Z2JETVJOamNEN0FnRkZ3S2p2TEZVdDRLTkZmdEJqaFF0TDFLQ2VwblNmamtvRm1RUTVlX3RSS2ozX2U1V3pNSkJkekpQejNkR2YxZEk3OF9wYmJFbmFMcWhqNWg0WUx2UU5JUUhVcURYSGx4ZDc1Qlh3aFJReE1nUDRfd1EwTFk2cVRKNGFDa2Q0RDJBTUtqMzJqeVFiVTRKTE9jQjFNMnZBRWFyc2NTU3l0USIsCiAgICAgICAgICAgICJlIjogIkFRQUIiLAogICAgICAgICAgICAidXNlIjogInNpZyIsCiAgICAgICAgICAgICJraWQiOiAiQy1FMW5DandnQkMtUHVHTTJPNDY3RlJEaEt4OEFrVmN0SVNBYm8zcmlldyIsCiAgICAgICAgICAgICJxaSI6ICJ0N2VOQjhQV21xVHdKREZLQlZKZExrZnJJT2drMFJ4MnREODBGNHB5cjhmNzRuNGlVWXFmWG1haVZtbGx2c2FlT3JlNHlIczQ4UE45NVZsZlVvS3Z6ZEJFaDNZTDFINGZTOGlYYXNzNGJiVnVuWHR4U0hMZFFPYUNZYUplSmhBbGMyUWQ4elR0NFFQWk9yRWVWLVJTYU0tN095ekkwUWtSSF9tcmk1YmRrOXMiLAogICAgICAgICAgICAiZHAiOiAiYnBLckQtVXhrRENDal81MFZLU0NFeE1Ec1Zob2VBZm1tNjMxb1o5aDhUTkZ4TUU1YVptbUJ2VzBJUG9wMm1PUF9qTW9FVWxfUG1RYUlBOEgtVEdqTFp2QTMxSlZBeFN3TU5aQzdwaVFPRjYzVnhneTZUTzlmb1hENVdndC1oLUNxU1N6T2V3eFdmUWNTMmpMcTA3NUFxOTYwTnA2SHhjbE8weUdRN1JDSlpjIiwKICAgICAgICAgICAgImFsZyI6ICJQUzI1NiIsCiAgICAgICAgICAgICJkcSI6ICJpdVZveGwwckFKSEM1c2JzbTZpZWQ3c2ZIVXIwS2Rja0hiVFBLb0lPU1BFcU5YaXBlT3BrWkdEdU55NWlDTXNyRnNHaDFrRW9kTkhZdE40ay1USm5KSDliV296SGdXbGloNnN2R1V0Zi1raFMxWC16ckxaMTJudzlyNDRBbjllWG54bjFaVXMxZm5OakltM3dtZ083algyTWxIeVlNVUZVd0RMd09xNEFPUWsiLAogICAgICAgICAgICAibiI6ICJvUmhjeUREdmp3NFZ4SHRRNTZhRDlNSmRTaWhWSk1nTHd1b2FCQVhhc0RjVDNEWVZjcENlVGxDMVBPdzdPNW1Ec2ZSWVFtcGpoendyRDVZWU8yeDE4REl4czdyNTNJdFMxRy1ybnQxQ1diVE9fUzFJT01DR2xxYzh5VWJnLUhSUkRETXQyb2V3TjJoRGtxYlBKVFJNbXpjRkpNMHRpTm1RZVVMcWViZEVYaWVUblJMT1BkMWg2ZmJycVNLS01mSXlIbGZ1WXFQc1VWSEdkMVBESGljZ3NMazFtZDhtYTNIS1hWM0hJdzZrdUV6R0hQb1gxNHo4YWF6RFFZWndUR3ZxVGlPLUdRUlVDZUJueVo4bVhyWnRmSjNqVk83UUhXcEx3MlM1VDVwVTRwcE0xQXppWTFxUDVfY3ZpOTNZT2Zrb09PalRTX3V3RENZWGFxWjB5bTJHYlEiCiAgICAgICAgfQogICAgXQp9Cg==" diff --git a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/jwt-route-filter.yaml b/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/jwt-route-filter.yaml deleted file mode 100644 index ed0b0bbe5e..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/jwt-route-filter.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: HTTPRouteAuthFilter -metadata: - name: example-route-jwt-filter -spec: - type: JWT - JWTProviders: - - Provider: "local" - VerifyClaims: - - Path: - - "role" - Value: "doctor" diff --git a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/kustomization.yaml deleted file mode 100644 index 9730a1a4ac..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/jwt-auth/kustomization.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: -- ../../../bases/api-gateway -- ../../static-server-inject -- ./httproute.yaml -- ./jwt-provider.yaml - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -patches: -- patch: httproute-no-auth.yaml -- path: api-gateway.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/mesh/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/mesh/kustomization.yaml deleted file mode 100644 index c271e6af8b..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/mesh/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - proxydefaults.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/mesh/proxydefaults.yaml b/acceptance/tests/fixtures/cases/api-gateways/mesh/proxydefaults.yaml deleted file mode 100644 index ccc0905e32..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/mesh/proxydefaults.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ProxyDefaults -metadata: - name: global -spec: - config: - protocol: http - meshGateway: - mode: local \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/api-gateways/peer-resolver/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/peer-resolver/kustomization.yaml deleted file mode 100644 index cdbcd688c0..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/peer-resolver/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - serviceresolver.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/peer-resolver/serviceresolver.yaml b/acceptance/tests/fixtures/cases/api-gateways/peer-resolver/serviceresolver.yaml deleted file mode 100644 index 20874fe1f9..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/peer-resolver/serviceresolver.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: static-server -spec: - redirect: - peer: server - namespace: ns1 - service: static-server \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/api-gateways/resolver/kustomization.yaml b/acceptance/tests/fixtures/cases/api-gateways/resolver/kustomization.yaml deleted file mode 100644 index cdbcd688c0..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/resolver/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - serviceresolver.yaml diff --git a/acceptance/tests/fixtures/cases/api-gateways/resolver/serviceresolver.yaml b/acceptance/tests/fixtures/cases/api-gateways/resolver/serviceresolver.yaml deleted file mode 100644 index 18960a37db..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/resolver/serviceresolver.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: static-server -spec: - redirect: - partition: default - namespace: ns1 - service: static-server \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/api-gateways/tcproute/route.yaml b/acceptance/tests/fixtures/cases/api-gateways/tcproute/route.yaml deleted file mode 100644 index 37602c65af..0000000000 --- a/acceptance/tests/fixtures/cases/api-gateways/tcproute/route.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: gateway.networking.k8s.io/v1alpha2 -kind: TCPRoute -metadata: - name: tcp-route -spec: - parentRefs: - - name: gateway - rules: - - backendRefs: - - kind: Service - name: static-server-tcp \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml index f3d0bca3ce..499fdc5bc1 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/exportedservices-default -patches: -- path: patch.yaml + - ../../../bases/exportedservices-default + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml index a06855e317..c98ecb6f48 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml index f3d0bca3ce..499fdc5bc1 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/exportedservices-default -patches: -- path: patch.yaml + - ../../../bases/exportedservices-default + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml index 3e86df911d..f826174aec 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml index 77c6bd3fae..5a9c8412aa 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/exportedservices-secondary -patches: -- path: patch.yaml + - ../../../bases/exportedservices-secondary + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml index 141a080903..d2fc1ab914 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml index 77c6bd3fae..5a9c8412aa 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/exportedservices-secondary -patches: -- path: patch.yaml + - ../../../bases/exportedservices-secondary + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml index 3b8c2a4068..4165f2d21a 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/cases/crd-peers/default-namespace/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-peers/default-namespace/kustomization.yaml index f3d0bca3ce..499fdc5bc1 100644 --- a/acceptance/tests/fixtures/cases/crd-peers/default-namespace/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-peers/default-namespace/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/exportedservices-default -patches: -- path: patch.yaml + - ../../../bases/exportedservices-default + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-peers/default-namespace/patch.yaml b/acceptance/tests/fixtures/cases/crd-peers/default-namespace/patch.yaml index 0031c7f601..eed6bee4cc 100644 --- a/acceptance/tests/fixtures/cases/crd-peers/default-namespace/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-peers/default-namespace/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/cases/crd-peers/default/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-peers/default/kustomization.yaml index f3d0bca3ce..499fdc5bc1 100644 --- a/acceptance/tests/fixtures/cases/crd-peers/default/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-peers/default/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/exportedservices-default -patches: -- path: patch.yaml + - ../../../bases/exportedservices-default + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-peers/default/patch.yaml b/acceptance/tests/fixtures/cases/crd-peers/default/patch.yaml index e632512ff1..b0dcd89ebb 100644 --- a/acceptance/tests/fixtures/cases/crd-peers/default/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-peers/default/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/kustomization.yaml index f3d0bca3ce..499fdc5bc1 100644 --- a/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/exportedservices-default -patches: -- path: patch.yaml + - ../../../bases/exportedservices-default + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/patch.yaml b/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/patch.yaml index 300fbcf3d6..4162a0f27b 100644 --- a/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-peers/non-default-namespace/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: diff --git a/acceptance/tests/fixtures/cases/crds-ent/exportedservices.yaml b/acceptance/tests/fixtures/cases/crds-ent/exportedservices.yaml index dd39ab3626..4703d23493 100644 --- a/acceptance/tests/fixtures/cases/crds-ent/exportedservices.yaml +++ b/acceptance/tests/fixtures/cases/crds-ent/exportedservices.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: @@ -10,6 +7,4 @@ spec: - name: frontend namespace: frontend consumers: - - partition: partitionName - - peer: peerName - - samenessGroup: groupName \ No newline at end of file + - partition: other \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml b/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml index 3fd5556ebd..cdc3e60cb1 100644 --- a/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml @@ -1,9 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/crds-oss -patches: -- path: exportedservices.yaml + - ../../bases/crds-oss + - exportedservices.yaml diff --git a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-0s/kustomization.yaml b/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-0s/kustomization.yaml deleted file mode 100644 index d87dbf0481..0000000000 --- a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-0s/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ - -resources: - - ../../../bases/job-client - -patchesStrategicMerge: - - patch.yaml diff --git a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-0s/patch.yaml b/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-0s/patch.yaml deleted file mode 100644 index 46d1a417ea..0000000000 --- a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-0s/patch.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: job-client -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - "consul.hashicorp.com/transparent-proxy": "false" - "consul.hashicorp.com/connect-service-upstreams": "static-server:1234" - "consul.hashicorp.com/sidecar-proxy-lifecycle-shutdown-grace-period-seconds": "0" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-10s/kustomization.yaml b/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-10s/kustomization.yaml deleted file mode 100644 index d87dbf0481..0000000000 --- a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-10s/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ - -resources: - - ../../../bases/job-client - -patchesStrategicMerge: - - patch.yaml diff --git a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-10s/patch.yaml b/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-10s/patch.yaml deleted file mode 100644 index 4db2df127e..0000000000 --- a/acceptance/tests/fixtures/cases/jobs/job-client-inject-grace-period-10s/patch.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: job-client -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - "consul.hashicorp.com/transparent-proxy": "false" - "consul.hashicorp.com/connect-service-upstreams": "static-server:1234" - "consul.hashicorp.com/sidecar-proxy-lifecycle-shutdown-grace-period-seconds": "10" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/jobs/job-client-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/jobs/job-client-inject/kustomization.yaml deleted file mode 100644 index 0aee0558b7..0000000000 --- a/acceptance/tests/fixtures/cases/jobs/job-client-inject/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ../../../bases/job-client - -patchesStrategicMerge: - - patch.yaml diff --git a/acceptance/tests/fixtures/cases/jobs/job-client-inject/patch.yaml b/acceptance/tests/fixtures/cases/jobs/job-client-inject/patch.yaml deleted file mode 100644 index 5f390c1f7e..0000000000 --- a/acceptance/tests/fixtures/cases/jobs/job-client-inject/patch.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: job-client -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - "consul.hashicorp.com/transparent-proxy": "false" - "consul.hashicorp.com/sidecar-proxy-lifecycle-shutdown-grace-period-seconds": "5" - "consul.hashicorp.com/connect-service-upstreams": "static-server:1234" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/permissive-mtls/mesh-config-permissive-allowed.yaml b/acceptance/tests/fixtures/cases/permissive-mtls/mesh-config-permissive-allowed.yaml deleted file mode 100644 index c336a621e7..0000000000 --- a/acceptance/tests/fixtures/cases/permissive-mtls/mesh-config-permissive-allowed.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: Mesh -metadata: - name: mesh -spec: - allowEnablingPermissiveMutualTLS: true diff --git a/acceptance/tests/fixtures/cases/permissive-mtls/service-defaults-static-server-permissive.yaml b/acceptance/tests/fixtures/cases/permissive-mtls/service-defaults-static-server-permissive.yaml deleted file mode 100644 index 4559570544..0000000000 --- a/acceptance/tests/fixtures/cases/permissive-mtls/service-defaults-static-server-permissive.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceDefaults -metadata: - name: static-server - namespace: default -spec: - mutualTLSMode: "permissive" diff --git a/acceptance/tests/fixtures/cases/permissive-mtls/service-defaults-static-server-strict.yaml b/acceptance/tests/fixtures/cases/permissive-mtls/service-defaults-static-server-strict.yaml deleted file mode 100644 index cf84c73407..0000000000 --- a/acceptance/tests/fixtures/cases/permissive-mtls/service-defaults-static-server-strict.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceDefaults -metadata: - name: static-server - namespace: default -spec: - mutualTLSMode: "strict" diff --git a/acceptance/tests/fixtures/cases/resolver-redirect-virtualip/kustomization.yaml b/acceptance/tests/fixtures/cases/resolver-redirect-virtualip/kustomization.yaml deleted file mode 100644 index 09790e05c6..0000000000 --- a/acceptance/tests/fixtures/cases/resolver-redirect-virtualip/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ../../bases/resolver-redirect \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-01-a-acceptor/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-01-a-acceptor/kustomization.yaml deleted file mode 100644 index 08c7c9b818..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-01-a-acceptor/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../bases/sameness/peering/acceptor -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-01-a-acceptor/patch.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-01-a-acceptor/patch.yaml deleted file mode 100644 index 2746eeef2e..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-01-a-acceptor/patch.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: acceptor -spec: - peer: - secret: - name: "cluster-01-a-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-01-b-acceptor/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-01-b-acceptor/kustomization.yaml deleted file mode 100644 index 08c7c9b818..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-01-b-acceptor/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../bases/sameness/peering/acceptor -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-01-b-acceptor/patch.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-01-b-acceptor/patch.yaml deleted file mode 100644 index 9ca48dad0c..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-01-b-acceptor/patch.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: acceptor -spec: - peer: - secret: - name: "cluster-01-b-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-02-a-acceptor/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-02-a-acceptor/kustomization.yaml deleted file mode 100644 index 08c7c9b818..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-02-a-acceptor/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../bases/sameness/peering/acceptor -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-02-a-acceptor/patch.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-02-a-acceptor/patch.yaml deleted file mode 100644 index 4343992f8f..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-02-a-acceptor/patch.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: acceptor -spec: - peer: - secret: - name: "cluster-02-a-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-03-a-acceptor/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-03-a-acceptor/kustomization.yaml deleted file mode 100644 index 08c7c9b818..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-03-a-acceptor/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../bases/sameness/peering/acceptor -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/cluster-03-a-acceptor/patch.yaml b/acceptance/tests/fixtures/cases/sameness/cluster-03-a-acceptor/patch.yaml deleted file mode 100644 index 1cd49b79d7..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/cluster-03-a-acceptor/patch.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PeeringAcceptor -metadata: - name: acceptor -spec: - peer: - secret: - name: "cluster-03-a-peering-token" - key: "data" - backend: "kubernetes" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/sameness/exported-services/ap1-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/exported-services/ap1-partition/kustomization.yaml deleted file mode 100644 index d25bed6eee..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/exported-services/ap1-partition/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/sameness/exportedservices-ap1 -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/exported-services/ap1-partition/patch.yaml b/acceptance/tests/fixtures/cases/sameness/exported-services/ap1-partition/patch.yaml deleted file mode 100644 index 22fa816fed..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/exported-services/ap1-partition/patch.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ExportedServices -metadata: - name: ap1 -spec: - services: - - name: static-server - namespace: ns2 - consumers: - - samenessGroup: group-01 - - name: mesh-gateway - consumers: - - samenessGroup: group-01 diff --git a/acceptance/tests/fixtures/cases/sameness/exported-services/default-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/exported-services/default-partition/kustomization.yaml deleted file mode 100644 index 7f4ab4ba7c..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/exported-services/default-partition/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/exportedservices-default -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/exported-services/default-partition/patch.yaml b/acceptance/tests/fixtures/cases/sameness/exported-services/default-partition/patch.yaml deleted file mode 100644 index 4dbacf99e1..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/exported-services/default-partition/patch.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ExportedServices -metadata: - name: default -spec: - services: - - name: static-server - namespace: ns2 - consumers: - - samenessGroup: group-01 - - name: mesh-gateway - consumers: - - samenessGroup: group-01 diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition-tproxy/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition-tproxy/kustomization.yaml deleted file mode 100644 index 096edd19ed..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition-tproxy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-client -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition-tproxy/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition-tproxy/patch.yaml deleted file mode 100644 index 68f3c8dd91..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition-tproxy/patch.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-client -spec: - template: - metadata: - annotations: - 'consul.hashicorp.com/connect-inject': 'true' - spec: - containers: - - name: static-client - image: anubhavmishra/tiny-tools:latest - # Just spin & wait forever, we'll use `kubectl exec` to demo - command: ['/bin/sh', '-c', '--'] - args: ['while true; do sleep 30; done;'] - # If ACLs are enabled, the serviceAccountName must match the Consul service name. - serviceAccountName: static-client diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition/kustomization.yaml deleted file mode 100644 index 096edd19ed..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-client -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition/patch.yaml deleted file mode 100644 index c1a14c6070..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/ap1-partition/patch.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-client -spec: - template: - metadata: - annotations: - 'consul.hashicorp.com/connect-inject': 'true' - 'consul.hashicorp.com/connect-service-upstreams': 'static-server.ns2.ap1:8080' - spec: - containers: - - name: static-client - image: anubhavmishra/tiny-tools:latest - # Just spin & wait forever, we'll use `kubectl exec` to demo - command: ['/bin/sh', '-c', '--'] - args: ['while true; do sleep 30; done;'] - # If ACLs are enabled, the serviceAccountName must match the Consul service name. - serviceAccountName: static-client diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition-tproxy/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/default-partition-tproxy/kustomization.yaml deleted file mode 100644 index 096edd19ed..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition-tproxy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-client -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition-tproxy/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/default-partition-tproxy/patch.yaml deleted file mode 100644 index e53ef7b509..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition-tproxy/patch.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-client -spec: - template: - metadata: - annotations: - 'consul.hashicorp.com/connect-inject': 'true' - spec: - containers: - - name: static-client - image: anubhavmishra/tiny-tools:latest - # Just spin & wait forever, we'll use `kubectl exec` to demo - command: ['/bin/sh', '-c', '--'] - args: ['while true; do sleep 30; done;'] - # If ACLs are enabled, the serviceAccountName must match the Consul service name. - serviceAccountName: static-client \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/default-partition/kustomization.yaml deleted file mode 100644 index 096edd19ed..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-client -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-client/default-partition/patch.yaml deleted file mode 100644 index 1775e9abb1..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-client/default-partition/patch.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-client -spec: - template: - metadata: - annotations: - 'consul.hashicorp.com/connect-inject': 'true' - 'consul.hashicorp.com/connect-service-upstreams': 'static-server.ns2.default:8080' - spec: - containers: - - name: static-client - image: anubhavmishra/tiny-tools:latest - # Just spin & wait forever, we'll use `kubectl exec` to demo - command: ['/bin/sh', '-c', '--'] - args: ['while true; do sleep 30; done;'] - # If ACLs are enabled, the serviceAccountName must match the Consul service name. - serviceAccountName: static-client \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-default/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc1-default/kustomization.yaml deleted file mode 100644 index e03603d26d..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-default/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-server -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-default/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc1-default/patch.yaml deleted file mode 100644 index ca27b7ba42..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-default/patch.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-server -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine - args: - - -text="cluster-01-a" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - serviceAccountName: static-server diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc1-partition/kustomization.yaml deleted file mode 100644 index e03603d26d..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-partition/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-server -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-partition/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc1-partition/patch.yaml deleted file mode 100644 index 044115d1d1..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc1-partition/patch.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-server -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine - args: - - -text="cluster-01-b" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - serviceAccountName: static-server diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc2/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc2/kustomization.yaml deleted file mode 100644 index e03603d26d..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc2/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-server -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc2/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc2/patch.yaml deleted file mode 100644 index 07ac3b9aa9..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc2/patch.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-server -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine - args: - - -text="cluster-02-a" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - serviceAccountName: static-server diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc3/kustomization.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc3/kustomization.yaml deleted file mode 100644 index e03603d26d..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc3/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../../../../bases/static-server -patches: -- path: patch.yaml diff --git a/acceptance/tests/fixtures/cases/sameness/static-server/dc3/patch.yaml b/acceptance/tests/fixtures/cases/sameness/static-server/dc3/patch.yaml deleted file mode 100644 index 135e7b14fb..0000000000 --- a/acceptance/tests/fixtures/cases/sameness/static-server/dc3/patch.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-server -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine - args: - - -text="cluster-03-a" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - serviceAccountName: static-server diff --git a/acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml index 564d02a68f..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-client -patches: -- path: patch.yaml + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml b/acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml index c8b0ae8412..c38ce8e448 100644 --- a/acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml index 564d02a68f..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-client -patches: -- path: patch.yaml + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-inject/patch.yaml b/acceptance/tests/fixtures/cases/static-client-inject/patch.yaml index aea6e8c778..2f8b32ec0a 100644 --- a/acceptance/tests/fixtures/cases/static-client-inject/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-inject/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml index 564d02a68f..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-client -patches: -- path: patch.yaml + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml b/acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml index 17e635b1d5..7b9b095073 100644 --- a/acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml index 564d02a68f..4c5d895a98 100644 --- a/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-client -patches: -- path: patch.yaml + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml diff --git a/acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml b/acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml index 2ebdbf6d9e..b41a27df3f 100644 --- a/acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-openshift-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-openshift-inject/kustomization.yaml index 564d02a68f..4d4a53b87f 100644 --- a/acceptance/tests/fixtures/cases/static-client-openshift-inject/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-openshift-inject/kustomization.yaml @@ -1,9 +1,8 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-client -patches: -- path: patch.yaml + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-openshift-tproxy/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-openshift-tproxy/kustomization.yaml index 564d02a68f..4d4a53b87f 100644 --- a/acceptance/tests/fixtures/cases/static-client-openshift-tproxy/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-openshift-tproxy/kustomization.yaml @@ -1,9 +1,8 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-client -patches: -- path: patch.yaml + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/kustomization.yaml index 0ae44380dd..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/static-client -patches: -- path: patch.yaml + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml index 4044d78bdf..43507364f8 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml index 0ae44380dd..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/static-client -patches: -- path: patch.yaml + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/patch.yaml index f6a3c50f74..42857c3d2b 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml index 0ae44380dd..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/static-client -patches: -- path: patch.yaml + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml index 720252e833..2fa8ec7e27 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml index 0ae44380dd..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/static-client -patches: -- path: patch.yaml + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml index df04ceccda..f0ceb634bd 100644 --- a/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/kustomization.yaml index 0ae44380dd..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/static-client -patches: -- path: patch.yaml + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/patch.yaml b/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/patch.yaml index 075cb6ecd4..02ea8993ec 100644 --- a/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-peers/default-namespace/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-peers/default/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-peers/default/kustomization.yaml index 0ae44380dd..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-peers/default/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-peers/default/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/static-client -patches: -- path: patch.yaml + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-peers/default/patch.yaml b/acceptance/tests/fixtures/cases/static-client-peers/default/patch.yaml index a6a2f72b37..715485e0f8 100644 --- a/acceptance/tests/fixtures/cases/static-client-peers/default/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-peers/default/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/kustomization.yaml index 0ae44380dd..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../../bases/static-client -patches: -- path: patch.yaml + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/patch.yaml b/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/patch.yaml index 5a7ce34e1b..fd622759a4 100644 --- a/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-peers/non-default-namespace/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml index 564d02a68f..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-client -patches: -- path: patch.yaml + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml b/acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml index 8540fc4721..573bf93b01 100644 --- a/acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml index bd2c22ff5f..bac892baa0 100644 --- a/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml @@ -1,9 +1,5 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-server -patches: -- path: patch.yaml + - ../../bases/static-server + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-server-inject/patch.yaml b/acceptance/tests/fixtures/cases/static-server-inject/patch.yaml index 56ef015d8f..f2bf0d6539 100644 --- a/acceptance/tests/fixtures/cases/static-server-inject/patch.yaml +++ b/acceptance/tests/fixtures/cases/static-server-inject/patch.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: apps/v1 kind: Deployment metadata: diff --git a/acceptance/tests/fixtures/cases/static-server-openshift/kustomization.yaml b/acceptance/tests/fixtures/cases/static-server-openshift/kustomization.yaml index bd2c22ff5f..bc50c78adf 100644 --- a/acceptance/tests/fixtures/cases/static-server-openshift/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-server-openshift/kustomization.yaml @@ -1,9 +1,8 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization resources: -- ../../bases/static-server -patches: -- path: patch.yaml + - ../../bases/static-server + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/wan-federation/dc1-ns2-static-server/kustomization.yaml b/acceptance/tests/fixtures/cases/wan-federation/dc1-ns2-static-server/kustomization.yaml deleted file mode 100644 index 0775282c18..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/dc1-ns2-static-server/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ../../../bases/static-server - -patchesStrategicMerge: - - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/wan-federation/dc1-ns2-static-server/patch.yaml b/acceptance/tests/fixtures/cases/wan-federation/dc1-ns2-static-server/patch.yaml deleted file mode 100644 index c4f181ce7d..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/dc1-ns2-static-server/patch.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-server -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/kschoche/http-echo:latest - args: - - -text="ns2" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - livenessProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - startupProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 30 - periodSeconds: 1 - readinessProbe: - exec: - command: ['sh', '-c', 'test ! -f /tmp/unhealthy'] - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - serviceAccountName: static-server diff --git a/acceptance/tests/fixtures/cases/wan-federation/dc1-static-server/kustomization.yaml b/acceptance/tests/fixtures/cases/wan-federation/dc1-static-server/kustomization.yaml deleted file mode 100644 index 0775282c18..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/dc1-static-server/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ../../../bases/static-server - -patchesStrategicMerge: - - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/wan-federation/dc1-static-server/patch.yaml b/acceptance/tests/fixtures/cases/wan-federation/dc1-static-server/patch.yaml deleted file mode 100644 index 60c1219e33..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/dc1-static-server/patch.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-server -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/kschoche/http-echo:latest - args: - - -text="dc1" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - livenessProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - startupProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 30 - periodSeconds: 1 - readinessProbe: - exec: - command: ['sh', '-c', 'test ! -f /tmp/unhealthy'] - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - serviceAccountName: static-server diff --git a/acceptance/tests/fixtures/cases/wan-federation/dc2-static-server/kustomization.yaml b/acceptance/tests/fixtures/cases/wan-federation/dc2-static-server/kustomization.yaml deleted file mode 100644 index 0775282c18..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/dc2-static-server/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ../../../bases/static-server - -patchesStrategicMerge: - - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/wan-federation/dc2-static-server/patch.yaml b/acceptance/tests/fixtures/cases/wan-federation/dc2-static-server/patch.yaml deleted file mode 100644 index b167f50c9a..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/dc2-static-server/patch.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-server -spec: - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "true" - spec: - containers: - - name: static-server - image: docker.mirror.hashicorp.services/kschoche/http-echo:latest - args: - - -text="dc2" - - -listen=:8080 - ports: - - containerPort: 8080 - name: http - livenessProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - startupProbe: - httpGet: - port: 8080 - initialDelaySeconds: 1 - failureThreshold: 30 - periodSeconds: 1 - readinessProbe: - exec: - command: ['sh', '-c', 'test ! -f /tmp/unhealthy'] - initialDelaySeconds: 1 - failureThreshold: 1 - periodSeconds: 1 - serviceAccountName: static-server diff --git a/acceptance/tests/fixtures/cases/wan-federation/service-resolver/kustomization.yaml b/acceptance/tests/fixtures/cases/wan-federation/service-resolver/kustomization.yaml deleted file mode 100644 index 36e8097f47..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/service-resolver/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ../../../bases/service-resolver - -patchesStrategicMerge: - - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/wan-federation/service-resolver/patch.yaml b/acceptance/tests/fixtures/cases/wan-federation/service-resolver/patch.yaml deleted file mode 100644 index e89156f605..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/service-resolver/patch.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: static-server -spec: - connectTimeout: 15s - failover: - '*': - targets: - - datacenter: "dc2" - - namespace: "ns2" - diff --git a/acceptance/tests/fixtures/cases/wan-federation/static-client/kustomization.yaml b/acceptance/tests/fixtures/cases/wan-federation/static-client/kustomization.yaml deleted file mode 100644 index 38bc36bffd..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/static-client/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -resources: - - ../../../bases/static-client - -patchesStrategicMerge: - - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/wan-federation/static-client/patch.yaml b/acceptance/tests/fixtures/cases/wan-federation/static-client/patch.yaml deleted file mode 100644 index f2f8981601..0000000000 --- a/acceptance/tests/fixtures/cases/wan-federation/static-client/patch.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: static-client -spec: - template: - metadata: - annotations: - 'consul.hashicorp.com/connect-inject': 'true' - "consul.hashicorp.com/connect-service-upstreams": "static-server:1234" - spec: - containers: - - name: static-client - image: anubhavmishra/tiny-tools:latest - # Just spin & wait forever, we'll use `kubectl exec` to demo - command: ['/bin/sh', '-c', '--'] - args: ['while true; do sleep 30; done;'] - # If ACLs are enabled, the serviceAccountName must match the Consul service name. - serviceAccountName: static-client \ No newline at end of file diff --git a/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go index 9edb1db010..b713620f1e 100644 --- a/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package ingressgateway import ( @@ -69,7 +66,7 @@ func TestIngressGatewaySingleNamespace(t *testing.T) { logger.Logf(t, "creating Kubernetes namespace %s", testNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", testNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", testNamespace) }) @@ -80,12 +77,12 @@ func TestIngressGatewaySingleNamespace(t *testing.T) { } logger.Logf(t, "creating server in %s namespace", testNamespace) - k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") // We use the static-client pod so that we can make calls to the ingress gateway // via kubectl exec without needing a route into the cluster from the test machine. logger.Logf(t, "creating static-client in %s namespace", testNamespace) - k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-client") + k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-client") // With the cluster up, we can create our ingress-gateway config entry. logger.Log(t, "creating config entry") @@ -188,7 +185,7 @@ func TestIngressGatewayNamespaceMirroring(t *testing.T) { logger.Logf(t, "creating Kubernetes namespace %s", testNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", testNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", testNamespace) }) @@ -199,12 +196,12 @@ func TestIngressGatewayNamespaceMirroring(t *testing.T) { } logger.Logf(t, "creating server in %s namespace", testNamespace) - k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") // We use the static-client pod so that we can make calls to the ingress gateway // via kubectl exec without needing a route into the cluster from the test machine. logger.Logf(t, "creating static-client in %s namespace", testNamespace) - k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-client") + k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-client") consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) diff --git a/acceptance/tests/ingress-gateway/ingress_gateway_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_test.go index d2b3d7193e..b6535439c1 100644 --- a/acceptance/tests/ingress-gateway/ingress_gateway_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package ingressgateway import ( @@ -52,12 +49,12 @@ func TestIngressGateway(t *testing.T) { consulCluster.Create(t) logger.Log(t, "creating server") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") // We use the static-client pod so that we can make calls to the ingress 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") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-client") // With the cluster up, we can create our ingress-gateway config entry. logger.Log(t, "creating config entry") diff --git a/acceptance/tests/ingress-gateway/main_test.go b/acceptance/tests/ingress-gateway/main_test.go index 4a74d2f361..bd927f96cb 100644 --- a/acceptance/tests/ingress-gateway/main_test.go +++ b/acceptance/tests/ingress-gateway/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package ingressgateway import ( diff --git a/acceptance/tests/metrics/main_test.go b/acceptance/tests/metrics/main_test.go index d3c15b811b..8717c7c4b5 100644 --- a/acceptance/tests/metrics/main_test.go +++ b/acceptance/tests/metrics/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package metrics import ( diff --git a/acceptance/tests/metrics/metrics_test.go b/acceptance/tests/metrics/metrics_test.go index ca80d38b75..5d05e45aa4 100644 --- a/acceptance/tests/metrics/metrics_test.go +++ b/acceptance/tests/metrics/metrics_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package metrics import ( @@ -71,15 +68,15 @@ func TestComponentMetrics(t *testing.T) { // This simulates queries that would be made by a prometheus server that runs externally to the consul // components in the cluster. logger.Log(t, "creating static-client") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-client") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-client") // Server Metrics - metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "-c", "static-client", "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:8500/v1/agent/metrics?format=prometheus", fmt.Sprintf("%s-consul-server.%s.svc", releaseName, ns))) + metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:8500/v1/agent/metrics?format=prometheus", fmt.Sprintf("%s-consul-server.%s.svc", releaseName, ns))) require.NoError(t, err) require.Contains(t, metricsOutput, `consul_acl_ResolveToken{quantile="0.5"}`) // Client Metrics - metricsOutput, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "-c", "static-client", "--", "sh", "-c", "curl --silent --show-error http://$HOST_IP:8500/v1/agent/metrics?format=prometheus") + metricsOutput, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "--", "sh", "-c", "curl --silent --show-error http://$HOST_IP:8500/v1/agent/metrics?format=prometheus") require.NoError(t, err) require.Contains(t, metricsOutput, `consul_acl_ResolveToken{quantile="0.5"}`) @@ -116,13 +113,13 @@ func TestAppMetrics(t *testing.T) { // Deploy service that will emit app and envoy metrics at merged metrics endpoint logger.Log(t, "creating static-metrics-app") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-metrics-app") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-metrics-app") // Create the static-client deployment so we can use it for in-cluster calls to metrics endpoints. // This simulates queries that would be made by a prometheus server that runs externally to the consul // components in the cluster. logger.Log(t, "creating static-client") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-client") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-client") // Merged App Metrics podList, err := ctx.KubernetesClient(t).CoreV1().Pods(ns).List(context.Background(), metav1.ListOptions{LabelSelector: "app=static-metrics-app"}) @@ -132,8 +129,8 @@ func TestAppMetrics(t *testing.T) { // Retry because sometimes the merged metrics server takes a couple hundred milliseconds // to start. - retry.RunWith(&retry.Counter{Count: 20, Wait: 2 * time.Second}, t, func(r *retry.R) { - metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "-c", "static-client", "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:20200/metrics", podIP)) + retry.RunWith(&retry.Counter{Count: 3, Wait: 1 * time.Second}, t, func(r *retry.R) { + metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:20200/metrics", podIP)) require.NoError(r, err) // This assertion represents the metrics from the envoy sidecar. require.Contains(r, metricsOutput, `envoy_cluster_assignment_stale{local_cluster="server",consul_source_service="server"`) @@ -147,7 +144,7 @@ func assertGatewayMetricsEnabled(t *testing.T, ctx environment.TestContext, ns, require.NoError(t, err) for _, pod := range pods.Items { podIP := pod.Status.PodIP - metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "-c", "static-client", "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:20200/metrics", podIP)) + metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+StaticClientName, "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:20200/metrics", podIP)) require.NoError(t, err) require.Contains(t, metricsOutput, metricsAssertion) } diff --git a/acceptance/tests/partitions/main_test.go b/acceptance/tests/partitions/main_test.go index 89833ec2cc..2052a1b74e 100644 --- a/acceptance/tests/partitions/main_test.go +++ b/acceptance/tests/partitions/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package partitions import ( diff --git a/acceptance/tests/partitions/partitions_connect_test.go b/acceptance/tests/partitions/partitions_connect_test.go index 444e70b952..ae2f0688f6 100644 --- a/acceptance/tests/partitions/partitions_connect_test.go +++ b/acceptance/tests/partitions/partitions_connect_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package partitions import ( @@ -108,7 +105,6 @@ func TestPartitions_Connect(t *testing.T) { "dns.enableRedirection": strconv.FormatBool(cfg.EnableTransparentProxy), } - // Setup the default partition defaultPartitionHelmValues := make(map[string]string) // On Kind, there are no load balancers but since all clusters @@ -130,7 +126,6 @@ func TestPartitions_Connect(t *testing.T) { serverConsulCluster := consul.NewHelmCluster(t, defaultPartitionHelmValues, defaultPartitionClusterContext, cfg, releaseName) serverConsulCluster.Create(t) - // Copy secrets from the default partition to the secondary partition // Get the TLS CA certificate and key secret from the server cluster and apply it to the client cluster. caCertSecretName := fmt.Sprintf("%s-consul-ca-cert", releaseName) @@ -148,7 +143,7 @@ func TestPartitions_Connect(t *testing.T) { k8sAuthMethodHost := k8s.KubernetesAPIServerHost(t, cfg, secondaryPartitionClusterContext) - // Create secondary partition cluster. + // Create client cluster. secondaryPartitionHelmValues := map[string]string{ "global.enabled": "false", @@ -206,14 +201,14 @@ func TestPartitions_Connect(t *testing.T) { logger.Logf(t, "creating namespaces %s and %s in servers cluster", staticServerNamespace, StaticClientNamespace) k8s.RunKubectl(t, defaultPartitionClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) k8s.RunKubectl(t, defaultPartitionClusterContext.KubectlOptions(t), "create", "ns", StaticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, defaultPartitionClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace, StaticClientNamespace) }) logger.Logf(t, "creating namespaces %s and %s in clients cluster", staticServerNamespace, StaticClientNamespace) k8s.RunKubectl(t, secondaryPartitionClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) k8s.RunKubectl(t, secondaryPartitionClusterContext.KubectlOptions(t), "create", "ns", StaticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, secondaryPartitionClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace, StaticClientNamespace) }) @@ -273,37 +268,37 @@ func TestPartitions_Connect(t *testing.T) { kustomizeDir := "../fixtures/bases/mesh-gateway" k8s.KubectlApplyK(t, defaultPartitionClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, defaultPartitionClusterContext.KubectlOptions(t), kustomizeDir) }) k8s.KubectlApplyK(t, secondaryPartitionClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, secondaryPartitionClusterContext.KubectlOptions(t), kustomizeDir) }) // This section of the tests runs the in-partition networking tests. t.Run("in-partition", func(t *testing.T) { logger.Log(t, "test in-partition networking") logger.Log(t, "creating static-server and static-client deployments in server cluster") - k8s.DeployKustomize(t, defaultPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, defaultPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } else { - k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") } } logger.Log(t, "creating static-server and static-client deployments in client cluster") - k8s.DeployKustomize(t, secondaryPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } else { - k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") } } // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. @@ -385,7 +380,7 @@ func TestPartitions_Connect(t *testing.T) { require.NoError(t, err) _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { _, err := consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: defaultPartition}) require.NoError(t, err) _, err = consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: secondaryPartition}) @@ -405,8 +400,8 @@ func TestPartitions_Connect(t *testing.T) { // Test that kubernetes readiness status is synced to Consul. // Create the file so that the readiness probe of the static-server pod fails. logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, defaultPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "-c", "static-server", "--", "touch", "/tmp/unhealthy") - k8s.RunKubectl(t, secondaryPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "-c", "static-server", "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, defaultPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, secondaryPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. @@ -426,25 +421,25 @@ func TestPartitions_Connect(t *testing.T) { t.Run("cross-partition", func(t *testing.T) { logger.Log(t, "test cross-partition networking") logger.Log(t, "creating static-server and static-client deployments in server cluster") - k8s.DeployKustomize(t, defaultPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, defaultPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-partition") + k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-partition") } else { - k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-partition") + k8s.DeployKustomize(t, defaultPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-partition") } } logger.Log(t, "creating static-server and static-client deployments in client cluster") - k8s.DeployKustomize(t, secondaryPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-default-partition") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-default-partition") } else { - k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-default-partition") + k8s.DeployKustomize(t, secondaryPartitionClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-default-partition") } } // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. @@ -498,14 +493,14 @@ func TestPartitions_Connect(t *testing.T) { if c.destinationNamespace == defaultNamespace { k8s.KubectlApplyK(t, defaultPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-default") k8s.KubectlApplyK(t, secondaryPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-default") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, defaultPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-default") k8s.KubectlDeleteK(t, secondaryPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-default") }) } else { k8s.KubectlApplyK(t, defaultPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-ns1") k8s.KubectlApplyK(t, secondaryPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-ns1") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, defaultPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-ns1") k8s.KubectlDeleteK(t, secondaryPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-ns1") }) @@ -553,7 +548,7 @@ func TestPartitions_Connect(t *testing.T) { intention.Sources[0].Partition = defaultPartition _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { _, err := consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: defaultPartition}) require.NoError(t, err) _, err = consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: secondaryPartition}) @@ -578,8 +573,8 @@ func TestPartitions_Connect(t *testing.T) { // Test that kubernetes readiness status is synced to Consul. // Create the file so that the readiness probe of the static-server pod fails. logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, defaultPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "-c", "static-server", "--", "touch", "/tmp/unhealthy") - k8s.RunKubectl(t, secondaryPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "-c", "static-server", "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, defaultPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, secondaryPartitionClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. diff --git a/acceptance/tests/partitions/partitions_gateway_test.go b/acceptance/tests/partitions/partitions_gateway_test.go deleted file mode 100644 index a90a790cb6..0000000000 --- a/acceptance/tests/partitions/partitions_gateway_test.go +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package partitions - -import ( - "context" - "fmt" - "strconv" - "testing" - "time" - - terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "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" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -// Test that Gateway works in a default and ACLsEnabled installations for X-Partition and in-partition networking. -func TestPartitions_Gateway(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - - if !cfg.EnableEnterprise { - t.Skipf("skipping this test because -enable-enterprise is not set") - } - - const defaultPartition = "default" - const secondaryPartition = "secondary" - - defaultPartitionClusterContext := env.DefaultContext(t) - secondaryPartitionClusterContext := env.Context(t, 1) - - commonHelmValues := map[string]string{ - "global.adminPartitions.enabled": "true", - "global.enableConsulNamespaces": "true", - "global.logLevel": "debug", - - "global.tls.enabled": "true", - "global.tls.httpsOnly": "true", - - "global.acls.manageSystemACLs": "true", - - "connectInject.enabled": "true", - // When mirroringK8S is set, this setting is ignored. - "connectInject.consulNamespaces.consulDestinationNamespace": staticServerNamespace, - "connectInject.consulNamespaces.mirroringK8S": "true", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - - "dns.enabled": "true", - "dns.enableRedirection": strconv.FormatBool(cfg.EnableTransparentProxy), - } - - defaultPartitionHelmValues := make(map[string]string) - - // On Kind, there are no load balancers but since all clusters - // share the same node network (docker bridge), we can use - // a NodePort service so that we can access node(s) in a different Kind cluster. - if cfg.UseKind { - defaultPartitionHelmValues["meshGateway.service.type"] = "NodePort" - defaultPartitionHelmValues["meshGateway.service.nodePort"] = "30200" // todo: do we need to set this port? - defaultPartitionHelmValues["server.exposeService.type"] = "NodePort" - defaultPartitionHelmValues["server.exposeService.nodePort.https"] = "30000" - defaultPartitionHelmValues["server.exposeService.nodePort.grpc"] = "30100" - } - - releaseName := helpers.RandomName() - - helpers.MergeMaps(defaultPartitionHelmValues, commonHelmValues) - - // Install the consul cluster with servers in the default kubernetes context. - serverConsulCluster := consul.NewHelmCluster(t, defaultPartitionHelmValues, defaultPartitionClusterContext, cfg, releaseName) - serverConsulCluster.Create(t) - - // Get the TLS CA certificate and key secret from the server cluster and apply it to the client cluster. - caCertSecretName := fmt.Sprintf("%s-consul-ca-cert", releaseName) - - logger.Logf(t, "retrieving ca cert secret %s from the server cluster and applying to the client cluster", caCertSecretName) - k8s.CopySecret(t, defaultPartitionClusterContext, secondaryPartitionClusterContext, caCertSecretName) - - partitionToken := fmt.Sprintf("%s-consul-partitions-acl-token", releaseName) - logger.Logf(t, "retrieving partition token secret %s from the server cluster and applying to the client cluster", partitionToken) - k8s.CopySecret(t, defaultPartitionClusterContext, secondaryPartitionClusterContext, partitionToken) - - partitionServiceName := fmt.Sprintf("%s-consul-expose-servers", releaseName) - partitionSvcAddress := k8s.ServiceHost(t, cfg, defaultPartitionClusterContext, partitionServiceName) - - k8sAuthMethodHost := k8s.KubernetesAPIServerHost(t, cfg, secondaryPartitionClusterContext) - - // Create client cluster. - secondaryPartitionHelmValues := map[string]string{ - "global.enabled": "false", - - "global.adminPartitions.name": secondaryPartition, - - "global.tls.caCert.secretName": caCertSecretName, - "global.tls.caCert.secretKey": "tls.crt", - - "externalServers.enabled": "true", - "externalServers.hosts[0]": partitionSvcAddress, - "externalServers.tlsServerName": "server.dc1.consul", - } - - // Setup partition token and auth method host since ACLs enabled. - secondaryPartitionHelmValues["global.acls.bootstrapToken.secretName"] = partitionToken - secondaryPartitionHelmValues["global.acls.bootstrapToken.secretKey"] = "token" - secondaryPartitionHelmValues["externalServers.k8sAuthMethodHost"] = k8sAuthMethodHost - - if cfg.UseKind { - secondaryPartitionHelmValues["externalServers.httpsPort"] = "30000" - secondaryPartitionHelmValues["externalServers.grpcPort"] = "30100" - secondaryPartitionHelmValues["meshGateway.service.type"] = "NodePort" - secondaryPartitionHelmValues["meshGateway.service.nodePort"] = "30200" - } - - helpers.MergeMaps(secondaryPartitionHelmValues, commonHelmValues) - - // Install the consul cluster without servers in the client cluster kubernetes context. - clientConsulCluster := consul.NewHelmCluster(t, secondaryPartitionHelmValues, secondaryPartitionClusterContext, cfg, releaseName) - clientConsulCluster.Create(t) - - defaultPartitionClusterStaticServerOpts := &terratestk8s.KubectlOptions{ - ContextName: defaultPartitionClusterContext.KubectlOptions(t).ContextName, - ConfigPath: defaultPartitionClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticServerNamespace, - } - secondaryPartitionClusterStaticServerOpts := &terratestk8s.KubectlOptions{ - ContextName: secondaryPartitionClusterContext.KubectlOptions(t).ContextName, - ConfigPath: secondaryPartitionClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticServerNamespace, - } - secondaryPartitionClusterStaticClientOpts := &terratestk8s.KubectlOptions{ - ContextName: secondaryPartitionClusterContext.KubectlOptions(t).ContextName, - ConfigPath: secondaryPartitionClusterContext.KubectlOptions(t).ConfigPath, - Namespace: StaticClientNamespace, - } - - logger.Logf(t, "creating namespaces %s and %s in servers cluster", staticServerNamespace, StaticClientNamespace) - k8s.RunKubectl(t, defaultPartitionClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - k8s.RunKubectl(t, defaultPartitionClusterContext.KubectlOptions(t), "create", "ns", StaticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, defaultPartitionClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace, StaticClientNamespace) - }) - - logger.Logf(t, "creating namespaces %s and %s in clients cluster", staticServerNamespace, StaticClientNamespace) - k8s.RunKubectl(t, secondaryPartitionClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - k8s.RunKubectl(t, secondaryPartitionClusterContext.KubectlOptions(t), "create", "ns", StaticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, secondaryPartitionClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace, StaticClientNamespace) - }) - - consulClient, _ := serverConsulCluster.SetupConsulClient(t, true) - - serverQueryServerOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: defaultPartition} - clientQueryServerOpts := &api.QueryOptions{Namespace: StaticClientNamespace, Partition: defaultPartition} - - serverQueryClientOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: secondaryPartition} - clientQueryClientOpts := &api.QueryOptions{Namespace: StaticClientNamespace, Partition: secondaryPartition} - - // We need to register the cleanup function before we create the deployments - // because golang will execute them in reverse order i.e. the last registered - // cleanup function will be executed first. - t.Cleanup(func() { - retry.Run(t, func(r *retry.R) { - tokens, _, err := consulClient.ACL().TokenList(serverQueryServerOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, staticServerName) - } - - tokens, _, err = consulClient.ACL().TokenList(clientQueryServerOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, StaticClientName) - } - tokens, _, err = consulClient.ACL().TokenList(serverQueryClientOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, staticServerName) - } - - tokens, _, err = consulClient.ACL().TokenList(clientQueryClientOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, StaticClientName) - } - }) - }) - - // Create a ProxyDefaults resource to configure services to use the mesh - // gateways. - logger.Log(t, "creating proxy-defaults config") - kustomizeDir := "../fixtures/cases/api-gateways/mesh" - - k8s.KubectlApplyK(t, defaultPartitionClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, defaultPartitionClusterContext.KubectlOptions(t), kustomizeDir) - }) - - k8s.KubectlApplyK(t, secondaryPartitionClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, secondaryPartitionClusterContext.KubectlOptions(t), kustomizeDir) - }) - - // 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. - // Since we're deploying the gateway in the secondary cluster, we create the static client - // in the secondary as well. - 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") - - logger.Log(t, "creating api-gateway resources") - 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 - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, secondaryPartitionClusterStaticServerOpts, "delete", "-k", "../fixtures/bases/api-gateway") - }) - - // Grab a kubernetes client so that we can verify binding - // behavior prior to issuing requests through the gateway. - k8sClient := secondaryPartitionClusterContext.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 1m timeout here). - var gatewayAddress string - counter := &retry.Counter{Count: 600, Wait: 2 * time.Second} - retry.RunWith(counter, t, func(r *retry.R) { - var gateway gwv1beta1.Gateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: staticServerNamespace}, &gateway) - require.NoError(r, err) - - // check that we have an address to use - require.Len(r, gateway.Status.Addresses, 1) - // now we know we have an address, set it so we can use it - gatewayAddress = gateway.Status.Addresses[0].Value - }) - - targetAddress := fmt.Sprintf("http://%s/", gatewayAddress) - - // This section of the tests runs the in-partition networking tests. - t.Run("in-partition", func(t *testing.T) { - logger.Log(t, "test in-partition networking") - logger.Log(t, "creating target server in secondary partition cluster") - k8s.DeployKustomize(t, secondaryPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - // Check that static-server injected 2 containers. - for _, labelSelector := range []string{"app=static-server"} { - podList, err := secondaryPartitionClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } - - logger.Log(t, "patching route to target server") - k8s.RunKubectl(t, secondaryPartitionClusterStaticServerOpts, "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"group":"consul.hashicorp.com","kind":"MeshService","name":"mesh-service","port":80}]}]}}`, "--type=merge") - - logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerHTTPConnectionFailing(t, secondaryPartitionClusterStaticClientOpts, StaticClientName, targetAddress) - - intention := &api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: staticServerName, - Namespace: staticServerNamespace, - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Namespace: staticServerNamespace, - Action: api.IntentionActionAllow, - }, - }, - } - - logger.Log(t, "creating intention") - _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) - require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - _, err = consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: secondaryPartition}) - require.NoError(t, err) - }) - - logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, secondaryPartitionClusterStaticClientOpts, StaticClientName, targetAddress) - }) - - // This section of the tests runs the cross-partition networking tests. - t.Run("cross-partition", func(t *testing.T) { - logger.Log(t, "test cross-partition networking") - - logger.Log(t, "creating target server in default partition cluster") - k8s.DeployKustomize(t, defaultPartitionClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - // Check that static-server injected 2 containers. - for _, labelSelector := range []string{"app=static-server"} { - podList, err := defaultPartitionClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } - - logger.Log(t, "creating exported services") - k8s.KubectlApplyK(t, defaultPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-ns1") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, defaultPartitionClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-ns1") - }) - - logger.Log(t, "creating local service resolver") - k8s.KubectlApplyK(t, secondaryPartitionClusterStaticServerOpts, "../fixtures/cases/api-gateways/resolver") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, secondaryPartitionClusterStaticServerOpts, "../fixtures/cases/api-gateways/resolver") - }) - - logger.Log(t, "patching route to target server") - k8s.RunKubectl(t, secondaryPartitionClusterStaticServerOpts, "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"group":"consul.hashicorp.com","kind":"MeshService","name":"mesh-service","port":80}]}]}}`, "--type=merge") - - logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerHTTPConnectionFailing(t, secondaryPartitionClusterStaticClientOpts, StaticClientName, targetAddress) - - intention := &api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: staticServerName, - Namespace: staticServerNamespace, - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Namespace: staticServerNamespace, - Action: api.IntentionActionAllow, - Partition: secondaryPartition, - }, - }, - } - - logger.Log(t, "creating intention") - _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: defaultPartition}) - require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - _, err = consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: defaultPartition}) - require.NoError(t, err) - }) - - logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, secondaryPartitionClusterStaticClientOpts, StaticClientName, targetAddress) - }) -} diff --git a/acceptance/tests/partitions/partitions_sync_test.go b/acceptance/tests/partitions/partitions_sync_test.go index da95d7f272..8d761d0765 100644 --- a/acceptance/tests/partitions/partitions_sync_test.go +++ b/acceptance/tests/partitions/partitions_sync_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package partitions import ( @@ -195,13 +192,13 @@ func TestPartitions_Sync(t *testing.T) { logger.Logf(t, "creating namespaces %s in servers cluster", staticServerNamespace) k8s.RunKubectl(t, primaryClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, primaryClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) }) logger.Logf(t, "creating namespaces %s in clients cluster", staticServerNamespace) k8s.RunKubectl(t, secondaryClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, secondaryClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) }) @@ -241,13 +238,13 @@ func TestPartitions_Sync(t *testing.T) { logger.Log(t, "creating a static-server with a service") // create service in default partition. - k8s.DeployKustomize(t, primaryStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, primaryStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-server") // create service in secondary partition. - k8s.DeployKustomize(t, secondaryStaticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, secondaryStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-server") logger.Log(t, "checking that the service has been synced to Consul") var services map[string][]string - counter := &retry.Counter{Count: 30, Wait: 30 * time.Second} + counter := &retry.Counter{Count: 20, Wait: 30 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { var err error // list services in default partition catalog. diff --git a/acceptance/tests/peering/main_test.go b/acceptance/tests/peering/main_test.go index 075051861d..df9812171c 100644 --- a/acceptance/tests/peering/main_test.go +++ b/acceptance/tests/peering/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package peering import ( diff --git a/acceptance/tests/peering/peering_connect_namespaces_test.go b/acceptance/tests/peering/peering_connect_namespaces_test.go index 618248c6a9..b52d2793d0 100644 --- a/acceptance/tests/peering/peering_connect_namespaces_test.go +++ b/acceptance/tests/peering/peering_connect_namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package peering import ( @@ -166,12 +163,12 @@ func TestPeering_ConnectNamespaces(t *testing.T) { kustomizeMeshDir := "../fixtures/bases/mesh-peering" k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) }) k8s.KubectlApplyK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) }) @@ -198,7 +195,7 @@ func TestPeering_ConnectNamespaces(t *testing.T) { // Create the peering acceptor on the client peer. k8s.KubectlApply(t, staticClientPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-acceptor.yaml") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDelete(t, staticClientPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-acceptor.yaml") }) @@ -214,7 +211,7 @@ func TestPeering_ConnectNamespaces(t *testing.T) { // Create the peering dialer on the server peer. k8s.KubectlApply(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-dialer.yaml") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "delete", "secret", "api-token") k8s.KubectlDelete(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-dialer.yaml") }) @@ -232,13 +229,13 @@ func TestPeering_ConnectNamespaces(t *testing.T) { logger.Logf(t, "creating namespaces %s in server peer", staticServerNamespace) k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) }) logger.Logf(t, "creating namespaces %s in client peer", staticClientNamespace) k8s.RunKubectl(t, staticClientPeerClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, staticClientPeerClusterContext.KubectlOptions(t), "delete", "ns", staticClientNamespace) }) @@ -256,26 +253,26 @@ func TestPeering_ConnectNamespaces(t *testing.T) { kustomizeDir := "../fixtures/bases/mesh-gateway" k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeDir) }) k8s.KubectlApplyK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeDir) }) logger.Log(t, "creating static-server in server peer") - k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") logger.Log(t, "creating static-client deployments in client peer") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-peers/default-namespace") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-peers/default-namespace") } else { - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-peers/non-default-namespace") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-peers/non-default-namespace") } } // Check that both static-server and static-client have been injected and now have 2 containers. @@ -312,12 +309,12 @@ func TestPeering_ConnectNamespaces(t *testing.T) { logger.Log(t, "creating exported services") if c.destinationNamespace == defaultNamespace { k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/default-namespace") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/default-namespace") }) } else { k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/non-default-namespace") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/non-default-namespace") }) } diff --git a/acceptance/tests/peering/peering_connect_test.go b/acceptance/tests/peering/peering_connect_test.go index d92ab59990..470ada08a1 100644 --- a/acceptance/tests/peering/peering_connect_test.go +++ b/acceptance/tests/peering/peering_connect_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package peering import ( @@ -121,12 +118,12 @@ func TestPeering_Connect(t *testing.T) { kustomizeMeshDir := "../fixtures/bases/mesh-peering" k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) }) k8s.KubectlApplyK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) }) @@ -153,7 +150,7 @@ func TestPeering_Connect(t *testing.T) { // Create the peering acceptor on the client peer. k8s.KubectlApply(t, staticClientPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-acceptor.yaml") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDelete(t, staticClientPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-acceptor.yaml") }) @@ -169,7 +166,7 @@ func TestPeering_Connect(t *testing.T) { // Create the peering dialer on the server peer. k8s.KubectlApply(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-dialer.yaml") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "delete", "secret", "api-token") k8s.KubectlDelete(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-dialer.yaml") }) @@ -187,13 +184,13 @@ func TestPeering_Connect(t *testing.T) { logger.Logf(t, "creating namespaces %s in server peer", staticServerNamespace) k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) }) logger.Logf(t, "creating namespaces %s in client peer", staticClientNamespace) k8s.RunKubectl(t, staticClientPeerClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, staticClientPeerClusterContext.KubectlOptions(t), "delete", "ns", staticClientNamespace) }) @@ -203,23 +200,23 @@ func TestPeering_Connect(t *testing.T) { kustomizeDir := "../fixtures/bases/mesh-gateway" k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeDir) }) k8s.KubectlApplyK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeDir) }) logger.Log(t, "creating static-server in server peer") - k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") logger.Log(t, "creating static-client deployments in client peer") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-peers/default") + k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-peers/default") } // Check that both static-server and static-client have been injected and now have 2 containers. podList, err := staticServerPeerClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ @@ -249,7 +246,7 @@ func TestPeering_Connect(t *testing.T) { logger.Log(t, "creating exported services") k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/default") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/default") }) diff --git a/acceptance/tests/peering/peering_gateway_test.go b/acceptance/tests/peering/peering_gateway_test.go deleted file mode 100644 index 3ba04980a9..0000000000 --- a/acceptance/tests/peering/peering_gateway_test.go +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package peering - -import ( - "context" - "fmt" - "testing" - "time" - - terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "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/hashicorp/go-version" - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/types" - - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestPeering_Gateway(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - - if !cfg.EnableEnterprise { - t.Skipf("skipping this test because -enable-enterprise is not set") - } - - ver, err := version.NewVersion("1.13.0") - require.NoError(t, err) - if cfg.ConsulVersion != nil && cfg.ConsulVersion.LessThan(ver) { - t.Skipf("skipping this test because peering is not supported in version %v", cfg.ConsulVersion.String()) - } - - const staticServerPeer = "server" - const staticClientPeer = "client" - - staticServerPeerClusterContext := env.DefaultContext(t) - staticClientPeerClusterContext := env.Context(t, 1) - - commonHelmValues := map[string]string{ - "global.peering.enabled": "true", - "global.enableConsulNamespaces": "true", - - "global.tls.enabled": "true", - "global.tls.httpsOnly": "true", - - "global.acls.manageSystemACLs": "true", - - "connectInject.enabled": "true", - - // When mirroringK8S is set, this setting is ignored. - "connectInject.consulNamespaces.mirroringK8S": "true", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - - "dns.enabled": "true", - } - - staticServerPeerHelmValues := map[string]string{ - "global.datacenter": staticServerPeer, - } - - if !cfg.UseKind { - staticServerPeerHelmValues["server.replicas"] = "3" - } - - // On Kind, there are no load balancers but since all clusters - // share the same node network (docker bridge), we can use - // a NodePort service so that we can access node(s) in a different Kind cluster. - if cfg.UseKind { - staticServerPeerHelmValues["server.exposeGossipAndRPCPorts"] = "true" - staticServerPeerHelmValues["meshGateway.service.type"] = "NodePort" - staticServerPeerHelmValues["meshGateway.service.nodePort"] = "30100" - } - - releaseName := helpers.RandomName() - - helpers.MergeMaps(staticServerPeerHelmValues, commonHelmValues) - - // Install the first peer where static-server will be deployed in the static-server kubernetes context. - staticServerPeerCluster := consul.NewHelmCluster(t, staticServerPeerHelmValues, staticServerPeerClusterContext, cfg, releaseName) - staticServerPeerCluster.Create(t) - - staticClientPeerHelmValues := map[string]string{ - "global.datacenter": staticClientPeer, - } - - if !cfg.UseKind { - staticClientPeerHelmValues["server.replicas"] = "3" - } - - if cfg.UseKind { - staticClientPeerHelmValues["server.exposeGossipAndRPCPorts"] = "true" - staticClientPeerHelmValues["meshGateway.service.type"] = "NodePort" - staticClientPeerHelmValues["meshGateway.service.nodePort"] = "30100" - } - - helpers.MergeMaps(staticClientPeerHelmValues, commonHelmValues) - - // Install the second peer where static-client will be deployed in the static-client kubernetes context. - staticClientPeerCluster := consul.NewHelmCluster(t, staticClientPeerHelmValues, staticClientPeerClusterContext, cfg, releaseName) - staticClientPeerCluster.Create(t) - - // Create Mesh resource to use mesh gateways. - logger.Log(t, "creating mesh config") - kustomizeMeshDir := "../fixtures/bases/mesh-peering" - - k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - }) - - k8s.KubectlApplyK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeMeshDir) - }) - - staticServerPeerClient, _ := staticServerPeerCluster.SetupConsulClient(t, true) - staticClientPeerClient, _ := staticClientPeerCluster.SetupConsulClient(t, true) - - // Ensure mesh config entries are created in Consul. - timer := &retry.Timer{Timeout: 1 * time.Minute, Wait: 1 * time.Second} - retry.RunWith(timer, t, func(r *retry.R) { - ceServer, _, err := staticServerPeerClient.ConfigEntries().Get(api.MeshConfig, "mesh", &api.QueryOptions{}) - require.NoError(r, err) - configEntryServer, ok := ceServer.(*api.MeshConfigEntry) - require.True(r, ok) - require.Equal(r, configEntryServer.GetName(), "mesh") - require.NoError(r, err) - - ceClient, _, err := staticClientPeerClient.ConfigEntries().Get(api.MeshConfig, "mesh", &api.QueryOptions{}) - require.NoError(r, err) - configEntryClient, ok := ceClient.(*api.MeshConfigEntry) - require.True(r, ok) - require.Equal(r, configEntryClient.GetName(), "mesh") - require.NoError(r, err) - }) - - // Create the peering acceptor on the client peer. - k8s.KubectlApply(t, staticClientPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-acceptor.yaml") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDelete(t, staticClientPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-acceptor.yaml") - }) - - // Ensure the secret is created. - retry.RunWith(timer, t, func(r *retry.R) { - acceptorSecretName, err := k8s.RunKubectlAndGetOutputE(t, staticClientPeerClusterContext.KubectlOptions(t), "get", "peeringacceptor", "server", "-o", "jsonpath={.status.secret.name}") - require.NoError(r, err) - require.NotEmpty(r, acceptorSecretName) - }) - - // Copy secret from client peer to server peer. - k8s.CopySecret(t, staticClientPeerClusterContext, staticServerPeerClusterContext, "api-token") - - // Create the peering dialer on the server peer. - k8s.KubectlApply(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-dialer.yaml") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "delete", "secret", "api-token") - k8s.KubectlDelete(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/bases/peering/peering-dialer.yaml") - }) - - staticServerOpts := &terratestk8s.KubectlOptions{ - ContextName: staticServerPeerClusterContext.KubectlOptions(t).ContextName, - ConfigPath: staticServerPeerClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticServerNamespace, - } - staticClientOpts := &terratestk8s.KubectlOptions{ - ContextName: staticClientPeerClusterContext.KubectlOptions(t).ContextName, - ConfigPath: staticClientPeerClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticClientNamespace, - } - - logger.Logf(t, "creating namespaces %s in server peer", staticServerNamespace) - k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, staticServerPeerClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) - }) - - logger.Logf(t, "creating namespaces %s in client peer", staticClientNamespace) - k8s.RunKubectl(t, staticClientPeerClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, staticClientPeerClusterContext.KubectlOptions(t), "delete", "ns", staticClientNamespace) - }) - - // Create a ProxyDefaults resource to configure services to use the mesh - // gateways. - logger.Log(t, "creating proxy-defaults config") - kustomizeDir := "../fixtures/cases/api-gateways/mesh" - - k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), kustomizeDir) - }) - - k8s.KubectlApplyK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, staticClientPeerClusterContext.KubectlOptions(t), kustomizeDir) - }) - - // 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. - // Since we're deploying the gateway in the secondary cluster, we create the static client - // in the secondary as well. - logger.Log(t, "creating static-client pod in client peer") - k8s.DeployKustomize(t, staticClientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-peers/non-default-namespace") - - logger.Log(t, "creating static-server in server peer") - k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - logger.Log(t, "creating exported services") - k8s.KubectlApplyK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/non-default-namespace") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, staticServerPeerClusterContext.KubectlOptions(t), "../fixtures/cases/crd-peers/non-default-namespace") - }) - - logger.Log(t, "creating api-gateway resources in client peer") - 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 - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, staticClientOpts, "delete", "-k", "../fixtures/bases/api-gateway") - }) - - // Grab a kubernetes client so that we can verify binding - // behavior prior to issuing requests through the gateway. - k8sClient := staticClientPeerClusterContext.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 1m timeout here). - var gatewayAddress string - counter := &retry.Counter{Count: 600, Wait: 2 * time.Second} - retry.RunWith(counter, t, func(r *retry.R) { - var gateway gwv1beta1.Gateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: staticClientNamespace}, &gateway) - require.NoError(r, err) - - // check that we have an address to use - require.Len(r, gateway.Status.Addresses, 1) - // now we know we have an address, set it so we can use it - gatewayAddress = gateway.Status.Addresses[0].Value - }) - - targetAddress := fmt.Sprintf("http://%s/", gatewayAddress) - - logger.Log(t, "creating local service resolver") - k8s.KubectlApplyK(t, staticClientOpts, "../fixtures/cases/api-gateways/peer-resolver") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, staticClientOpts, "../fixtures/cases/api-gateways/peer-resolver") - }) - - logger.Log(t, "patching route to target server") - k8s.RunKubectl(t, staticClientOpts, "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"group":"consul.hashicorp.com","kind":"MeshService","name":"mesh-service","port":80}]}]}}`, "--type=merge") - - logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerHTTPConnectionFailing(t, staticClientOpts, staticClientName, targetAddress) - - intention := &api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: staticServerName, - Namespace: staticServerNamespace, - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Namespace: staticClientNamespace, - Action: api.IntentionActionAllow, - Peer: staticClientPeer, - }, - }, - } - - logger.Log(t, "creating intention") - _, _, err = staticServerPeerClient.ConfigEntries().Set(intention, &api.WriteOptions{}) - require.NoError(t, err) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - _, err = staticServerPeerClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{}) - require.NoError(t, err) - }) - - logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, staticClientOpts, staticClientName, targetAddress) -} diff --git a/acceptance/tests/sameness/main_test.go b/acceptance/tests/sameness/main_test.go deleted file mode 100644 index ded943c6f0..0000000000 --- a/acceptance/tests/sameness/main_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package sameness - -import ( - "fmt" - "os" - "testing" - - testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" -) - -var suite testsuite.Suite - -func TestMain(m *testing.M) { - suite = testsuite.NewSuite(m) - - expectedNumberOfClusters := 4 - - if suite.Config().EnableMultiCluster && suite.Config().IsExpectedClusterCount(expectedNumberOfClusters) && suite.Config().UseKind { - os.Exit(suite.Run()) - } else { - fmt.Println(fmt.Sprintf("Skipping sameness tests because either -enable-multi-cluster is "+ - "not set, the number of clusters did not match the expected count of %d, or --useKind is false. "+ - "Sameness acceptance tests are currently only supported on Kind clusters", expectedNumberOfClusters)) - } -} diff --git a/acceptance/tests/sameness/sameness_test.go b/acceptance/tests/sameness/sameness_test.go deleted file mode 100644 index 9688ff9855..0000000000 --- a/acceptance/tests/sameness/sameness_test.go +++ /dev/null @@ -1,874 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package sameness - -import ( - ctx "context" - "fmt" - "strconv" - "strings" - "sync" - "testing" - "time" - - terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/environment" - "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/assert" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - cluster01Partition = "ap1" - cluster01Datacenter = "dc1" - cluster02Datacenter = "dc2" - cluster03Datacenter = "dc3" - staticClientNamespace = "ns1" - staticServerNamespace = "ns2" - - keyCluster01a = "cluster-01-a" - keyCluster01b = "cluster-01-b" - keyCluster02a = "cluster-02-a" - keyCluster03a = "cluster-03-a" - - staticServerName = "static-server" - staticClientName = "static-client" - - staticServerDeployment = "deploy/static-server" - staticClientDeployment = "deploy/static-client" - - peerName1a = keyCluster01a - peerName1b = keyCluster01b - peerName2a = keyCluster02a - peerName3a = keyCluster03a - - samenessGroupName = "group-01" - - cluster01Region = "us-east-1" - cluster02Region = "us-west-1" - cluster03Region = "us-east-2" - - retryTimeout = 5 * time.Minute -) - -func TestFailover_Connect(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - - if !cfg.EnableEnterprise { - t.Skipf("skipping this test because -enable-enterprise is not set") - } - - cases := []struct { - name string - ACLsEnabled bool - }{ - { - "default failover", - false, - }, - { - "secure failover", - true, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - /* - Architecture Overview: - Primary Datacenter (DC1) - Default Partition - Peer -> DC2 (cluster-02-a) - Peer -> DC3 (cluster-03-a) - AP1 Partition - Peer -> DC2 (cluster-02-a) - Peer -> DC3 (cluster-03-a) - Datacenter 2 (DC2) - Default Partition - Peer -> DC1 (cluster-01-a) - Peer -> DC1 (cluster-01-b) - Peer -> DC3 (cluster-03-a) - Datacenter 3 (DC3) - Default Partition - Peer -> DC1 (cluster-01-a) - Peer -> DC1 (cluster-01-b) - Peer -> DC2 (cluster-02-a) - - - Architecture Diagram + failover scenarios from perspective of DC1 Default Partition Static-Server - +-------------------------------------------+ - | | - | DC1 | - | | - | +-----------------------------+ | +-----------------------------------+ - | | | | | DC2 | - | | +------------------+ | | Failover 2 | +------------------+ | - | | | +-------+--------+-----------------+------>| | | - | | | Static-Server | | | | | Static-Server | | - | | | +-------+---+ | | | | | - | | | | | | | | | | | - | | | | | | | | | | | - | | | +-------+---+----+-------------+ | | | | - | | +------------------+ | | | | | +------------------+ | - | | Admin Partitions: Default | | | | | | - | | Name: cluster-01-a | | | | | Admin Partitions: Default | - | | Region: us-east-1 | | | | | Name: cluster-02-a | - | +-----------------------------+ | | | | Region: us-west-1 | - | | | | +-----------------------------------+ - | Failover 1| | Failover 3 | - | +-------------------------------+ | | | +-----------------------------------+ - | | | | | | | DC3 | - | | +------------------+ | | | | | +------------------+ | - | | | | | | | | | | Static-Server | | - | | | Static-Server | | | | | | | | | - | | | | | | | | | | | | - | | | | | | | +---+------>| | | - | | | |<------+--+ | | | | | - | | | | | | | +------------------+ | - | | +------------------+ | | | | - | | Admin Partitions: ap1 | | | Admin Partitions: Default | - | | Name: cluster-01-b | | | Name: cluster-03-a | - | | Region: us-east-1 | | | Region: us-east-2 | - | +-------------------------------+ | | | - | | +-----------------------------------+ - +-------------------------------------------+ - */ - - testClusters := clusters{ - keyCluster01a: {name: peerName1a, context: env.DefaultContext(t), hasServer: true, acceptors: []string{peerName2a, peerName3a}, locality: localityForRegion(cluster01Region)}, - keyCluster01b: {name: peerName1b, context: env.Context(t, 1), partition: cluster01Partition, hasServer: false, acceptors: []string{peerName2a, peerName3a}, locality: localityForRegion(cluster01Region)}, - keyCluster02a: {name: peerName2a, context: env.Context(t, 2), hasServer: true, acceptors: []string{peerName3a}, locality: localityForRegion(cluster02Region)}, - keyCluster03a: {name: peerName3a, context: env.Context(t, 3), hasServer: true, locality: localityForRegion(cluster03Region)}, - } - - // Set primary clusters per cluster - // This is helpful for cases like DNS with partitions where many aspects of the primary cluster must be used - testClusters[keyCluster01a].primaryCluster = testClusters[keyCluster01a] - testClusters[keyCluster01b].primaryCluster = testClusters[keyCluster01a] - testClusters[keyCluster02a].primaryCluster = testClusters[keyCluster02a] - testClusters[keyCluster03a].primaryCluster = testClusters[keyCluster03a] - - // Setup Namespaces. - for _, v := range testClusters { - createNamespaces(t, cfg, v.context) - } - - commonHelmValues := map[string]string{ - "global.peering.enabled": "true", - - "global.tls.enabled": "true", - "global.tls.httpsOnly": strconv.FormatBool(c.ACLsEnabled), - - "global.enableConsulNamespaces": "true", - - "global.adminPartitions.enabled": "true", - - "global.logLevel": "warn", - - "global.acls.manageSystemACLs": strconv.FormatBool(c.ACLsEnabled), - - "connectInject.enabled": "true", - "connectInject.consulNamespaces.mirroringK8S": "true", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - - "dns.enabled": "true", - "connectInject.sidecarProxy.lifecycle.defaultEnabled": "false", - } - - releaseName := helpers.RandomName() - - var wg sync.WaitGroup - - // Create the cluster-01-a and cluster-01-b - // create in same routine as 01-b depends on 01-a being created first - wg.Add(1) - go func() { - // Create the cluster-01-a - defaultPartitionHelmValues := map[string]string{ - "global.datacenter": cluster01Datacenter, - } - - // On Kind, there are no load balancers but since all clusters - // share the same node network (docker bridge), we can use - // a NodePort service so that we can access node(s) in a different Kind cluster. - if cfg.UseKind { - defaultPartitionHelmValues["meshGateway.service.type"] = "NodePort" - defaultPartitionHelmValues["meshGateway.service.nodePort"] = "30200" - defaultPartitionHelmValues["server.exposeService.type"] = "NodePort" - defaultPartitionHelmValues["server.exposeService.nodePort.https"] = "30000" - defaultPartitionHelmValues["server.exposeService.nodePort.grpc"] = "30100" - } - helpers.MergeMaps(defaultPartitionHelmValues, commonHelmValues) - - testClusters[keyCluster01a].helmCluster = consul.NewHelmCluster(t, defaultPartitionHelmValues, testClusters[keyCluster01a].context, cfg, releaseName) - testClusters[keyCluster01a].helmCluster.Create(t) - - // Get the TLS CA certificate and key secret from the server cluster and apply it to the client cluster. - caCertSecretName := fmt.Sprintf("%s-consul-ca-cert", releaseName) - - logger.Logf(t, "retrieving ca cert secret %s from the server cluster and applying to the client cluster", caCertSecretName) - k8s.CopySecret(t, testClusters[keyCluster01a].context, testClusters[keyCluster01b].context, caCertSecretName) - - // Create Secondary Partition Cluster (cluster-01-b) which will apply the primary (dc1) datacenter. - partitionToken := fmt.Sprintf("%s-consul-partitions-acl-token", releaseName) - if c.ACLsEnabled { - logger.Logf(t, "retrieving partition token secret %s from the server cluster and applying to the client cluster", partitionToken) - k8s.CopySecret(t, testClusters[keyCluster01a].context, testClusters[keyCluster01b].context, partitionToken) - } - - partitionServiceName := fmt.Sprintf("%s-consul-expose-servers", releaseName) - partitionSvcAddress := k8s.ServiceHost(t, cfg, testClusters[keyCluster01a].context, partitionServiceName) - - k8sAuthMethodHost := k8s.KubernetesAPIServerHost(t, cfg, testClusters[keyCluster01b].context) - - secondaryPartitionHelmValues := map[string]string{ - "global.enabled": "false", - "global.datacenter": cluster01Datacenter, - - "global.adminPartitions.name": cluster01Partition, - - "global.tls.caCert.secretName": caCertSecretName, - "global.tls.caCert.secretKey": "tls.crt", - - "externalServers.enabled": "true", - "externalServers.hosts[0]": partitionSvcAddress, - "externalServers.tlsServerName": fmt.Sprintf("server.%s.consul", cluster01Datacenter), - "global.server.enabled": "false", - } - - if c.ACLsEnabled { - // Setup partition token and auth method host if ACLs enabled. - secondaryPartitionHelmValues["global.acls.bootstrapToken.secretName"] = partitionToken - secondaryPartitionHelmValues["global.acls.bootstrapToken.secretKey"] = "token" - secondaryPartitionHelmValues["externalServers.k8sAuthMethodHost"] = k8sAuthMethodHost - } - - if cfg.UseKind { - secondaryPartitionHelmValues["externalServers.httpsPort"] = "30000" - secondaryPartitionHelmValues["externalServers.grpcPort"] = "30100" - secondaryPartitionHelmValues["meshGateway.service.type"] = "NodePort" - secondaryPartitionHelmValues["meshGateway.service.nodePort"] = "30200" - } - helpers.MergeMaps(secondaryPartitionHelmValues, commonHelmValues) - - testClusters[keyCluster01b].helmCluster = consul.NewHelmCluster(t, secondaryPartitionHelmValues, testClusters[keyCluster01b].context, cfg, releaseName) - testClusters[keyCluster01b].helmCluster.Create(t) - wg.Done() - }() - - // Create cluster-02-a Cluster. - wg.Add(1) - go func() { - PeerOneHelmValues := map[string]string{ - "global.datacenter": cluster02Datacenter, - } - - if cfg.UseKind { - PeerOneHelmValues["server.exposeGossipAndRPCPorts"] = "true" - PeerOneHelmValues["meshGateway.service.type"] = "NodePort" - PeerOneHelmValues["meshGateway.service.nodePort"] = "30100" - } - helpers.MergeMaps(PeerOneHelmValues, commonHelmValues) - - testClusters[keyCluster02a].helmCluster = consul.NewHelmCluster(t, PeerOneHelmValues, testClusters[keyCluster02a].context, cfg, releaseName) - testClusters[keyCluster02a].helmCluster.Create(t) - wg.Done() - }() - - // Create cluster-03-a Cluster. - wg.Add(1) - go func() { - PeerTwoHelmValues := map[string]string{ - "global.datacenter": cluster03Datacenter, - } - - if cfg.UseKind { - PeerTwoHelmValues["server.exposeGossipAndRPCPorts"] = "true" - PeerTwoHelmValues["meshGateway.service.type"] = "NodePort" - PeerTwoHelmValues["meshGateway.service.nodePort"] = "30100" - } - helpers.MergeMaps(PeerTwoHelmValues, commonHelmValues) - - testClusters[keyCluster03a].helmCluster = consul.NewHelmCluster(t, PeerTwoHelmValues, testClusters[keyCluster03a].context, cfg, releaseName) - testClusters[keyCluster03a].helmCluster.Create(t) - wg.Done() - }() - - // Wait for the clusters to start up - wg.Wait() - - // Create a ProxyDefaults resource to configure services to use the mesh - // gateways and set server and client opts. - for k, v := range testClusters { - logger.Logf(t, "applying resources on %s", v.context.KubectlOptions(t).ContextName) - - // Client will use the client namespace. - testClusters[k].clientOpts = &terratestk8s.KubectlOptions{ - ContextName: v.context.KubectlOptions(t).ContextName, - ConfigPath: v.context.KubectlOptions(t).ConfigPath, - Namespace: staticClientNamespace, - } - - // Server will use the server namespace. - testClusters[k].serverOpts = &terratestk8s.KubectlOptions{ - ContextName: v.context.KubectlOptions(t).ContextName, - ConfigPath: v.context.KubectlOptions(t).ConfigPath, - Namespace: staticServerNamespace, - } - - // Sameness Defaults need to be applied first so that the sameness group exists. - applyResources(t, cfg, "../fixtures/bases/mesh-gateway", v.context.KubectlOptions(t)) - applyResources(t, cfg, "../fixtures/bases/sameness/override-ns", v.serverOpts) - - // Only assign a client if the cluster is running a Consul server. - if v.hasServer { - testClusters[k].client, _ = testClusters[k].helmCluster.SetupConsulClient(t, c.ACLsEnabled) - } - } - - // Assign the client default partition client to the partition - testClusters[keyCluster01b].client = testClusters[keyCluster01a].client - - // Apply Mesh resource to default partition and peers - for _, v := range testClusters { - if v.hasServer { - applyResources(t, cfg, "../fixtures/bases/sameness/peering/mesh", v.context.KubectlOptions(t)) - } - } - - // Apply locality to clusters - for _, v := range testClusters { - setK8sNodeLocality(t, v.context, v) - } - - // Peering/Dialer relationship - /* - cluster-01-a cluster-02-a - Dialer -> 2a 1a -> acceptor - Dialer -> 3a 1b -> acceptor - Dialer -> 3a - - cluster-01-b cluster-03-a - Dialer -> 2a 1a -> acceptor - Dialer -> 3a 1b -> acceptor - 2a -> acceptor - */ - for _, v := range []*cluster{testClusters[keyCluster02a], testClusters[keyCluster03a]} { - logger.Logf(t, "creating acceptor on %s", v.name) - // Create an acceptor token on the cluster - applyResources(t, cfg, fmt.Sprintf("../fixtures/bases/sameness/peering/%s-acceptor", v.name), v.context.KubectlOptions(t)) - - // Copy secrets to the necessary peers to be used for dialing later - for _, vv := range testClusters { - if isAcceptor(v.name, vv.acceptors) { - acceptorSecretName := v.getPeeringAcceptorSecret(t, cfg, vv.name) - logger.Logf(t, "acceptor %s created on %s", acceptorSecretName, v.name) - - logger.Logf(t, "copying acceptor token %s from %s to %s", acceptorSecretName, v.name, vv.name) - copySecret(t, cfg, v.context, vv.context, acceptorSecretName) - } - } - } - - // Create the dialers - for _, v := range []*cluster{testClusters[keyCluster01a], testClusters[keyCluster01b], testClusters[keyCluster02a]} { - applyResources(t, cfg, fmt.Sprintf("../fixtures/bases/sameness/peering/%s-dialer", v.name), v.context.KubectlOptions(t)) - } - - // If ACLs are enabled, we need to create the intentions - if c.ACLsEnabled { - intention := &api.ServiceIntentionsConfigEntry{ - Name: staticServerName, - Kind: api.ServiceIntentions, - Namespace: staticServerNamespace, - Sources: []*api.SourceIntention{ - { - Name: staticClientName, - Namespace: staticClientNamespace, - SamenessGroup: samenessGroupName, - Action: api.IntentionActionAllow, - }, - }, - } - - for _, v := range testClusters { - logger.Logf(t, "creating intentions on server %s", v.name) - _, _, err := v.client.ConfigEntries().Set(intention, &api.WriteOptions{Partition: v.partition}) - require.NoError(t, err) - } - } - - logger.Log(t, "creating exported services") - for _, v := range testClusters { - if v.hasServer { - applyResources(t, cfg, "../fixtures/cases/sameness/exported-services/default-partition", v.context.KubectlOptions(t)) - } else { - applyResources(t, cfg, "../fixtures/cases/sameness/exported-services/ap1-partition", v.context.KubectlOptions(t)) - } - } - - // Create sameness group after exporting the services, this will reduce flakiness in an automated test - for _, v := range testClusters { - applyResources(t, cfg, fmt.Sprintf("../fixtures/bases/sameness/%s-default-ns", v.name), v.context.KubectlOptions(t)) - } - - // Setup DNS. - for _, v := range testClusters { - dnsService, err := v.context.KubernetesClient(t).CoreV1().Services("default").Get(ctx.Background(), fmt.Sprintf("%s-%s", releaseName, "consul-dns"), metav1.GetOptions{}) - require.NoError(t, err) - v.dnsIP = &dnsService.Spec.ClusterIP - logger.Logf(t, "%s dnsIP: %s", v.name, *v.dnsIP) - } - - // Setup Prepared Query. - - for k, v := range testClusters { - definition := &api.PreparedQueryDefinition{ - Name: fmt.Sprintf("my-query-%s", v.fullTextPartition()), - Service: api.ServiceQuery{ - Service: staticServerName, - SamenessGroup: samenessGroupName, - Namespace: staticServerNamespace, - OnlyPassing: false, - Partition: v.fullTextPartition(), - }, - } - - pqID, _, err := v.client.PreparedQuery().Create(definition, &api.WriteOptions{}) - require.NoError(t, err) - logger.Logf(t, "%s PQ ID: %s", v.name, pqID) - testClusters[k].pqID = &pqID - testClusters[k].pqName = &definition.Name - } - - // Create static server/client after the rest of the config is setup for a more stable testing experience - // Create static server deployments. - logger.Log(t, "creating static-server and static-client deployments") - deployCustomizeAsync(t, testClusters[keyCluster01a].serverOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - "../fixtures/cases/sameness/static-server/dc1-default", &wg) - deployCustomizeAsync(t, testClusters[keyCluster01b].serverOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - "../fixtures/cases/sameness/static-server/dc1-partition", &wg) - deployCustomizeAsync(t, testClusters[keyCluster02a].serverOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - "../fixtures/cases/sameness/static-server/dc2", &wg) - deployCustomizeAsync(t, testClusters[keyCluster03a].serverOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - "../fixtures/cases/sameness/static-server/dc3", &wg) - - // Create static client deployments. - staticClientKustomizeDirDefault := "../fixtures/cases/sameness/static-client/default-partition" - staticClientKustomizeDirAP1 := "../fixtures/cases/sameness/static-client/ap1-partition" - - // If transparent proxy is enabled create clients without explicit upstreams - if cfg.EnableTransparentProxy { - staticClientKustomizeDirDefault = fmt.Sprintf("%s-%s", staticClientKustomizeDirDefault, "tproxy") - staticClientKustomizeDirAP1 = fmt.Sprintf("%s-%s", staticClientKustomizeDirAP1, "tproxy") - } - - deployCustomizeAsync(t, testClusters[keyCluster01a].clientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - staticClientKustomizeDirDefault, &wg) - deployCustomizeAsync(t, testClusters[keyCluster02a].clientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - staticClientKustomizeDirDefault, &wg) - deployCustomizeAsync(t, testClusters[keyCluster03a].clientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - staticClientKustomizeDirDefault, &wg) - deployCustomizeAsync(t, testClusters[keyCluster01b].clientOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, - staticClientKustomizeDirAP1, &wg) - wg.Wait() - - // Verify that both static-server and static-client have been injected and now have 2 containers in each cluster. - // Also get the server IP - testClusters.setServerIP(t) - - // Everything should be up and running now - testClusters.verifyServerUpState(t, cfg.EnableTransparentProxy) - logger.Log(t, "all infrastructure up and running") - - // Verify locality is set on services based on node labels previously applied. - // - // This is currently the only locality testing we do for k8s and ensures that single-partition - // locality-aware routing will function in consul-k8s. In the future, this test will be expanded - // to test multi-cluster locality-based failover with sameness groups. - for _, v := range testClusters { - v.checkLocalities(t) - } - - // Verify all the failover Scenarios - logger.Log(t, "verifying failover scenarios") - - subCases := []struct { - name string - server *cluster - failovers []struct { - failoverServer *cluster - expectedPQ expectedPQ - } - }{ - { - name: "cluster-01-a perspective", // This matches the diagram at the beginning of the test - server: testClusters[keyCluster01a], - failovers: []struct { - failoverServer *cluster - expectedPQ expectedPQ - }{ - {failoverServer: testClusters[keyCluster01a], expectedPQ: expectedPQ{partition: "default", peerName: "", namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster01b], expectedPQ: expectedPQ{partition: "ap1", peerName: "", namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster02a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster02a].name, namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster03a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster03a].name, namespace: "ns2"}}, - }, - }, - { - name: "cluster-01-b partition perspective", - server: testClusters[keyCluster01b], - failovers: []struct { - failoverServer *cluster - expectedPQ expectedPQ - }{ - {failoverServer: testClusters[keyCluster01b], expectedPQ: expectedPQ{partition: "ap1", peerName: "", namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster01a], expectedPQ: expectedPQ{partition: "default", peerName: "", namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster02a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster02a].name, namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster03a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster03a].name, namespace: "ns2"}}, - }, - }, - { - name: "cluster-02-a perspective", - server: testClusters[keyCluster02a], - failovers: []struct { - failoverServer *cluster - expectedPQ expectedPQ - }{ - {failoverServer: testClusters[keyCluster02a], expectedPQ: expectedPQ{partition: "default", peerName: "", namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster01a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster01a].name, namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster01b], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster01b].name, namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster03a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster03a].name, namespace: "ns2"}}, - }, - }, - { - name: "cluster-03-a perspective", - server: testClusters[keyCluster03a], - failovers: []struct { - failoverServer *cluster - expectedPQ expectedPQ - }{ - {failoverServer: testClusters[keyCluster03a], expectedPQ: expectedPQ{partition: "default", peerName: "", namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster01a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster01a].name, namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster01b], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster01b].name, namespace: "ns2"}}, - {failoverServer: testClusters[keyCluster02a], expectedPQ: expectedPQ{partition: "default", peerName: testClusters[keyCluster02a].name, namespace: "ns2"}}, - }, - }, - } - for _, sc := range subCases { - t.Run(sc.name, func(t *testing.T) { - // Reset the scale of all servers - testClusters.resetScale(t) - testClusters.verifyServerUpState(t, cfg.EnableTransparentProxy) - // We're resetting the scale, so make sure we have all the new IP addresses saved - testClusters.setServerIP(t) - - for _, v := range sc.failovers { - // Verify Failover (If this is the first check, then just verifying we're starting with the right server) - logger.Log(t, "checking service failover") - - if cfg.EnableTransparentProxy { - sc.server.serviceTargetCheck(t, v.failoverServer.name, fmt.Sprintf("http://static-server.virtual.ns2.ns.%s.ap.consul", sc.server.fullTextPartition())) - } else { - sc.server.serviceTargetCheck(t, v.failoverServer.name, "localhost:8080") - } - - // 1. The admin partition does not contain a server, so DNS service will not resolve on the admin partition cluster - // 2. A workaround to perform the DNS and PQ queries on the primary datacenter cluster by specifying the admin partition - // e.g kubectl --context kind-dc1 --namespace ns1 exec -i deploy/static-client -c static-client \ - // -- dig @test-3lmypr-consul-dns.default static-server.service.ns2.ns.mine.sg.ap1.ap.consul - // Verify DNS. - logger.Log(t, "verifying dns") - sc.server.dnsFailoverCheck(t, cfg, releaseName, v.failoverServer) - - logger.Log(t, "verifying prepared query") - sc.server.preparedQueryFailoverCheck(t, releaseName, v.expectedPQ, v.failoverServer) - - // Scale down static-server on the current failover, will fail over to the next. - logger.Logf(t, "scaling server down on %s", v.failoverServer.name) - k8s.KubectlScale(t, v.failoverServer.serverOpts, staticServerDeployment, 0) - } - }) - } - }) - } -} - -type expectedPQ struct { - partition string - peerName string - namespace string -} - -type cluster struct { - name string - partition string - locality api.Locality - context environment.TestContext - helmCluster *consul.HelmCluster - client *api.Client - hasServer bool - serverOpts *terratestk8s.KubectlOptions - clientOpts *terratestk8s.KubectlOptions - staticServerIP *string - pqID *string - pqName *string - dnsIP *string - acceptors []string - primaryCluster *cluster -} - -func (c *cluster) fullTextPartition() string { - if c.partition == "" { - return "default" - } else { - return c.partition - } -} - -// serviceTargetCheck verifies that curling the `static-server` using the `static-client` responds with the expected -// cluster name. Each static-server responds with a unique name so that we can verify failover occured as expected. -func (c *cluster) serviceTargetCheck(t *testing.T, expectedName string, curlAddress string) { - timer := &retry.Timer{Timeout: retryTimeout, Wait: 5 * time.Second} - var resp string - var err error - retry.RunWith(timer, t, func(r *retry.R) { - // Use -s/--silent and -S/--show-error flags w/ curl to reduce noise during retries. - // This silences extra output like the request progress bar, but preserves errors. - resp, err = k8s.RunKubectlAndGetOutputE(t, c.clientOpts, "exec", "-i", - staticClientDeployment, "-c", staticClientName, "--", "curl", "-sS", curlAddress) - require.NoError(r, err) - assert.Contains(r, resp, expectedName) - }) - logger.Log(t, resp) -} - -// preparedQueryFailoverCheck verifies that failover occurs when executing the prepared query. It also assures that -// executing the prepared query via DNS also provides expected results. -func (c *cluster) preparedQueryFailoverCheck(t *testing.T, releaseName string, epq expectedPQ, failover *cluster) { - timer := &retry.Timer{Timeout: retryTimeout, Wait: 5 * time.Second} - resp, _, err := c.client.PreparedQuery().Execute(*c.pqID, &api.QueryOptions{Namespace: staticServerNamespace, Partition: c.partition}) - require.NoError(t, err) - require.Len(t, resp.Nodes, 1) - - assert.Equal(t, epq.partition, resp.Nodes[0].Service.Partition) - assert.Equal(t, epq.peerName, resp.Nodes[0].Service.PeerName) - assert.Equal(t, epq.namespace, resp.Nodes[0].Service.Namespace) - assert.Equal(t, *failover.staticServerIP, resp.Nodes[0].Service.Address) - - // Verify that dns lookup is successful, there is no guarantee that the ip address is unique, so for PQ this is - // just verifying that we can query using DNS and that the ip address is correct. It does not however prove - // that failover occurred, that is left to client `Execute` - dnsPQLookup := []string{fmt.Sprintf("%s.query.consul", *c.pqName)} - retry.RunWith(timer, t, func(r *retry.R) { - logs := dnsQuery(t, releaseName, dnsPQLookup, c.primaryCluster, failover) - assert.Contains(r, logs, fmt.Sprintf("SERVER: %s", *c.primaryCluster.dnsIP)) - assert.Contains(r, logs, "ANSWER SECTION:") - assert.Contains(r, logs, *failover.staticServerIP) - }) -} - -// DNS failover check verifies that failover occurred when querying the DNS. -func (c *cluster) dnsFailoverCheck(t *testing.T, cfg *config.TestConfig, releaseName string, failover *cluster) { - timer := &retry.Timer{Timeout: retryTimeout, Wait: 5 * time.Second} - dnsLookup := []string{fmt.Sprintf("static-server.service.ns2.ns.%s.sg.%s.ap.consul", samenessGroupName, c.fullTextPartition()), "+tcp", "SRV"} - retry.RunWith(timer, t, func(r *retry.R) { - // Use the primary cluster when performing a DNS lookup, this mostly affects cases - // where we are verifying DNS for a partition - logs := dnsQuery(t, releaseName, dnsLookup, c.primaryCluster, failover) - - assert.Contains(r, logs, fmt.Sprintf("SERVER: %s", *c.primaryCluster.dnsIP)) - assert.Contains(r, logs, "ANSWER SECTION:") - assert.Contains(r, logs, *failover.staticServerIP) - - // Additional checks - // When accessing the SRV record for DNS we can get more information. In the case of Kind, - // the context can be used to determine that failover occured to the expected kubernetes cluster - // hosting Consul - assert.Contains(r, logs, "ADDITIONAL SECTION:") - expectedName := failover.context.KubectlOptions(t).ContextName - if cfg.UseKind { - expectedName = strings.Replace(expectedName, "kind-", "", -1) - } - assert.Contains(r, logs, expectedName) - }) -} - -// getPeeringAcceptorSecret assures that the secret is created and retrieves the secret from the provided acceptor. -func (c *cluster) getPeeringAcceptorSecret(t *testing.T, cfg *config.TestConfig, acceptorName string) string { - // Ensure the secrets are created. - var acceptorSecretName string - timer := &retry.Timer{Timeout: retryTimeout, Wait: 1 * time.Second} - retry.RunWith(timer, t, func(r *retry.R) { - var err error - acceptorSecretName, err = k8s.RunKubectlAndGetOutputE(t, c.context.KubectlOptions(t), "get", "peeringacceptor", acceptorName, "-o", "jsonpath={.status.secret.name}") - require.NoError(r, err) - require.NotEmpty(r, acceptorSecretName) - }) - - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, c.context.KubectlOptions(t), "delete", "secret", acceptorSecretName) - }) - - return acceptorSecretName -} - -// checkLocalities checks the given cluster for `static-client` and `static-server` instances matching the locality -// expected for the cluster. -func (c *cluster) checkLocalities(t *testing.T) { - for ns, svcs := range map[string][]string{ - staticClientNamespace: { - staticClientName, - staticClientName + "-sidecar-proxy", - }, - staticServerNamespace: { - staticServerName, - staticServerName + "-sidecar-proxy", - }, - } { - for _, svc := range svcs { - cs := c.getCatalogService(t, svc, ns, c.partition) - assert.NotNil(t, cs.ServiceLocality, "service %s in %s did not have locality set", svc, c.name) - assert.Equal(t, c.locality, *cs.ServiceLocality, "locality for service %s in %s did not match expected", svc, c.name) - } - } -} - -func (c *cluster) getCatalogService(t *testing.T, svc, ns, partition string) *api.CatalogService { - resp, _, err := c.client.Catalog().Service(svc, "", &api.QueryOptions{Namespace: ns, Partition: partition}) - require.NoError(t, err) - assert.NotEmpty(t, resp, "did not find service %s in cluster %s (partition=%s ns=%s)", svc, c.name, partition, ns) - return resp[0] -} - -type clusters map[string]*cluster - -func (c clusters) resetScale(t *testing.T) { - for _, v := range c { - k8s.KubectlScale(t, v.serverOpts, staticServerDeployment, 1) - } -} - -// setServerIP makes sure everything is up and running and then saves the -// static-server IP to the appropriate cluster. IP addresses can change when -// services are scaled up and down. -func (c clusters) setServerIP(t *testing.T) { - for _, labelSelector := range []string{"app=static-server", "app=static-client"} { - for k, v := range c { - podList, err := v.context.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(ctx.Background(), - metav1.ListOptions{LabelSelector: labelSelector}) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - if labelSelector == "app=static-server" { - ip := &podList.Items[0].Status.PodIP - require.NotNil(t, ip) - logger.Logf(t, "%s-static-server-ip: %s", v.name, *ip) - c[k].staticServerIP = ip - } - } - } -} - -// verifyServerUpState will verify that the static-servers are all up and running as -// expected by curling them from their local datacenters. -func (c clusters) verifyServerUpState(t *testing.T, isTproxyEnabled bool) { - logger.Logf(t, "verifying that static-servers are up") - for _, v := range c { - // Query using a client and expect its own name, no failover should occur - if isTproxyEnabled { - v.serviceTargetCheck(t, v.name, fmt.Sprintf("http://static-server.virtual.ns2.ns.%s.ap.consul", v.fullTextPartition())) - } else { - v.serviceTargetCheck(t, v.name, "localhost:8080") - } - } -} - -func copySecret(t *testing.T, cfg *config.TestConfig, sourceContext, destContext environment.TestContext, secretName string) { - k8s.CopySecret(t, sourceContext, destContext, secretName) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, destContext.KubectlOptions(t), "delete", "secret", secretName) - }) -} - -func createNamespaces(t *testing.T, cfg *config.TestConfig, context environment.TestContext) { - logger.Logf(t, "creating namespaces in %s", context.KubectlOptions(t).ContextName) - k8s.RunKubectl(t, context.KubectlOptions(t), "create", "ns", staticServerNamespace) - k8s.RunKubectl(t, context.KubectlOptions(t), "create", "ns", staticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.RunKubectl(t, context.KubectlOptions(t), "delete", "ns", staticClientNamespace, staticServerNamespace) - }) -} - -func applyResources(t *testing.T, cfg *config.TestConfig, kustomizeDir string, opts *terratestk8s.KubectlOptions) { - k8s.KubectlApplyK(t, opts, kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, opts, kustomizeDir) - }) -} - -// setK8sNodeLocality labels the k8s node corresponding to the given cluster with standard labels indicating the -// locality of that node. These are propagated by connect-inject to registered Consul services. -func setK8sNodeLocality(t *testing.T, context environment.TestContext, c *cluster) { - nodeList, err := context.KubernetesClient(t).CoreV1().Nodes().List(ctx.Background(), metav1.ListOptions{}) - require.NoError(t, err) - // Get the name of the (only) node from the Kind cluster. - node := nodeList.Items[0].Name - k8s.KubectlLabel(t, context.KubectlOptions(t), "node", node, corev1.LabelTopologyRegion, c.locality.Region) - k8s.KubectlLabel(t, context.KubectlOptions(t), "node", node, corev1.LabelTopologyZone, c.locality.Zone) -} - -// dnsQuery performs a dns query with the provided query string. -func dnsQuery(t *testing.T, releaseName string, dnsQuery []string, dnsServer, failover *cluster) string { - timer := &retry.Timer{Timeout: retryTimeout, Wait: 1 * time.Second} - var logs string - retry.RunWith(timer, t, func(r *retry.R) { - args := []string{"exec", "-i", - staticClientDeployment, "-c", staticClientName, "--", "dig", fmt.Sprintf("@%s-consul-dns.default", - releaseName)} - args = append(args, dnsQuery...) - var err error - logs, err = k8s.RunKubectlAndGetOutputE(t, dnsServer.clientOpts, args...) - require.NoError(r, err) - }) - logger.Logf(t, "%s: %s", failover.name, logs) - return logs -} - -// isAcceptor iterates through the provided acceptor list of cluster names and determines if -// any match the provided name. Returns true if a match is found, false otherwise. -func isAcceptor(name string, acceptorList []string) bool { - for _, v := range acceptorList { - if name == v { - return true - } - } - return false -} - -// localityForRegion returns the full api.Locality to use in tests for a given region string. -func localityForRegion(r string) api.Locality { - return api.Locality{ - Region: r, - Zone: r + "a", - } -} - -func deployCustomizeAsync(t *testing.T, opts *terratestk8s.KubectlOptions, noCleanupOnFailure bool, noCleanup bool, debugDirectory string, kustomizeDir string, wg *sync.WaitGroup) { - wg.Add(1) - go func() { - k8s.DeployKustomize(t, opts, noCleanupOnFailure, noCleanup, debugDirectory, kustomizeDir) - wg.Done() - }() -} diff --git a/acceptance/tests/snapshot-agent/main_test.go b/acceptance/tests/snapshot-agent/main_test.go index 3d70823059..daa389d4c4 100644 --- a/acceptance/tests/snapshot-agent/main_test.go +++ b/acceptance/tests/snapshot-agent/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package snapshotagent import ( diff --git a/acceptance/tests/snapshot-agent/snapshot_agent_k8s_secret_test.go b/acceptance/tests/snapshot-agent/snapshot_agent_k8s_secret_test.go index b5613fe76d..a4c1ef7494 100644 --- a/acceptance/tests/snapshot-agent/snapshot_agent_k8s_secret_test.go +++ b/acceptance/tests/snapshot-agent/snapshot_agent_k8s_secret_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package snapshotagent import ( diff --git a/acceptance/tests/snapshot-agent/snapshot_agent_vault_test.go b/acceptance/tests/snapshot-agent/snapshot_agent_vault_test.go index 10cceb5952..ee20ffd9d7 100644 --- a/acceptance/tests/snapshot-agent/snapshot_agent_vault_test.go +++ b/acceptance/tests/snapshot-agent/snapshot_agent_vault_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package snapshotagent import ( diff --git a/acceptance/tests/sync/main_test.go b/acceptance/tests/sync/main_test.go index a26ecc9670..80c394e561 100644 --- a/acceptance/tests/sync/main_test.go +++ b/acceptance/tests/sync/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package sync import ( diff --git a/acceptance/tests/sync/sync_catalog_namespaces_test.go b/acceptance/tests/sync/sync_catalog_namespaces_test.go index 67123d6e4f..79f592033c 100644 --- a/acceptance/tests/sync/sync_catalog_namespaces_test.go +++ b/acceptance/tests/sync/sync_catalog_namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package sync import ( @@ -97,12 +94,12 @@ func TestSyncCatalogNamespaces(t *testing.T) { logger.Logf(t, "creating namespace %s", staticServerNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", staticServerNamespace) }) logger.Log(t, "creating a static-server with a service") - k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, staticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-server") consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) diff --git a/acceptance/tests/sync/sync_catalog_test.go b/acceptance/tests/sync/sync_catalog_test.go index dc30570422..3e3880b618 100644 --- a/acceptance/tests/sync/sync_catalog_test.go +++ b/acceptance/tests/sync/sync_catalog_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package sync import ( @@ -50,7 +47,7 @@ func TestSyncCatalog(t *testing.T) { consulCluster.Create(t) logger.Log(t, "creating a static-server with a service") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), suite.Config().NoCleanupOnFailure, suite.Config().NoCleanup, suite.Config().DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), suite.Config().NoCleanupOnFailure, suite.Config().DebugDirectory, "../fixtures/bases/static-server") consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) @@ -120,7 +117,7 @@ func TestSyncCatalogWithIngress(t *testing.T) { // endpoint fails initially. out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/ingress") require.NoError(r, err, out) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, 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/ingress") @@ -130,7 +127,7 @@ func TestSyncCatalogWithIngress(t *testing.T) { consulCluster.Create(t) logger.Log(t, "creating a static-server with a service") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), suite.Config().NoCleanupOnFailure, suite.Config().NoCleanup, suite.Config().DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), suite.Config().NoCleanupOnFailure, suite.Config().DebugDirectory, "../fixtures/bases/static-server") consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) diff --git a/acceptance/tests/terminating-gateway/common.go b/acceptance/tests/terminating-gateway/common.go index 908e6cbec1..b94dd8a897 100644 --- a/acceptance/tests/terminating-gateway/common.go +++ b/acceptance/tests/terminating-gateway/common.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminatinggateway import ( diff --git a/acceptance/tests/terminating-gateway/main_test.go b/acceptance/tests/terminating-gateway/main_test.go index 0c8127623d..477e125f94 100644 --- a/acceptance/tests/terminating-gateway/main_test.go +++ b/acceptance/tests/terminating-gateway/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminatinggateway import ( diff --git a/acceptance/tests/terminating-gateway/terminating_gateway_destinations_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_destinations_test.go index 62485c6e44..4ff4ae7bd4 100644 --- a/acceptance/tests/terminating-gateway/terminating_gateway_destinations_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_destinations_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminatinggateway import ( @@ -73,7 +70,7 @@ func TestTerminatingGatewayDestinations(t *testing.T) { // Deploy a static-server that will play the role of an external service. logger.Log(t, "creating static-server deployment") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server-https") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-server-https") // If ACLs are enabled we need to update the role of the terminating gateway // with service:write permissions to the static-server service @@ -91,7 +88,7 @@ func TestTerminatingGatewayDestinations(t *testing.T) { // Deploy the static client logger.Log(t, "deploying static client") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") staticServerIP, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "get", "po", "-l", "app=static-server", `-o=jsonpath={.items[0].status.podIP}`) require.NoError(t, err) diff --git a/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go index 73250ea810..8c4435ae75 100644 --- a/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminatinggateway import ( @@ -62,7 +59,7 @@ func TestTerminatingGatewaySingleNamespace(t *testing.T) { logger.Logf(t, "creating Kubernetes namespace %s", testNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", testNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", testNamespace) }) @@ -74,7 +71,7 @@ func TestTerminatingGatewaySingleNamespace(t *testing.T) { // Deploy a static-server that will play the role of an external service. logger.Log(t, "creating static-server deployment") - k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-server") // Register the external service. registerExternalService(t, consulClient, testNamespace) @@ -91,7 +88,7 @@ func TestTerminatingGatewaySingleNamespace(t *testing.T) { // Deploy the static client. logger.Log(t, "deploying static client") - k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + k8s.DeployKustomize(t, nsK8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") // If ACLs are enabled, test that intentions prevent connections. if c.secure { @@ -159,14 +156,14 @@ func TestTerminatingGatewayNamespaceMirroring(t *testing.T) { logger.Logf(t, "creating Kubernetes namespace %s", testNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", testNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", testNamespace) }) StaticClientNamespace := "ns2" logger.Logf(t, "creating Kubernetes namespace %s", StaticClientNamespace) k8s.RunKubectl(t, ctx.KubectlOptions(t), "create", "ns", StaticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ns", StaticClientNamespace) }) @@ -183,7 +180,7 @@ func TestTerminatingGatewayNamespaceMirroring(t *testing.T) { // Deploy a static-server that will play the role of an external service. logger.Log(t, "creating static-server deployment") - k8s.DeployKustomize(t, ns1K8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, ns1K8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-server") // Register the external service registerExternalService(t, consulClient, testNamespace) @@ -200,7 +197,7 @@ func TestTerminatingGatewayNamespaceMirroring(t *testing.T) { // Deploy the static client logger.Log(t, "deploying static client") - k8s.DeployKustomize(t, ns2K8SOptions, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + k8s.DeployKustomize(t, ns2K8SOptions, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") // If ACLs are enabled, test that intentions prevent connections. if c.secure { diff --git a/acceptance/tests/terminating-gateway/terminating_gateway_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_test.go index 6e7e95032f..16809de5e2 100644 --- a/acceptance/tests/terminating-gateway/terminating_gateway_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminatinggateway import ( @@ -51,7 +48,7 @@ func TestTerminatingGateway(t *testing.T) { // Deploy a static-server that will play the role of an external service. logger.Log(t, "creating static-server deployment") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/static-server") // Once the cluster is up, register the external service, then create the config entry. consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) @@ -71,7 +68,7 @@ func TestTerminatingGateway(t *testing.T) { // Deploy the static client logger.Log(t, "deploying static client") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") // If ACLs are enabled, test that intentions prevent connections. if c.secure { diff --git a/acceptance/tests/vault/main_test.go b/acceptance/tests/vault/main_test.go index 02a22c2b79..6b38cad022 100644 --- a/acceptance/tests/vault/main_test.go +++ b/acceptance/tests/vault/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( diff --git a/acceptance/tests/vault/vault_namespaces_test.go b/acceptance/tests/vault/vault_namespaces_test.go index 4a9ca092d0..8d0beefdc0 100644 --- a/acceptance/tests/vault/vault_namespaces_test.go +++ b/acceptance/tests/vault/vault_namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( @@ -265,13 +262,13 @@ func TestVault_VaultNamespace(t *testing.T) { // Deploy two services and check that they can talk to each other. logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") }) k8s.KubectlApplyK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") diff --git a/acceptance/tests/vault/vault_partitions_test.go b/acceptance/tests/vault/vault_partitions_test.go index 63002993a6..609147b676 100644 --- a/acceptance/tests/vault/vault_partitions_test.go +++ b/acceptance/tests/vault/vault_partitions_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 9dab0a3e71..fdde364b5b 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( @@ -17,7 +14,6 @@ import ( "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/portforward" "github.com/hashicorp/consul-k8s/acceptance/framework/vault" - "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/go-uuid" "github.com/hashicorp/go-version" "github.com/stretchr/testify/require" @@ -35,29 +31,6 @@ const ( // TestVault installs Vault, bootstraps it with secrets, policies, and Kube Auth Method. // It then configures Consul to use vault as the backend and checks that it works. func TestVault(t *testing.T) { - cases := map[string]struct { - autoBootstrap bool - }{ - "manual ACL bootstrap": {}, - "automatic ACL bootstrap": { - autoBootstrap: true, - }, - } - for name, c := range cases { - c := c - t.Run(name, func(t *testing.T) { - testVault(t, c.autoBootstrap) - }) - } -} - -// testVault is the implementation for TestVault: -// -// - testAutoBootstrap = false. Test when ACL bootstrapping has already occurred. -// The test pre-populates a Vault secret with the bootstrap token. -// - testAutoBootstrap = true. Test that server-acl-init automatically ACL bootstraps -// consul and writes the bootstrap token to Vault. -func testVault(t *testing.T, testAutoBootstrap bool) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) kubectlOptions := ctx.KubectlOptions(t) @@ -111,6 +84,20 @@ func testVault(t *testing.T, testAutoBootstrap bool) { } serverPKIConfig.ConfigurePKIAndAuthRole(t, vaultClient) + // Configure controller webhook PKI + controllerWebhookPKIConfig := &vault.PKIAndAuthRoleConfiguration{ + BaseURL: "controller", + PolicyName: "controller-ca-policy", + RoleName: "controller-ca-role", + KubernetesNamespace: ns, + DataCenter: "dc1", + ServiceAccountName: fmt.Sprintf("%s-consul-%s", consulReleaseName, "controller"), + AllowedSubdomain: fmt.Sprintf("%s-consul-%s", consulReleaseName, "controller-webhook"), + MaxTTL: fmt.Sprintf("%ds", expirationInSeconds), + AuthMethodPath: KubernetesAuthMethodPath, + } + controllerWebhookPKIConfig.ConfigurePKIAndAuthRole(t, vaultClient) + // Configure connect injector webhook PKI connectInjectorWebhookPKIConfig := &vault.PKIAndAuthRoleConfiguration{ BaseURL: "connect", @@ -150,22 +137,16 @@ func testVault(t *testing.T, testAutoBootstrap bool) { licenseSecret.SaveSecretAndAddReadPolicy(t, vaultClient) } + // Bootstrap Token + bootstrapToken, err := uuid.GenerateUUID() + require.NoError(t, err) bootstrapTokenSecret := &vault.KV2Secret{ Path: "consul/data/secret/bootstrap", Key: "token", - Value: "", + Value: bootstrapToken, PolicyName: "bootstrap", } - if testAutoBootstrap { - bootstrapTokenSecret.SaveSecretAndAddUpdatePolicy(t, vaultClient) - } else { - id, err := uuid.GenerateUUID() - require.NoError(t, err) - bootstrapTokenSecret.Value = id - bootstrapTokenSecret.SaveSecretAndAddReadPolicy(t, vaultClient) - } - - bootstrapToken := bootstrapTokenSecret.Value + bootstrapTokenSecret.SaveSecretAndAddReadPolicy(t, vaultClient) // ------------------------- // Additional Auth Roles @@ -231,12 +212,15 @@ func testVault(t *testing.T, testAutoBootstrap bool) { "connectInject.replicas": "1", "global.secretsBackend.vault.connectInject.tlsCert.secretName": connectInjectorWebhookPKIConfig.CertPath, "global.secretsBackend.vault.connectInject.caCert.secretName": connectInjectorWebhookPKIConfig.CAPath, + "global.secretsBackend.vault.controller.tlsCert.secretName": controllerWebhookPKIConfig.CertPath, + "global.secretsBackend.vault.controller.caCert.secretName": controllerWebhookPKIConfig.CAPath, "global.secretsBackend.vault.enabled": "true", "global.secretsBackend.vault.consulServerRole": consulServerRole, "global.secretsBackend.vault.consulClientRole": consulClientRole, "global.secretsBackend.vault.consulCARole": serverPKIConfig.RoleName, "global.secretsBackend.vault.connectInjectRole": connectInjectorWebhookPKIConfig.RoleName, + "global.secretsBackend.vault.controllerRole": controllerWebhookPKIConfig.RoleName, "global.secretsBackend.vault.manageSystemACLsRole": manageSystemACLsRole, "global.secretsBackend.vault.ca.secretName": vaultCASecret, @@ -298,26 +282,6 @@ func testVault(t *testing.T, testAutoBootstrap bool) { logger.Logf(t, "Wait %d seconds for certificates to rotate....", expirationInSeconds) time.Sleep(time.Duration(expirationInSeconds) * time.Second) - if testAutoBootstrap { - logger.Logf(t, "Validating the ACL bootstrap token was stored in Vault.") - timer := &retry.Timer{Timeout: 10 * time.Second, Wait: 1 * time.Second} - retry.RunWith(timer, t, func(r *retry.R) { - secret, err := vaultClient.Logical().Read("consul/data/secret/bootstrap") - require.NoError(r, err) - - data, ok := secret.Data["data"].(map[string]interface{}) - require.True(r, ok) - require.NotNil(r, data) - - tok, ok := data["token"].(string) - require.True(r, ok) - require.NotEmpty(r, tok) - - // Set bootstrapToken for subsequent validations. - bootstrapToken = tok - }) - } - // Validate that the gossip encryption key is set correctly. logger.Log(t, "Validating the gossip key has been set correctly.") consulCluster.ACLToken = bootstrapToken @@ -350,13 +314,13 @@ func testVault(t *testing.T, testAutoBootstrap bool) { // Deploy two services and check that they can talk to each other. logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") }) k8s.KubectlApplyK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") diff --git a/acceptance/tests/vault/vault_tls_auto_reload_test.go b/acceptance/tests/vault/vault_tls_auto_reload_test.go index d5d4d33c4c..f079ee7492 100644 --- a/acceptance/tests/vault/vault_tls_auto_reload_test.go +++ b/acceptance/tests/vault/vault_tls_auto_reload_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( @@ -246,13 +243,13 @@ func TestVault_TLSAutoReload(t *testing.T) { // Deploy two services and check that they can talk to each other. logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") }) k8s.KubectlApplyK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go index fa63c4d5fb..a65702907f 100644 --- a/acceptance/tests/vault/vault_wan_fed_test.go +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package vault import ( @@ -31,7 +28,6 @@ import ( // in the secondary that will treat the Vault server in the primary as an external server. func TestVault_WANFederationViaGateways(t *testing.T) { cfg := suite.Config() - if cfg.UseKind { t.Skipf("Skipping this test because it's currently flaky on kind") } @@ -492,18 +488,16 @@ func TestVault_WANFederationViaGateways(t *testing.T) { logger.Log(t, "creating proxy-defaults config") kustomizeDir := "../fixtures/bases/mesh-gateway" k8s.KubectlApplyK(t, primaryCtx.KubectlOptions(t), kustomizeDir) - - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, primaryCtx.KubectlOptions(t), kustomizeDir) }) // Check that we can connect services over the mesh gateways. - logger.Log(t, "creating static-server in dc2") - k8s.DeployKustomize(t, secondaryCtx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, secondaryCtx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") logger.Log(t, "creating static-client in dc1") - k8s.DeployKustomize(t, primaryCtx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") + k8s.DeployKustomize(t, primaryCtx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") logger.Log(t, "creating intention") _, _, err = primaryClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ @@ -520,7 +514,6 @@ func TestVault_WANFederationViaGateways(t *testing.T) { logger.Log(t, "checking that connection is successful") k8s.CheckStaticServerConnectionSuccessful(t, primaryCtx.KubectlOptions(t), StaticClientName, "http://localhost:1234") - } // vaultAddress returns Vault's server URL depending on test configuration. diff --git a/acceptance/tests/wan-federation/main_test.go b/acceptance/tests/wan-federation/main_test.go index 4a47a8a00f..4f6b0a7b54 100644 --- a/acceptance/tests/wan-federation/main_test.go +++ b/acceptance/tests/wan-federation/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package wanfederation import ( diff --git a/acceptance/tests/wan-federation/wan_federation_gateway_test.go b/acceptance/tests/wan-federation/wan_federation_gateway_test.go deleted file mode 100644 index ec466c93ec..0000000000 --- a/acceptance/tests/wan-federation/wan_federation_gateway_test.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package wanfederation - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/hashicorp/consul-k8s/acceptance/framework/connhelper" - "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/environment" - "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/serf/testutil/retry" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestWANFederation_Gateway(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - - if cfg.UseKind { - // the only way this test can currently run on kind, at least on a Mac, is via leveraging MetalLB, which - // isn't in CI, so we just skip for now. - t.Skipf("skipping wan federation tests as they currently fail on Kind even though they work on other clouds.") - } - - primaryContext := env.DefaultContext(t) - secondaryContext := env.Context(t, 1) - - primaryHelmValues := map[string]string{ - "global.datacenter": "dc1", - - "global.tls.enabled": "true", - "global.tls.httpsOnly": "true", - - "global.federation.enabled": "true", - "global.federation.createFederationSecret": "true", - - "global.acls.manageSystemACLs": "true", - "global.acls.createReplicationToken": "true", - - "connectInject.enabled": "true", - "connectInject.replicas": "1", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - } - - releaseName := helpers.RandomName() - - // Install the primary consul cluster in the default kubernetes context - primaryConsulCluster := consul.NewHelmCluster(t, primaryHelmValues, primaryContext, cfg, releaseName) - primaryConsulCluster.Create(t) - - var k8sAuthMethodHost string - // When running on kind, the kube API address in kubeconfig will have a localhost address - // which will not work from inside the container. That's why we need to use the endpoints address instead - // which will point the node IP. - if cfg.UseKind { - // The Kubernetes AuthMethod host is read from the endpoints for the Kubernetes service. - kubernetesEndpoint, err := secondaryContext.KubernetesClient(t).CoreV1().Endpoints("default").Get(context.Background(), "kubernetes", metav1.GetOptions{}) - require.NoError(t, err) - k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) - } else { - k8sAuthMethodHost = k8s.KubernetesAPIServerHostFromOptions(t, secondaryContext.KubectlOptions(t)) - } - - federationSecretName := copyFederationSecret(t, releaseName, primaryContext, secondaryContext) - - // Create secondary cluster - secondaryHelmValues := map[string]string{ - "global.datacenter": "dc2", - - "global.tls.enabled": "true", - "global.tls.httpsOnly": "false", - "global.acls.manageSystemACLs": "true", - "global.tls.caCert.secretName": federationSecretName, - "global.tls.caCert.secretKey": "caCert", - "global.tls.caKey.secretName": federationSecretName, - "global.tls.caKey.secretKey": "caKey", - - "global.federation.enabled": "true", - - "server.extraVolumes[0].type": "secret", - "server.extraVolumes[0].name": federationSecretName, - "server.extraVolumes[0].load": "true", - "server.extraVolumes[0].items[0].key": "serverConfigJSON", - "server.extraVolumes[0].items[0].path": "config.json", - - "connectInject.enabled": "true", - "connectInject.replicas": "1", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - - "global.acls.replicationToken.secretName": federationSecretName, - "global.acls.replicationToken.secretKey": "replicationToken", - "global.federation.k8sAuthMethodHost": k8sAuthMethodHost, - "global.federation.primaryDatacenter": "dc1", - } - - // Install the secondary consul cluster in the secondary kubernetes context - secondaryConsulCluster := consul.NewHelmCluster(t, secondaryHelmValues, secondaryContext, cfg, releaseName) - secondaryConsulCluster.Create(t) - - primaryClient, _ := primaryConsulCluster.SetupConsulClient(t, true) - secondaryClient, _ := secondaryConsulCluster.SetupConsulClient(t, true) - - // Verify federation between servers - logger.Log(t, "verifying federation was successful") - helpers.VerifyFederation(t, primaryClient, secondaryClient, releaseName, true) - - // Create a ProxyDefaults resource to configure services to use the mesh - // gateways. - logger.Log(t, "creating proxy-defaults config in dc1") - kustomizeDir := "../fixtures/cases/api-gateways/mesh" - k8s.KubectlApplyK(t, primaryContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, primaryContext.KubectlOptions(t), kustomizeDir) - }) - - // these clients are just there so we can exec in and curl on them. - logger.Log(t, "creating static-client in dc1") - k8s.DeployKustomize(t, primaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") - - logger.Log(t, "creating static-client in dc2") - k8s.DeployKustomize(t, secondaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") - - t.Run("from primary to secondary", func(t *testing.T) { - logger.Log(t, "creating static-server in dc2") - k8s.DeployKustomize(t, secondaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - logger.Log(t, "creating api-gateway resources in dc1") - out, err := k8s.RunKubectlAndGetOutputE(t, primaryContext.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 - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, primaryContext.KubectlOptions(t), "delete", "-k", "../fixtures/bases/api-gateway") - }) - - // create a service resolver for doing cross-dc redirects. - k8s.KubectlApplyK(t, secondaryContext.KubectlOptions(t), "../fixtures/cases/api-gateways/dc1-to-dc2-resolver") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, secondaryContext.KubectlOptions(t), "../fixtures/cases/api-gateways/dc1-to-dc2-resolver") - }) - - // patching the route to target a MeshService since we don't have the corresponding Kubernetes service in this - // cluster. - k8s.RunKubectl(t, primaryContext.KubectlOptions(t), "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"group":"consul.hashicorp.com","kind":"MeshService","name":"mesh-service","port":80}]}]}}`, "--type=merge") - - checkConnectivity(t, primaryContext, primaryClient) - }) - - t.Run("from secondary to primary", func(t *testing.T) { - // Check that we can connect services over the mesh gateways - logger.Log(t, "creating static-server in dc1") - k8s.DeployKustomize(t, primaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - logger.Log(t, "creating api-gateway resources in dc2") - out, err := k8s.RunKubectlAndGetOutputE(t, secondaryContext.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 - // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, secondaryContext.KubectlOptions(t), "delete", "-k", "../fixtures/bases/api-gateway") - }) - - // create a service resolver for doing cross-dc redirects. - k8s.KubectlApplyK(t, secondaryContext.KubectlOptions(t), "../fixtures/cases/api-gateways/dc2-to-dc1-resolver") - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, secondaryContext.KubectlOptions(t), "../fixtures/cases/api-gateways/dc2-to-dc1-resolver") - }) - - // patching the route to target a MeshService since we don't have the corresponding Kubernetes service in this - // cluster. - k8s.RunKubectl(t, secondaryContext.KubectlOptions(t), "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"group":"consul.hashicorp.com","kind":"MeshService","name":"mesh-service","port":80}]}]}}`, "--type=merge") - - checkConnectivity(t, secondaryContext, primaryClient) - }) -} - -func checkConnectivity(t *testing.T, ctx environment.TestContext, client *api.Client) { - 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 1m timeout here). - var gatewayAddress string - counter := &retry.Counter{Count: 600, Wait: 2 * time.Second} - retry.RunWith(counter, t, func(r *retry.R) { - var gateway gwv1beta1.Gateway - err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: "default"}, &gateway) - require.NoError(r, err) - - // check that we have an address to use - require.Len(r, gateway.Status.Addresses, 1) - // now we know we have an address, set it so we can use it - gatewayAddress = gateway.Status.Addresses[0].Value - }) - - targetAddress := fmt.Sprintf("http://%s/", gatewayAddress) - - logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerHTTPConnectionFailing(t, ctx.KubectlOptions(t), connhelper.StaticClientName, targetAddress) - - logger.Log(t, "creating intention") - _, _, err := client.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: "static-server", - Sources: []*api.SourceIntention{ - { - Name: "gateway", - Action: api.IntentionActionAllow, - }, - }, - }, nil) - require.NoError(t, err) - defer func() { - _, err := client.ConfigEntries().Delete(api.ServiceIntentions, "static-server", &api.WriteOptions{}) - require.NoError(t, err) - }() - - logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), connhelper.StaticClientName, targetAddress) -} diff --git a/acceptance/tests/wan-federation/wan_federation_test.go b/acceptance/tests/wan-federation/wan_federation_test.go index 41d237113a..d347695faa 100644 --- a/acceptance/tests/wan-federation/wan_federation_test.go +++ b/acceptance/tests/wan-federation/wan_federation_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package wanfederation import ( @@ -8,35 +5,17 @@ import ( "fmt" "strconv" "testing" - "time" - terratestK8s "github.com/gruntwork-io/terratest/modules/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/connhelper" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/acceptance/framework/environment" "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/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -const ( - staticClientDeployment = "deploy/static-client" - staticServerDeployment = "deploy/static-server" - - retryTimeout = 5 * time.Minute - - primaryDatacenter = "dc1" - secondaryDatacenter = "dc2" - - localServerPort = "1234" - - primaryNamespace = "ns1" - secondaryNamespace = "ns2" -) +const StaticClientName = "static-client" // Test that Connect and wan federation over mesh gateways work in a default installation // i.e. without ACLs because TLS is required for WAN federation over mesh gateways. @@ -65,7 +44,7 @@ func TestWANFederation(t *testing.T) { secondaryContext := env.Context(t, 1) primaryHelmValues := map[string]string{ - "global.datacenter": primaryDatacenter, + "global.datacenter": "dc1", "global.tls.enabled": "true", "global.tls.httpsOnly": strconv.FormatBool(c.secure), @@ -95,13 +74,31 @@ func TestWANFederation(t *testing.T) { primaryConsulCluster.Create(t) // Get the federation secret from the primary cluster and apply it to secondary cluster - federationSecretName := copyFederationSecret(t, releaseName, primaryContext, secondaryContext) - - k8sAuthMethodHost := k8s.KubernetesAPIServerHost(t, cfg, secondaryContext) + federationSecretName := fmt.Sprintf("%s-consul-federation", releaseName) + logger.Logf(t, "retrieving federation secret %s from the primary cluster and applying to the secondary", federationSecretName) + federationSecret, err := primaryContext.KubernetesClient(t).CoreV1().Secrets(primaryContext.KubectlOptions(t).Namespace).Get(context.Background(), federationSecretName, metav1.GetOptions{}) + require.NoError(t, err) + federationSecret.ResourceVersion = "" + federationSecret.Namespace = secondaryContext.KubectlOptions(t).Namespace + _, err = secondaryContext.KubernetesClient(t).CoreV1().Secrets(secondaryContext.KubectlOptions(t).Namespace).Create(context.Background(), federationSecret, metav1.CreateOptions{}) + require.NoError(t, err) + + var k8sAuthMethodHost string + // When running on kind, the kube API address in kubeconfig will have a localhost address + // which will not work from inside the container. That's why we need to use the endpoints address instead + // which will point the node IP. + if cfg.UseKind { + // The Kubernetes AuthMethod host is read from the endpoints for the Kubernetes service. + kubernetesEndpoint, err := secondaryContext.KubernetesClient(t).CoreV1().Endpoints("default").Get(context.Background(), "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + } else { + k8sAuthMethodHost = k8s.KubernetesAPIServerHostFromOptions(t, secondaryContext.KubectlOptions(t)) + } // Create secondary cluster secondaryHelmValues := map[string]string{ - "global.datacenter": secondaryDatacenter, + "global.datacenter": "dc2", "global.tls.enabled": "true", "global.tls.httpsOnly": "false", @@ -130,7 +127,7 @@ func TestWANFederation(t *testing.T) { secondaryHelmValues["global.acls.replicationToken.secretName"] = federationSecretName secondaryHelmValues["global.acls.replicationToken.secretKey"] = "replicationToken" secondaryHelmValues["global.federation.k8sAuthMethodHost"] = k8sAuthMethodHost - secondaryHelmValues["global.federation.primaryDatacenter"] = primaryDatacenter + secondaryHelmValues["global.federation.primaryDatacenter"] = "dc1" } if cfg.UseKind { @@ -154,7 +151,7 @@ func TestWANFederation(t *testing.T) { logger.Log(t, "creating proxy-defaults config") kustomizeDir := "../fixtures/bases/mesh-gateway" k8s.KubectlApplyK(t, secondaryContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, secondaryContext.KubectlOptions(t), kustomizeDir) }) @@ -184,272 +181,17 @@ func TestWANFederation(t *testing.T) { // Check that we can connect services over the mesh gateways logger.Log(t, "creating static-server in dc2") - k8s.DeployKustomize(t, secondaryHelper.KubectlOptsForApp(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + k8s.DeployKustomize(t, secondaryHelper.KubectlOptsForApp(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") logger.Log(t, "creating static-client in dc1") - k8s.DeployKustomize(t, primaryHelper.KubectlOptsForApp(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") + k8s.DeployKustomize(t, primaryHelper.KubectlOptsForApp(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") if c.secure { - primaryHelper.CreateIntention(t, connhelper.IntentionOpts{}) + primaryHelper.CreateIntention(t) } logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, primaryHelper.KubectlOptsForApp(t), connhelper.StaticClientName, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, primaryHelper.KubectlOptsForApp(t), StaticClientName, "http://localhost:1234") }) } } - -// Test failover scenarios with a static-server in dc1 and a static-server -// in dc2. Use the static-client on dc1 to reach static-server on dc1 in the -// nominal scenario, then cause a failure in dc1 static-server to see the static-client failover to -// the static-server in dc2 -/* - dc1-static-client -- nominal -- > dc1-static-server in namespace ns1 - dc1-static-client -- failover --> dc2-static-server in namespace ns1 - dc1-static-client -- failover --> dc1-static-server in namespace ns2 -*/ -func TestWANFederationFailover(t *testing.T) { - cases := []struct { - name string - secure bool - }{ - { - name: "secure", - secure: true, - }, - { - name: "default", - secure: false, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - - if cfg.EnableRestrictedPSAEnforcement { - t.Skip("This test case is not run with enable restricted PSA enforcement enabled") - } - - primaryContext := env.DefaultContext(t) - secondaryContext := env.Context(t, 1) - - primaryHelmValues := map[string]string{ - "global.datacenter": primaryDatacenter, - - "global.tls.enabled": "true", - "global.tls.httpsOnly": strconv.FormatBool(c.secure), - - "global.federation.enabled": "true", - "global.federation.createFederationSecret": "true", - - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - "global.acls.createReplicationToken": strconv.FormatBool(c.secure), - - "connectInject.enabled": "true", - "connectInject.replicas": "1", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - - "global.enableConsulNamespaces": "true", - "connectInject.consulNamespaces.mirroringK8S": "true", - } - - if cfg.UseKind { - primaryHelmValues["meshGateway.service.type"] = "NodePort" - primaryHelmValues["meshGateway.service.nodePort"] = "30000" - } - - releaseName := helpers.RandomName() - - // Install the primary consul cluster in the default kubernetes context - primaryConsulCluster := consul.NewHelmCluster(t, primaryHelmValues, primaryContext, cfg, releaseName) - primaryConsulCluster.Create(t) - - // Get the federation secret from the primary cluster and apply it to secondary cluster - federationSecretName := copyFederationSecret(t, releaseName, primaryContext, secondaryContext) - - k8sAuthMethodHost := k8s.KubernetesAPIServerHost(t, cfg, secondaryContext) - - // Create secondary cluster - secondaryHelmValues := map[string]string{ - "global.datacenter": secondaryDatacenter, - - "global.tls.enabled": "true", - "global.tls.httpsOnly": "false", - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - "global.tls.caCert.secretName": federationSecretName, - "global.tls.caCert.secretKey": "caCert", - "global.tls.caKey.secretName": federationSecretName, - "global.tls.caKey.secretKey": "caKey", - - "global.federation.enabled": "true", - - "server.extraVolumes[0].type": "secret", - "server.extraVolumes[0].name": federationSecretName, - "server.extraVolumes[0].load": "true", - "server.extraVolumes[0].items[0].key": "serverConfigJSON", - "server.extraVolumes[0].items[0].path": "config.json", - - "connectInject.enabled": "true", - "connectInject.replicas": "1", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - - "global.enableConsulNamespaces": "true", - "connectInject.consulNamespaces.mirroringK8S": "true", - } - - if c.secure { - secondaryHelmValues["global.acls.replicationToken.secretName"] = federationSecretName - secondaryHelmValues["global.acls.replicationToken.secretKey"] = "replicationToken" - secondaryHelmValues["global.federation.k8sAuthMethodHost"] = k8sAuthMethodHost - secondaryHelmValues["global.federation.primaryDatacenter"] = primaryDatacenter - } - - if cfg.UseKind { - secondaryHelmValues["meshGateway.service.type"] = "NodePort" - secondaryHelmValues["meshGateway.service.nodePort"] = "30000" - } - - // Install the secondary consul cluster in the secondary kubernetes context - secondaryConsulCluster := consul.NewHelmCluster(t, secondaryHelmValues, secondaryContext, cfg, releaseName) - secondaryConsulCluster.Create(t) - - primaryClient, _ := primaryConsulCluster.SetupConsulClient(t, c.secure) - secondaryClient, _ := secondaryConsulCluster.SetupConsulClient(t, c.secure) - - // Verify federation between servers - logger.Log(t, "Verifying federation was successful") - helpers.VerifyFederation(t, primaryClient, secondaryClient, releaseName, c.secure) - - // Create a ProxyDefaults resource to configure services to use the mesh - // gateways. - logger.Log(t, "Creating proxy-defaults config") - kustomizeDir := "../fixtures/bases/mesh-gateway" - k8s.KubectlApplyK(t, secondaryContext.KubectlOptions(t), kustomizeDir) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { - k8s.KubectlDeleteK(t, secondaryContext.KubectlOptions(t), kustomizeDir) - }) - - primaryHelper := connhelper.ConnectHelper{ - Secure: c.secure, - ReleaseName: releaseName, - Ctx: primaryContext, - UseAppNamespace: false, - Cfg: cfg, - ConsulClient: primaryClient, - } - secondaryHelper := connhelper.ConnectHelper{ - Secure: c.secure, - ReleaseName: releaseName, - Ctx: secondaryContext, - UseAppNamespace: false, - Cfg: cfg, - ConsulClient: secondaryClient, - } - - // Create Namespaces - // We create a namespace (ns1) in both the primary and secondary datacenters (dc1, dc2) - // We then create a secondary namespace (ns2) in the primary datacenter (dc1) - primaryNamespaceOpts := primaryHelper.Ctx.KubectlOptionsForNamespace(primaryNamespace) - primaryHelper.CreateNamespace(t, primaryNamespaceOpts.Namespace) - primarySecondaryNamepsaceOpts := primaryHelper.Ctx.KubectlOptionsForNamespace(secondaryNamespace) - primaryHelper.CreateNamespace(t, primarySecondaryNamepsaceOpts.Namespace) - secondaryNamespaceOpts := secondaryHelper.Ctx.KubectlOptionsForNamespace(primaryNamespace) - secondaryHelper.CreateNamespace(t, secondaryNamespaceOpts.Namespace) - - // Create a static-server in dc2 to respond with its own name for checking failover. - logger.Log(t, "Creating static-server in dc2") - k8s.DeployKustomize(t, secondaryNamespaceOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/wan-federation/dc2-static-server") - - // Spin up a server on dc1 which will be the primary upstream for our client - logger.Log(t, "Creating static-server in dc1") - k8s.DeployKustomize(t, primaryNamespaceOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/wan-federation/dc1-static-server") - logger.Log(t, "Creating static-client in dc1") - k8s.DeployKustomize(t, primaryNamespaceOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/wan-federation/static-client") - - // Spin up a second server on dc1 in a separate namespace - logger.Logf(t, "Creating server on dc1 in namespace %s", primarySecondaryNamepsaceOpts.Namespace) - k8s.DeployKustomize(t, primarySecondaryNamepsaceOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/wan-federation/dc1-ns2-static-server") - - // There is currently an issue that requires the intentions and resolvers to be created after - // the static-server/clients when using namespaces. When created before, Consul gives a "namespace does not exist" - // error - if c.secure { - // Only need to create intentions in the primary datacenter as they will be replicated to the secondary - // ns1 static-client (source) -> ns1 static-server (destination) - primaryHelper.CreateIntention(t, connhelper.IntentionOpts{DestinationNamespace: primaryNamespaceOpts.Namespace, SourceNamespace: primaryNamespaceOpts.Namespace}) - - // ns1 static-client (source) -> ns2 static-server (destination) - primaryHelper.CreateIntention(t, connhelper.IntentionOpts{DestinationNamespace: primarySecondaryNamepsaceOpts.Namespace, SourceNamespace: primaryNamespaceOpts.Namespace}) - } - - // Create a service resolver for failover - logger.Log(t, "Creating service resolver") - k8s.DeployKustomize(t, primaryNamespaceOpts, cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/cases/wan-federation/service-resolver") - - // Verify that we respond with the static-server in the primary datacenter - logger.Log(t, "Verifying static-server in dc1 responds") - serviceFailoverCheck(t, primaryNamespaceOpts, localServerPort, primaryDatacenter) - - // Scale down the primary datacenter static-server and see the failover - logger.Log(t, "Scale down dc1 static-server") - k8s.KubectlScale(t, primaryNamespaceOpts, staticServerDeployment, 0) - - // Verify that we respond with the static-server in the secondary datacenter - logger.Log(t, "Verifying static-server in dc2 responds") - serviceFailoverCheck(t, primaryNamespaceOpts, localServerPort, secondaryDatacenter) - - // scale down the primary datacenter static-server and see the failover - logger.Log(t, "Scale down dc2 static-server") - k8s.KubectlScale(t, secondaryNamespaceOpts, staticServerDeployment, 0) - - // Verify that we respond with the static-server in the secondary datacenter - logger.Log(t, "Verifying static-server in secondary namespace (ns2) responds") - serviceFailoverCheck(t, primaryNamespaceOpts, localServerPort, secondaryNamespace) - }) - } -} - -// serviceFailoverCheck verifies that the server failed over as expected by checking that curling the `static-server` -// using the `static-client` responds with the expected cluster name. Each static-server responds with a unique -// name so that we can verify failover occurred as expected. -func serviceFailoverCheck(t *testing.T, options *terratestK8s.KubectlOptions, port string, expectedName string) { - timer := &retry.Timer{Timeout: retryTimeout, Wait: 5 * time.Second} - var resp string - var err error - - f := func(ft require.TestingT) { - resp, err = k8s.RunKubectlAndGetOutputE(t, options, "exec", "-i", - staticClientDeployment, "-c", connhelper.StaticClientName, "--", "curl", fmt.Sprintf("localhost:%s", port)) - require.NoError(ft, err) - assert.Contains(ft, resp, expectedName) - } - - retry.RunWith(timer, t, func(r *retry.R) { - f(r) - }) - - // Try again to rule out load-balancing - f(t) - - logger.Log(t, resp) -} - -func copyFederationSecret(t *testing.T, releaseName string, primaryContext, secondaryContext environment.TestContext) string { - // Get the federation secret from the primary cluster and apply it to secondary cluster - federationSecretName := fmt.Sprintf("%s-consul-federation", releaseName) - logger.Logf(t, "Retrieving federation secret %s from the primary cluster and applying to the secondary", federationSecretName) - federationSecret, err := primaryContext.KubernetesClient(t).CoreV1().Secrets(primaryContext.KubectlOptions(t).Namespace).Get(context.Background(), federationSecretName, metav1.GetOptions{}) - require.NoError(t, err) - federationSecret.ResourceVersion = "" - federationSecret.Namespace = secondaryContext.KubectlOptions(t).Namespace - _, err = secondaryContext.KubernetesClient(t).CoreV1().Secrets(secondaryContext.KubectlOptions(t).Namespace).Create(context.Background(), federationSecret, metav1.CreateOptions{}) - require.NoError(t, err) - - return federationSecretName -} diff --git a/charts/consul/.helmignore b/charts/consul/.helmignore index 3fa2f24edf..d1180d2fb7 100644 --- a/charts/consul/.helmignore +++ b/charts/consul/.helmignore @@ -2,4 +2,3 @@ .terraform/ bin/ test/ -crds/kustomization.yaml diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index de8e6e9df6..84642eb7ac 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,11 +1,8 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v2 name: consul -version: 1.3.0-dev -appVersion: 1.17-dev -kubeVersion: ">=1.22.0-0" +version: 1.0.10-dev +appVersion: 1.14-dev +kubeVersion: ">=1.21.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io icon: https://raw.githubusercontent.com/hashicorp/consul-k8s/main/assets/icon.png @@ -16,13 +13,13 @@ annotations: artifacthub.io/prerelease: true artifacthub.io/images: | - name: consul - image: docker.mirror.hashicorp.services/hashicorppreview/consul-enterprise:1.17-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul:1.14-dev - name: consul-k8s-control-plane - image: docker.mirror.hashicorp.services/hashicorppreview/consul-k8s-control-plane:1.3.0-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul-k8s-control-plane:1.0.10-dev - name: consul-dataplane - image: docker.mirror.hashicorp.services/hashicorppreview/consul-dataplane:1.3-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul-dataplane:1.0-dev - name: envoy - image: envoyproxy/envoy:v1.26.2 + image: envoyproxy/envoy:v1.24.10 artifacthub.io/license: MPL-2.0 artifacthub.io/links: | - name: Documentation diff --git a/charts/consul/addons/gen.sh b/charts/consul/addons/gen.sh index 1d03390bed..967b368c63 100755 --- a/charts/consul/addons/gen.sh +++ b/charts/consul/addons/gen.sh @@ -1,7 +1,4 @@ #!/usr/bin/env bash -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - WD=$(dirname "$0") WD=$(cd "$WD"; pwd) diff --git a/charts/consul/addons/values/prometheus.yaml b/charts/consul/addons/values/prometheus.yaml index 1f90636f2e..9ffe9af5ae 100644 --- a/charts/consul/addons/values/prometheus.yaml +++ b/charts/consul/addons/values/prometheus.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # Disable non-essential components alertmanager: enabled: false diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 06efdbc3a5..bdcf2ecb19 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -15,8 +15,23 @@ as well as the global.name setting. {{- end -}} {{- end -}} + {{- define "consul.restrictedSecurityContext" -}} {{- if not .Values.global.enablePodSecurityPolicies -}} +{{/* +To be compatible with the 'restricted' Pod Security Standards profile, we +should set this securityContext on containers whenever possible. + +In OpenShift < 4.11 the restricted SCC disallows setting most of these fields, +so we do not set any for simplicity (and because that's how it was configured +prior to adding restricted PSA support here). In OpenShift >= 4.11, the new +restricted-v2 SCC allows setting these in the securityContext, and by setting +them we avoid PSA warnings that are enabled by default. + +We use the K8s version as a proxy for the OpenShift version because there is a +1:1 mapping of versions. OpenShift 4.11 corresponds to K8s 1.24.x. +*/}} +{{- if (or (not .Values.global.openshift.enabled) (and (ge .Capabilities.KubeVersion.Major "1") (ge .Capabilities.KubeVersion.Minor "24"))) -}} securityContext: allowPrivilegeEscalation: false capabilities: @@ -27,11 +42,12 @@ securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault +{{- end -}} {{- if not .Values.global.openshift.enabled -}} {{/* We must set runAsUser or else the root user will be used in some cases and containers will fail to start due to runAsNonRoot above (e.g. -tls-init-cleanup). On OpenShift, runAsUser is automatically. We pick user 100 +tls-init-cleanup). On OpenShift, runAsUser is set automatically. We pick user 100 because it is a non-root user id that exists in the consul, consul-dataplane, and consul-k8s-control-plane images. */}} @@ -98,6 +114,22 @@ and consul-k8s-control-plane images. {{ "{{" }}- end -{{ "}}" }} {{- end -}} +{{- define "consul.controllerWebhookTLSCertTemplate" -}} + | + {{ "{{" }}- with secret "{{ .Values.global.secretsBackend.vault.controller.tlsCert.secretName }}" "{{- $name := include "consul.fullname" . -}}{{ printf "common_name=%s-controller-webhook" $name }}" + "alt_names={{ include "consul.controllerWebhookTLSAltNames" . }}" -{{ "}}" }} + {{ "{{" }}- .Data.certificate -{{ "}}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} + +{{- define "consul.controllerWebhookTLSKeyTemplate" -}} + | + {{ "{{" }}- with secret "{{ .Values.global.secretsBackend.vault.controller.tlsCert.secretName }}" "{{- $name := include "consul.fullname" . -}}{{ printf "common_name=%s-controller-webhook" $name }}" + "alt_names={{ include "consul.controllerWebhookTLSAltNames" . }}" -{{ "}}" }} + {{ "{{" }}- .Data.private_key -{{ "}}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} + {{- define "consul.serverTLSAltNames" -}} {{- $name := include "consul.fullname" . -}} {{- $ns := .Release.Namespace -}} @@ -118,6 +150,12 @@ and consul-k8s-control-plane images. {{ printf "%s-connect-injector,%s-connect-injector.%s,%s-connect-injector.%s.svc,%s-connect-injector.%s.svc.cluster.local" $name $name $ns $name $ns $name $ns}} {{- end -}} +{{- define "consul.controllerWebhookTLSAltNames" -}} +{{- $name := include "consul.fullname" . -}} +{{- $ns := .Release.Namespace -}} +{{ printf "%s-controller-webhook,%s-controller-webhook.%s,%s-controller-webhook.%s.svc,%s-controller-webhook.%s.svc.cluster.local" $name $name $ns $name $ns $name $ns}} +{{- end -}} + {{- define "consul.vaultReplicationTokenTemplate" -}} | {{ "{{" }}- with secret "{{ .Values.global.acls.replicationToken.secretName }}" -{{ "}}" }} @@ -288,17 +326,20 @@ Fails when at least one but not all of the following have been set: - global.secretsBackend.vault.connectInjectRole - global.secretsBackend.vault.connectInject.tlsCert.secretName - global.secretsBackend.vault.connectInject.caCert.secretName +- global.secretsBackend.vault.controllerRole +- global.secretsBackend.vault.controller.tlsCert.secretName +- global.secretsBackend.vault.controller.caCert.secretName The above values are needed in full to turn off web cert manager and allow -connect inject to manage its own webhook certs. +connect inject and controller to manage its own webhook certs. Usage: {{ template "consul.validateVaultWebhookCertConfiguration" . }} */}} {{- define "consul.validateVaultWebhookCertConfiguration" -}} -{{- if or .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName}} -{{- if or (not .Values.global.secretsBackend.vault.connectInjectRole) (not .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName) (not .Values.global.secretsBackend.vault.connectInject.caCert.secretName) }} -{{fail "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName"}} +{{- if or .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName .Values.global.secretsBackend.vault.controllerRole .Values.global.secretsBackend.vault.controller.tlsCert.secretName .Values.global.secretsBackend.vault.controller.caCert.secretName}} +{{- if or (not .Values.global.secretsBackend.vault.connectInjectRole) (not .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName) (not .Values.global.secretsBackend.vault.connectInject.caCert.secretName) (not .Values.global.secretsBackend.vault.controllerRole) (not .Values.global.secretsBackend.vault.controller.tlsCert.secretName) (not .Values.global.secretsBackend.vault.controller.caCert.secretName) }} +{{fail "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and global.secretsBackend.vault.controller.caCert.secretName."}} {{ end }} {{ end }} {{- end -}} @@ -360,7 +401,7 @@ Consul server environment variables for consul-k8s commands. {{- end }} {{- if and .Values.externalServers.enabled .Values.externalServers.skipServerWatch }} - name: CONSUL_SKIP_SERVER_WATCH - value: "true" + value: "true" {{- end }} {{- end -}} @@ -391,7 +432,7 @@ Usage: {{ template "consul.validateCloudSecretKeys" . }} */}} {{- define "consul.validateCloudSecretKeys" -}} -{{- if and .Values.global.cloud.enabled }} +{{- if and .Values.global.cloud.enabled }} {{- if or (and .Values.global.cloud.resourceId.secretName (not .Values.global.cloud.resourceId.secretKey)) (and .Values.global.cloud.resourceId.secretKey (not .Values.global.cloud.resourceId.secretName)) }} {{fail "When either global.cloud.resourceId.secretName or global.cloud.resourceId.secretKey is defined, both must be set."}} {{- end }} @@ -413,87 +454,3 @@ Usage: {{ template "consul.validateCloudSecretKeys" . }} {{- end }} {{- end -}} - -{{/* -Fails if temeletryCollector.clientId or telemetryCollector.clientSecret exist and one of other secrets is nil or empty. -- telemetryCollector.cloud.clientId.secretName -- telemetryCollector.cloud.clientSecret.secretName -- global.cloud.resourceId.secretName - -Usage: {{ template "consul.validateTelemetryCollectorCloud" . }} - -*/}} -{{- define "consul.validateTelemetryCollectorCloud" -}} -{{- if (and .Values.telemetryCollector.cloud.clientId.secretName (or (not .Values.global.cloud.resourceId.secretName) (not .Values.telemetryCollector.cloud.clientSecret.secretName))) }} -{{fail "When telemetryCollector.cloud.clientId.secretName is set, global.cloud.resourceId.secretName, telemetryCollector.cloud.clientSecret.secretName must also be set."}} -{{- end }} -{{- if (and .Values.telemetryCollector.cloud.clientSecret.secretName (or (not .Values.global.cloud.resourceId.secretName) (not .Values.telemetryCollector.cloud.clientSecret.secretName))) }} -{{fail "When telemetryCollector.cloud.clientSecret.secretName is set, global.cloud.resourceId.secretName,telemetryCollector.cloud.clientId.secretName must also be set."}} -{{- end }} -{{- end }} - -{{/**/}} - -{{- define "consul.validateTelemetryCollectorCloudSecretKeys" -}} -{{- if or (and .Values.telemetryCollector.cloud.clientId.secretName (not .Values.telemetryCollector.cloud.clientId.secretKey)) (and .Values.telemetryCollector.cloud.clientId.secretKey (not .Values.telemetryCollector.cloud.clientId.secretName)) }} -{{fail "When either telemetryCollector.cloud.clientId.secretName or telemetryCollector.cloud.clientId.secretKey is defined, both must be set."}} -{{- end }} -{{- if or (and .Values.telemetryCollector.cloud.clientSecret.secretName (not .Values.telemetryCollector.cloud.clientSecret.secretKey)) (and .Values.telemetryCollector.cloud.clientSecret.secretKey (not .Values.telemetryCollector.cloud.clientSecret.secretName)) }} -{{fail "When either telemetryCollector.cloud.clientSecret.secretName or telemetryCollector.cloud.clientSecret.secretKey is defined, both must be set."}} -{{- end }} -{{- if or (and .Values.telemetryCollector.cloud.clientSecret.secretName .Values.telemetryCollector.cloud.clientSecret.secretKey .Values.telemetryCollector.cloud.clientId.secretName .Values.telemetryCollector.cloud.clientId.secretKey (not .Values.global.cloud.resourceId.secretName)) }} -{{fail "When telemetryCollector has clientId and clientSecret global.cloud.resourceId.secretName must be set"}} -{{- end }} -{{- if or (and .Values.telemetryCollector.cloud.clientSecret.secretName .Values.telemetryCollector.cloud.clientSecret.secretKey .Values.telemetryCollector.cloud.clientId.secretName .Values.telemetryCollector.cloud.clientId.secretKey (not .Values.global.cloud.resourceId.secretKey)) }} -{{fail "When telemetryCollector has clientId and clientSecret .global.cloud.resourceId.secretKey must be set"}} -{{- end }} -{{- end -}} - -{{/* -Fails if global.experiments.resourceAPIs is set along with any of these unsupported features. -- global.peering.enabled -- global.federation.enabled -- global.cloud.enabled -- client.enabled -- ui.enabled -- syncCatalog.enabled -- meshGateway.enabled -- ingressGateways.enabled -- terminatingGateways.enabled -- apiGateway.enabled - -Usage: {{ template "consul.validateResourceAPIs" . }} - -*/}} -{{- define "consul.validateResourceAPIs" -}} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.global.peering.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, global.peering.enabled is currently unsupported."}} -{{- end }} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.global.federation.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, global.federation.enabled is currently unsupported."}} -{{- end }} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.global.cloud.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, global.cloud.enabled is currently unsupported."}} -{{- end }} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.client.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, client.enabled is currently unsupported."}} -{{- end }} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.ui.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, ui.enabled is currently unsupported."}} -{{- end }} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.syncCatalog.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, syncCatalog.enabled is currently unsupported."}} -{{- end }} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.meshGateway.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, meshGateway.enabled is currently unsupported."}} -{{- end }} -{{- if (and (mustHas "resource-apis" .Values.global.experiments) .Values.ingressGateways.enabled ) }} -{{fail "When the value global.experiments.resourceAPIs is set, ingressGateways.enabled is currently unsupported."}} -{{- end }} -{{- 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 }} \ No newline at end of file diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index c95b7c143a..f2e12f0ad9 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -24,17 +24,10 @@ rules: - serviceintentions - ingressgateways - terminatinggateways - - gatewayclassconfigs - - meshservices - - samenessgroups - - controlplanerequestlimits - - routeretryfilters - - routetimeoutfilters {{- if .Values.global.peering.enabled }} - peeringacceptors - peeringdialers {{- end }} - - jwtproviders verbs: - create - delete @@ -56,35 +49,26 @@ rules: - serviceintentions/status - ingressgateways/status - terminatinggateways/status - - samenessgroups/status - - controlplanerequestlimits/status {{- if .Values.global.peering.enabled }} - peeringacceptors/status - peeringdialers/status {{- end }} - - jwtproviders/status verbs: - get - patch - update +{{- if .Values.global.acls.manageSystemACLs }} - apiGroups: [ "" ] - resources: [ "secrets", "serviceaccounts", "endpoints", "services", "namespaces", "nodes" ] + resources: [ "serviceaccounts", "secrets" ] verbs: - - create - get - - list - - watch - - delete - - update -- apiGroups: [ "rbac.authorization.k8s.io" ] - resources: [ "roles", "rolebindings" ] +{{- end }} +- apiGroups: [ "" ] + resources: [ "endpoints", "services", "namespaces", "nodes" ] verbs: - - get - - list - - watch - - delete - - create - - update + - "get" + - "list" + - "watch" - apiGroups: [ "" ] resources: - pods @@ -124,78 +108,12 @@ rules: - "update" - "delete" {{- end }} +{{- if .Values.global.enablePodSecurityPolicies }} - apiGroups: [ "policy" ] resources: [ "podsecuritypolicies" ] - verbs: - - use -- apiGroups: - - gateway.networking.k8s.io - resources: - - gatewayclasses - - gateways - - httproutes - - tcproutes - - referencegrants - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - gateway.networking.k8s.io - resources: - - gatewayclasses/finalizers - - gateways/finalizers - - httproutes/finalizers - - tcproutes/finalizers - verbs: - - update -- apiGroups: - - gateway.networking.k8s.io - resources: - - gatewayclasses/status - - gateways/status - - httproutes/status - - tcproutes/status - verbs: - - get - - patch - - update -- apiGroups: - - apps - resources: - - deployments - verbs: - - create - - get - - list - - update - - watch - - delete -- apiGroups: - - core - resources: - - services - verbs: - - watch - - list -- apiGroups: [ "" ] - resources: [ "secrets" ] - verbs: - - "get" - - "list" - - "watch" -{{- if .Values.global.openshift.enabled }} -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints resourceNames: - - {{ .Values.connectInject.apiGateway.managedGatewayClass.openshiftSCCName }} + - {{ template "consul.fullname" . }}-connect-injector verbs: - - use - {{- end }} + - use +{{- end }} {{- end }} diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index a1be4a79b7..f9e79ced52 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -11,7 +11,6 @@ {{- $dnsRedirectionEnabled := (or (and (ne (.Values.dns.enableRedirection | toString) "-") .Values.dns.enableRedirection) (and (eq (.Values.dns.enableRedirection | toString) "-") .Values.connectInject.transparentProxy.defaultEnabled)) -}} {{ template "consul.validateRequiredCloudSecretsExist" . }} {{ template "consul.validateCloudSecretKeys" . }} -{{ template "consul.validateResourceAPIs" . }} # The deployment for running the Connect sidecar injector apiVersion: apps/v1 kind: Deployment @@ -147,9 +146,6 @@ spec: -release-namespace="{{ .Release.Namespace }}" \ -resource-prefix={{ template "consul.fullname" . }} \ -listen=:8080 \ - {{- if (mustHas "resource-apis" .Values.global.experiments) }} - -enable-resource-apis=true - {{- end }} {{- range $k, $v := .Values.connectInject.consulNode.meta }} -node-meta={{ $k }}={{ $v }} \ {{- end }} @@ -275,7 +271,6 @@ spec: {{- if and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt }} -enable-auto-encrypt \ {{- end }} - -enable-telemetry-collector={{ .Values.global.metrics.enableTelemetryCollector}} \ startupProbe: httpGet: path: /readyz/ready diff --git a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml index e4fe79f621..afcfd3800f 100644 --- a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml +++ b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml @@ -222,27 +222,6 @@ webhooks: resources: - exportedservices sideEffects: None -- clientConfig: - service: - name: {{ template "consul.fullname" . }}-connect-injector - namespace: {{ .Release.Namespace }} - path: /mutate-v1alpha1-controlplanerequestlimits - failurePolicy: Fail - admissionReviewVersions: - - "v1beta1" - - "v1" - name: mutate-controlplanerequestlimit.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - controlplanerequestlimits - sideEffects: None - name: {{ template "consul.fullname" . }}-connect-injector.consul.hashicorp.com # The webhook will fail scheduling all pods that are not part of consul if all replicas of the webhook are unhealthy. objectSelector: @@ -312,47 +291,5 @@ webhooks: admissionReviewVersions: - "v1beta1" - "v1" -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: {{ template "consul.fullname" . }}-connect-injector - namespace: {{ .Release.Namespace }} - path: /mutate-v1alpha1-samenessgroup - failurePolicy: Fail - name: mutate-samenessgroup.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - samenessgroups - sideEffects: None {{- end }} -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: {{ template "consul.fullname" . }}-connect-injector - namespace: {{ .Release.Namespace }} - path: /mutate-v1alpha1-jwtprovider - failurePolicy: Fail - name: mutate-jwtprovider.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - jwtproviders - sideEffects: None {{- end }} diff --git a/charts/consul/templates/crd-controlplanerequestlimits.yaml b/charts/consul/templates/crd-controlplanerequestlimits.yaml deleted file mode 100644 index 01722c0cf0..0000000000 --- a/charts/consul/templates/crd-controlplanerequestlimits.yaml +++ /dev/null @@ -1,206 +0,0 @@ -{{- if .Values.connectInject.enabled }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: controlplanerequestlimits.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: ControlPlaneRequestLimit - listKind: ControlPlaneRequestLimitList - plural: controlplanerequestlimits - singular: controlplanerequestlimit - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: ControlPlaneRequestLimit is the Schema for the controlplanerequestlimits - API. - 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: ControlPlaneRequestLimitSpec defines the desired state of - ControlPlaneRequestLimit. - properties: - acl: - properties: - readRate: - type: number - writeRate: - type: number - type: object - catalog: - properties: - readRate: - type: number - writeRate: - type: number - type: object - configEntry: - properties: - readRate: - type: number - writeRate: - type: number - type: object - connectCA: - properties: - readRate: - type: number - writeRate: - type: number - type: object - coordinate: - properties: - readRate: - type: number - writeRate: - type: number - type: object - discoveryChain: - properties: - readRate: - type: number - writeRate: - type: number - type: object - health: - properties: - readRate: - type: number - writeRate: - type: number - type: object - intention: - properties: - readRate: - type: number - writeRate: - type: number - type: object - kv: - properties: - readRate: - type: number - writeRate: - type: number - type: object - mode: - type: string - perparedQuery: - properties: - readRate: - type: number - writeRate: - type: number - type: object - readRate: - type: number - session: - properties: - readRate: - type: number - writeRate: - type: number - type: object - tenancy: - properties: - readRate: - type: number - writeRate: - type: number - type: object - txn: - properties: - readRate: - type: number - writeRate: - type: number - type: object - writeRate: - type: number - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-exportedservices.yaml b/charts/consul/templates/crd-exportedservices.yaml index dd6b6ba3b8..007990372c 100644 --- a/charts/consul/templates/crd-exportedservices.yaml +++ b/charts/consul/templates/crd-exportedservices.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: exportedservices.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: exportedservices.consul.hashicorp.com spec: group: consul.hashicorp.com names: @@ -79,12 +76,8 @@ spec: the service to. type: string peer: - description: Peer is the name of the peer to export the - service to. - type: string - samenessGroup: - description: SamenessGroup is the name of the sameness - group to export the service to. + description: '[Experimental] Peer is the name of the peer + to export the service to.' type: string type: object type: array diff --git a/charts/consul/templates/crd-gatewayclassconfigs.yaml b/charts/consul/templates/crd-gatewayclassconfigs.yaml deleted file mode 100644 index 98ecb345f3..0000000000 --- a/charts/consul/templates/crd-gatewayclassconfigs.yaml +++ /dev/null @@ -1,211 +0,0 @@ -{{- if .Values.connectInject.enabled }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: gatewayclassconfigs.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: GatewayClassConfig - listKind: GatewayClassConfigList - plural: gatewayclassconfigs - singular: gatewayclassconfig - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: GatewayClassConfig defines the values that may be set on a GatewayClass - for Consul API Gateway. - 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 GatewayClassConfig. - properties: - copyAnnotations: - description: Annotation Information to copy to services or deployments - properties: - service: - description: List of annotations to copy to the gateway service. - items: - type: string - type: array - type: object - deployment: - description: Deployment defines the deployment configuration for the - gateway. - properties: - defaultInstances: - default: 1 - description: Number of gateway instances that should be deployed - by default - format: int32 - maximum: 8 - minimum: 1 - type: integer - maxInstances: - default: 8 - description: Max allowed number of gateway instances - format: int32 - maximum: 8 - minimum: 1 - type: integer - minInstances: - default: 1 - description: Minimum allowed number of gateway instances - format: int32 - maximum: 8 - minimum: 1 - type: integer - resources: - description: Resources defines the resource requirements for the - gateway. - properties: - claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be - set for containers." - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: Name must match the name of one entry in - pod.spec.resourceClaims of the Pod where this field - is used. It makes that resource available inside a - container. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - 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. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - type: object - mapPrivilegedContainerPorts: - description: The value to add to privileged ports ( ports < 1024) - for gateway containers - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: 'NodeSelector is a selector which must be true for the - pod to fit on a node. Selector which must match a node''s labels - for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' - type: object - openshiftSCCName: - description: The name of the OpenShift SecurityContextConstraints - resource for this gateway class to use. - type: string - podSecurityPolicy: - description: The name of an existing Kubernetes PodSecurityPolicy - to bind to the managed ServiceAccount if ACLs are managed. - type: string - serviceType: - description: Service Type string describes ingress methods for a service - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - tolerations: - description: 'Tolerations allow the scheduler to schedule nodes with - matching taints. More Info: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/' - items: - description: The pod this Toleration is attached to tolerates any - taint that matches the triple using the matching - operator . - properties: - effect: - description: Effect indicates the taint effect to match. Empty - means match all taint effects. When specified, allowed values - are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Key is the taint key that the toleration applies - to. Empty means match all taint keys. If the key is empty, - operator must be Exists; this combination means to match all - values and all keys. - type: string - operator: - description: Operator represents a key's relationship to the - value. Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod - can tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: TolerationSeconds represents the period of time - the toleration (which must be of effect NoExecute, otherwise - this field is ignored) tolerates the taint. By default, it - is not set, which means tolerate the taint forever (do not - evict). Zero and negative values will be treated as 0 (evict - immediately) by the system. - format: int64 - type: integer - value: - description: Value is the taint value the toleration matches - to. If the operator is Exists, the value should be empty, - otherwise just a regular string. - type: string - type: object - type: array - type: object - type: object - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-gatewayclasses.yaml b/charts/consul/templates/crd-gatewayclasses.yaml deleted file mode 100644 index 391637b5f7..0000000000 --- a/charts/consul/templates/crd-gatewayclasses.yaml +++ /dev/null @@ -1,331 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: gatewayclasses.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: GatewayClass - listKind: GatewayClassList - plural: gatewayclasses - shortNames: - - gc - singular: gatewayclass - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .spec.controllerName - name: Controller - type: string - - jsonPath: .status.conditions[?(@.type=="Accepted")].status - name: Accepted - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - jsonPath: .spec.description - name: Description - priority: 1 - type: string - deprecated: true - deprecationWarning: The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1. - name: v1alpha2 - schema: - openAPIV3Schema: - description: "GatewayClass describes a class of Gateways available to the user for creating Gateway resources. \n It is recommended that this resource be used as a template for Gateways. This means that a Gateway is based on the state of the GatewayClass at the time it was created and changes to the GatewayClass or associated parameters are not propagated down to existing Gateways. This recommendation is intended to limit the blast radius of changes to GatewayClass or associated parameters. If implementations choose to propagate GatewayClass changes to existing Gateways, that MUST be clearly documented by the implementation. \n Whenever one or more Gateways are using a GatewayClass, implementations MUST add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the associated GatewayClass. This ensures that a GatewayClass associated with a Gateway is not deleted while in use. \n GatewayClass is a Cluster level resource." - 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 GatewayClass. - properties: - controllerName: - description: "ControllerName is the name of the controller that is managing Gateways of this class. The value of this field MUST be a domain prefixed path. \n Example: \"example.net/gateway-controller\". \n This field is not mutable and cannot be empty. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - description: - description: Description helps describe a GatewayClass with more details. - maxLength: 64 - type: string - parametersRef: - description: "ParametersRef is a reference to a resource that contains the configuration parameters corresponding to the GatewayClass. This is optional if the controller does not require any additional configuration. \n ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, or an implementation-specific custom resource. The resource can be cluster-scoped or namespace-scoped. \n If the referent cannot be found, the GatewayClass's \"InvalidParameters\" status condition will be true. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. This field is required when referring to a Namespace-scoped resource and MUST be unset when referring to a Cluster-scoped resource. - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - required: - - controllerName - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: Unknown - type: Accepted - description: Status defines the current state of GatewayClass. - properties: - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - description: "Conditions is the current status from the controller for this GatewayClass. \n Controllers should prefer to publish conditions using values of GatewayClassConditionType for the type of each Condition." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.controllerName - name: Controller - type: string - - jsonPath: .status.conditions[?(@.type=="Accepted")].status - name: Accepted - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - jsonPath: .spec.description - name: Description - priority: 1 - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: "GatewayClass describes a class of Gateways available to the user for creating Gateway resources. \n It is recommended that this resource be used as a template for Gateways. This means that a Gateway is based on the state of the GatewayClass at the time it was created and changes to the GatewayClass or associated parameters are not propagated down to existing Gateways. This recommendation is intended to limit the blast radius of changes to GatewayClass or associated parameters. If implementations choose to propagate GatewayClass changes to existing Gateways, that MUST be clearly documented by the implementation. \n Whenever one or more Gateways are using a GatewayClass, implementations MUST add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the associated GatewayClass. This ensures that a GatewayClass associated with a Gateway is not deleted while in use. \n GatewayClass is a Cluster level resource." - 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 GatewayClass. - properties: - controllerName: - description: "ControllerName is the name of the controller that is managing Gateways of this class. The value of this field MUST be a domain prefixed path. \n Example: \"example.net/gateway-controller\". \n This field is not mutable and cannot be empty. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - description: - description: Description helps describe a GatewayClass with more details. - maxLength: 64 - type: string - parametersRef: - description: "ParametersRef is a reference to a resource that contains the configuration parameters corresponding to the GatewayClass. This is optional if the controller does not require any additional configuration. \n ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, or an implementation-specific custom resource. The resource can be cluster-scoped or namespace-scoped. \n If the referent cannot be found, the GatewayClass's \"InvalidParameters\" status condition will be true. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. This field is required when referring to a Namespace-scoped resource and MUST be unset when referring to a Cluster-scoped resource. - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - required: - - controllerName - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: Unknown - type: Accepted - description: Status defines the current state of GatewayClass. - properties: - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - description: "Conditions is the current status from the controller for this GatewayClass. \n Controllers should prefer to publish conditions using values of GatewayClassConditionType for the type of each Condition." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-gateways.yaml b/charts/consul/templates/crd-gateways.yaml deleted file mode 100644 index ab56d4f5fb..0000000000 --- a/charts/consul/templates/crd-gateways.yaml +++ /dev/null @@ -1,885 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: gateways.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: Gateway - listKind: GatewayList - plural: gateways - shortNames: - - gtw - singular: gateway - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.gatewayClassName - name: Class - type: string - - jsonPath: .status.addresses[*].value - name: Address - type: string - - jsonPath: .status.conditions[?(@.type=="Programmed")].status - name: Programmed - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - deprecated: true - deprecationWarning: The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1. - name: v1alpha2 - schema: - openAPIV3Schema: - description: Gateway represents an instance of a service-traffic handling infrastructure by binding Listeners to a set of IP addresses. - 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 Gateway. - properties: - addresses: - description: "Addresses requested for this Gateway. This is optional and behavior can depend on the implementation. If a value is set in the spec and the requested address is invalid or unavailable, the implementation MUST indicate this in the associated entry in GatewayStatus.Addresses. \n The Addresses field represents a request for the address(es) on the \"outside of the Gateway\", that traffic bound for this Gateway will use. This could be the IP address or hostname of an external load balancer or other networking infrastructure, or some other address that traffic will be sent to. \n The .listener.hostname field is used to route traffic that has already arrived at the Gateway to the correct in-cluster destination. \n If no Addresses are specified, the implementation MAY schedule the Gateway in an implementation-specific manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. \n Support: Extended" - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - gatewayClassName: - description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. - maxLength: 253 - minLength: 1 - type: string - listeners: - description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At least one Listener MUST be specified. \n Each listener in a Gateway must have a unique combination of Hostname, Port, and Protocol. \n An implementation MAY group Listeners by Port and then collapse each group of Listeners into a single Listener if the implementation determines that the Listeners in the group are \"compatible\". An implementation MAY also group together and collapse compatible Listeners belonging to different Gateways. \n For example, an implementation might consider Listeners to be compatible with each other if all of the following conditions are met: \n 1. Either each Listener within the group specifies the \"HTTP\" Protocol or each Listener within the group specifies either the \"HTTPS\" or \"TLS\" Protocol. \n 2. Each Listener within the group specifies a Hostname that is unique within the group. \n 3. As a special case, one Listener within a group may omit Hostname, in which case this Listener matches when no other Listener matches. \n If the implementation does collapse compatible Listeners, the hostname provided in the incoming client request MUST be matched to a Listener to find the correct set of Routes. The incoming hostname MUST be matched using the Hostname field for each Listener in order of most to least specific. That is, exact matches must be processed before wildcard matches. \n If this field specifies multiple Listeners that have the same Port value but are not compatible, the implementation must raise a \"Conflicted\" condition in the Listener status. \n Support: Core" - items: - description: Listener embodies the concept of a logical endpoint where a Gateway accepts network connections. - properties: - allowedRoutes: - default: - namespaces: - from: Same - description: "AllowedRoutes defines the types of routes that MAY be attached to a Listener and the trusted namespaces where those Route resources MAY be present. \n Although a client request may match multiple route rules, only one rule may ultimately receive the request. Matching precedence MUST be determined in order of the following criteria: \n * The most specific match as defined by the Route type. * The oldest Route based on creation timestamp. For example, a Route with a creation timestamp of \"2020-09-08 01:02:03\" is given precedence over a Route with a creation timestamp of \"2020-09-08 01:02:04\". * If everything else is equivalent, the Route appearing first in alphabetical order (namespace/name) should be given precedence. For example, foo/bar is given precedence over foo/baz. \n All valid rules within a Route attached to this Listener should be implemented. Invalid Route rules can be ignored (sometimes that will mean the full Route). If a Route rule transitions from valid to invalid, support for that Route rule should be dropped to ensure consistency. For example, even if a filter specified by a Route rule is invalid, the rest of the rules within that Route should still be supported. \n Support: Core" - properties: - kinds: - description: "Kinds specifies the groups and kinds of Routes that are allowed to bind to this Gateway Listener. When unspecified or empty, the kinds of Routes selected are determined using the Listener protocol. \n A RouteGroupKind MUST correspond to kinds of Routes that are compatible with the application protocol specified in the Listener's Protocol field. If an implementation does not support or recognize this resource type, it MUST set the \"ResolvedRefs\" condition to False for this Listener with the \"InvalidRouteKinds\" reason. \n Support: Core" - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - namespaces: - default: - from: Same - description: "Namespaces indicates namespaces from which Routes may be attached to this Listener. This is restricted to the namespace of this Gateway by default. \n Support: Core" - properties: - from: - default: Same - description: "From indicates where Routes will be selected for this Gateway. Possible values are: * All: Routes in all namespaces may be used by this Gateway. * Selector: Routes in namespaces selected by the selector may be used by this Gateway. * Same: Only Routes in the same namespace may be used by this Gateway. \n Support: Core" - enum: - - All - - Selector - - Same - type: string - selector: - description: "Selector must be specified when From is set to \"Selector\". In that case, only Routes in Namespaces matching this Selector will be selected by this Gateway. This field is ignored for other values of \"From\". \n Support: Core" - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - type: object - type: object - hostname: - description: "Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified, all hostnames are matched. This field is ignored for protocols that don't require hostname based matching. \n Implementations MUST apply Hostname matching appropriately for each of the following protocols: \n * TLS: The Listener Hostname MUST match the SNI. * HTTP: The Listener Hostname MUST match the Host header of the request. * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP protocol layers as described above. If an implementation does not ensure that both the SNI and Host header match the Listener hostname, it MUST clearly document that. \n For HTTPRoute and TLSRoute resources, there is an interaction with the `spec.hostnames` array. When both listener and route specify hostnames, there MUST be an intersection between the values for a Route to be accepted. For more information, refer to the Route specific Hostnames documentation. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - name: - description: "Name is the name of the Listener. This name MUST be unique within a Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - port: - description: "Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - description: "Protocol specifies the network protocol this listener expects to receive. \n Support: Core" - maxLength: 255 - minLength: 1 - pattern: ^[a-zA-Z0-9]([-a-zSA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ - type: string - tls: - description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\". \n The association of SNIs to Certificate defined in GatewayTLSConfig is defined based on the Hostname field for this listener. \n The GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake. \n Support: Core" - properties: - certificateRefs: - description: "CertificateRefs contains a series of references to Kubernetes objects that contains TLS certificates and private keys. These certificates are used to establish a TLS handshake for requests that match the hostname of the associated listener. \n A single CertificateRef to a Kubernetes Secret has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a Listener, but this behavior is implementation-specific. \n References to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason. \n This field is required to have at least one element when the mode is set to \"Terminate\" (default) and is optional otherwise. \n CertificateRefs can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources. \n Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls \n Support: Implementation-specific (More than one reference or other resource types)" - items: - description: "SecretObjectReference identifies an API object including its namespace, defaulting to Secret. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid. \n References to objects with invalid Group and Kind are not valid, and must be rejected by the implementation, with appropriate Conditions set on the containing object." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Secret - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - name - type: object - maxItems: 64 - type: array - mode: - default: Terminate - description: "Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes: \n - Terminate: The TLS session between the downstream client and the Gateway is terminated at the Gateway. This mode requires certificateRefs to be set and contain at least one element. - Passthrough: The TLS session is NOT terminated by the Gateway. This implies that the Gateway can't decipher the TLS stream except for the ClientHello message of the TLS protocol. CertificateRefs field is ignored in this mode. \n Support: Core" - enum: - - Terminate - - Passthrough - type: string - options: - additionalProperties: - description: AnnotationValue is the value of an annotation in Gateway API. This is used for validation of maps such as TLS options. This roughly matches Kubernetes annotation validation, although the length validation in that case is based on the entire size of the annotations struct. - maxLength: 4096 - minLength: 0 - type: string - description: "Options are a list of key/value pairs to enable extended TLS configuration for each implementation. For example, configuring the minimum TLS version or supported cipher suites. \n A set of common keys MAY be defined by the API in the future. To avoid any ambiguity, implementation-specific definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. Un-prefixed names are reserved for key names defined by Gateway API. \n Support: Implementation-specific" - maxProperties: 16 - type: object - type: object - required: - - name - - port - - protocol - type: object - maxItems: 64 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - gatewayClassName - - listeners - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: Unknown - type: Accepted - description: Status defines the current state of Gateway. - properties: - addresses: - description: Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address from a reserved pool. - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Programmed - description: "Conditions describe the current conditions of the Gateway. \n Implementations should prefer to express Gateway conditions using the `GatewayConditionType` and `GatewayConditionReason` constants so that operators and tools can converge on a common vocabulary to describe Gateway state. \n Known condition types are: \n * \"Accepted\" * \"Ready\"" - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - listeners: - description: Listeners provide status for each unique listener port defined in the Spec. - items: - description: ListenerStatus is the status associated with a Listener. - properties: - attachedRoutes: - description: AttachedRoutes represents the total number of Routes that have been successfully attached to this Listener. - format: int32 - type: integer - conditions: - description: Conditions describe the current condition of this listener. - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - name: - description: Name is the name of the Listener that this status corresponds to. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - supportedKinds: - description: "SupportedKinds is the list indicating the Kinds supported by this listener. This MUST represent the kinds an implementation supports for that Listener configuration. \n If kinds are specified in Spec that are not supported, they MUST NOT appear in this list and an implementation MUST set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" reason. If both valid and invalid Route kinds are specified, the implementation MUST reference the valid Route kinds that have been specified." - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - required: - - attachedRoutes - - conditions - - name - - supportedKinds - type: object - maxItems: 64 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.gatewayClassName - name: Class - type: string - - jsonPath: .status.addresses[*].value - name: Address - type: string - - jsonPath: .status.conditions[?(@.type=="Programmed")].status - name: Programmed - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1beta1 - schema: - openAPIV3Schema: - description: Gateway represents an instance of a service-traffic handling infrastructure by binding Listeners to a set of IP addresses. - 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 Gateway. - properties: - addresses: - description: "Addresses requested for this Gateway. This is optional and behavior can depend on the implementation. If a value is set in the spec and the requested address is invalid or unavailable, the implementation MUST indicate this in the associated entry in GatewayStatus.Addresses. \n The Addresses field represents a request for the address(es) on the \"outside of the Gateway\", that traffic bound for this Gateway will use. This could be the IP address or hostname of an external load balancer or other networking infrastructure, or some other address that traffic will be sent to. \n The .listener.hostname field is used to route traffic that has already arrived at the Gateway to the correct in-cluster destination. \n If no Addresses are specified, the implementation MAY schedule the Gateway in an implementation-specific manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. \n Support: Extended" - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - gatewayClassName: - description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. - maxLength: 253 - minLength: 1 - type: string - listeners: - description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At least one Listener MUST be specified. \n Each listener in a Gateway must have a unique combination of Hostname, Port, and Protocol. \n An implementation MAY group Listeners by Port and then collapse each group of Listeners into a single Listener if the implementation determines that the Listeners in the group are \"compatible\". An implementation MAY also group together and collapse compatible Listeners belonging to different Gateways. \n For example, an implementation might consider Listeners to be compatible with each other if all of the following conditions are met: \n 1. Either each Listener within the group specifies the \"HTTP\" Protocol or each Listener within the group specifies either the \"HTTPS\" or \"TLS\" Protocol. \n 2. Each Listener within the group specifies a Hostname that is unique within the group. \n 3. As a special case, one Listener within a group may omit Hostname, in which case this Listener matches when no other Listener matches. \n If the implementation does collapse compatible Listeners, the hostname provided in the incoming client request MUST be matched to a Listener to find the correct set of Routes. The incoming hostname MUST be matched using the Hostname field for each Listener in order of most to least specific. That is, exact matches must be processed before wildcard matches. \n If this field specifies multiple Listeners that have the same Port value but are not compatible, the implementation must raise a \"Conflicted\" condition in the Listener status. \n Support: Core" - items: - description: Listener embodies the concept of a logical endpoint where a Gateway accepts network connections. - properties: - allowedRoutes: - default: - namespaces: - from: Same - description: "AllowedRoutes defines the types of routes that MAY be attached to a Listener and the trusted namespaces where those Route resources MAY be present. \n Although a client request may match multiple route rules, only one rule may ultimately receive the request. Matching precedence MUST be determined in order of the following criteria: \n * The most specific match as defined by the Route type. * The oldest Route based on creation timestamp. For example, a Route with a creation timestamp of \"2020-09-08 01:02:03\" is given precedence over a Route with a creation timestamp of \"2020-09-08 01:02:04\". * If everything else is equivalent, the Route appearing first in alphabetical order (namespace/name) should be given precedence. For example, foo/bar is given precedence over foo/baz. \n All valid rules within a Route attached to this Listener should be implemented. Invalid Route rules can be ignored (sometimes that will mean the full Route). If a Route rule transitions from valid to invalid, support for that Route rule should be dropped to ensure consistency. For example, even if a filter specified by a Route rule is invalid, the rest of the rules within that Route should still be supported. \n Support: Core" - properties: - kinds: - description: "Kinds specifies the groups and kinds of Routes that are allowed to bind to this Gateway Listener. When unspecified or empty, the kinds of Routes selected are determined using the Listener protocol. \n A RouteGroupKind MUST correspond to kinds of Routes that are compatible with the application protocol specified in the Listener's Protocol field. If an implementation does not support or recognize this resource type, it MUST set the \"ResolvedRefs\" condition to False for this Listener with the \"InvalidRouteKinds\" reason. \n Support: Core" - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - namespaces: - default: - from: Same - description: "Namespaces indicates namespaces from which Routes may be attached to this Listener. This is restricted to the namespace of this Gateway by default. \n Support: Core" - properties: - from: - default: Same - description: "From indicates where Routes will be selected for this Gateway. Possible values are: * All: Routes in all namespaces may be used by this Gateway. * Selector: Routes in namespaces selected by the selector may be used by this Gateway. * Same: Only Routes in the same namespace may be used by this Gateway. \n Support: Core" - enum: - - All - - Selector - - Same - type: string - selector: - description: "Selector must be specified when From is set to \"Selector\". In that case, only Routes in Namespaces matching this Selector will be selected by this Gateway. This field is ignored for other values of \"From\". \n Support: Core" - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - type: object - type: object - hostname: - description: "Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified, all hostnames are matched. This field is ignored for protocols that don't require hostname based matching. \n Implementations MUST apply Hostname matching appropriately for each of the following protocols: \n * TLS: The Listener Hostname MUST match the SNI. * HTTP: The Listener Hostname MUST match the Host header of the request. * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP protocol layers as described above. If an implementation does not ensure that both the SNI and Host header match the Listener hostname, it MUST clearly document that. \n For HTTPRoute and TLSRoute resources, there is an interaction with the `spec.hostnames` array. When both listener and route specify hostnames, there MUST be an intersection between the values for a Route to be accepted. For more information, refer to the Route specific Hostnames documentation. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - name: - description: "Name is the name of the Listener. This name MUST be unique within a Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - port: - description: "Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - description: "Protocol specifies the network protocol this listener expects to receive. \n Support: Core" - maxLength: 255 - minLength: 1 - pattern: ^[a-zA-Z0-9]([-a-zSA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ - type: string - tls: - description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\". \n The association of SNIs to Certificate defined in GatewayTLSConfig is defined based on the Hostname field for this listener. \n The GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake. \n Support: Core" - properties: - certificateRefs: - description: "CertificateRefs contains a series of references to Kubernetes objects that contains TLS certificates and private keys. These certificates are used to establish a TLS handshake for requests that match the hostname of the associated listener. \n A single CertificateRef to a Kubernetes Secret has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a Listener, but this behavior is implementation-specific. \n References to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason. \n This field is required to have at least one element when the mode is set to \"Terminate\" (default) and is optional otherwise. \n CertificateRefs can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources. \n Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls \n Support: Implementation-specific (More than one reference or other resource types)" - items: - description: "SecretObjectReference identifies an API object including its namespace, defaulting to Secret. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid. \n References to objects with invalid Group and Kind are not valid, and must be rejected by the implementation, with appropriate Conditions set on the containing object." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Secret - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - name - type: object - maxItems: 64 - type: array - mode: - default: Terminate - description: "Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes: \n - Terminate: The TLS session between the downstream client and the Gateway is terminated at the Gateway. This mode requires certificateRefs to be set and contain at least one element. - Passthrough: The TLS session is NOT terminated by the Gateway. This implies that the Gateway can't decipher the TLS stream except for the ClientHello message of the TLS protocol. CertificateRefs field is ignored in this mode. \n Support: Core" - enum: - - Terminate - - Passthrough - type: string - options: - additionalProperties: - description: AnnotationValue is the value of an annotation in Gateway API. This is used for validation of maps such as TLS options. This roughly matches Kubernetes annotation validation, although the length validation in that case is based on the entire size of the annotations struct. - maxLength: 4096 - minLength: 0 - type: string - description: "Options are a list of key/value pairs to enable extended TLS configuration for each implementation. For example, configuring the minimum TLS version or supported cipher suites. \n A set of common keys MAY be defined by the API in the future. To avoid any ambiguity, implementation-specific definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. Un-prefixed names are reserved for key names defined by Gateway API. \n Support: Implementation-specific" - maxProperties: 16 - type: object - type: object - required: - - name - - port - - protocol - type: object - maxItems: 64 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - gatewayClassName - - listeners - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: Unknown - type: Accepted - description: Status defines the current state of Gateway. - properties: - addresses: - description: Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address from a reserved pool. - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Programmed - description: "Conditions describe the current conditions of the Gateway. \n Implementations should prefer to express Gateway conditions using the `GatewayConditionType` and `GatewayConditionReason` constants so that operators and tools can converge on a common vocabulary to describe Gateway state. \n Known condition types are: \n * \"Accepted\" * \"Ready\"" - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - listeners: - description: Listeners provide status for each unique listener port defined in the Spec. - items: - description: ListenerStatus is the status associated with a Listener. - properties: - attachedRoutes: - description: AttachedRoutes represents the total number of Routes that have been successfully attached to this Listener. - format: int32 - type: integer - conditions: - description: Conditions describe the current condition of this listener. - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - name: - description: Name is the name of the Listener that this status corresponds to. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - supportedKinds: - description: "SupportedKinds is the list indicating the Kinds supported by this listener. This MUST represent the kinds an implementation supports for that Listener configuration. \n If kinds are specified in Spec that are not supported, they MUST NOT appear in this list and an implementation MUST set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" reason. If both valid and invalid Route kinds are specified, the implementation MUST reference the valid Route kinds that have been specified." - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - required: - - attachedRoutes - - conditions - - name - - supportedKinds - type: object - maxItems: 64 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-grpcroutes.yaml b/charts/consul/templates/crd-grpcroutes.yaml deleted file mode 100644 index 3e4aa75853..0000000000 --- a/charts/consul/templates/crd-grpcroutes.yaml +++ /dev/null @@ -1,769 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: grpcroutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: GRPCRoute - listKind: GRPCRouteList - plural: grpcroutes - singular: grpcroute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "GRPCRoute provides a way to route gRPC requests. This includes the capability to match requests by hostname, gRPC service, gRPC method, or HTTP/2 header. Filters can be used to specify additional processing steps. Backends specify where matching requests will be routed. \n GRPCRoute falls under extended support within the Gateway API. Within the following specification, the word \"MUST\" indicates that an implementation supporting GRPCRoute must conform to the indicated requirement, but an implementation not supporting this route type need not follow the requirement unless explicitly indicated. \n Implementations supporting `GRPCRoute` with the `HTTPS` `ProtocolType` MUST accept HTTP/2 connections without an initial upgrade from HTTP/1.1, i.e. via ALPN. If the implementation does not support this, then it MUST set the \"Accepted\" condition to \"False\" for the affected listener with a reason of \"UnsupportedProtocol\". Implementations MAY also accept HTTP/2 connections with an upgrade from HTTP/1. \n Implementations supporting `GRPCRoute` with the `HTTP` `ProtocolType` MUST support HTTP/2 over cleartext TCP (h2c, https://www.rfc-editor.org/rfc/rfc7540#section-3.1) without an initial upgrade from HTTP/1.1, i.e. with prior knowledge (https://www.rfc-editor.org/rfc/rfc7540#section-3.4). If the implementation does not support this, then it MUST set the \"Accepted\" condition to \"False\" for the affected listener with a reason of \"UnsupportedProtocol\". Implementations MAY also accept HTTP/2 connections with an upgrade from HTTP/1, i.e. without prior knowledge. \n Support: Extended" - 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 GRPCRoute. - properties: - hostnames: - description: "Hostnames defines a set of hostnames to match against the GRPC Host header to select a GRPCRoute to process the request. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label MUST appear by itself as the first label. \n If a hostname is specified by both the Listener and GRPCRoute, there MUST be at least one intersecting hostname for the GRPCRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches GRPCRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches GRPCRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `test.example.com` and `*.example.com` would both match. On the other hand, `example.com` and `test.example.net` would not match. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n If both the Listener and GRPCRoute have specified hostnames, any GRPCRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the GRPCRoute specified `test.example.com` and `test.example.net`, `test.example.net` MUST NOT be considered for a match. \n If both the Listener and GRPCRoute have specified hostnames, and none match with the criteria above, then the GRPCRoute MUST NOT be accepted by the implementation. The implementation MUST raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n If a Route (A) of type HTTPRoute or GRPCRoute is attached to a Listener and that listener already has another Route (B) of the other type attached and the intersection of the hostnames of A and B is non-empty, then the implementation MUST accept exactly one of these two routes, determined by the following criteria, in order: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n The rejected Route MUST raise an 'Accepted' condition with a status of 'False' in the corresponding RouteParentStatus. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - default: - - matches: - - method: - type: Exact - description: Rules are a list of GRPC matchers, filters and actions. - items: - description: GRPCRouteRule defines the semantics for matching an gRPC request based on conditions (matches), processing it (filters), and forwarding the request to an API object (backendRefs). - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. \n Failure behavior here depends on how many BackendRefs are specified and how many are invalid. \n If *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive an `UNAVAILABLE` status. \n See the GRPCBackendRef definition for the rules about what makes a single GRPCBackendRef invalid. \n When a GRPCBackendRef is invalid, `UNAVAILABLE` statuses MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive an `UNAVAILABLE` status. \n For example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic MUST receive an `UNAVAILABLE` status. Implementations may choose how that 50 percent is determined. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Core" - items: - description: GRPCBackendRef defines how a GRPCRoute forwards a gRPC request. - properties: - filters: - description: "Filters defined at this level MUST be executed if and only if the request is being forwarded to the backend defined here. \n Support: Implementation-specific (For broader support of filters, use the Filters field in GRPCRouteRule.)" - items: - description: GRPCRouteFilter defines processing steps that must be completed during the request or response lifecycle. GRPCRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations supporting GRPCRoute MUST support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` MUST be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n " - enum: - - ResponseHeaderModifier - - RequestHeaderModifier - - RequestMirror - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - type: array - filters: - description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: \n - ALL core filters MUST be supported by all implementations that support GRPCRoute. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or implementation-specific conformance. Support: Core" - items: - description: GRPCRouteFilter defines processing steps that must be completed during the request or response lifecycle. GRPCRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations supporting GRPCRoute MUST support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` MUST be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n " - enum: - - ResponseHeaderModifier - - RequestHeaderModifier - - RequestMirror - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - matches: - default: - - method: - type: Exact - description: "Matches define conditions used for matching the rule against incoming gRPC requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - method: service: foo.bar headers: values: version: 2 - method: service: foo.bar.v2 ``` \n For a request to match against this rule, it MUST satisfy EITHER of the two conditions: \n - service of foo.bar AND contains the header `version: 2` - service of foo.bar.v2 \n See the documentation for GRPCRouteMatch on how to specify multiple match conditions to be ANDed together. \n If no matches are specified, the implementation MUST match every gRPC request. \n Proxy or Load Balancer routing configuration generated from GRPCRoutes MUST prioritize rules based on the following criteria, continuing on ties. Merging MUST not be done between GRPCRoutes and HTTPRoutes. Precedence MUST be given to the rule with the largest number of: \n * Characters in a matching non-wildcard hostname. * Characters in a matching hostname. * Characters in a matching service. * Characters in a matching method. * Header matches. \n If ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n If ties still exist within the Route that has been given precedence, matching precedence MUST be granted to the first matching rule meeting the above criteria." - items: - description: "GRPCRouteMatch defines the predicate used to match requests to a given action. Multiple match types are ANDed together, i.e. the match will evaluate to true only if all conditions are satisfied. \n For example, the match below will match a gRPC request only if its service is `foo` AND it contains the `version: v1` header: \n ``` matches: - method: type: Exact service: \"foo\" headers: - name: \"version\" value \"v1\" \n ```" - properties: - headers: - description: Headers specifies gRPC request header matchers. Multiple match values are ANDed together, meaning, a request MUST match all the specified headers to select the route. - items: - description: GRPCHeaderMatch describes how to select a gRPC route by matching gRPC request headers. - properties: - name: - description: "Name is the name of the gRPC Header to be matched. \n If multiple entries specify equivalent header names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: Type specifies how to match against the value of the header. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of the gRPC Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - method: - default: - type: Exact - description: Method specifies a gRPC request service/method matcher. If this field is not specified, all services and methods will match. - properties: - method: - description: "Value of the method to match against. If left empty or omitted, will match all services. \n At least one of Service and Method MUST be a non-empty string. \n A GRPC Method must be a valid Protobuf Method (https://protobuf.com/docs/language-spec#methods)." - maxLength: 1024 - pattern: ^[A-Za-z_][A-Za-z_0-9]*$ - type: string - service: - description: "Value of the service to match against. If left empty or omitted, will match any service. \n At least one of Service and Method MUST be a non-empty string. \n A GRPC Service must be a valid Protobuf Type Name (https://protobuf.com/docs/language-spec#type-references)." - maxLength: 1024 - pattern: ^(?i)\.?[a-z_][a-z_0-9]*(\.[a-z_][a-z_0-9]*)*$ - type: string - type: - default: Exact - description: "Type specifies how to match against the service and/or method. Support: Core (Exact with service and method specified) \n Support: Implementation-specific (Exact with method specified but no service specified) \n Support: Implementation-specific (RegularExpression)" - enum: - - Exact - - RegularExpression - type: string - type: object - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - type: object - status: - description: Status defines the current state of GRPCRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-httproutes.yaml b/charts/consul/templates/crd-httproutes.yaml deleted file mode 100644 index c89591376a..0000000000 --- a/charts/consul/templates/crd-httproutes.yaml +++ /dev/null @@ -1,1917 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: httproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: HTTPRoute - listKind: HTTPRouteList - plural: httproutes - singular: httproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - deprecated: true - deprecationWarning: The v1alpha2 version of HTTPRoute has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1. - name: v1alpha2 - schema: - openAPIV3Schema: - description: HTTPRoute provides a way to route HTTP requests. This includes the capability to match requests by hostname, path, header, or query param. Filters can be used to specify additional processing steps. Backends specify where matching requests should be routed. - 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 HTTPRoute. - properties: - hostnames: - description: "Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n If a hostname is specified by both the Listener and HTTPRoute, there must be at least one intersecting hostname for the HTTPRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `*.example.com`, `test.example.com`, and `foo.test.example.com` would all match. On the other hand, `example.com` and `test.example.net` would not match. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n If both the Listener and HTTPRoute have specified hostnames, any HTTPRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the HTTPRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match. \n If both the Listener and HTTPRoute have specified hostnames, and none match with the criteria above, then the HTTPRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. overlapping wildcard matching and exact matching hostnames), precedence must be given to rules from the HTTPRoute with the largest number of: \n * Characters in a matching non-wildcard hostname. * Characters in a matching hostname. \n If ties exist across multiple Routes, the matching precedence rules for HTTPRouteMatches takes over. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - default: - - matches: - - path: - type: PathPrefix - value: / - description: Rules are a list of HTTP matchers, filters and actions. - items: - description: HTTPRouteRule defines semantics for matching an HTTP request based on conditions (matches), processing it (filters), and forwarding the request to an API object (backendRefs). - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. \n Failure behavior here depends on how many BackendRefs are specified and how many are invalid. \n If *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive a 500 status code. \n See the HTTPBackendRef definition for the rules about what makes a single HTTPBackendRef invalid. \n When a HTTPBackendRef is invalid, 500 status codes MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive a 500 status code. \n For example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic must receive a 500. Implementations may choose how that 50 percent is determined. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Core" - items: - description: HTTPBackendRef defines how a HTTPRoute should forward an HTTP request. - properties: - filters: - description: "Filters defined at this level should be executed if and only if the request is being forwarded to the backend defined here. \n Support: Implementation-specific (For broader support of filters, use the Filters field in HTTPRouteRule.)" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - type: array - filters: - description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: \n - ALL core filters MUST be supported by all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or implementation-specific conformance. \n All filters are expected to be compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In all cases where incompatible or unsupported filters are specified, implementations MUST add a warning condition to status. \n Support: Core" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - default: - - path: - type: PathPrefix - value: / - description: "Matches define conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - path: value: \"/foo\" headers: - name: \"version\" value: \"v2\" - path: value: \"/v2/foo\" ``` \n For a request to match against this rule, a request must satisfy EITHER of the two conditions: \n - path prefixed with `/foo` AND contains the header `version: v2` - path prefix of `/v2/foo` \n See the documentation for HTTPRouteMatch on how to specify multiple match conditions that should be ANDed together. \n If no matches are specified, the default is a prefix path match on \"/\", which has the effect of matching every HTTP request. \n Proxy or Load Balancer routing configuration generated from HTTPRoutes MUST prioritize matches based on the following criteria, continuing on ties. Across all rules specified on applicable Routes, precedence must be given to the match with the largest number of: \n * Characters in a matching path. * Header matches. * Query param matches. \n If ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n If ties still exist within an HTTPRoute, matching precedence MUST be granted to the FIRST matching rule (in list order) with a match meeting the above criteria. \n When no rules matching a request have been successfully attached to the parent a request is coming from, a HTTP 404 status code MUST be returned." - items: - description: "HTTPRouteMatch defines the predicate used to match requests to a given action. Multiple match types are ANDed together, i.e. the match will evaluate to true only if all conditions are satisfied. \n For example, the match below will match a HTTP request only if its path starts with `/foo` AND it contains the `version: v1` header: \n ``` match: \n \tpath: \t value: \"/foo\" \theaders: \t- name: \"version\" \t value \"v1\" \n ```" - properties: - headers: - description: Headers specifies HTTP request header matchers. Multiple match values are ANDed together, meaning, a request must match all the specified headers to select the route. - items: - description: HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request headers. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent. \n When a header is repeated in an HTTP request, it is implementation-specific behavior as to how this is represented. Generally, proxies should follow the guidance from the RFC: https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding processing a repeated header, with special handling for \"Set-Cookie\"." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the header. \n Support: Core (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression HeaderMatchType has implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - method: - description: "Method specifies HTTP method matcher. When specified, this route will be matched only if the request has the specified method. \n Support: Extended" - enum: - - GET - - HEAD - - POST - - PUT - - DELETE - - CONNECT - - OPTIONS - - TRACE - - PATCH - type: string - path: - default: - type: PathPrefix - value: / - description: Path specifies a HTTP request path matcher. If this field is not specified, a default prefix match on the "/" path is provided. - properties: - type: - default: PathPrefix - description: "Type specifies how to match against the path Value. \n Support: Core (Exact, PathPrefix) \n Support: Implementation-specific (RegularExpression)" - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, meaning, a request must match all the specified query parameters to select the route. \n Support: Extended" - items: - description: HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP query parameters. - properties: - name: - description: "Name is the name of the HTTP query param to be matched. This must be an exact string match. (See https://tools.ietf.org/html/rfc7230#section-2.7.3). \n If multiple entries specify equivalent query param names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent query param name MUST be ignored. \n If a query param is repeated in an HTTP request, the behavior is purposely left undefined, since different data planes have different capabilities. However, it is *recommended* that implementations should match against the first value of the param if the data plane supports it, as this behavior is expected in other load balancing contexts outside of the Gateway API. \n Users SHOULD NOT route traffic based on repeated query params to guard themselves against potential differences in the implementations." - maxLength: 256 - minLength: 1 - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the query parameter. \n Support: Extended (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression QueryParamMatchType has Implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - type: object - status: - description: Status defines the current state of HTTPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1beta1 - schema: - openAPIV3Schema: - description: HTTPRoute provides a way to route HTTP requests. This includes the capability to match requests by hostname, path, header, or query param. Filters can be used to specify additional processing steps. Backends specify where matching requests should be routed. - 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 HTTPRoute. - properties: - hostnames: - description: "Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n If a hostname is specified by both the Listener and HTTPRoute, there must be at least one intersecting hostname for the HTTPRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `*.example.com`, `test.example.com`, and `foo.test.example.com` would all match. On the other hand, `example.com` and `test.example.net` would not match. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n If both the Listener and HTTPRoute have specified hostnames, any HTTPRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the HTTPRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match. \n If both the Listener and HTTPRoute have specified hostnames, and none match with the criteria above, then the HTTPRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. overlapping wildcard matching and exact matching hostnames), precedence must be given to rules from the HTTPRoute with the largest number of: \n * Characters in a matching non-wildcard hostname. * Characters in a matching hostname. \n If ties exist across multiple Routes, the matching precedence rules for HTTPRouteMatches takes over. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - default: - - matches: - - path: - type: PathPrefix - value: / - description: Rules are a list of HTTP matchers, filters and actions. - items: - description: HTTPRouteRule defines semantics for matching an HTTP request based on conditions (matches), processing it (filters), and forwarding the request to an API object (backendRefs). - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. \n Failure behavior here depends on how many BackendRefs are specified and how many are invalid. \n If *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive a 500 status code. \n See the HTTPBackendRef definition for the rules about what makes a single HTTPBackendRef invalid. \n When a HTTPBackendRef is invalid, 500 status codes MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive a 500 status code. \n For example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic must receive a 500. Implementations may choose how that 50 percent is determined. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Core" - items: - description: HTTPBackendRef defines how a HTTPRoute should forward an HTTP request. - properties: - filters: - description: "Filters defined at this level should be executed if and only if the request is being forwarded to the backend defined here. \n Support: Implementation-specific (For broader support of filters, use the Filters field in HTTPRouteRule.)" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - type: array - filters: - description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: \n - ALL core filters MUST be supported by all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or implementation-specific conformance. \n All filters are expected to be compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In all cases where incompatible or unsupported filters are specified, implementations MUST add a warning condition to status. \n Support: Core" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - default: - - path: - type: PathPrefix - value: / - description: "Matches define conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - path: value: \"/foo\" headers: - name: \"version\" value: \"v2\" - path: value: \"/v2/foo\" ``` \n For a request to match against this rule, a request must satisfy EITHER of the two conditions: \n - path prefixed with `/foo` AND contains the header `version: v2` - path prefix of `/v2/foo` \n See the documentation for HTTPRouteMatch on how to specify multiple match conditions that should be ANDed together. \n If no matches are specified, the default is a prefix path match on \"/\", which has the effect of matching every HTTP request. \n Proxy or Load Balancer routing configuration generated from HTTPRoutes MUST prioritize matches based on the following criteria, continuing on ties. Across all rules specified on applicable Routes, precedence must be given to the match with the largest number of: \n * Characters in a matching path. * Header matches. * Query param matches. \n If ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n If ties still exist within an HTTPRoute, matching precedence MUST be granted to the FIRST matching rule (in list order) with a match meeting the above criteria. \n When no rules matching a request have been successfully attached to the parent a request is coming from, a HTTP 404 status code MUST be returned." - items: - description: "HTTPRouteMatch defines the predicate used to match requests to a given action. Multiple match types are ANDed together, i.e. the match will evaluate to true only if all conditions are satisfied. \n For example, the match below will match a HTTP request only if its path starts with `/foo` AND it contains the `version: v1` header: \n ``` match: \n \tpath: \t value: \"/foo\" \theaders: \t- name: \"version\" \t value \"v1\" \n ```" - properties: - headers: - description: Headers specifies HTTP request header matchers. Multiple match values are ANDed together, meaning, a request must match all the specified headers to select the route. - items: - description: HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request headers. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent. \n When a header is repeated in an HTTP request, it is implementation-specific behavior as to how this is represented. Generally, proxies should follow the guidance from the RFC: https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding processing a repeated header, with special handling for \"Set-Cookie\"." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the header. \n Support: Core (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression HeaderMatchType has implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - method: - description: "Method specifies HTTP method matcher. When specified, this route will be matched only if the request has the specified method. \n Support: Extended" - enum: - - GET - - HEAD - - POST - - PUT - - DELETE - - CONNECT - - OPTIONS - - TRACE - - PATCH - type: string - path: - default: - type: PathPrefix - value: / - description: Path specifies a HTTP request path matcher. If this field is not specified, a default prefix match on the "/" path is provided. - properties: - type: - default: PathPrefix - description: "Type specifies how to match against the path Value. \n Support: Core (Exact, PathPrefix) \n Support: Implementation-specific (RegularExpression)" - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, meaning, a request must match all the specified query parameters to select the route. \n Support: Extended" - items: - description: HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP query parameters. - properties: - name: - description: "Name is the name of the HTTP query param to be matched. This must be an exact string match. (See https://tools.ietf.org/html/rfc7230#section-2.7.3). \n If multiple entries specify equivalent query param names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent query param name MUST be ignored. \n If a query param is repeated in an HTTP request, the behavior is purposely left undefined, since different data planes have different capabilities. However, it is *recommended* that implementations should match against the first value of the param if the data plane supports it, as this behavior is expected in other load balancing contexts outside of the Gateway API. \n Users SHOULD NOT route traffic based on repeated query params to guard themselves against potential differences in the implementations." - maxLength: 256 - minLength: 1 - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the query parameter. \n Support: Extended (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression QueryParamMatchType has Implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - type: object - status: - description: Status defines the current state of HTTPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-ingressgateways.yaml b/charts/consul/templates/crd-ingressgateways.yaml index 098d7a71b7..67884ca040 100644 --- a/charts/consul/templates/crd-ingressgateways.yaml +++ b/charts/consul/templates/crd-ingressgateways.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: ingressgateways.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: ingressgateways.consul.hashicorp.com spec: group: consul.hashicorp.com names: diff --git a/charts/consul/templates/crd-jwtproviders.yaml b/charts/consul/templates/crd-jwtproviders.yaml deleted file mode 100644 index 18b6e9bdcb..0000000000 --- a/charts/consul/templates/crd-jwtproviders.yaml +++ /dev/null @@ -1,268 +0,0 @@ -{{- if .Values.connectInject.enabled }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: jwtproviders.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: JWTProvider - listKind: JWTProviderList - plural: jwtproviders - singular: jwtprovider - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: JWTProvider is the Schema for the jwtproviders API. - 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: JWTProviderSpec defines the desired state of JWTProvider - properties: - audiences: - description: Audiences is the set of audiences the JWT is allowed - to access. If specified, all JWTs verified with this provider must - address at least one of these to be considered valid. - items: - type: string - type: array - cacheConfig: - description: CacheConfig defines configuration for caching the validation - result for previously seen JWTs. Caching results can speed up verification - when individual tokens are expected to be handled multiple times. - properties: - size: - description: "Size specifies the maximum number of JWT verification - results to cache. \n Defaults to 0, meaning that JWT caching - is disabled." - type: integer - type: object - clockSkewSeconds: - description: "ClockSkewSeconds specifies the maximum allowable time - difference from clock skew when validating the \"exp\" (Expiration) - and \"nbf\" (Not Before) claims. \n Default value is 30 seconds." - type: integer - forwarding: - description: Forwarding defines rules for forwarding verified JWTs - to the backend. - properties: - headerName: - description: "HeaderName is a header name to use when forwarding - a verified JWT to the backend. The verified JWT could have been - extracted from any location (query param, header, or cookie). - \n The header value will be base64-URL-encoded, and will not - be padded unless PadForwardPayloadHeader is true." - type: string - padForwardPayloadHeader: - description: "PadForwardPayloadHeader determines whether padding - should be added to the base64 encoded token forwarded with ForwardPayloadHeader. - \n Default value is false." - type: boolean - type: object - issuer: - description: Issuer is the entity that must have issued the JWT. This - value must match the "iss" claim of the token. - type: string - jsonWebKeySet: - description: JSONWebKeySet defines a JSON Web Key Set, its location - on disk, or the means with which to fetch a key set from a remote - server. - properties: - local: - description: Local specifies a local source for the key set. - properties: - filename: - description: Filename configures a location on disk where - the JWKS can be found. If specified, the file must be present - on the disk of ALL proxies with intentions referencing this - provider. - type: string - jwks: - description: JWKS contains a base64 encoded JWKS. - type: string - type: object - remote: - description: Remote specifies how to fetch a key set from a remote - server. - properties: - cacheDuration: - description: "CacheDuration is the duration after which cached - keys should be expired. \n Default value is 5 minutes." - format: int64 - type: integer - fetchAsynchronously: - description: "FetchAsynchronously indicates that the JWKS - should be fetched when a client request arrives. Client - requests will be paused until the JWKS is fetched. If false, - the proxy listener will wait for the JWKS to be fetched - before being activated. \n Default value is false." - type: boolean - requestTimeoutMs: - description: RequestTimeoutMs is the number of milliseconds - to time out when making a request for the JWKS. - type: integer - retryPolicy: - description: "RetryPolicy defines a retry policy for fetching - JWKS. \n There is no retry by default." - properties: - numRetries: - description: "NumRetries is the number of times to retry - fetching the JWKS. The retry strategy uses jittered - exponential backoff with a base interval of 1s and max - of 10s. \n Default value is 0." - type: integer - retryPolicyBackOff: - description: "Backoff policy \n Defaults to Envoy's backoff - policy" - properties: - baseInterval: - description: "BaseInterval to be used for the next - back off computation \n The default value from envoy - is 1s" - format: int64 - type: integer - maxInterval: - description: "MaxInternal to be used to specify the - maximum interval between retries. Optional but should - be greater or equal to BaseInterval. \n Defaults - to 10 times BaseInterval" - format: int64 - type: integer - type: object - type: object - uri: - description: URI is the URI of the server to query for the - JWKS. - type: string - type: object - type: object - locations: - description: 'Locations where the JWT will be present in requests. - Envoy will check all of these locations to extract a JWT. If no - locations are specified Envoy will default to: 1. Authorization - header with Bearer schema: "Authorization: Bearer " 2. accessToken - query parameter.' - items: - description: "JWTLocation is a location where the JWT could be present - in requests. \n Only one of Header, QueryParam, or Cookie can - be specified." - properties: - cookie: - description: Cookie defines how to extract a JWT from an HTTP - request cookie. - properties: - name: - description: Name is the name of the cookie containing the - token. - type: string - type: object - header: - description: Header defines how to extract a JWT from an HTTP - request header. - properties: - forward: - description: "Forward defines whether the header with the - JWT should be forwarded after the token has been verified. - If false, the header will not be forwarded to the backend. - \n Default value is false." - type: boolean - name: - description: Name is the name of the header containing the - token. - type: string - valuePrefix: - description: 'ValuePrefix is an optional prefix that precedes - the token in the header value. For example, "Bearer " - is a standard value prefix for a header named "Authorization", - but the prefix is not part of the token itself: "Authorization: - Bearer "' - type: string - type: object - queryParam: - description: QueryParam defines how to extract a JWT from an - HTTP request query parameter. - properties: - name: - description: Name is the name of the query param containing - the token. - type: string - type: object - type: object - type: array - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-meshes.yaml b/charts/consul/templates/crd-meshes.yaml index b1b2319579..2e33eb9653 100644 --- a/charts/consul/templates/crd-meshes.yaml +++ b/charts/consul/templates/crd-meshes.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: meshes.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: meshes.consul.hashicorp.com spec: group: consul.hashicorp.com names: @@ -58,11 +55,6 @@ spec: spec: description: MeshSpec defines the desired state of Mesh. properties: - allowEnablingPermissiveMutualTLS: - description: AllowEnablingPermissiveMutualTLS must be true in order - to allow setting MutualTLSMode=permissive in either service-defaults - or proxy-defaults. - type: boolean http: description: HTTP defines the HTTP configuration for the service mesh. properties: diff --git a/charts/consul/templates/crd-meshservices.yaml b/charts/consul/templates/crd-meshservices.yaml deleted file mode 100644 index d52da5a028..0000000000 --- a/charts/consul/templates/crd-meshservices.yaml +++ /dev/null @@ -1,66 +0,0 @@ -{{- if .Values.connectInject.enabled }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: meshservices.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: MeshService - listKind: MeshServiceList - plural: meshservices - singular: meshservice - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: MeshService holds a reference to an externally managed Consul - Service Mesh service. - 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 MeshService. - properties: - name: - description: Name holds the service name for a Consul service. - type: string - peer: - description: Peer optionally specifies the name of the peer exporting - the Consul service. If not specified, the Consul service is assumed - to be in the local datacenter. - type: string - type: object - type: object - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-peeringacceptors.yaml b/charts/consul/templates/crd-peeringacceptors.yaml index 6f335e83a2..e06e830f04 100644 --- a/charts/consul/templates/crd-peeringacceptors.yaml +++ b/charts/consul/templates/crd-peeringacceptors.yaml @@ -1,21 +1,18 @@ {{- if and .Values.connectInject.enabled .Values.global.peering.enabled }} -# 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.8.0 + creationTimestamp: null + name: peeringacceptors.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: peeringacceptors.consul.hashicorp.com spec: group: consul.hashicorp.com names: diff --git a/charts/consul/templates/crd-peeringdialers.yaml b/charts/consul/templates/crd-peeringdialers.yaml index 5fa49f1eed..e24401e761 100644 --- a/charts/consul/templates/crd-peeringdialers.yaml +++ b/charts/consul/templates/crd-peeringdialers.yaml @@ -1,21 +1,18 @@ {{- if and .Values.connectInject.enabled .Values.global.peering.enabled }} -# 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.8.0 + creationTimestamp: null + name: peeringdialers.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: peeringdialers.consul.hashicorp.com spec: group: consul.hashicorp.com names: diff --git a/charts/consul/templates/crd-proxydefaults.yaml b/charts/consul/templates/crd-proxydefaults.yaml index 8596cc9a6f..e66543637f 100644 --- a/charts/consul/templates/crd-proxydefaults.yaml +++ b/charts/consul/templates/crd-proxydefaults.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: proxydefaults.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: proxydefaults.consul.hashicorp.com spec: group: consul.hashicorp.com names: @@ -60,60 +57,12 @@ spec: spec: description: ProxyDefaultsSpec defines the desired state of ProxyDefaults. properties: - accessLogs: - description: AccessLogs controls all envoy instances' access logging - configuration. - properties: - disableListenerLogs: - description: DisableListenerLogs turns off just listener logs - for connections rejected by Envoy because they don't have a - matching listener filter. - type: boolean - enabled: - description: Enabled turns on all access logging - type: boolean - jsonFormat: - description: 'JSONFormat is a JSON-formatted string of an Envoy - access log format dictionary. See for more info on formatting: - https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#format-dictionaries - Defining JSONFormat and TextFormat is invalid.' - type: string - path: - description: Path is the output file to write logs for file-type - logging - type: string - textFormat: - description: 'TextFormat is a representation of Envoy access logs - format. See for more info on formatting: https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#format-strings - Defining JSONFormat and TextFormat is invalid.' - type: string - type: - description: Type selects the output for logs one of "file", "stderr". - "stdout" - type: string - type: object config: description: Config is an arbitrary map of configuration values used by Connect proxies. Any values that your proxy allows can be configured globally here. Supports JSON config values. See https://www.consul.io/docs/connect/proxies/envoy#configuration-formatting type: object x-kubernetes-preserve-unknown-fields: true - envoyExtensions: - description: EnvoyExtensions are a list of extensions to modify Envoy - proxy configuration. - items: - description: EnvoyExtension has configuration for an extension that - patches Envoy resources. - properties: - arguments: - type: object - x-kubernetes-preserve-unknown-fields: true - name: - type: string - required: - type: boolean - type: object - type: array expose: description: Expose controls the default expose path configuration for Envoy. @@ -146,32 +95,6 @@ spec: type: object type: array type: object - failoverPolicy: - description: FailoverPolicy specifies the exact mechanism used for - failover. - properties: - mode: - description: Mode specifies the type of failover that will be - performed. Valid values are "sequential", "" (equivalent to - "sequential") and "order-by-locality". - type: string - regions: - description: Regions is the ordered list of the regions of the - failover targets. Valid values can be "us-west-1", "us-west-2", - and so on. - items: - type: string - type: array - type: object - prioritizeByLocality: - description: PrioritizeByLocality contains the configuration for - locality aware routing. - properties: - mode: - description: Mode specifies the behavior of PrioritizeByLocality - routing. Valid values are "", "none", and "failover". - type: string - type: object meshGateway: description: MeshGateway controls the default mesh gateway configuration for this service. @@ -192,18 +115,6 @@ spec: CRD and should be set using annotations on the services that are part of the mesh.' type: string - mutualTLSMode: - description: 'MutualTLSMode controls whether mutual TLS is required - for all incoming connections when transparent proxy is enabled. - This can be set to "permissive" or "strict". "strict" is the default - which requires mutual TLS for incoming connections. In the insecure - "permissive" mode, connections to the sidecar proxy public listener - port require mutual TLS, but connections to the service port do - not require mutual TLS and are proxied to the application unmodified. - Note: Intentions are not enforced for non-mTLS connections. To keep - your services secure, we recommend using "strict" mode whenever - possible and enabling "permissive" mode only when necessary.' - type: string transparentProxy: description: 'TransparentProxy controls configuration specific to proxies in transparent mode. Note: This cannot be set using the diff --git a/charts/consul/templates/crd-referencegrants.yaml b/charts/consul/templates/crd-referencegrants.yaml deleted file mode 100644 index 6ae177d987..0000000000 --- a/charts/consul/templates/crd-referencegrants.yaml +++ /dev/null @@ -1,211 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: referencegrants.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: ReferenceGrant - listKind: ReferenceGrantList - plural: referencegrants - shortNames: - - refgrant - singular: referencegrant - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "ReferenceGrant identifies kinds of resources in other namespaces that are trusted to reference the specified kinds of resources in the same namespace as the policy. \n Each ReferenceGrant can be used to represent a unique trust relationship. Additional Reference Grants can be used to add to the set of trusted sources of inbound references for the namespace they are defined within. \n All cross-namespace references in Gateway API (with the exception of cross-namespace Gateway-route attachment) require a ReferenceGrant. \n ReferenceGrant is a form of runtime verification allowing users to assert which cross-namespace object references are permitted. Implementations that support ReferenceGrant MUST NOT permit cross-namespace references which have no grant, and MUST respond to the removal of a grant by revoking the access that the grant allowed. \n Support: Core" - 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 ReferenceGrant. - properties: - from: - description: "From describes the trusted namespaces and kinds that can reference the resources described in \"To\". Each entry in this list MUST be considered to be an additional place that references can be valid from, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantFrom describes trusted namespaces and kinds. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field. \n When used to permit a SecretObjectReference: \n * Gateway \n When used to permit a BackendObjectReference: \n * GRPCRoute * HTTPRoute * TCPRoute * TLSRoute * UDPRoute" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - namespace: - description: "Namespace is the namespace of the referent. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - namespace - type: object - maxItems: 16 - minItems: 1 - type: array - to: - description: "To describes the resources that may be referenced by the resources described in \"From\". Each entry in this list MUST be considered to be an additional place that references can be valid to, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantTo describes what Kinds are allowed as targets of the references. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field: \n * Secret when used to permit a SecretObjectReference * Service when used to permit a BackendObjectReference" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. When unspecified, this policy refers to all resources of the specified Group and Kind in the local namespace. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - from - - to - type: object - type: object - served: true - storage: true - subresources: {} - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1beta1 - schema: - openAPIV3Schema: - description: "ReferenceGrant identifies kinds of resources in other namespaces that are trusted to reference the specified kinds of resources in the same namespace as the policy. \n Each ReferenceGrant can be used to represent a unique trust relationship. Additional Reference Grants can be used to add to the set of trusted sources of inbound references for the namespace they are defined within. \n All cross-namespace references in Gateway API (with the exception of cross-namespace Gateway-route attachment) require a ReferenceGrant. \n ReferenceGrant is a form of runtime verification allowing users to assert which cross-namespace object references are permitted. Implementations that support ReferenceGrant MUST NOT permit cross-namespace references which have no grant, and MUST respond to the removal of a grant by revoking the access that the grant allowed. \n Support: Core" - 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 ReferenceGrant. - properties: - from: - description: "From describes the trusted namespaces and kinds that can reference the resources described in \"To\". Each entry in this list MUST be considered to be an additional place that references can be valid from, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantFrom describes trusted namespaces and kinds. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field. \n When used to permit a SecretObjectReference: \n * Gateway \n When used to permit a BackendObjectReference: \n * GRPCRoute * HTTPRoute * TCPRoute * TLSRoute * UDPRoute" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - namespace: - description: "Namespace is the namespace of the referent. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - namespace - type: object - maxItems: 16 - minItems: 1 - type: array - to: - description: "To describes the resources that may be referenced by the resources described in \"From\". Each entry in this list MUST be considered to be an additional place that references can be valid to, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantTo describes what Kinds are allowed as targets of the references. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field: \n * Secret when used to permit a SecretObjectReference * Service when used to permit a BackendObjectReference" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. When unspecified, this policy refers to all resources of the specified Group and Kind in the local namespace. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - from - - to - type: object - type: object - served: true - storage: false - subresources: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-routeretryfilters.yaml b/charts/consul/templates/crd-routeretryfilters.yaml deleted file mode 100644 index 3c69a5a2ae..0000000000 --- a/charts/consul/templates/crd-routeretryfilters.yaml +++ /dev/null @@ -1,117 +0,0 @@ -{{- if .Values.connectInject.enabled }} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: routeretryfilters.consul.hashicorp.com - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd -spec: - group: consul.hashicorp.com - names: - kind: RouteRetryFilter - listKind: RouteRetryFilterList - plural: routeretryfilters - singular: routeretryfilter - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The last successful synced time of the resource with Consul - jsonPath: .status.lastSyncedTime - name: Last Synced - type: date - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: RouteRetryFilter is the Schema for the routeretryfilters API - 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: RouteRetryFilterSpec defines the desired state of RouteRetryFilter - properties: - numRetries: - format: int32 - minimum: 0 - type: integer - retryOn: - items: - type: string - type: array - retryOnConnectFailure: - type: boolean - retryOnStatusCodes: - items: - format: int32 - type: integer - type: array - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -{{- end }} diff --git a/charts/consul/templates/crd-routetimeoutfilters.yaml b/charts/consul/templates/crd-routetimeoutfilters.yaml deleted file mode 100644 index 992d21b35b..0000000000 --- a/charts/consul/templates/crd-routetimeoutfilters.yaml +++ /dev/null @@ -1,115 +0,0 @@ -{{- if .Values.connectInject.enabled }} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: routetimeoutfilters.consul.hashicorp.com - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd -spec: - group: consul.hashicorp.com - names: - kind: RouteTimeoutFilter - listKind: RouteTimeoutFilterList - plural: routetimeoutfilters - singular: routetimeoutfilter - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The last successful synced time of the resource with Consul - jsonPath: .status.lastSyncedTime - name: Last Synced - type: date - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: RouteTimeoutFilter is the Schema for the httproutetimeoutfilters - API - 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: RouteTimeoutFilterSpec defines the desired state of RouteTimeoutFilter - properties: - idleTimeout: - description: A Duration represents the elapsed time between two instants - as an int64 nanosecond count. The representation limits the largest - representable duration to approximately 290 years. - format: int64 - type: integer - requestTimeout: - description: A Duration represents the elapsed time between two instants - as an int64 nanosecond count. The representation limits the largest - representable duration to approximately 290 years. - format: int64 - type: integer - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -{{- end }} diff --git a/charts/consul/templates/crd-samenessgroups.yaml b/charts/consul/templates/crd-samenessgroups.yaml deleted file mode 100644 index 179972a9d6..0000000000 --- a/charts/consul/templates/crd-samenessgroups.yaml +++ /dev/null @@ -1,140 +0,0 @@ -{{- if .Values.connectInject.enabled }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: samenessgroups.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: SamenessGroup - listKind: SamenessGroupList - plural: samenessgroups - shortNames: - - sameness-group - singular: samenessgroup - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The last successful synced time of the resource with Consul - jsonPath: .status.lastSyncedTime - name: Last Synced - type: date - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: SamenessGroup is the Schema for the samenessgroups API - 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: SamenessGroupSpec defines the desired state of SamenessGroup. - properties: - defaultForFailover: - description: DefaultForFailover indicates that upstream requests to - members of the given sameness group will implicitly failover between - members of this sameness group. When DefaultForFailover is true, - the local partition must be a member of the sameness group or IncludeLocal - must be set to true. - type: boolean - includeLocal: - description: IncludeLocal is used to include the local partition as - the first member of the sameness group. The local partition can - only be a member of a single sameness group. - type: boolean - members: - description: Members are the partitions and peers that are part of - the sameness group. If a member of a sameness group does not exist, - it will be ignored. - items: - properties: - partition: - description: The partitions and peers that are part of the sameness - group. A sameness group member cannot define both peer and - partition at the same time. - type: string - peer: - type: string - type: object - type: array - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-servicedefaults.yaml b/charts/consul/templates/crd-servicedefaults.yaml index a0c26df70b..3b5503eebe 100644 --- a/charts/consul/templates/crd-servicedefaults.yaml +++ b/charts/consul/templates/crd-servicedefaults.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: servicedefaults.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: servicedefaults.consul.hashicorp.com spec: group: consul.hashicorp.com names: @@ -60,12 +57,6 @@ spec: spec: description: ServiceDefaultsSpec defines the desired state of ServiceDefaults. properties: - balanceInboundConnections: - description: BalanceInboundConnections sets the strategy for allocating - inbound connections to the service across proxy threads. The only - supported value is exact_balance. By default, no connection balancing - is used. Refer to the Envoy Connection Balance config for details. - type: string destination: description: Destination is an address(es)/port combination that represents an endpoint outside the mesh. This is only valid when the mesh is @@ -85,22 +76,6 @@ spec: format: int32 type: integer type: object - envoyExtensions: - description: EnvoyExtensions are a list of extensions to modify Envoy - proxy configuration. - items: - description: EnvoyExtension has configuration for an extension that - patches Envoy resources. - properties: - arguments: - type: object - x-kubernetes-preserve-unknown-fields: true - name: - type: string - required: - type: boolean - type: object - type: array expose: description: Expose controls the default expose path configuration for Envoy. @@ -139,15 +114,15 @@ spec: with an external system. type: string localConnectTimeoutMs: - description: LocalConnectTimeoutMs is the number of milliseconds allowed - to make connections to the local application instance before timing - out. Defaults to 5000. + description: The number of milliseconds allowed to make connections + to the local application instance before timing out. Defaults to + 5000. type: integer localRequestTimeoutMs: - description: LocalRequestTimeoutMs is the timeout for HTTP requests - to the local application instance in milliseconds. Applies to HTTP-based - protocols only. If not specified, inherits the Envoy default for - route timeouts (15s). + description: In milliseconds, the timeout for HTTP requests to the + local application instance. Applies to HTTP-based protocols only. + If not specified, inherits the Envoy default for route timeouts + (15s). type: integer maxInboundConnections: description: MaxInboundConnections is the maximum number of concurrent @@ -174,18 +149,6 @@ spec: CRD and should be set using annotations on the services that are part of the mesh.' type: string - mutualTLSMode: - description: 'MutualTLSMode controls whether mutual TLS is required - for all incoming connections when transparent proxy is enabled. - This can be set to "permissive" or "strict". "strict" is the default - which requires mutual TLS for incoming connections. In the insecure - "permissive" mode, connections to the sidecar proxy public listener - port require mutual TLS, but connections to the service port do - not require mutual TLS and are proxied to the application unmodified. - Note: Intentions are not enforced for non-mTLS connections. To keep - your services secure, we recommend using "strict" mode whenever - possible and enabling "permissive" mode only when necessary.' - type: string protocol: description: Protocol sets the protocol of the service. This is used by Connect proxies for things like observability features and to @@ -273,15 +236,15 @@ spec: type: string type: object name: - description: Name is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Name is only accepted within a service-defaults config entry. type: string namespace: - description: Namespace is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Namespace is only accepted within a service-defaults config entry. type: string partition: - description: Partition is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Partition is only accepted within a service-defaults config entry. type: string passiveHealthCheck: @@ -320,10 +283,6 @@ spec: format: int32 type: integer type: object - peer: - description: Peer is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides - config entry. - type: string protocol: description: Protocol describes the upstream's service protocol. Valid values are "tcp", "http" and "grpc". Anything else @@ -390,15 +349,15 @@ spec: type: string type: object name: - description: Name is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Name is only accepted within a service-defaults config entry. type: string namespace: - description: Namespace is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Namespace is only accepted within a service-defaults config entry. type: string partition: - description: Partition is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Partition is only accepted within a service-defaults config entry. type: string passiveHealthCheck: @@ -439,10 +398,6 @@ spec: format: int32 type: integer type: object - peer: - description: Peer is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides - config entry. - type: string protocol: description: Protocol describes the upstream's service protocol. Valid values are "tcp", "http" and "grpc". Anything else diff --git a/charts/consul/templates/crd-serviceintentions.yaml b/charts/consul/templates/crd-serviceintentions.yaml index edc7c7078b..cdbb5413b0 100644 --- a/charts/consul/templates/crd-serviceintentions.yaml +++ b/charts/consul/templates/crd-serviceintentions.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: serviceintentions.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: serviceintentions.consul.hashicorp.com spec: group: consul.hashicorp.com names: @@ -77,43 +74,6 @@ spec: have intentions defined. type: string type: object - jwt: - description: JWT specifies the configuration to validate a JSON Web - Token for all incoming requests. - properties: - providers: - description: Providers is a list of providers to consider when - verifying a JWT. - items: - properties: - name: - description: Name is the name of the JWT provider. There - MUST be a corresponding "jwt-provider" config entry with - this name. - type: string - verifyClaims: - description: VerifyClaims is a list of additional claims - to verify in a JWT's payload. - items: - properties: - path: - description: Path is the path to the claim in the - token JSON. - items: - type: string - type: array - value: - description: Value is the expected value at the given - path. If the type at the path is a list then we - verify that this value is contained in the list. - If the type at the path is a string then we verify - that this value matches. - type: string - type: object - type: array - type: object - type: array - type: object sources: description: Sources is the list of all intention sources and the authorization granted to those sources. The order of this list does @@ -142,7 +102,8 @@ spec: description: Partition is the Admin Partition for the Name parameter. type: string peer: - description: Peer is the peer name for the Name parameter. + description: '[Experimental] Peer is the peer name for the Name + parameter.' type: string permissions: description: Permissions is the list of all additional L7 attributes @@ -223,50 +184,8 @@ spec: match on the HTTP request path. type: string type: object - jwt: - description: JWT specifies configuration to validate a - JSON Web Token for incoming requests. - properties: - providers: - description: Providers is a list of providers to consider - when verifying a JWT. - items: - properties: - name: - description: Name is the name of the JWT provider. - There MUST be a corresponding "jwt-provider" - config entry with this name. - type: string - verifyClaims: - description: VerifyClaims is a list of additional - claims to verify in a JWT's payload. - items: - properties: - path: - description: Path is the path to the claim - in the token JSON. - items: - type: string - type: array - value: - description: Value is the expected value - at the given path. If the type at the - path is a list then we verify that this - value is contained in the list. If the - type at the path is a string then we - verify that this value matches. - type: string - type: object - type: array - type: object - type: array - type: object type: object type: array - samenessGroup: - description: SamenessGroup is the name of the sameness group, - if applicable. - type: string type: object type: array type: object diff --git a/charts/consul/templates/crd-serviceresolvers.yaml b/charts/consul/templates/crd-serviceresolvers.yaml index 7965a9df53..e058052e97 100644 --- a/charts/consul/templates/crd-serviceresolvers.yaml +++ b/charts/consul/templates/crd-serviceresolvers.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: serviceresolvers.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: serviceresolvers.consul.hashicorp.com spec: group: consul.hashicorp.com names: @@ -82,26 +79,6 @@ spec: service from to form the failover group of instances. If empty the current namespace is used. type: string - policy: - description: Policy specifies the exact mechanism used for failover. - properties: - mode: - description: Mode specifies the type of failover that will - be performed. Valid values are "sequential", "" (equivalent - to "sequential") and "order-by-locality". - type: string - regions: - description: Regions is the ordered list of the regions - of the failover targets. Valid values can be "us-west-1", - "us-west-2", and so on. - items: - type: string - type: array - type: object - samenessGroup: - description: SamenessGroup is the name of the sameness group - to try during failover. - type: string service: description: Service is the service to resolve instead of the default as the failover group of instances during failover. @@ -230,16 +207,6 @@ spec: type: integer type: object type: object - prioritizeByLocality: - description: PrioritizeByLocality controls whether the locality of - services within the local partition will be used to prioritize connectivity. - properties: - mode: - description: 'Mode specifies the type of prioritization that will - be performed when selecting nodes in the local partition. Valid - values are: "" (default "none"), "none", and "failover".' - type: string - type: object redirect: description: Redirect when configured, all attempts to resolve the service this resolver defines will be substituted for the supplied @@ -265,10 +232,6 @@ spec: description: Peer is the name of the cluster peer to resolve the service from instead of the current one. type: string - samenessGroup: - description: SamenessGroup is the name of the sameness group to - resolve the service from instead of the current one. - type: string service: description: Service is a service to resolve instead of the current service. @@ -279,10 +242,6 @@ spec: If empty the default subset is used. type: string type: object - requestTimeout: - description: RequestTimeout is the timeout for receiving an HTTP response - from this service before the connection is terminated. - type: string subsets: additionalProperties: properties: diff --git a/charts/consul/templates/crd-servicerouters.yaml b/charts/consul/templates/crd-servicerouters.yaml index d36e8028b5..f28da9e7c1 100644 --- a/charts/consul/templates/crd-servicerouters.yaml +++ b/charts/consul/templates/crd-servicerouters.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: servicerouters.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: servicerouters.consul.hashicorp.com spec: group: consul.hashicorp.com names: diff --git a/charts/consul/templates/crd-servicesplitters.yaml b/charts/consul/templates/crd-servicesplitters.yaml index 15f7714a84..a2af050c3d 100644 --- a/charts/consul/templates/crd-servicesplitters.yaml +++ b/charts/consul/templates/crd-servicesplitters.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: servicesplitters.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: servicesplitters.consul.hashicorp.com spec: group: consul.hashicorp.com names: diff --git a/charts/consul/templates/crd-tcproutes.yaml b/charts/consul/templates/crd-tcproutes.yaml deleted file mode 100644 index 91989135e2..0000000000 --- a/charts/consul/templates/crd-tcproutes.yaml +++ /dev/null @@ -1,284 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: tcproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: TCPRoute - listKind: TCPRouteList - plural: tcproutes - singular: tcproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: TCPRoute provides a way to route TCP requests. When combined with a Gateway listener, it can be used to forward connections on the port specified by the listener to a set of backends specified by the TCPRoute. - 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 TCPRoute. - properties: - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of TCP matchers and actions. - items: - description: TCPRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a non-existent resource or a Service with no endpoints), the underlying implementation MUST actively reject connection attempts to this backend. Connection rejections must respect weight; if an invalid backend is requested to have 80% of connections, then 80% of connections must be rejected instead. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward a request to a Kubernetes resource. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TCPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-terminatinggateways.yaml b/charts/consul/templates/crd-terminatinggateways.yaml index fae09bff53..583c218be8 100644 --- a/charts/consul/templates/crd-terminatinggateways.yaml +++ b/charts/consul/templates/crd-terminatinggateways.yaml @@ -1,21 +1,18 @@ {{- if .Values.connectInject.enabled }} -# 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.8.0 + creationTimestamp: null + name: terminatinggateways.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: crd - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: terminatinggateways.consul.hashicorp.com spec: group: consul.hashicorp.com names: diff --git a/charts/consul/templates/crd-tlsroutes.yaml b/charts/consul/templates/crd-tlsroutes.yaml deleted file mode 100644 index dfabd80713..0000000000 --- a/charts/consul/templates/crd-tlsroutes.yaml +++ /dev/null @@ -1,294 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: tlsroutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: TLSRoute - listKind: TLSRouteList - plural: tlsroutes - singular: tlsroute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "The TLSRoute resource is similar to TCPRoute, but can be configured to match against TLS-specific metadata. This allows more flexibility in matching streams for a given TLS listener. \n If you need to forward traffic to a single target for a TLS listener, you could choose to use a TCPRoute with a TLS listener." - 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 TLSRoute. - properties: - hostnames: - description: "Hostnames defines a set of SNI names that should match against the SNI attribute of TLS ClientHello message in TLS handshake. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed in SNI names per RFC 6066. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n If a hostname is specified by both the Listener and TLSRoute, there must be at least one intersecting hostname for the TLSRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches TLSRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches TLSRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `test.example.com` and `*.example.com` would both match. On the other hand, `example.com` and `test.example.net` would not match. \n If both the Listener and TLSRoute have specified hostnames, any TLSRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the TLSRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match. \n If both the Listener and TLSRoute have specified hostnames, and none match with the criteria above, then the TLSRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of TLS matchers and actions. - items: - description: TLSRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a non-existent resource or a Service with no endpoints), the rule performs no forwarding; if no filters are specified that would result in a response being sent, the underlying implementation must actively reject request attempts to this backend, by rejecting the connection or returning a 500 status code. Request rejections must respect weight; if an invalid backend is requested to have 80% of requests, then 80% of requests must be rejected instead. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward a request to a Kubernetes resource. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TLSRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/crd-udproutes.yaml b/charts/consul/templates/crd-udproutes.yaml deleted file mode 100644 index 935cce22fa..0000000000 --- a/charts/consul/templates/crd-udproutes.yaml +++ /dev/null @@ -1,284 +0,0 @@ -{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }} -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: udproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: UDPRoute - listKind: UDPRouteList - plural: udproutes - singular: udproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: UDPRoute provides a way to route UDP traffic. When combined with a Gateway listener, it can be used to forward traffic on the port specified by the listener to a set of backends specified by the UDPRoute. - 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 UDPRoute. - properties: - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of UDP matchers and actions. - items: - description: UDPRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a non-existent resource or a Service with no endpoints), the underlying implementation MUST actively reject connection attempts to this backend. Packet drops must respect weight; if an invalid backend is requested to have 80% of the packets, then 80% of packets must be dropped instead. \n Support: Core for Kubernetes Service Support: Implementation-specific for any other resource \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward a request to a Kubernetes resource. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of UDPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] -{{- end }} diff --git a/charts/consul/templates/gateway-cleanup-clusterrole.yaml b/charts/consul/templates/gateway-cleanup-clusterrole.yaml deleted file mode 100644 index c533a882f5..0000000000 --- a/charts/consul/templates/gateway-cleanup-clusterrole.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ template "consul.fullname" . }}-gateway-cleanup - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-cleanup -rules: - - apiGroups: - - consul.hashicorp.com - resources: - - gatewayclassconfigs - verbs: - - get - - delete - - apiGroups: - - gateway.networking.k8s.io - resources: - - gatewayclasses - verbs: - - get - - delete -{{- if .Values.global.enablePodSecurityPolicies }} - - apiGroups: ["policy"] - resources: ["podsecuritypolicies"] - resourceNames: - - {{ template "consul.fullname" . }}-gateway-cleanup - verbs: - - use -{{- end }} -{{- end }} diff --git a/charts/consul/templates/gateway-cleanup-clusterrolebinding.yaml b/charts/consul/templates/gateway-cleanup-clusterrolebinding.yaml deleted file mode 100644 index 9235f32101..0000000000 --- a/charts/consul/templates/gateway-cleanup-clusterrolebinding.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ template "consul.fullname" . }}-gateway-cleanup - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-cleanup -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ template "consul.fullname" . }}-gateway-cleanup -subjects: - - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-gateway-cleanup - namespace: {{ .Release.Namespace }} -{{- end }} \ No newline at end of file diff --git a/charts/consul/templates/gateway-cleanup-job.yaml b/charts/consul/templates/gateway-cleanup-job.yaml deleted file mode 100644 index a987c3b591..0000000000 --- a/charts/consul/templates/gateway-cleanup-job.yaml +++ /dev/null @@ -1,65 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ template "consul.fullname" . }}-gateway-cleanup - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-cleanup - {{- if .Values.global.extraLabels }} - {{- toYaml .Values.global.extraLabels | nindent 4 }} - {{- end }} - annotations: - "helm.sh/hook": pre-delete - "helm.sh/hook-weight": "0" - "helm.sh/hook-delete-policy": hook-succeeded,hook-failed -spec: - template: - metadata: - name: {{ template "consul.fullname" . }}-gateway-cleanup - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - release: {{ .Release.Name }} - component: gateway-cleanup - {{- if .Values.global.extraLabels }} - {{- toYaml .Values.global.extraLabels | nindent 8 }} - {{- end }} - annotations: - "consul.hashicorp.com/connect-inject": "false" - {{- if .Values.global.acls.annotations }} - {{- tpl .Values.global.acls.annotations . | nindent 8 }} - {{- end }} - spec: - restartPolicy: Never - serviceAccountName: {{ template "consul.fullname" . }}-gateway-cleanup - containers: - - name: gateway-cleanup - image: {{ .Values.global.imageK8S }} - {{- include "consul.restrictedSecurityContext" . | nindent 10 }} - command: - - consul-k8s-control-plane - args: - - gateway-cleanup - - -gateway-class-name=consul - - -gateway-class-config-name=consul-api-gateway - resources: - requests: - memory: "50Mi" - cpu: "50m" - limits: - memory: "50Mi" - cpu: "50m" - {{- if .Values.global.acls.tolerations }} - tolerations: - {{ tpl .Values.global.acls.tolerations . | indent 8 | trim }} - {{- end }} - {{- if .Values.global.acls.nodeSelector }} - nodeSelector: - {{ tpl .Values.global.acls.nodeSelector . | indent 8 | trim }} - {{- end }} -{{- end }} diff --git a/charts/consul/templates/gateway-cleanup-podsecuritypolicy.yaml b/charts/consul/templates/gateway-cleanup-podsecuritypolicy.yaml deleted file mode 100644 index ffbad130cc..0000000000 --- a/charts/consul/templates/gateway-cleanup-podsecuritypolicy.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if (and .Values.connectInject.enabled .Values.global.enablePodSecurityPolicies)}} -apiVersion: policy/v1beta1 -kind: PodSecurityPolicy -metadata: - name: {{ template "consul.fullname" . }}-gateway-cleanup - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-cleanup -spec: - privileged: false - allowPrivilegeEscalation: false - # This is redundant with non-root + disallow privilege escalation, - # but we can provide it for defense in depth. - requiredDropCapabilities: - - ALL - hostNetwork: false - hostIPC: false - hostPID: false - runAsUser: - rule: 'RunAsAny' - seLinux: - rule: 'RunAsAny' - supplementalGroups: - rule: 'RunAsAny' - fsGroup: - rule: 'RunAsAny' - readOnlyRootFilesystem: false -{{- end }} diff --git a/charts/consul/templates/gateway-cleanup-serviceaccount.yaml b/charts/consul/templates/gateway-cleanup-serviceaccount.yaml deleted file mode 100644 index f50eb72d97..0000000000 --- a/charts/consul/templates/gateway-cleanup-serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ template "consul.fullname" . }}-gateway-cleanup - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-cleanup -{{- end }} diff --git a/charts/consul/templates/gateway-resources-clusterrole.yaml b/charts/consul/templates/gateway-resources-clusterrole.yaml deleted file mode 100644 index c3bdfeb4a3..0000000000 --- a/charts/consul/templates/gateway-resources-clusterrole.yaml +++ /dev/null @@ -1,37 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ template "consul.fullname" . }}-gateway-resources - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-resources -rules: - - apiGroups: - - consul.hashicorp.com - resources: - - gatewayclassconfigs - verbs: - - get - - update - - create - - apiGroups: - - gateway.networking.k8s.io - resources: - - gatewayclasses - verbs: - - get - - update - - create -{{- if .Values.global.enablePodSecurityPolicies }} - - apiGroups: ["policy"] - resources: ["podsecuritypolicies"] - resourceNames: - - {{ template "consul.fullname" . }}-gateway-resources - verbs: - - use -{{- end }} -{{- end }} diff --git a/charts/consul/templates/gateway-resources-clusterrolebinding.yaml b/charts/consul/templates/gateway-resources-clusterrolebinding.yaml deleted file mode 100644 index 921df23239..0000000000 --- a/charts/consul/templates/gateway-resources-clusterrolebinding.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ template "consul.fullname" . }}-gateway-resources - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-resources -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ template "consul.fullname" . }}-gateway-resources -subjects: - - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-gateway-resources - namespace: {{ .Release.Namespace }} -{{- end }} \ No newline at end of file diff --git a/charts/consul/templates/gateway-resources-configmap.yaml b/charts/consul/templates/gateway-resources-configmap.yaml deleted file mode 100644 index 591aaa2129..0000000000 --- a/charts/consul/templates/gateway-resources-configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .Values.connectInject.enabled }} -# Configuration of Gateway Resources Job which creates managed Gateway configuration. -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "consul.fullname" . }}-gateway-resources-config - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-resources -data: - {{- if .Values.connectInject.apiGateway.managedGatewayClass.resources }} - resources.json: | - {{ toJson .Values.connectInject.apiGateway.managedGatewayClass.resources }} - {{- end }} -{{- end }} diff --git a/charts/consul/templates/gateway-resources-job.yaml b/charts/consul/templates/gateway-resources-job.yaml deleted file mode 100644 index a94c3f4e4e..0000000000 --- a/charts/consul/templates/gateway-resources-job.yaml +++ /dev/null @@ -1,130 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ template "consul.fullname" . }}-gateway-resources - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-resources - {{- if .Values.global.extraLabels }} - {{- toYaml .Values.global.extraLabels | nindent 4 }} - {{- end }} - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-weight": "0" - "helm.sh/hook-delete-policy": hook-succeeded -spec: - template: - metadata: - name: {{ template "consul.fullname" . }}-gateway-resources - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - release: {{ .Release.Name }} - component: gateway-resources - {{- if .Values.global.extraLabels }} - {{- toYaml .Values.global.extraLabels | nindent 8 }} - {{- end }} - annotations: - "consul.hashicorp.com/connect-inject": "false" - {{- if .Values.global.acls.annotations }} - {{- tpl .Values.global.acls.annotations . | nindent 8 }} - {{- end }} - spec: - restartPolicy: Never - serviceAccountName: {{ template "consul.fullname" . }}-gateway-resources - containers: - - name: gateway-resources - image: {{ .Values.global.imageK8S }} - {{- include "consul.restrictedSecurityContext" . | nindent 10 }} - command: - - consul-k8s-control-plane - args: - - gateway-resources - - -gateway-class-name=consul - - -gateway-class-config-name=consul-api-gateway - - -controller-name=consul.hashicorp.com/gateway-controller - - -app={{template "consul.name" .}} - - -chart={{template "consul.chart" .}} - - -heritage={{ .Release.Service }} - - -release-name={{ .Release.Name }} - - -component=api-gateway - {{- if .Values.apiGateway.enabled }} # Overide values from the old stanza. To be removed in 1.17 (t-eckert 2023-05-19) - {{- 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 }} - {{- end}} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.deployment.maxInstances }} - - -deployment-max-instances={{ .Values.connectInject.apiGateway.managedGatewayClass.deployment.maxInstances }} - {{- end}} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.deployment.minInstances }} - - -deployment-min-instances={{ .Values.connectInject.apiGateway.managedGatewayClass.deployment.minInstances }} - {{- end}} - {{- end}} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.nodeSelector }} - - -node-selector - - {{- toYaml .Values.connectInject.apiGateway.managedGatewayClass.nodeSelector | nindent 14 -}} - {{- end }} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.tolerations }} - - -tolerations={{ .Values.connectInject.apiGateway.managedGatewayClass.tolerations }} - {{- end }} - {{- if .Values.connectInject.apiGateway.managedGatewayClass.copyAnnotations.service }} - - -service-annotations - - {{- toYaml .Values.connectInject.apiGateway.managedGatewayClass.copyAnnotations.service.annotations | nindent 14 -}} - {{- end }} - - -service-type={{ .Values.connectInject.apiGateway.managedGatewayClass.serviceType }} - {{- if .Values.global.openshift.enabled }} - - -openshift-scc-name={{ .Values.connectInject.apiGateway.managedGatewayClass.openshiftSCCName }} - {{- end }} - - -map-privileged-container-ports={{ .Values.connectInject.apiGateway.managedGatewayClass.mapPrivilegedContainerPorts }} - {{- end}} - resources: - requests: - memory: "50Mi" - cpu: "50m" - limits: - memory: "50Mi" - cpu: "50m" - volumeMounts: - - name: config - mountPath: /consul/config - readOnly: true - {{- if .Values.global.acls.tolerations }} - tolerations: - {{ tpl .Values.global.acls.tolerations . | indent 8 | trim }} - {{- end }} - {{- if .Values.global.acls.nodeSelector }} - nodeSelector: - {{ tpl .Values.global.acls.nodeSelector . | indent 8 | trim }} - {{- end }} - volumes: - - name: config - configMap: - name: {{ template "consul.fullname" . }}-gateway-resources-config -{{- end }} diff --git a/charts/consul/templates/gateway-resources-podsecuritypolicy.yaml b/charts/consul/templates/gateway-resources-podsecuritypolicy.yaml deleted file mode 100644 index da5299194c..0000000000 --- a/charts/consul/templates/gateway-resources-podsecuritypolicy.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if (and .Values.global.enablePodSecurityPolicies .Values.connectInject.enabled)}} -apiVersion: policy/v1beta1 -kind: PodSecurityPolicy -metadata: - name: {{ template "consul.fullname" . }}-gateway-resources - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-resources -spec: - privileged: false - allowPrivilegeEscalation: false - # This is redundant with non-root + disallow privilege escalation, - # but we can provide it for defense in depth. - requiredDropCapabilities: - - ALL - hostNetwork: false - hostIPC: false - hostPID: false - runAsUser: - rule: 'RunAsAny' - seLinux: - rule: 'RunAsAny' - supplementalGroups: - rule: 'RunAsAny' - fsGroup: - rule: 'RunAsAny' - readOnlyRootFilesystem: false -{{- end }} diff --git a/charts/consul/templates/gateway-resources-serviceaccount.yaml b/charts/consul/templates/gateway-resources-serviceaccount.yaml deleted file mode 100644 index 4611dc38e1..0000000000 --- a/charts/consul/templates/gateway-resources-serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ template "consul.fullname" . }}-gateway-resources - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: gateway-resources -{{- end }} diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml index 34f5888a58..9209f850c8 100644 --- a/charts/consul/templates/partition-init-job.yaml +++ b/charts/consul/templates/partition-init-job.yaml @@ -114,9 +114,6 @@ spec: {{- if .Values.global.cloud.enabled }} -tls-server-name=server.{{ .Values.global.datacenter}}.{{ .Values.global.domain}} \ {{- end }} - {{- if (mustHas "resource-apis" .Values.global.experiments) }} - -enable-resource-apis=true - {{- end }} resources: requests: memory: "50Mi" diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index e8a06cf7aa..282aa7258f 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -50,23 +50,14 @@ spec: {{- tpl .Values.global.acls.annotations . | nindent 8 }} {{- end }} {{- if .Values.global.secretsBackend.vault.enabled }} - - {{- /* Run the Vault agent as both an init container and sidecar. - The Vault agent sidecar is needed when server-acl-init bootstraps ACLs - and writes the bootstrap token back to Vault. - * agent-pre-populate: true - Run the Vault agent init container. - * agent-pre-populate-only: false - Also, run the Vault agent sidecar. - * agent-cache-enable: true - Enable the Agent cache listener. - * agent-cache-listener-port: 8200 - (optional) Listen on 127.0.0.1:8200. - * agent-enable-quit: true - Enable a "quit" endpoint. server-acl-init - tells the Vault agent to stop (without this the Job will not complete). - */}} - "vault.hashicorp.com/agent-pre-populate": "true" - "vault.hashicorp.com/agent-pre-populate-only": "false" - "vault.hashicorp.com/agent-cache-enable": "true" - "vault.hashicorp.com/agent-cache-listener-port": "8200" - "vault.hashicorp.com/agent-enable-quit": "true" + "vault.hashicorp.com/agent-pre-populate-only": "true" "vault.hashicorp.com/agent-inject": "true" + {{- if .Values.global.acls.bootstrapToken.secretName }} + {{- with .Values.global.acls.bootstrapToken }} + "vault.hashicorp.com/agent-inject-secret-bootstrap-token": "{{ .secretName }}" + "vault.hashicorp.com/agent-inject-template-bootstrap-token": {{ template "consul.vaultSecretTemplate" . }} + {{- end }} + {{- end }} {{- if .Values.global.acls.partitionToken.secretName }} {{- with .Values.global.acls.partitionToken }} "vault.hashicorp.com/agent-inject-secret-partition-token": "{{ .secretName }}" @@ -117,7 +108,14 @@ spec: path: tls.crt {{- end }} {{- end }} - {{- if and .Values.global.acls.replicationToken.secretName (not .Values.global.secretsBackend.vault.enabled) }} + {{- if (and .Values.global.acls.bootstrapToken.secretName (not .Values.global.secretsBackend.vault.enabled)) }} + - name: bootstrap-token + secret: + secretName: {{ .Values.global.acls.bootstrapToken.secretName }} + items: + - key: {{ .Values.global.acls.bootstrapToken.secretKey }} + path: bootstrap-token + {{- else if and .Values.global.acls.replicationToken.secretName (not .Values.global.secretsBackend.vault.enabled) }} - name: acl-replication-token secret: secretName: {{ .Values.global.acls.replicationToken.secretName }} @@ -141,13 +139,6 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name - # Extract the Vault namespace from the Vault agent annotations. - {{- if .Values.global.secretsBackend.vault.enabled }} - {{- if .Values.global.secretsBackend.vault.agentAnnotations }} - - name: VAULT_NAMESPACE - value: {{ get (tpl .Values.global.secretsBackend.vault.agentAnnotations . | fromYaml) "vault.hashicorp.com/namespace" }} - {{- end }} - {{- end }} {{- include "consul.consulK8sConsulServerEnvVars" . | nindent 8 }} {{- if (or .Values.global.tls.enabled .Values.global.acls.replicationToken.secretName .Values.global.acls.bootstrapToken.secretName) }} volumeMounts: @@ -158,7 +149,11 @@ spec: readOnly: true {{- end }} {{- end }} - {{- if and .Values.global.acls.replicationToken.secretName (not .Values.global.secretsBackend.vault.enabled) }} + {{- if (and .Values.global.acls.bootstrapToken.secretName (not .Values.global.secretsBackend.vault.enabled)) }} + - name: bootstrap-token + mountPath: /consul/acl/tokens + readOnly: true + {{- else if and .Values.global.acls.replicationToken.secretName (not .Values.global.secretsBackend.vault.enabled) }} - name: acl-replication-token mountPath: /consul/acl/tokens readOnly: true @@ -176,15 +171,13 @@ spec: -resource-prefix=${CONSUL_FULLNAME} \ -k8s-namespace={{ .Release.Namespace }} \ -set-server-tokens={{ $serverEnabled }} \ + + {{- if .Values.global.acls.bootstrapToken.secretName }} {{- if .Values.global.secretsBackend.vault.enabled }} - -secrets-backend=vault \ + -bootstrap-token-file=/vault/secrets/bootstrap-token \ {{- else }} - -secrets-backend=kubernetes \ + -bootstrap-token-file=/consul/acl/tokens/bootstrap-token \ {{- end }} - - {{- if .Values.global.acls.bootstrapToken.secretName }} - -bootstrap-token-secret-name={{ .Values.global.acls.bootstrapToken.secretName }} \ - -bootstrap-token-secret-key={{ .Values.global.acls.bootstrapToken.secretKey }} \ {{- end }} {{- if .Values.syncCatalog.enabled }} diff --git a/charts/consul/templates/server-clusterrole.yaml b/charts/consul/templates/server-clusterrole.yaml deleted file mode 100644 index c22f562264..0000000000 --- a/charts/consul/templates/server-clusterrole.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ template "consul.fullname" . }}-server - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: server -rules: -- apiGroups: [""] - resources: ["nodes"] - verbs: - - get diff --git a/charts/consul/templates/server-clusterrolebinding.yaml b/charts/consul/templates/server-clusterrolebinding.yaml deleted file mode 100644 index 854fda870e..0000000000 --- a/charts/consul/templates/server-clusterrolebinding.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ template "consul.fullname" . }}-server - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: server -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ template "consul.fullname" . }}-server -subjects: -- kind: ServiceAccount - name: {{ template "consul.fullname" . }}-server - namespace: {{ .Release.Namespace }} diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index 6c102f0ae3..f4f787cb24 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -1,5 +1,4 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (not (or (eq .Values.server.limits.requestLimits.mode "disabled") (eq .Values.server.limits.requestLimits.mode "permissive") (eq .Values.server.limits.requestLimits.mode "enforce"))) }}{{fail "server.limits.requestLimits.mode must be one of the following values: disabled, permissive, and enforce." }}{{ end -}} {{- if and .Values.server.auditLogs.enabled (not .Values.global.acls.manageSystemACLs) }}{{fail "ACLs must be enabled inorder to configure audit logs"}}{{ end -}} # StatefulSet to run the actual Consul server cluster. apiVersion: v1 @@ -31,13 +30,6 @@ data: "log_level": "{{ .Values.server.logLevel | upper }}", {{- end }} "domain": "{{ .Values.global.domain }}", - "limits": { - "request_limits": { - "mode": "{{ .Values.server.limits.requestLimits.mode }}", - "read_rate": {{ .Values.server.limits.requestLimits.readRate }}, - "write_rate": {{ .Values.server.limits.requestLimits.writeRate }} - } - }, "ports": { {{- if not .Values.global.tls.enabled }} "grpc": 8502, diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 568d28d386..8987bd68c0 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -119,13 +119,7 @@ spec: {{- if (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics) }} "prometheus.io/scrape": "true" "prometheus.io/path": "/v1/agent/metrics" - {{- if .Values.global.tls.enabled }} - "prometheus.io/port": "8501" - "prometheus.io/scheme": "https" - {{- else }} "prometheus.io/port": "8500" - "prometheus.io/scheme": "http" - {{- end }} {{- end }} spec: {{- if .Values.server.affinity }} @@ -204,11 +198,6 @@ spec: medium: "Memory" {{- end }} {{- end }} - {{- if .Values.global.trustedCAs }} - - name: trusted-cas - emptyDir: - medium: "Memory" - {{- end }} {{- range .Values.server.extraVolumes }} - name: userconfig-{{ .name }} {{ .type }}: @@ -228,27 +217,9 @@ spec: {{- if .Values.server.priorityClassName }} priorityClassName: {{ .Values.server.priorityClassName | quote }} {{- end }} - initContainers: - - name: locality-init - image: {{ .Values.global.imageK8S }} - env: - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - command: - - "/bin/sh" - - "-ec" - - | - consul-k8s-control-plane fetch-server-region -node-name "$NODE_NAME" -output-file /consul/extra-config/locality.json - volumeMounts: - - name: extra-config - mountPath: /consul/extra-config - {{- include "consul.restrictedSecurityContext" . | nindent 8 }} containers: - name: consul image: "{{ default .Values.global.image .Values.server.image }}" - imagePullPolicy: {{ .Values.global.imagePullPolicy }} env: - name: ADVERTISE_IP valueFrom: @@ -320,9 +291,9 @@ spec: {{- end }} {{- if .Values.global.cloud.enabled}} # These are mounted as secrets so that the consul server agent can use them. - # - the hcp-go-sdk in consul agent will already look for HCP_CLIENT_ID, HCP_CLIENT_SECRET, HCP_AUTH_URL, + # - the hcp-go-sdk in consul agent will already look for HCP_CLIENT_ID, HCP_CLIENT_SECRET, HCP_AUTH_URL, # HCP_SCADA_ADDRESS, and HCP_API_HOST. so nothing more needs to be done. - # - HCP_RESOURCE_ID is created for use in the + # - HCP_RESOURCE_ID is created for use in the # `-hcl="cloud { resource_id = \"${HCP_RESOURCE_ID}\" }"` logic in the command below. {{- if .Values.global.cloud.clientId.secretName }} - name: HCP_CLIENT_ID @@ -357,7 +328,7 @@ spec: valueFrom: secretKeyRef: name: {{ .Values.global.cloud.apiHost.secretName }} - key: {{ .Values.global.cloud.apiHost.secretKey }} + key: {{ .Values.global.cloud.apiHost.secretKey }} {{- end}} {{- if .Values.global.cloud.scadaAddress.secretName }} - name: HCP_SCADA_ADDRESS @@ -365,25 +336,13 @@ spec: secretKeyRef: name: {{ .Values.global.cloud.scadaAddress.secretName }} key: {{ .Values.global.cloud.scadaAddress.secretKey }} - {{- end}} - {{- end }} - {{- if .Values.global.trustedCAs }} - - name: SSL_CERT_DIR - value: "/etc/ssl/certs:/trusted-cas" + {{- end}} {{- end }} {{- include "consul.extraEnvironmentVars" .Values.server | nindent 12 }} command: - "/bin/sh" - "-ec" - | - {{- if .Values.global.trustedCAs }} - {{- range $i, $cert := .Values.global.trustedCAs }} - cat < /trusted-cas/custom-ca-{{$i}}.pem - {{- $cert | nindent 14 }} - EOF - {{- end }} - {{- end }} - {{- if and .Values.global.secretsBackend.vault.enabled .Values.global.gossipEncryption.secretName }} GOSSIP_KEY=`cat /vault/secrets/gossip.txt` {{- end }} @@ -416,14 +375,10 @@ spec: -config-dir=/consul/userconfig/{{ .name }} \ {{- end }} {{- end }} - -config-file=/consul/extra-config/extra-from-values.json \ - -config-file=/consul/extra-config/locality.json + -config-file=/consul/extra-config/extra-from-values.json {{- if and .Values.global.cloud.enabled .Values.global.cloud.resourceId.secretName }} -hcl="cloud { resource_id = \"${HCP_RESOURCE_ID}\" }" {{- end }} - {{- if (mustHas "resource-apis" .Values.global.experiments) }} - -hcl="experiments=[\"resource-apis\"]" - {{- end }} volumeMounts: - name: data-{{ .Release.Namespace | trunc 58 | trimSuffix "-" }} mountPath: /consul/data @@ -454,11 +409,6 @@ spec: mountPath: /consul/vault-ca/ readOnly: true {{- end }} - {{- if .Values.global.trustedCAs }} - - name: trusted-cas - mountPath: /trusted-cas - readOnly: false - {{- end }} ports: {{- if (or (not .Values.global.tls.enabled) (not .Values.global.tls.httpsOnly)) }} - name: http diff --git a/charts/consul/templates/telemetry-collector-configmap.yaml b/charts/consul/templates/telemetry-collector-configmap.yaml deleted file mode 100644 index 0bf5b8753c..0000000000 --- a/charts/consul/templates/telemetry-collector-configmap.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- if (and .Values.telemetryCollector.enabled .Values.telemetryCollector.customExporterConfig) }} -# Immutable ConfigMap which saves the partition name. Attempting to update this configmap -# with a new Admin Partition name will cause the helm upgrade to fail -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "consul.fullname" . }}-telemetry-collector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: consul-telemetry-collector -data: - config.json: |- - {{ tpl .Values.telemetryCollector.customExporterConfig . | trimAll "\"" | indent 4 }} -{{- end }} diff --git a/charts/consul/templates/telemetry-collector-deployment.yaml b/charts/consul/templates/telemetry-collector-deployment.yaml deleted file mode 100644 index 4b5bb6df7b..0000000000 --- a/charts/consul/templates/telemetry-collector-deployment.yaml +++ /dev/null @@ -1,391 +0,0 @@ -{{- if .Values.telemetryCollector.enabled }} -{{- if not .Values.telemetryCollector.image}}{{ fail "telemetryCollector.image must be set to enable consul-telemetry-collector" }}{{ end }} -{{- if not .Values.connectInject.enabled }}{{ fail "connectInject.enabled must be true" }}{{ 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.validateCloudSecretKeys" . }} -{{ template "consul.validateTelemetryCollectorCloud" . }} -{{ template "consul.validateTelemetryCollectorCloudSecretKeys" . }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "consul.fullname" . }}-telemetry-collector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: consul-telemetry-collector - {{- if .Values.global.extraLabels }} - {{- toYaml .Values.global.extraLabels | nindent 4 }} - {{- end }} -spec: - replicas: {{ .Values.telemetryCollector.replicas }} - selector: - matchLabels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - release: {{ .Release.Name }} - component: consul-telemetry-collector - template: - metadata: - annotations: - "consul.hashicorp.com/connect-inject": "false" - # This annotation tells the endpoints controller that this pod was injected even though it wasn't. The - # endpoints controller would then sync the endpoint into Consul - "consul.hashicorp.com/connect-inject-status": "injected" - # We aren't using tproxy and we don't have an original pod. This would be simpler if we made a path similar - # to gateways - "consul.hashicorp.com/connect-service-port": "metricsserver" - "consul.hashicorp.com/transparent-proxy": "false" - "consul.hashicorp.com/transparent-proxy-overwrite-probes": "false" - "consul.hashicorp.com/connect-k8s-version": {{ $.Chart.Version }} - {{- if .Values.telemetryCollector.customExporterConfig }} - # configmap checksum - "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/telemetry-collector-configmap.yaml") . | sha256sum }} - {{- end }} - # vault annotations - {{- 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 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 }} - {{- if .Values.global.secretsBackend.vault.agentAnnotations }} - {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} - {{- end }} - {{- end }} - - labels: - consul.hashicorp.com/connect-inject-managed-by: consul-k8s-endpoints-controller - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - release: {{ .Release.Name }} - component: consul-telemetry-collector - {{- if .Values.global.extraLabels }} - {{- toYaml .Values.global.extraLabels | nindent 8 }} - {{- end }} - spec: - # This needs to explicitly be consul-telemetry-collector because we look this up from each service consul-dataplane - # to forward metrics to it. - serviceAccountName: consul-telemetry-collector - initContainers: - # We're manually managing this init container instead of using the connect injector so that we don't run into - # any race conditions on the connect-injector deployment or upgrade - - name: consul-connect-init - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - {{- if .Values.global.acls.manageSystemACLs }} - - name: CONSUL_LOGIN_AUTH_METHOD - value: {{ template "consul.fullname" . }}-k8s-auth-method - - name: CONSUL_LOGIN_META - value: "component=consul-telemetry-collector,pod=$(NAMESPACE)/$(POD_NAME)" - {{- end }} - - name: CONSUL_NODE_NAME - value: $(NODE_NAME)-virtual - {{- include "consul.consulK8sConsulServerEnvVars" . | nindent 10 }} - {{- if .Values.global.enableConsulNamespaces }} - - name: CONSUL_NAMESPACE - value: {{ .Values.syncCatalog.consulNamespaces.consulDestinationNamespace }} - {{- if .Values.syncCatalog.consulNamespaces.mirroringK8S }} - - name: CONSUL_LOGIN_NAMESPACE - value: "default" - {{- else }} - - name: CONSUL_LOGIN_NAMESPACE - value: {{ .Values.syncCatalog.consulNamespaces.consulDestinationNamespace }} - {{- end }} - {{- end }} - command: - - /bin/sh - - -ec - - |- - consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ - -log-level={{ default .Values.global.logLevel .Values.telemetryCollector.logLevel }} \ - -log-json={{ .Values.global.logJSON }} \ - -service-account-name="consul-telemetry-collector" \ - -service-name="" \ - -proxy-id-file="/consul/connect-inject/proxyid" - - image: {{ .Values.global.imageK8S }} - imagePullPolicy: IfNotPresent - {{- if .Values.telemetryCollector.initContainer.resources }} - resources: - {{- toYaml .Values.telemetryCollector.initContainer.resources | nindent 12 }} - {{- else }} - resources: - limits: - cpu: 50m - memory: 150Mi - requests: - cpu: 50m - memory: 25Mi - {{- end }} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumeMounts: - - mountPath: /consul/connect-inject - name: consul-connect-inject-data - {{- if .Values.global.tls.enabled }} - {{- if not (or (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) .Values.global.secretsBackend.vault.enabled) }} - - name: consul-ca-cert - mountPath: /consul/tls/ca - readOnly: true - {{- end }} - {{- end }} - containers: - - name: consul-telemetry-collector - image: {{ .Values.telemetryCollector.image }} - imagePullPolicy: {{ .Values.global.imagePullPolicy }} - ports: - - containerPort: 9090 - name: metrics - protocol: TCP - - containerPort: 9356 - name: metricsserver - protocol: TCP - env: - # These are mounted as secrets so that the telemetry-collector can use them when cloud is enabled. - # - the hcp-go-sdk in consul agent will already look for HCP_CLIENT_ID, HCP_CLIENT_SECRET, HCP_AUTH_URL, - # HCP_SCADA_ADDRESS, and HCP_API_HOST. so nothing more needs to be done. - # - HCP_RESOURCE_ID is created for use in the global cloud section but we will share it here - {{- if .Values.telemetryCollector.cloud.clientId.secretName }} - - name: HCP_CLIENT_ID - valueFrom: - secretKeyRef: - name: {{ .Values.telemetryCollector.cloud.clientId.secretName }} - key: {{ .Values.telemetryCollector.cloud.clientId.secretKey }} - {{- end }} - {{- if .Values.telemetryCollector.cloud.clientSecret.secretName }} - - name: HCP_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: {{ .Values.telemetryCollector.cloud.clientSecret.secretName }} - key: {{ .Values.telemetryCollector.cloud.clientSecret.secretKey }} - {{- end}} - {{- if .Values.global.cloud.resourceId.secretName }} - - name: HCP_RESOURCE_ID - valueFrom: - secretKeyRef: - name: {{ .Values.global.cloud.resourceId.secretName }} - key: {{ .Values.global.cloud.resourceId.secretKey }} - {{- end }} - {{- if .Values.global.cloud.authUrl.secretName }} - - name: HCP_AUTH_URL - valueFrom: - secretKeyRef: - name: {{ .Values.global.cloud.authUrl.secretName }} - key: {{ .Values.global.cloud.authUrl.secretKey }} - {{- end}} - {{- if .Values.global.cloud.apiHost.secretName }} - - name: HCP_API_HOST - valueFrom: - secretKeyRef: - name: {{ .Values.global.cloud.apiHost.secretName }} - key: {{ .Values.global.cloud.apiHost.secretKey }} - {{- end}} - {{- if .Values.global.cloud.scadaAddress.secretName }} - - name: HCP_SCADA_ADDRESS - valueFrom: - secretKeyRef: - name: {{ .Values.global.cloud.scadaAddress.secretName }} - key: {{ .Values.global.cloud.scadaAddress.secretKey }} - {{- end}} - {{- if .Values.global.trustedCAs }} - - name: SSL_CERT_DIR - value: "/etc/ssl/certs:/trusted-cas" - {{- end }} - {{- include "consul.extraEnvironmentVars" .Values.telemetryCollector | nindent 12 }} - command: - - "/bin/sh" - - "-ec" - - | - {{- if .Values.global.trustedCAs }} - {{- range $i, $cert := .Values.global.trustedCAs }} - cat < /trusted-cas/custom-ca-{{$i}}.pem - {{- $cert | nindent 10 }} - EOF - {{- end }} - {{- end }} - - consul-telemetry-collector agent \ - {{- if .Values.telemetryCollector.customExporterConfig }} - -config-file-path /consul/config/config.json \ - {{ end }} - volumeMounts: - {{- if .Values.telemetryCollector.customExporterConfig }} - - name: config - mountPath: /consul/config - {{- end }} - {{- if .Values.global.trustedCAs }} - - name: trusted-cas - mountPath: /trusted-cas - readOnly: false - {{- end }} - resources: - {{- if .Values.telemetryCollector.resources }} - {{- toYaml .Values.telemetryCollector.resources | nindent 12 }} - {{- end }} - # consul-dataplane container - - name: consul-dataplane - image: "{{ .Values.global.imageConsulDataplane }}" - imagePullPolicy: IfNotPresent - command: - - consul-dataplane - args: - # addresses - {{- if .Values.externalServers.enabled }} - - -addresses={{ .Values.externalServers.hosts | first }} - {{- else }} - - -addresses={{ template "consul.fullname" . }}-server.{{ .Release.Namespace }}.svc - {{- end }} - # grpc - {{- if .Values.externalServers.enabled }} - - -grpc-port={{ .Values.externalServers.grpcPort }} - {{- else }} - - -grpc-port=8502 - {{- end }} - - -proxy-service-id-path=/consul/connect-inject/proxyid - # tls - {{- if .Values.global.tls.enabled }} - {{- if (not (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots)) }} - {{- if .Values.global.secretsBackend.vault.enabled }} - - -ca-certs=/vault/secrets/serverca.crt - {{- else }} - - -ca-certs=/consul/tls/ca/tls.crt - {{- end }} - {{- end }} - {{- if and .Values.externalServers.enabled .Values.externalServers.tlsServerName }} - - -tls-server-name={{.Values.externalServers.tlsServerName }} - {{- else if .Values.global.cloud.enabled }} - - -tls-server-name=server.{{ .Values.global.datacenter}}.{{ .Values.global.domain}} - {{- end }} - {{- else }} - - -tls-disabled - {{- end }} - # credentials - {{- if .Values.global.acls.manageSystemACLs }} - - -credential-type=login - - -login-bearer-token-path=/var/run/secrets/kubernetes.io/serviceaccount/token - - -login-auth-method={{ template "consul.fullname" . }}-k8s-auth-method - {{- if .Values.global.enableConsulNamespaces }} - {{- if .Values.syncCatalog.consulNamespaces.mirroringK8S }} - - -login-namespace="default" - {{- else }} - - -login-namespace={{ .Values.syncCatalog.consulNamespaces.consulDestinationNamespace }} - {{- end }} - {{- end }} - {{- if .Values.global.adminPartitions.enabled }} - - foo - - -login-partition={{ .Values.global.adminPartitions.name }} - {{- end }} - {{- end }} - {{- if .Values.global.enableConsulNamespaces }} - - -service-namespace={{ .Values.syncCatalog.consulNamespaces.consulDestinationNamespace }} - {{- end }} - {{- if .Values.global.adminPartitions.enabled }} - - -service-partition={{ .Values.global.adminPartitions.name }} - {{- end }} - {{- if .Values.global.metrics.enabled }} - - -telemetry-prom-scrape-path=/metrics - {{- end }} - - -log-level={{ default .Values.global.logLevel .Values.telemetryCollector.logLevel }} - - -log-json={{ .Values.global.logJSON }} - - -envoy-concurrency=2 - {{- if and .Values.externalServers.enabled .Values.externalServers.skipServerWatch }} - - -server-watch-disabled=true - {{- end }} - env: - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: DP_CREDENTIAL_LOGIN_META1 - value: pod=$(NAMESPACE)/$(POD_NAME) - - name: DP_CREDENTIAL_LOGIN_META2 - value: component=consul-telemetry-collector - - name: DP_SERVICE_NODE_NAME - value: $(NODE_NAME)-virtual - - name: TMPDIR - value: /consul/connect-inject - readinessProbe: - failureThreshold: 3 - initialDelaySeconds: 1 - periodSeconds: 10 - successThreshold: 1 - tcpSocket: - port: 20000 - timeoutSeconds: 1 - securityContext: - readOnlyRootFilesystem: true - runAsGroup: 5995 - runAsNonRoot: true - runAsUser: 5995 - # dataplane volume mounts - volumeMounts: - - mountPath: /consul/connect-inject - name: consul-connect-inject-data - {{- if .Values.global.tls.enabled }} - {{- if not (or (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) .Values.global.secretsBackend.vault.enabled) }} - - name: consul-ca-cert - mountPath: /consul/tls/ca - readOnly: true - {{- end }} - {{- end }} - - {{- if .Values.telemetryCollector.nodeSelector }} - nodeSelector: - {{ tpl .Values.telemetryCollector.nodeSelector . | indent 8 | trim }} - {{- end }} - {{- if .Values.telemetryCollector.priorityClassName }} - priorityClassName: {{ .Values.telemetryCollector.priorityClassName }} - {{- end }} - volumes: - - emptyDir: - medium: Memory - name: consul-connect-inject-data - {{- if .Values.global.trustedCAs }} - - name: trusted-cas - emptyDir: - medium: "Memory" - {{- 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 }} - {{- end }} - - name: config - configMap: - name: {{ template "consul.fullname" . }}-telemetry-collector -{{- end }} diff --git a/charts/consul/templates/telemetry-collector-podsecuritypolicy.yaml b/charts/consul/templates/telemetry-collector-podsecuritypolicy.yaml deleted file mode 100644 index 286a92d0bd..0000000000 --- a/charts/consul/templates/telemetry-collector-podsecuritypolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- if and .Values.global.enablePodSecurityPolicies .Values.telemetryCollector.enabled }} -apiVersion: policy/v1beta1 -kind: PodSecurityPolicy -metadata: - name: {{ template "consul.fullname" . }}-telemetry-collector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: telemetry-collector -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: false -{{- end }} diff --git a/charts/consul/templates/telemetry-collector-role.yaml b/charts/consul/templates/telemetry-collector-role.yaml deleted file mode 100644 index f89373252d..0000000000 --- a/charts/consul/templates/telemetry-collector-role.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if and .Values.global.enablePodSecurityPolicies .Values.telemetryCollector.enabled }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ template "consul.fullname" . }}-telemetry-collector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: consul-telemetry-collector -rules: - - apiGroups: ["policy"] - resources: ["podsecuritypolicies"] - resourceNames: - - {{ template "consul.fullname" . }}-telemetry-collector - verbs: - - use -{{- end }} - diff --git a/charts/consul/templates/telemetry-collector-rolebinding.yaml b/charts/consul/templates/telemetry-collector-rolebinding.yaml deleted file mode 100644 index 1f9a896997..0000000000 --- a/charts/consul/templates/telemetry-collector-rolebinding.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if and .Values.global.enablePodSecurityPolicies .Values.telemetryCollector.enabled }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ template "consul.fullname" . }}-telemetry-collector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: consul-telemetry-collector -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ template "consul.fullname" . }}-telemetry-collector -subjects: - - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-telemetry-collector -{{- end }} - diff --git a/charts/consul/templates/telemetry-collector-service.yaml b/charts/consul/templates/telemetry-collector-service.yaml deleted file mode 100644 index 266c80b4bf..0000000000 --- a/charts/consul/templates/telemetry-collector-service.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if .Values.telemetryCollector.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: consul-telemetry-collector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - release: {{ .Release.Name }} - component: consul-telemetry-collector - {{ if .Values.telemetryCollector.service.annotations }} - annotations: - {{ tpl .Values.telemetryCollector.service.annotations . | nindent 4 | trim }} - {{- end }} -spec: - type: ClusterIP - ports: - - port: 9356 - targetPort: 9356 - selector: - app: consul - component: consul-telemetry-collector -{{- end }} \ No newline at end of file diff --git a/charts/consul/templates/telemetry-collector-serviceaccount.yaml b/charts/consul/templates/telemetry-collector-serviceaccount.yaml deleted file mode 100644 index fca58eede9..0000000000 --- a/charts/consul/templates/telemetry-collector-serviceaccount.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- if .Values.telemetryCollector.enabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: consul-telemetry-collector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - release: {{ .Release.Name }} - component: consul-telemetry-collector - {{- if .Values.telemetryCollector.serviceAccount.annotations }} - annotations: - {{ tpl .Values.telemetryCollector.serviceAccount.annotations . | nindent 4 | trim }} - {{- end }} -automountServiceAccountToken: true -{{- with .Values.global.imagePullSecrets }} -imagePullSecrets: -{{- range . }} - - name: {{ .name }} -{{- end }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/charts/consul/templates/webhook-cert-manager-clusterrole.yaml b/charts/consul/templates/webhook-cert-manager-clusterrole.yaml index e13e2dc741..c2a2422d02 100644 --- a/charts/consul/templates/webhook-cert-manager-clusterrole.yaml +++ b/charts/consul/templates/webhook-cert-manager-clusterrole.yaml @@ -1,4 +1,4 @@ -{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName) -}} +{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName .Values.global.secretsBackend.vault.controllerRole .Values.global.secretsBackend.vault.controller.tlsCert.secretName .Values.global.secretsBackend.vault.controller.caCert.secretName) -}} {{- if (and .Values.connectInject.enabled (not $hasConfiguredWebhookCertsUsingVault)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/charts/consul/templates/webhook-cert-manager-clusterrolebinding.yaml b/charts/consul/templates/webhook-cert-manager-clusterrolebinding.yaml index 472ef4ee1d..ca2bb84bda 100644 --- a/charts/consul/templates/webhook-cert-manager-clusterrolebinding.yaml +++ b/charts/consul/templates/webhook-cert-manager-clusterrolebinding.yaml @@ -1,4 +1,4 @@ -{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName) -}} +{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName .Values.global.secretsBackend.vault.controllerRole .Values.global.secretsBackend.vault.controller.tlsCert.secretName .Values.global.secretsBackend.vault.controller.caCert.secretName) -}} {{- if (and .Values.connectInject.enabled (not $hasConfiguredWebhookCertsUsingVault)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/charts/consul/templates/webhook-cert-manager-configmap.yaml b/charts/consul/templates/webhook-cert-manager-configmap.yaml index 293dd32d9f..914d2b87dd 100644 --- a/charts/consul/templates/webhook-cert-manager-configmap.yaml +++ b/charts/consul/templates/webhook-cert-manager-configmap.yaml @@ -1,4 +1,4 @@ -{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName) -}} +{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName .Values.global.secretsBackend.vault.controllerRole .Values.global.secretsBackend.vault.controller.tlsCert.secretName .Values.global.secretsBackend.vault.controller.caCert.secretName) -}} {{- if (and .Values.connectInject.enabled (not $hasConfiguredWebhookCertsUsingVault)) }} apiVersion: v1 kind: ConfigMap diff --git a/charts/consul/templates/webhook-cert-manager-deployment.yaml b/charts/consul/templates/webhook-cert-manager-deployment.yaml index 7ba25b330c..ffa68216f3 100644 --- a/charts/consul/templates/webhook-cert-manager-deployment.yaml +++ b/charts/consul/templates/webhook-cert-manager-deployment.yaml @@ -1,4 +1,4 @@ -{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName) -}} +{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName .Values.global.secretsBackend.vault.controllerRole .Values.global.secretsBackend.vault.controller.tlsCert.secretName .Values.global.secretsBackend.vault.controller.caCert.secretName) -}} {{- if (and .Values.connectInject.enabled (not $hasConfiguredWebhookCertsUsingVault)) }} apiVersion: apps/v1 kind: Deployment diff --git a/charts/consul/templates/webhook-cert-manager-podsecuritypolicy.yaml b/charts/consul/templates/webhook-cert-manager-podsecuritypolicy.yaml index 4d685edc39..b67dbda510 100644 --- a/charts/consul/templates/webhook-cert-manager-podsecuritypolicy.yaml +++ b/charts/consul/templates/webhook-cert-manager-podsecuritypolicy.yaml @@ -1,4 +1,4 @@ -{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName) -}} +{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName .Values.global.secretsBackend.vault.controllerRole .Values.global.secretsBackend.vault.controller.tlsCert.secretName .Values.global.secretsBackend.vault.controller.caCert.secretName) -}} {{- if (and .Values.global.enablePodSecurityPolicies (or (and (ne (.Values.connectInject.enabled | toString) "-") .Values.connectInject.enabled) (and (eq (.Values.connectInject.enabled | toString) "-") .Values.global.enabled))) }} {{- if (and .Values.connectInject.enabled (not $hasConfiguredWebhookCertsUsingVault)) }} apiVersion: policy/v1beta1 diff --git a/charts/consul/templates/webhook-cert-manager-serviceaccount.yaml b/charts/consul/templates/webhook-cert-manager-serviceaccount.yaml index 68c54f3c27..fa4b24ef8b 100644 --- a/charts/consul/templates/webhook-cert-manager-serviceaccount.yaml +++ b/charts/consul/templates/webhook-cert-manager-serviceaccount.yaml @@ -1,4 +1,4 @@ -{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName) -}} +{{ $hasConfiguredWebhookCertsUsingVault := (and .Values.global.secretsBackend.vault.enabled .Values.global.secretsBackend.vault.connectInjectRole .Values.global.secretsBackend.vault.connectInject.tlsCert.secretName .Values.global.secretsBackend.vault.connectInject.caCert.secretName .Values.global.secretsBackend.vault.controllerRole .Values.global.secretsBackend.vault.controller.tlsCert.secretName .Values.global.secretsBackend.vault.controller.caCert.secretName) -}} {{- if (and .Values.connectInject.enabled (not $hasConfiguredWebhookCertsUsingVault)) }} apiVersion: v1 kind: ServiceAccount diff --git a/charts/consul/test/docker/Test.dockerfile b/charts/consul/test/docker/Test.dockerfile index e6a4caa6e0..85f3a607e3 100644 --- a/charts/consul/test/docker/Test.dockerfile +++ b/charts/consul/test/docker/Test.dockerfile @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # This Dockerfile installs all the dependencies necessary to run the unit and # acceptance tests. This image also contains gcloud so you can run tests # against a GKE cluster easily. diff --git a/charts/consul/test/terraform/eks/main.tf b/charts/consul/test/terraform/eks/main.tf index 3bc8b40451..c404d0bb72 100644 --- a/charts/consul/test/terraform/eks/main.tf +++ b/charts/consul/test/terraform/eks/main.tf @@ -68,7 +68,7 @@ module "eks" { kubeconfig_api_version = "client.authentication.k8s.io/v1beta1" cluster_name = "consul-k8s-${random_id.suffix[count.index].dec}" - cluster_version = "1.26" + cluster_version = "1.25" subnets = module.vpc[count.index].private_subnets enable_irsa = true @@ -124,13 +124,12 @@ resource "aws_iam_role_policy_attachment" "csi" { } resource "aws_eks_addon" "csi-driver" { - count = var.cluster_count - cluster_name = module.eks[count.index].cluster_id - addon_name = "aws-ebs-csi-driver" - addon_version = "v1.15.0-eksbuild.1" - service_account_role_arn = aws_iam_role.csi-driver-role[count.index].arn - resolve_conflicts_on_create = "OVERWRITE" - resolve_conflicts_on_update = "OVERWRITE" + count = var.cluster_count + cluster_name = module.eks[count.index].cluster_id + addon_name = "aws-ebs-csi-driver" + addon_version = "v1.15.0-eksbuild.1" + service_account_role_arn = aws_iam_role.csi-driver-role[count.index].arn + resolve_conflicts = "OVERWRITE" } data "aws_eks_cluster" "cluster" { diff --git a/charts/consul/test/terraform/eks/outputs.tf b/charts/consul/test/terraform/eks/outputs.tf index 1d971bf0b5..986a917f6a 100644 --- a/charts/consul/test/terraform/eks/outputs.tf +++ b/charts/consul/test/terraform/eks/outputs.tf @@ -3,4 +3,4 @@ output "kubeconfigs" { value = [for cl in module.eks : pathexpand(format("~/.kube/%s", cl.cluster_id))] -} +} \ No newline at end of file diff --git a/charts/consul/test/terraform/eks/variables.tf b/charts/consul/test/terraform/eks/variables.tf index 548cddeb33..7536668442 100644 --- a/charts/consul/test/terraform/eks/variables.tf +++ b/charts/consul/test/terraform/eks/variables.tf @@ -27,4 +27,4 @@ variable "tags" { type = map(any) default = {} description = "Tags to attach to the created resources." -} +} \ No newline at end of file diff --git a/charts/consul/test/terraform/gke/main.tf b/charts/consul/test/terraform/gke/main.tf index 34bb07906f..fe5adc5e8d 100644 --- a/charts/consul/test/terraform/gke/main.tf +++ b/charts/consul/test/terraform/gke/main.tf @@ -21,7 +21,7 @@ resource "random_id" "suffix" { data "google_container_engine_versions" "main" { location = var.zone - version_prefix = "1.25.9" + version_prefix = "1.25." } # We assume that the subnets are already created to save time. diff --git a/charts/consul/test/terraform/gke/outputs.tf b/charts/consul/test/terraform/gke/outputs.tf index a0ffac907f..17a2aac4fd 100644 --- a/charts/consul/test/terraform/gke/outputs.tf +++ b/charts/consul/test/terraform/gke/outputs.tf @@ -11,4 +11,4 @@ output "cluster_names" { output "kubeconfigs" { value = [for cl in google_container_cluster.cluster : format("$HOME/.kube/%s", cl.name)] -} +} \ No newline at end of file diff --git a/charts/consul/test/terraform/gke/variables.tf b/charts/consul/test/terraform/gke/variables.tf index f33952850a..ba580a540d 100644 --- a/charts/consul/test/terraform/gke/variables.tf +++ b/charts/consul/test/terraform/gke/variables.tf @@ -42,4 +42,4 @@ variable "subnet" { type = string default = "default" description = "Subnet to create the cluster in. Currently all clusters use the default subnet and we are running out of IPs" -} +} \ No newline at end of file diff --git a/charts/consul/test/terraform/openshift/main.tf b/charts/consul/test/terraform/openshift/main.tf index 3605c37a7b..88da265c17 100644 --- a/charts/consul/test/terraform/openshift/main.tf +++ b/charts/consul/test/terraform/openshift/main.tf @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - provider "azurerm" { features {} } diff --git a/charts/consul/test/terraform/openshift/oc-login.sh b/charts/consul/test/terraform/openshift/oc-login.sh index f463c03af7..e7db48761d 100755 --- a/charts/consul/test/terraform/openshift/oc-login.sh +++ b/charts/consul/test/terraform/openshift/oc-login.sh @@ -1,7 +1,4 @@ #!/usr/bin/env bash -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - resource_group=$1 cluster_name=$2 diff --git a/charts/consul/test/terraform/openshift/outputs.tf b/charts/consul/test/terraform/openshift/outputs.tf index 7a395e33b7..66fc892934 100644 --- a/charts/consul/test/terraform/openshift/outputs.tf +++ b/charts/consul/test/terraform/openshift/outputs.tf @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - output "kubeconfigs" { value = [for rg in azurerm_resource_group.test : format("$HOME/.kube/%s", rg.name)] } \ No newline at end of file diff --git a/charts/consul/test/terraform/openshift/variables.tf b/charts/consul/test/terraform/openshift/variables.tf index 5aa3cc0180..1df518f8ed 100644 --- a/charts/consul/test/terraform/openshift/variables.tf +++ b/charts/consul/test/terraform/openshift/variables.tf @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - variable "location" { default = "westus2" description = "The Azure Region to create all resources in." diff --git a/charts/consul/test/unit/_helpers.bash b/charts/consul/test/unit/_helpers.bash index d57d2a0fbf..1b9d1aa4d2 100644 --- a/charts/consul/test/unit/_helpers.bash +++ b/charts/consul/test/unit/_helpers.bash @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # chart_dir returns the directory for the chart chart_dir() { echo ${BATS_TEST_DIRNAME}/../.. diff --git a/charts/consul/test/unit/connect-inject-clusterrole.bats b/charts/consul/test/unit/connect-inject-clusterrole.bats index d02b9eacde..b1ad10a80c 100644 --- a/charts/consul/test/unit/connect-inject-clusterrole.bats +++ b/charts/consul/test/unit/connect-inject-clusterrole.bats @@ -77,7 +77,7 @@ load _helpers --set 'client.enabled=true' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | - yq -r '.rules[4]' | tee /dev/stderr) + yq -r '.rules[3]' | tee /dev/stderr) local actual=$(echo $object | yq -r '.resources[| index("pods")' | tee /dev/stderr) [ "${actual}" != null ] @@ -106,7 +106,7 @@ load _helpers --set 'client.enabled=true' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | - yq -r '.rules[5]' | tee /dev/stderr) + yq -r '.rules[4]' | tee /dev/stderr) local actual=$(echo $object | yq -r '.resources[| index("leases")' | tee /dev/stderr) [ "${actual}" != null ] @@ -154,7 +154,7 @@ load _helpers #-------------------------------------------------------------------- # global.enablePodSecurityPolicies -@test "connectInject/ClusterRole: allows podsecuritypolicies access with global.enablePodSecurityPolicies=false" { +@test "connectInject/ClusterRole: no podsecuritypolicies access with global.enablePodSecurityPolicies=false" { cd `chart_dir` local actual=$(helm template \ -s templates/connect-inject-clusterrole.yaml \ @@ -162,7 +162,7 @@ load _helpers --set 'global.enablePodSecurityPolicies=false' \ . | tee /dev/stderr | yq -r '.rules | map(select(.resources[0] == "podsecuritypolicies")) | length' | tee /dev/stderr) - [ "${actual}" = "1" ] + [ "${actual}" = "0" ] } @test "connectInject/ClusterRole: allows podsecuritypolicies access with global.enablePodSecurityPolicies=true" { @@ -193,11 +193,14 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ . | tee /dev/stderr | - yq -r '.rules[6]' | tee /dev/stderr) + yq -r '.rules[5]' | tee /dev/stderr) local actual=$(echo $object | yq -r '.resources[0]' | tee /dev/stderr) [ "${actual}" = "mutatingwebhookconfigurations" ] @@ -217,27 +220,3 @@ load _helpers local actual=$(echo $object | yq -r '.verbs | index("watch")' | tee /dev/stderr) [ "${actual}" != null ] } - -#-------------------------------------------------------------------- -# openshift - -@test "connectInject/ClusterRole: adds permission to securitycontextconstraints for Openshift with global.openshift.enabled=true with default apiGateway Openshift SCC Name" { - cd `chart_dir` - local object=$(helm template \ - -s templates/connect-inject-clusterrole.yaml \ - --set 'global.openshift.enabled=true' \ - . | tee /dev/stderr | - yq '.rules[13].resourceNames | index("restricted-v2")' | tee /dev/stderr) - [ "${object}" == 0 ] -} - -@test "connectInject/ClusterRole: adds permission to securitycontextconstraints for Openshift with global.openshift.enabled=true and sets apiGateway Openshift SCC Name" { - cd `chart_dir` - local object=$(helm template \ - -s templates/connect-inject-clusterrole.yaml \ - --set 'global.openshift.enabled=true' \ - --set 'connectInject.apiGateway.managedGatewayClass.openshiftSCCName=fakescc' \ - . | tee /dev/stderr | - yq '.rules[13].resourceNames | index("fakescc")' | tee /dev/stderr) - [ "${object}" == 0 ] -} diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index 7180468cea..8a4716889a 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -211,19 +211,6 @@ load _helpers [ "${actual}" = "true" ] } -@test "connectInject/Deployment: metrics.enableTelemetryCollector can be configured" { - cd `chart_dir` - local cmd=$(helm template \ - -s templates/connect-inject-deployment.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.metrics.enableTelemetryCollector=true' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) - - local actual=$(echo "$cmd" | - yq 'any(contains("-enable-telemetry-collector=true"))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} #-------------------------------------------------------------------- # consul and consul-dataplane images @@ -1813,6 +1800,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=test' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=foo/ca' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=foo/tls' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command | any(contains("-enable-webhook-ca-update"))' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -1919,7 +1909,7 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=connectinjectcarole' \ --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' . [ "$status" -eq 1 ] - [[ "$output" =~ "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName" ]] + [[ "$output" =~ "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and global.secretsBackend.vault.controller.caCert.secretName." ]] } @test "connectInject/Deployment: fails if vault is enabled and global.secretsBackend.vault.connectInject.tlsCert.secretName is set but global.secretsBackend.vault.connectInjectRole and global.secretsBackend.vault.connectInject.caCert.secretName are not" { @@ -1936,7 +1926,7 @@ load _helpers --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' . [ "$status" -eq 1 ] - [[ "$output" =~ "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName" ]] + [[ "$output" =~ "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and global.secretsBackend.vault.controller.caCert.secretName." ]] } @test "connectInject/Deployment: fails if vault is enabled and global.secretsBackend.vault.connectInject.caCert.secretName is set but global.secretsBackend.vault.connectInjectRole and global.secretsBackend.vault.connectInject.tlsCert.secretName are not" { @@ -1953,7 +1943,7 @@ load _helpers --set 'global.secretsBackend.vault.connectInject.caCert.secretName=foo/ca' \ --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' . [ "$status" -eq 1 ] - [[ "$output" =~ "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName" ]] + [[ "$output" =~ "When one of the following has been set, all must be set: global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and global.secretsBackend.vault.controller.caCert.secretName." ]] } @test "connectInject/Deployment: vault tls annotations are set when tls is enabled" { @@ -1971,6 +1961,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=test' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=foo/ca' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ . | tee /dev/stderr | yq -r '.spec.template.metadata' | tee /dev/stderr) @@ -2044,6 +2037,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ @@ -2066,6 +2062,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'server.serverCert.secretName=pki_int/issue/test' \ --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ . | tee /dev/stderr | @@ -2095,6 +2094,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ . | tee /dev/stderr | yq '.spec.template.spec.volumes[] | select(.name == "certs")' | tee /dev/stderr) [ "${actual}" == "" ] @@ -2114,6 +2116,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "certs")' | tee /dev/stderr) [ "${actual}" == "" ] @@ -2587,30 +2592,3 @@ reservedNameTest() { jq -r '. | select( .name == "CONSUL_TLS_SERVER_NAME").value' | tee /dev/stderr) [ "${actual}" = "server.dc1.consul" ] } - -#-------------------------------------------------------------------- -# resource-apis - -@test "connectInject/Deployment: resource-apis is not set by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/connect-inject-deployment.yaml \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | any(contains("-enable-resource-apis=true"))' | tee /dev/stderr) - - [ "${actual}" = "false" ] -} - -@test "connectInject/Deployment: -enable-resource-apis=true is set when global.experiments contains [\"resource-apis\"] " { - cd `chart_dir` - local actual=$(helm template \ - -s templates/connect-inject-deployment.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | any(contains("-enable-resource-apis=true"))' | tee /dev/stderr) - - [ "${actual}" = "true" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/connect-inject-mutatingwebhookconfiguration.bats b/charts/consul/test/unit/connect-inject-mutatingwebhookconfiguration.bats index bc0876586c..81eda87875 100755 --- a/charts/consul/test/unit/connect-inject-mutatingwebhookconfiguration.bats +++ b/charts/consul/test/unit/connect-inject-mutatingwebhookconfiguration.bats @@ -60,7 +60,7 @@ load _helpers --set 'meshGateway.enabled=true' \ --set 'global.peering.enabled=true' \ . | tee /dev/stderr | - yq '.webhooks[12].name | contains("peeringacceptors.consul.hashicorp.com")' | tee /dev/stderr) + yq '.webhooks[11].name | contains("peeringacceptors.consul.hashicorp.com")' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(helm template \ -s templates/connect-inject-mutatingwebhookconfiguration.yaml \ @@ -69,6 +69,6 @@ load _helpers --set 'meshGateway.enabled=true' \ --set 'global.peering.enabled=true' \ . | tee /dev/stderr | - yq '.webhooks[13].name | contains("peeringdialers.consul.hashicorp.com")' | tee /dev/stderr) + yq '.webhooks[12].name | contains("peeringdialers.consul.hashicorp.com")' | tee /dev/stderr) [ "${actual}" = "true" ] } diff --git a/charts/consul/test/unit/crd-controlplanerequestlimits.bats b/charts/consul/test/unit/crd-controlplanerequestlimits.bats deleted file mode 100644 index ed98fc539f..0000000000 --- a/charts/consul/test/unit/crd-controlplanerequestlimits.bats +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "controlPlaneRequestLimit/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-controlplanerequestlimits.yaml \ - . | tee /dev/stderr | - yq -s 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "controlPlaneRequestLimit/CustomResourceDefinition: enabled with connectInject.enabled=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-controlplanerequestlimits.yaml \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - # The generated CRDs have "---" at the top which results in two objects - # being detected by yq, the first of which is null. We must therefore use - # yq -s so that length operates on both objects at once rather than - # individually, which would output false\ntrue and fail the test. - yq -s 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} diff --git a/charts/consul/test/unit/crd-exportedservices.bats b/charts/consul/test/unit/crd-exportedservices.bats index 235fe6bd24..1b8f4430b5 100644 --- a/charts/consul/test/unit/crd-exportedservices.bats +++ b/charts/consul/test/unit/crd-exportedservices.bats @@ -7,7 +7,7 @@ load _helpers local actual=$(helm template \ -s templates/crd-exportedservices.yaml \ . | tee /dev/stderr | - yq -s 'length > 0' | tee /dev/stderr) + yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } diff --git a/charts/consul/test/unit/crd-gatewayclassconfigs.bats b/charts/consul/test/unit/crd-gatewayclassconfigs.bats deleted file mode 100644 index 0228110b6b..0000000000 --- a/charts/consul/test/unit/crd-gatewayclassconfigs.bats +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "gatewayclassconfigs/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-gatewayclassconfigs.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewayclassconfigs/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-gatewayclassconfigs.yaml \ - --set 'connectInject.enabled=false' \ - . -} diff --git a/charts/consul/test/unit/crd-gatewayclasses.bats b/charts/consul/test/unit/crd-gatewayclasses.bats deleted file mode 100644 index 8400590606..0000000000 --- a/charts/consul/test/unit/crd-gatewayclasses.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "gatewayclasses/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-gatewayclasses.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewayclasses/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-gatewayclasses.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewayclasses/CustomResourceDefinition: disabled with connectInject.apiGateway.manageExternalCRDs=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-gatewayclasses.yaml \ - --set 'connectInject.apiGateway.manageExternalCRDs=false' \ - . -} diff --git a/charts/consul/test/unit/crd-gateways.bats b/charts/consul/test/unit/crd-gateways.bats deleted file mode 100644 index 8a7f0284e2..0000000000 --- a/charts/consul/test/unit/crd-gateways.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "gateways/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-gateways.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gateways/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-gateways.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gateways/CustomResourceDefinition: disabled with connectInject.apiGateway.manageExternalCRDs=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-gateways.yaml \ - --set 'connectInject.apiGateway.manageExternalCRDs=false' \ - . -} diff --git a/charts/consul/test/unit/crd-grpcroutes.bats b/charts/consul/test/unit/crd-grpcroutes.bats deleted file mode 100644 index d5e3e298d7..0000000000 --- a/charts/consul/test/unit/crd-grpcroutes.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "grpcroutes/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-grpcroutes.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "grpcroutes/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-grpcroutes.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "grpcroutes/CustomResourceDefinition: disabled with connectInject.apiGateway.manageExternalCRDs=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-grpcroutes.yaml \ - --set 'connectInject.apiGateway.manageExternalCRDs=false' \ - . -} diff --git a/charts/consul/test/unit/crd-httproutes.bats b/charts/consul/test/unit/crd-httproutes.bats deleted file mode 100644 index 99c58e0492..0000000000 --- a/charts/consul/test/unit/crd-httproutes.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "httproutes/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-httproutes.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "httproutes/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-httproutes.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "httproutes/CustomResourceDefinition: disabled with connectInject.apiGateway.manageExternalCRDs=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-httproutes.yaml \ - --set 'connectInject.apiGateway.manageExternalCRDs=false' \ - . -} diff --git a/charts/consul/test/unit/crd-meshservices.bats b/charts/consul/test/unit/crd-meshservices.bats deleted file mode 100644 index c1ee806ad4..0000000000 --- a/charts/consul/test/unit/crd-meshservices.bats +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "meshservices/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-meshservices.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "meshservices/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-meshservices.yaml \ - --set 'connectInject.enabled=false' \ - . -} - diff --git a/charts/consul/test/unit/crd-tcproutes.bats b/charts/consul/test/unit/crd-tcproutes.bats deleted file mode 100644 index 6916efdc6f..0000000000 --- a/charts/consul/test/unit/crd-tcproutes.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "tcproutes/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-tcproutes.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "tcproutes/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-tcproutes.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "tcproutes/CustomResourceDefinition: disabled with connectInject.apiGateway.manageExternalCRDs=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-tcproutes.yaml \ - --set 'connectInject.apiGateway.manageExternalCRDs=false' \ - . -} diff --git a/charts/consul/test/unit/crd-tlsroutes.bats b/charts/consul/test/unit/crd-tlsroutes.bats deleted file mode 100644 index 7e1d5c471f..0000000000 --- a/charts/consul/test/unit/crd-tlsroutes.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "tlsroutes/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-tlsroutes.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "tlsroutes/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-tlsroutes.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "tlsroutes/CustomResourceDefinition: disabled with connectInject.apiGateway.manageExternalCRDs=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-tlsroutes.yaml \ - --set 'connectInject.apiGateway.manageExternalCRDs=false' \ - . -} diff --git a/charts/consul/test/unit/crd-udproutes.bats b/charts/consul/test/unit/crd-udproutes.bats deleted file mode 100644 index 407592a770..0000000000 --- a/charts/consul/test/unit/crd-udproutes.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "udproutes/CustomResourceDefinition: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/crd-udproutes.yaml \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "udproutes/CustomResourceDefinition: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-udproutes.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "udproutes/CustomResourceDefinition: disabled with connectInject.apiGateway.manageExternalCRDs=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/crd-udproutes.yaml \ - --set 'connectInject.apiGateway.manageExternalCRDs=false' \ - . -} diff --git a/charts/consul/test/unit/gateway-cleanup-clusterrole.bats b/charts/consul/test/unit/gateway-cleanup-clusterrole.bats deleted file mode 100644 index c672ac5593..0000000000 --- a/charts/consul/test/unit/gateway-cleanup-clusterrole.bats +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-cleanup-clusterrole.yaml - -@test "gatewaycleanup/ClusterRole: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewaycleanup/ClusterRole: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewaycleanup/ClusterRole: can use podsecuritypolicies with global.enablePodSecurityPolicy=true" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - --set "global.enablePodSecurityPolicies=true" \ - . | tee /dev/stderr | - yq '.rules[] | select((.resources[0] == "podsecuritypolicies") and (.verbs[0] == "use")) | length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - diff --git a/charts/consul/test/unit/gateway-cleanup-clusterrolebinding.bats b/charts/consul/test/unit/gateway-cleanup-clusterrolebinding.bats deleted file mode 100644 index a6e4af5d2c..0000000000 --- a/charts/consul/test/unit/gateway-cleanup-clusterrolebinding.bats +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-cleanup-clusterrolebinding.yaml - -@test "gatewaycleanup/ClusterRoleBinding: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewaycleanup/ClusterRoleBinding: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - diff --git a/charts/consul/test/unit/gateway-cleanup-job.bats b/charts/consul/test/unit/gateway-cleanup-job.bats deleted file mode 100644 index 657bf4a791..0000000000 --- a/charts/consul/test/unit/gateway-cleanup-job.bats +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-cleanup-job.yaml - -@test "gatewaycleanup/Job: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewaycleanup/Job: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - - -#-------------------------------------------------------------------- -# annotations - -@test "gatewaycleanup/Job: no annotations defined by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."consul.hashicorp.com/config-checksum")' | tee /dev/stderr) - [ "${actual}" = "{}" ] -} - -@test "gatewaycleanup/Job: annotations can be set" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - --set 'global.acls.annotations=foo: bar' \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) - [ "${actual}" = "bar" ] -} diff --git a/charts/consul/test/unit/gateway-cleanup-podsecuritypolicy.bats b/charts/consul/test/unit/gateway-cleanup-podsecuritypolicy.bats deleted file mode 100644 index 66974da2fd..0000000000 --- a/charts/consul/test/unit/gateway-cleanup-podsecuritypolicy.bats +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-cleanup-podsecuritypolicy.yaml - -@test "gatewaycleanup/PodSecurityPolicy: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewaycleanup/PodSecurityPolicy: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewaycleanup/PodSecurityPolicy: disabled with global.enablePodSecurityPolicies=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'global.enablePodSecurityPolicies=false' \ - . -} - - -@test "gatewaycleanup/PodSecurityPolicy: enabled with connectInject.enabled=true and global.enablePodSecurityPolicies=true" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - --set 'connectInject.enabled=true' \ - --set 'global.enablePodSecurityPolicies=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} diff --git a/charts/consul/test/unit/gateway-cleanup-serviceaccount.bats b/charts/consul/test/unit/gateway-cleanup-serviceaccount.bats deleted file mode 100644 index 50d01b99e9..0000000000 --- a/charts/consul/test/unit/gateway-cleanup-serviceaccount.bats +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-cleanup-serviceaccount.yaml - -@test "gatewaycleanup/ServiceAccount: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewaycleanup/ServiceAccount: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - diff --git a/charts/consul/test/unit/gateway-resources-clusterrole.bats b/charts/consul/test/unit/gateway-resources-clusterrole.bats deleted file mode 100644 index 152209a1b5..0000000000 --- a/charts/consul/test/unit/gateway-resources-clusterrole.bats +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-resources-clusterrole.yaml - -@test "gatewayresources/ClusterRole: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewayresources/ClusterRole: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewayresources/ClusterRole: can use podsecuritypolicies with global.enablePodSecurityPolicy=true" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - --set "global.enablePodSecurityPolicies=true" \ - . | tee /dev/stderr | - yq '.rules[] | select((.resources[0] == "podsecuritypolicies") and (.verbs[0] == "use")) | length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - diff --git a/charts/consul/test/unit/gateway-resources-clusterrolebinding.bats b/charts/consul/test/unit/gateway-resources-clusterrolebinding.bats deleted file mode 100644 index efc1429e20..0000000000 --- a/charts/consul/test/unit/gateway-resources-clusterrolebinding.bats +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-resources-clusterrolebinding.yaml - -@test "gatewayresources/ClusterRoleBinding: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewayresources/ClusterRoleBinding: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - diff --git a/charts/consul/test/unit/gateway-resources-configmap.bats b/charts/consul/test/unit/gateway-resources-configmap.bats deleted file mode 100644 index 80225eeefb..0000000000 --- a/charts/consul/test/unit/gateway-resources-configmap.bats +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "gateway-resources/ConfigMap: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/gateway-resources-configmap.yaml \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gateway-resources/ConfigMap: enabled with connectInject.enabled=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/gateway-resources-configmap.yaml \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gateway-resources/ConfigMap: contains resources configuration as JSON" { - cd `chart_dir` - local resources=$(helm template \ - -s templates/gateway-resources-configmap.yaml \ - --set 'connectInject.enabled=true' \ - --set 'connectInject.apiGateway.managedGatewayClass.resources.requests.memory=200Mi' \ - --set 'connectInject.apiGateway.managedGatewayClass.resources.requests.cpu=200m' \ - --set 'connectInject.apiGateway.managedGatewayClass.resources.limits.memory=220Mi' \ - --set 'connectInject.apiGateway.managedGatewayClass.resources.limits.cpu=220m' \ - . | tee /dev/stderr | - yq '.data["resources.json"] | fromjson' | tee /dev/stderr) - - local actual=$(echo $resources | jq -r '.requests.memory') - [ $actual = '200Mi' ] - - local actual=$(echo $resources | jq -r '.requests.cpu') - [ $actual = '200m' ] - - local actual=$(echo $resources | jq -r '.limits.memory') - [ $actual = '220Mi' ] - - local actual=$(echo $resources | jq -r '.limits.cpu') - [ $actual = '220m' ] -} diff --git a/charts/consul/test/unit/gateway-resources-job.bats b/charts/consul/test/unit/gateway-resources-job.bats deleted file mode 100644 index 09322bd2a7..0000000000 --- a/charts/consul/test/unit/gateway-resources-job.bats +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-resources-job.yaml - -@test "gatewayresources/Job: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewayresources/Job: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewayresources/Job: imageK8S set properly" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - --set 'global.imageK8S=foo' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].image == "foo"' | tee /dev/stderr) - [ "$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 - -@test "gatewayresources/Job: default configuration" { - cd `chart_dir` - local spec=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].args' | tee /dev/stderr) - - local actual=$(echo "$spec" | jq 'any(index("-deployment-default-instances=1"))') - [ "${actual}" = "true" ] - - local actual=$(echo "$spec" | jq 'any(index("-deployment-max-instances=1"))') - [ "${actual}" = "true" ] - - local actual=$(echo "$spec" | jq 'any(index("-deployment-min-instances=1"))') - [ "${actual}" = "true" ] - - local actual=$(echo "$spec" | jq 'any(index("-service-type=LoadBalancer"))') - [ "${actual}" = "true" ] -} - -@test "apiGateway/GatewayClassConfig: custom configuration" { - cd `chart_dir` - local spec=$(helm template \ - -s $target \ - --set 'connectInject.apiGateway.managedGatewayClass.deployment.defaultInstances=2' \ - --set 'connectInject.apiGateway.managedGatewayClass.deployment.minInstances=1' \ - --set 'connectInject.apiGateway.managedGatewayClass.deployment.maxInstances=3' \ - --set 'connectInject.apiGateway.managedGatewayClass.nodeSelector=foo: bar' \ - --set 'connectInject.apiGateway.managedGatewayClass.tolerations=- key: bar' \ - --set 'connectInject.apiGateway.managedGatewayClass.copyAnnotations.service.annotations=- bingo' \ - --set 'connectInject.apiGateway.managedGatewayClass.serviceType=Foo' \ - --set 'connectInject.apiGateway.managedGatewayClass.openshiftSCCName=hello' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].args' | tee /dev/stderr) - - local actual=$(echo "$spec" | jq 'any(index("-deployment-default-instances=2"))') - [ "${actual}" = "true" ] - - local actual=$(echo "$spec" | jq 'any(index("-deployment-max-instances=3"))') - [ "${actual}" = "true" ] - - local actual=$(echo "$spec" | jq 'any(index("-deployment-min-instances=1"))') - [ "${actual}" = "true" ] - - local actual=$(echo "$spec" | jq 'any(index("-service-type=Foo"))') - [ "${actual}" = "true" ] - - local actual=$(echo "$spec" | jq '.[12]') - [ "${actual}" = "\"-node-selector\"" ] - - local actual=$(echo "$spec" | jq '.[13]') - [ "${actual}" = "\"foo: bar\"" ] - - local actual=$(echo "$spec" | jq '.[14] | ."-tolerations=- key"') - [ "${actual}" = "\"bar\"" ] - - local actual=$(echo "$spec" | jq '.[15]') - [ "${actual}" = "\"-service-annotations\"" ] - - local actual=$(echo "$spec" | jq '.[16]') - [ "${actual}" = "\"- bingo\"" ] - - local actual=$(echo "$spec" | jq '.[17]') - [ "${actual}" = "\"-service-type=Foo\"" ] -} - -@test "apiGateway/GatewayClassConfig: custom configuration openshift enabled" { - cd `chart_dir` - local spec=$(helm template \ - -s $target \ - --set 'global.openshift.enabled=true' \ - --set 'connectInject.apiGateway.managedGatewayClass.openshiftSCCName=hello' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].args' | tee /dev/stderr) - - local actual=$(echo "$spec" | jq '.[13]') - [ "${actual}" = "\"-openshift-scc-name=hello\"" ] -} - - -#-------------------------------------------------------------------- -# annotations - -@test "gatewayresources/Job: no annotations defined by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."consul.hashicorp.com/config-checksum")' | tee /dev/stderr) - [ "${actual}" = "{}" ] -} - -@test "gatewayresources/Job: annotations can be set" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - --set 'global.acls.annotations=foo: bar' \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) - [ "${actual}" = "bar" ] -} diff --git a/charts/consul/test/unit/gateway-resources-podsecuritypolicy.bats b/charts/consul/test/unit/gateway-resources-podsecuritypolicy.bats deleted file mode 100644 index 81818c525a..0000000000 --- a/charts/consul/test/unit/gateway-resources-podsecuritypolicy.bats +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-resources-podsecuritypolicy.yaml - -@test "gatewayresources/PodSecurityPolicy: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewayresources/PodSecurityPolicy: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - -@test "gatewayresources/PodSecurityPolicy: disabled with global.enablePodSecurityPolicies=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'global.enablePodSecurityPolicies=false' \ - . -} - - -@test "gatewayresources/PodSecurityPolicy: enabled with connectInject.enabled=true and global.enablePodSecurityPolicies=true" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - --set 'connectInject.enabled=true' \ - --set 'global.enablePodSecurityPolicies=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} diff --git a/charts/consul/test/unit/gateway-resources-serviceaccount.bats b/charts/consul/test/unit/gateway-resources-serviceaccount.bats deleted file mode 100644 index 90011e226b..0000000000 --- a/charts/consul/test/unit/gateway-resources-serviceaccount.bats +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -target=templates/gateway-resources-serviceaccount.yaml - -@test "gatewayresources/ServiceAccount: enabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s $target \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "$actual" = "true" ] -} - -@test "gatewayresources/ServiceAccount: disabled with connectInject.enabled=false" { - cd `chart_dir` - assert_empty helm template \ - -s $target \ - --set 'connectInject.enabled=false' \ - . -} - diff --git a/charts/consul/test/unit/helpers.bats b/charts/consul/test/unit/helpers.bats index 82fc54bcf2..4245b519c4 100644 --- a/charts/consul/test/unit/helpers.bats +++ b/charts/consul/test/unit/helpers.bats @@ -115,7 +115,7 @@ load _helpers @test "helper/namespace: used everywhere" { cd `chart_dir` # Grep for files that don't have 'namespace: ' in them - local actual=$(grep -L 'namespace: ' templates/*.yaml | grep -v 'crd' | grep -v 'clusterrole' | grep -v 'gateway-gateway' | tee /dev/stderr ) + local actual=$(grep -L 'namespace: ' templates/*.yaml | grep -v 'crd' | grep -v 'clusterrole' | grep -v 'api-gateway-gateway' | tee /dev/stderr ) [ "${actual}" = '' ] } @@ -327,140 +327,3 @@ load _helpers actual=$(echo $object | jq '.volumeMounts[] | select(.name == "consul-ca-cert")') [ "${actual}" = "" ] } - -#-------------------------------------------------------------------- -# consul.validateResourceAPIs -# These tests use test-runner.yaml to test the -# consul.validateResourceAPIs helper since we need an existing template - -@test "connectInject/Deployment: fails if resource-apis is set and peering is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.tls.enabled=true' \ - --set 'meshGateway.enabled=true' \ - --set 'global.peering.enabled=true' \ - . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, global.peering.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and federation is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.tls.enabled=true' \ - --set 'meshGateway.enabled=true' \ - --set 'global.federation.enabled=true' \ - . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, global.federation.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and cloud is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'global.cloud.enabled=true' \ - --set 'global.cloud.resourceId.secretName=hello' \ - --set 'global.cloud.resourceId.secretKey=hello' \ - --set 'global.cloud.clientId.secretName=hello' \ - --set 'global.cloud.clientId.secretKey=hello' \ - --set 'global.cloud.clientSecret.secretName=hello' \ - --set 'global.cloud.clientSecret.secretKey=hello' \ - . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, global.cloud.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and client is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'client.enabled=true' . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, client.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and ui is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, ui.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and syncCatalog is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'syncCatalog.enabled=true' . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, syncCatalog.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and meshGateway is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'meshGateway.enabled=true' . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, meshGateway.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and ingressGateways is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'ingressGateways.enabled=true' . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, ingressGateways.enabled is currently unsupported." ]] -} - -@test "connectInject/Deployment: fails if resource-apis is set and terminatingGateways is enabled" { - cd `chart_dir` - run helm template \ - -s templates/tests/test-runner.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - --set 'terminatingGateways.enabled=true' . - [ "$status" -eq 1 ] - [[ "$output" =~ "When the value global.experiments.resourceAPIs is set, terminatingGateways.enabled is currently unsupported." ]] -} - -@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 '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." ]] -} diff --git a/charts/consul/test/unit/partition-init-job.bats b/charts/consul/test/unit/partition-init-job.bats index d4b3b4e38a..a3524090aa 100644 --- a/charts/consul/test/unit/partition-init-job.bats +++ b/charts/consul/test/unit/partition-init-job.bats @@ -938,43 +938,3 @@ reservedNameTest() { [ "${actualTemplateFoo}" = "bar" ] [ "${actualTemplateBaz}" = "qux" ] } - -#-------------------------------------------------------------------- -# global.experiments=["resource-apis"] - -@test "partitionInit/Job: -enable-resource-apis=true is not set in command when global.experiments is empty" { - cd `chart_dir` - local object=$(helm template \ - -s templates/partition-init-job.yaml \ - --set 'global.adminPartitions.enabled=true' \ - --set 'global.enableConsulNamespaces=true' \ - --set 'server.enabled=false' \ - --set 'global.adminPartitions.name=bar' \ - --set 'externalServers.enabled=true' \ - --set 'externalServers.hosts[0]=foo' \ - . | tee /dev/stderr) - - # Test the flag is set. - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[] | select(.name == "partition-init-job") | .command | any(contains("-enable-resource-apis=true"))' | tee /dev/stderr) - [ "${actual}" = "false" ] -} - -@test "partitionInit/Job: -enable-resource-apis=true is set in command when global.experiments contains \"resource-apis\"" { - cd `chart_dir` - local object=$(helm template \ - -s templates/partition-init-job.yaml \ - --set 'global.adminPartitions.enabled=true' \ - --set 'global.enableConsulNamespaces=true' \ - --set 'server.enabled=false' \ - --set 'global.adminPartitions.name=bar' \ - --set 'externalServers.enabled=true' \ - --set 'externalServers.hosts[0]=foo' \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - . | tee /dev/stderr) - - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[] | select(.name == "partition-init-job") | .command | any(contains("-enable-resource-apis=true"))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index 1dc55a9551..9b15f9e869 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -650,19 +650,7 @@ load _helpers yq -r '.spec.template' | tee /dev/stderr) # Check annotations - actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-pre-populate"]' | tee /dev/stderr) - [ "${actual}" = "true" ] - actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-pre-populate-only"]' | tee /dev/stderr) - [ "${actual}" = "false" ] - - actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-cache-enable"]' | tee /dev/stderr) - [ "${actual}" = "true" ] - - actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-cache-listener-port"]' | tee /dev/stderr) - [ "${actual}" = "8200" ] - - actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-enable-quit"]' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) @@ -671,13 +659,15 @@ load _helpers local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) [ "${actual}" = "aclrole" ] - local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-secrets-backend=vault"))') - [ "${actual}" = "true" ] + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-bootstrap-token"]' | tee /dev/stderr) + [ "${actual}" = "foo" ] - local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-name=foo"))') - [ "${actual}" = "true" ] + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-bootstrap-token"]' | tee /dev/stderr) + local expected=$'{{- with secret \"foo\" -}}\n{{- .Data.data.bar -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] - local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-key=bar"))') + # Check that the bootstrap token flag is set to the path of the Vault secret. + local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-file=/vault/secrets/bootstrap-token"))') [ "${actual}" = "true" ] # Check that no (secret) volumes are not attached @@ -708,31 +698,20 @@ load _helpers yq -r '.spec.template' | tee /dev/stderr) # Check annotations - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-pre-populate"]' | tee /dev/stderr) - [ "${actual}" = "true" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-pre-populate-only"]' | tee /dev/stderr) - [ "${actual}" = "false" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-cache-enable"]' | tee /dev/stderr) - [ "${actual}" = "true" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-cache-listener-port"]' | tee /dev/stderr) - [ "${actual}" = "8200" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-enable-quit"]' | tee /dev/stderr) + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-pre-populate-only"]' | tee /dev/stderr) [ "${actual}" = "true" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) [ "${actual}" = "true" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) [ "${actual}" = "aclrole" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr) + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr) [ "${actual}" = "foo" ] - - local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr) + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr) [ "${actual}" = $'{{- with secret \"foo\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' ] # Check that the consul-ca-cert volume is not attached @@ -918,14 +897,12 @@ load _helpers local expected=$'{{- with secret \"/vault/replication\" -}}\n{{- .Data.data.token -}}\n{{- end -}}' [ "${actual}" = "${expected}" ] - local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-secrets-backend=vault"))') - [ "${actual}" = "true" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-inject-secret-bootstrap-token"') + [ "${actual}" = "/vault/bootstrap" ] - local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-name=/vault/bootstrap"))') - [ "${actual}" = "true" ] - - local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-key=token"))') - [ "${actual}" = "true" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-inject-template-bootstrap-token"') + local expected=$'{{- with secret \"/vault/bootstrap\" -}}\n{{- .Data.data.token -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] # Check that replication token Kubernetes secret volumes and volumeMounts are not attached. local actual=$(echo $object | jq -r '.spec.volumes') @@ -934,9 +911,12 @@ load _helpers local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").volumeMounts') [ "${actual}" = "null" ] - # Replication token file is passed. + # Check that the replication and bootstrap token flags are set to the path of the Vault secret. local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-acl-replication-token-file=/vault/secrets/replication-token"))') [ "${actual}" = "true" ] + + local actual=$(echo $object | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-file=/vault/secrets/bootstrap-token"))') + [ "${actual}" = "true" ] } #-------------------------------------------------------------------- @@ -989,7 +969,7 @@ load _helpers #-------------------------------------------------------------------- # Vault agent annotations -@test "serverACLInit/Job: default vault agent annotations" { +@test "serverACLInit/Job: no vault agent annotations defined by default" { cd `chart_dir` local actual=$(helm template \ -s templates/server-acl-init-job.yaml \ @@ -1003,21 +983,8 @@ load _helpers --set 'global.secretsBackend.vault.consulCARole=carole' \ --set 'global.secretsBackend.vault.manageSystemACLsRole=aclrole' \ . | tee /dev/stderr | - yq -r .spec.template.metadata.annotations | tee /dev/stderr) - - local expected=$(echo '{ - "consul.hashicorp.com/connect-inject": "false", - "vault.hashicorp.com/agent-inject": "true", - "vault.hashicorp.com/agent-pre-populate": "true", - "vault.hashicorp.com/agent-pre-populate-only": "false", - "vault.hashicorp.com/agent-cache-enable": "true", - "vault.hashicorp.com/agent-cache-listener-port": "8200", - "vault.hashicorp.com/agent-enable-quit": "true", - "vault.hashicorp.com/role": "aclrole" - }' | tee /dev/stderr) - - local equal=$(jq -n --argjson a "$actual" --argjson b "$expected" '$a == $b') - [ "$equal" = "true" ] + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/agent-pre-populate-only") | del(."vault.hashicorp.com/role") | del(."vault.hashicorp.com/agent-inject-secret-bootstrap-token") | del(."vault.hashicorp.com/agent-inject-template-bootstrap-token")' | tee /dev/stderr) + [ "${actual}" = "{}" ] } @test "serverACLInit/Job: vault agent annotations can be set" { @@ -1856,23 +1823,55 @@ load _helpers [[ "$output" =~ "both global.acls.bootstrapToken.secretKey and global.acls.bootstrapToken.secretName must be set if one of them is provided" ]] } -@test "serverACLInit/Job: bootstrap token secret is passed when acls.bootstrapToken.secretKey and secretName are set" { +@test "serverACLInit/Job: -bootstrap-token-file is not set by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr) + + # Test the flag is not set. + local actual=$(echo "$object" | + yq '.spec.template.spec.containers[0].command | any(contains("-bootstrap-token-file"))' | tee /dev/stderr) + [ "${actual}" = "false" ] + + # Test the volume doesn't exist + local actual=$(echo "$object" | + yq '.spec.template.spec.volumes | length == 0' | tee /dev/stderr) + [ "${actual}" = "true" ] + + # Test the volume mount doesn't exist + local actual=$(echo "$object" | + yq '.spec.template.spec.containers[0].volumeMounts | length == 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "serverACLInit/Job: -bootstrap-token-file is set when acls.bootstrapToken.secretKey and secretName are set" { cd `chart_dir` local object=$(helm template \ -s templates/server-acl-init-job.yaml \ --set 'global.acls.manageSystemACLs=true' \ --set 'global.acls.bootstrapToken.secretName=name' \ --set 'global.acls.bootstrapToken.secretKey=key' \ - . | yq .spec.template | tee /dev/stderr) + . | tee /dev/stderr) - local actual=$(echo "$object" | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-name=name"))') + # Test the -bootstrap-token-file flag is set. + local actual=$(echo "$object" | + yq '.spec.template.spec.containers[0].command | any(contains("-bootstrap-token-file=/consul/acl/tokens/bootstrap-token"))' | tee /dev/stderr) [ "${actual}" = "true" ] - local actual=$(echo "$object" | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-key=key"))') + # Test the volume exists + local actual=$(echo "$object" | + yq '.spec.template.spec.volumes | map(select(.name == "bootstrap-token")) | length == 1' | tee /dev/stderr) + [ "${actual}" = "true" ] + + # Test the volume mount exists + local actual=$(echo "$object" | + yq '.spec.template.spec.containers[0].volumeMounts | map(select(.name == "bootstrap-token")) | length == 1' | tee /dev/stderr) [ "${actual}" = "true" ] } -@test "serverACLInit/Job: bootstrap token secret is passed when both acl.bootstrapToken and acls.replicationToken are set" { +@test "serverACLInit/Job: -bootstrap-token-file is preferred when both acls.bootstrapToken and acls.replicationToken are set" { cd `chart_dir` local object=$(helm template \ -s templates/server-acl-init-job.yaml \ @@ -1881,12 +1880,21 @@ load _helpers --set 'global.acls.bootstrapToken.secretKey=key' \ --set 'global.acls.replicationToken.secretName=replication' \ --set 'global.acls.replicationToken.secretKey=token' \ - . | yq .spec.template | tee /dev/stderr) + . | tee /dev/stderr) - local actual=$(echo "$object" | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-name=name"))') + # Test the -bootstrap-token-file flag is set. + local actual=$(echo "$object" | + yq '.spec.template.spec.containers[0].command | any(contains("-bootstrap-token-file=/consul/acl/tokens/bootstrap-token"))' | tee /dev/stderr) [ "${actual}" = "true" ] - local actual=$(echo "$object" | jq -r '.spec.containers[] | select(.name=="server-acl-init-job").command | any(contains("-bootstrap-token-secret-key=key"))') + # Test the volume exists + local actual=$(echo "$object" | + yq '.spec.template.spec.volumes | map(select(.name == "bootstrap-token")) | length == 1' | tee /dev/stderr) + [ "${actual}" = "true" ] + + # Test the volume mount exists + local actual=$(echo "$object" | + yq '.spec.template.spec.containers[0].volumeMounts | map(select(.name == "bootstrap-token")) | length == 1' | tee /dev/stderr) [ "${actual}" = "true" ] } diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 643caeb0a1..ad1c79d248 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -966,98 +966,6 @@ load _helpers [ "${actual}" = "true" ] } -#-------------------------------------------------------------------- -# server.limits.requestLimits - -@test "server/ConfigMap: server.limits.requestLimits.mode is disabled by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) - - [ "${actual}" = "disabled" ] -} - -@test "server/ConfigMap: server.limits.requestLimits.mode accepts disabled, permissive, and enforce" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - --set 'server.limits.requestLimits.mode=disabled' \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) - - [ "${actual}" = "disabled" ] - - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - --set 'server.limits.requestLimits.mode=permissive' \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) - - [ "${actual}" = "permissive" ] - - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - --set 'server.limits.requestLimits.mode=enforce' \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) - - [ "${actual}" = "enforce" ] -} - -@test "server/ConfigMap: server.limits.requestLimits.mode errors with value other than disabled, permissive, and enforce" { - cd `chart_dir` - run helm template \ - -s templates/server-config-configmap.yaml \ - --set 'server.limits.requestLimits.mode=notvalid' \ - . - [ "$status" -eq 1 ] - [[ "$output" =~ "server.limits.requestLimits.mode must be one of the following values: disabled, permissive, and enforce" ]] -} - -@test "server/ConfigMap: server.limits.request_limits.read_rate is -1 by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.read_rate | tee /dev/stderr) - - [ "${actual}" = "-1" ] -} - -@test "server/ConfigMap: server.limits.request_limits.read_rate is set properly when specified " { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - --set 'server.limits.requestLimits.readRate=100' \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.read_rate | tee /dev/stderr) - - [ "${actual}" = "100" ] -} - -@test "server/ConfigMap: server.limits.request_limits.write_rate is -1 by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.write_rate | tee /dev/stderr) - - [ "${actual}" = "-1" ] -} - -@test "server/ConfigMap: server.limits.request_limits.write_rate is set properly when specified " { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - --set 'server.limits.requestLimits.writeRate=100' \ - . | tee /dev/stderr | - yq -r '.data["server.json"]' | jq -r .limits.request_limits.write_rate | tee /dev/stderr) - - [ "${actual}" = "100" ] -} - #-------------------------------------------------------------------- # server.auditLogs @@ -1175,7 +1083,7 @@ load _helpers local actual=$(echo $object | jq -r .audit.sink.MySink1.path | tee /dev/stderr) [ "${actual}" = "/tmp/audit.json" ] - + local actual=$(echo $object | jq -r .audit.sink.MySink3.path | tee /dev/stderr) [ "${actual}" = "/tmp/audit-3.json" ] diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index dcef8d1382..063c62b1a3 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -677,41 +677,6 @@ load _helpers [ "${actual}" = "/v1/agent/metrics" ] } -@test "server/StatefulSet: when global.metrics.enableAgentMetrics=true, adds prometheus scheme=http annotation" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.metrics.enabled=true' \ - --set 'global.metrics.enableAgentMetrics=true' \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.annotations."prometheus.io/scheme"' | tee /dev/stderr) - [ "${actual}" = "http" ] -} - -@test "server/StatefulSet: when global.metrics.enableAgentMetrics=true and global.tls.enabled=true, adds prometheus port=8501 annotation" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.metrics.enabled=true' \ - --set 'global.metrics.enableAgentMetrics=true' \ - --set 'global.tls.enabled=true' \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.annotations."prometheus.io/port"' | tee /dev/stderr) - [ "${actual}" = "8501" ] -} - -@test "server/StatefulSet: when global.metrics.enableAgentMetrics=true and global.tls.enabled=true, adds prometheus scheme=https annotation" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.metrics.enabled=true' \ - --set 'global.metrics.enableAgentMetrics=true' \ - --set 'global.tls.enabled=true' \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.annotations."prometheus.io/scheme"' | tee /dev/stderr) - [ "${actual}" = "https" ] -} - #-------------------------------------------------------------------- # config-configmap @@ -721,7 +686,7 @@ load _helpers -s templates/server-statefulset.yaml \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 3714bf1fbca840dcd10b5aeb40c6ef35e349bd534727abe80b831c77f88da7da ] + [ "${actual}" = dc165411861bb45d37e20a0a337697336f333407f5fb29fca9252cdba652339c ] } @test "server/StatefulSet: adds config-checksum annotation when extraConfig is provided" { @@ -731,7 +696,7 @@ load _helpers --set 'server.extraConfig="{\"hello\": \"world\"}"' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 87126fac3c7704fba1d4265201ad0345f4d972d2123df6e6fb416b40c5823d80 ] + [ "${actual}" = d69874f33a862f6728265246a3e38b3f64702e013ecd4afc5dcdc33d34a66954 ] } @test "server/StatefulSet: adds config-checksum annotation when config is updated" { @@ -741,7 +706,7 @@ load _helpers --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = d98ff135c5dee661058f33e29970675761ecf235676db0d4d24f354908eee425 ] + [ "${actual}" = 95a3d3b4816a0f183b8a9aac41ff386e659cd2a465f3030f01c5c4a2b9052a6c ] } #-------------------------------------------------------------------- @@ -881,9 +846,11 @@ load _helpers #-------------------------------------------------------------------- # global.openshift.enabled -@test "server/StatefulSet: restricted container securityContexts are set when global.openshift.enabled=true" { +@test "server/StatefulSet: restricted container securityContexts are set when global.openshift.enabled=true on OpenShift >= 4.11" { cd `chart_dir` + # OpenShift 4.11 == Kube 1.24 local manifest=$(helm template \ + --kube-version '1.24' \ -s templates/server-statefulset.yaml \ --set 'global.openshift.enabled=true' \ . | tee /dev/stderr) @@ -904,11 +871,20 @@ load _helpers local actual=$(echo "$manifest" | yq -r '.spec.template.spec.containers | map(select(.name == "consul")) | .[0].securityContext') local equal=$(jq -n --argjson a "$actual" --argjson b "$expected" '$a == $b') [ "$equal" == "true" ] +} - # Check locality-init container - local actual=$(echo "$manifest" | yq -r '.spec.template.spec.initContainers | map(select(.name == "locality-init")) | .[0].securityContext') - local equal=$(jq -n --argjson a "$actual" --argjson b "$expected" '$a == $b') - [ "$equal" == "true" ] +@test "server/StatefulSet: restricted container securityContexts are not set when global.openshift.enabled=true on OpenShift < 4.11" { + cd `chart_dir` + # OpenShift 4.11 == Kube 1.24 + local manifest=$(helm template \ + --kube-version '1.23' \ + -s templates/server-statefulset.yaml \ + --set 'global.openshift.enabled=true' \ + . | tee /dev/stderr) + + # Check consul container + local actual=$(echo "$manifest" | yq -r '.spec.template.spec.containers | map(select(.name == "consul")) | .[0].securityContext') + [ "$actual" == "null" ] } #-------------------------------------------------------------------- @@ -937,11 +913,6 @@ load _helpers local actual=$(echo "$manifest" | yq -r '.spec.template.spec.containers | map(select(.name == "consul")) | .[0].securityContext') local equal=$(jq -n --argjson a "$actual" --argjson b "$expected" '$a == $b') [ "$equal" == "true" ] - - # Check locality-init container - local actual=$(echo "$manifest" | yq -r '.spec.template.spec.initContainers | map(select(.name == "locality-init")) | .[0].securityContext') - local equal=$(jq -n --argjson a "$actual" --argjson b "$expected" '$a == $b') - [ "$equal" == "true" ] } #-------------------------------------------------------------------- @@ -2687,64 +2658,6 @@ MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ } -#-------------------------------------------------------------------- -# global.trustedCAs - -@test "server/StatefulSet: trustedCAs: if trustedCAs is set command is modified correctly" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0].command[2] | contains("cat < /trusted-cas/custom-ca-0.pem")' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "server/StatefulSet: trustedCAs: if tustedCAs multiple are set" { - cd `chart_dir` - local object=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - --set 'global.trustedCAs[1]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0]' | tee /dev/stderr) - - - local actual=$(echo $object | jq '.command[2] | contains("cat < /trusted-cas/custom-ca-0.pem")' | tee /dev/stderr) - [ "${actual}" = "true" ] - local actual=$(echo $object | jq '.command[2] | contains("cat < /trusted-cas/custom-ca-1.pem")' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -# global.trustedCAs -@test "server/StatefulSet: trustedCAs: if trustedCAs is set /trusted-cas volumeMount is added" { - cd `chart_dir` - local object=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | yq -r '.spec.template.spec' | tee /dev/stderr) - local actual=$(echo $object | jq -r '.volumes[] | select(.name == "trusted-cas") | .name' | tee /dev/stderr) - [ "${actual}" = "trusted-cas" ] -} - -@test "server/StatefulSet: trustedCAs: if trustedCAs is set SSL_CERT_DIR env var is set" { - cd `chart_dir` - local object=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env[] | select(.name == "SSL_CERT_DIR")' | tee /dev/stderr) - - local actual=$(echo $object | jq -r '.name' | tee /dev/stderr) - [ "${actual}" = "SSL_CERT_DIR" ] - local actual=$(echo $object | jq -r '.value' | tee /dev/stderr) - [ "${actual}" = "/etc/ssl/certs:/trusted-cas" ] -} - #-------------------------------------------------------------------- # snapshotAgent license-autoload @@ -2933,31 +2846,3 @@ MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ yq -r '.spec.template.spec.containers[1].command[2] | contains("-interval=10h34m5s")' | tee /dev/stderr) [ "${actual}" = "true" ] } - -#-------------------------------------------------------------------- -# global.experiments=["resource-apis"] - -@test "server/StatefulSet: experiments=[\"resource-apis\"] is not set in command when global.experiments is empty" { - cd `chart_dir` - local object=$(helm template \ - -s templates/server-statefulset.yaml \ - . | tee /dev/stderr) - - # Test the flag is set. - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[] | select(.name == "consul") | .command | any(contains("-hcl=\"experiments=[\\\"resource-apis\\\"]\""))' | tee /dev/stderr) - [ "${actual}" = "false" ] -} - -@test "server/StatefulSet: experiments=[\"resource-apis\"] is set in command when global.experiments contains \"resource-apis\"" { - cd `chart_dir` - local object=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.experiments[0]=resource-apis' \ - --set 'ui.enabled=false' \ - . | tee /dev/stderr) - - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[] | select(.name == "consul") | .command | any(contains("-hcl=\"experiments=[\\\"resource-apis\\\"]\""))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/telemetry-collector-configmap.bats b/charts/consul/test/unit/telemetry-collector-configmap.bats deleted file mode 100644 index c866f0d3e1..0000000000 --- a/charts/consul/test/unit/telemetry-collector-configmap.bats +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "telemetryCollector/ConfigMap: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-configmap.yaml \ - . -} - -@test "telemetryCollector/ConfigMap: enabled with telemetryCollector enabled and config has content" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-configmap.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.customExporterConfig="{}"' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/ConfigMap: disabled with telemetryCollector enabled and config is empty content" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-configmap.yaml \ - --set 'telemetryCollector.enabled=true' \ - . -} \ No newline at end of file diff --git a/charts/consul/test/unit/telemetry-collector-deployment.bats b/charts/consul/test/unit/telemetry-collector-deployment.bats deleted file mode 100755 index 7809039e11..0000000000 --- a/charts/consul/test/unit/telemetry-collector-deployment.bats +++ /dev/null @@ -1,1133 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "telemetryCollector/Deployment: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-deployment.yaml \ - . -} - -@test "telemetryCollector/Deployment: fails if no image is set" { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=null' \ - . - [ "$status" -eq 1 ] - [[ "$output" =~ "telemetryCollector.image must be set to enable consul-telemetry-collector" ]] -} - -@test "telemetryCollector/Deployment: disable with telemetry-collector.enabled" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=false' \ - . -} - -@test "telemetryCollector/Deployment: disable with global.enabled" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'global.enabled=false' \ - . -} - -@test "telemetryCollector/Deployment: container image overrides" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "\"bar\"" ] -} - -#-------------------------------------------------------------------- -# nodeSelector - -@test "telemetryCollector/Deployment: nodeSelector is not set by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - . | tee /dev/stderr | - yq '.spec.template.spec.nodeSelector' | tee /dev/stderr) - [ "${actual}" = "null" ] -} - -@test "telemetryCollector/Deployment: specified nodeSelector" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.nodeSelector=testing' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.nodeSelector' | tee /dev/stderr) - [ "${actual}" = "testing" ] -} - -#-------------------------------------------------------------------- -# consul.name - -@test "telemetryCollector/Deployment: name is constant regardless of consul name" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'consul.name=foobar' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0].name' | tee /dev/stderr) - [ "${actual}" = "consul-telemetry-collector" ] -} - -#-------------------------------------------------------------------- -# global.tls.enabled - -@test "telemetryCollector/Deployment: Adds tls-ca-cert volume when global.tls.enabled is true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: Adds tls-ca-cert volumeMounts when global.tls.enabled is true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - --set 'global.tls.enabled=true' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[1].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) - [ "${actual}" != "" ] -} - -@test "telemetryCollector/Deployment: can overwrite CA secret with the provided one" { - cd `chart_dir` - local ca_cert_volume=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - --set 'global.tls.enabled=true' \ - --set 'global.tls.enableAutoEncrypt=true' \ - --set 'client.enabled=false' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[1].volumeMounts[] | select(.name == "consul-ca-cert") | length > 0' | tee - /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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}" = "" ] -} - -#-------------------------------------------------------------------- -# resources - -@test "telemetryCollector/Deployment: resources has default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0].resources' | tee /dev/stderr) - - [ $(echo "${actual}" | yq -r '.requests.memory') = "512Mi" ] - [ $(echo "${actual}" | yq -r '.requests.cpu') = "1000m" ] - [ $(echo "${actual}" | yq -r '.limits.memory') = "512Mi" ] - [ $(echo "${actual}" | yq -r '.limits.cpu') = "1000m" ] -} - -@test "telemetryCollector/Deployment: resources can be overridden" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - --set 'telemetryCollector.resources.foo=bar' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0].resources.foo' | tee /dev/stderr) - [ "${actual}" = "bar" ] -} - -#-------------------------------------------------------------------- -# init container resources - -@test "telemetryCollector/Deployment: init container has default resources" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: init container resources can be set" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - --set 'global.acls.manageSystemACLs=true' \ - --set 'telemetryCollector.initContainer.resources.requests.memory=memory' \ - --set 'telemetryCollector.initContainer.resources.requests.cpu=cpu' \ - --set 'telemetryCollector.initContainer.resources.limits.memory=memory2' \ - --set 'telemetryCollector.initContainer.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 "telemetryCollector/Deployment: no priorityClassName by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) - - [ "${actual}" = "null" ] -} - -@test "telemetryCollector/Deployment: can set a priorityClassName" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - --set 'telemetryCollector.priorityClassName=name' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) - - [ "${actual}" = "name" ] -} - -#-------------------------------------------------------------------- -# replicas - -@test "telemetryCollector/Deployment: replicas defaults to 1" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - . | tee /dev/stderr | - yq '.spec.replicas' | tee /dev/stderr) - - [ "${actual}" = "1" ] -} - -@test "telemetryCollector/Deployment: replicas can be set" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=foo' \ - --set 'telemetryCollector.replicas=3' \ - . | tee /dev/stderr | - yq '.spec.replicas' | tee /dev/stderr) - - [ "${actual}" = "3" ] -} - -#-------------------------------------------------------------------- -# Vault - -@test "telemetryCollector/Deployment: vault CA is not configured by default" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: vault CA is not configured when secretName is set but secretKey is not" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: vault CA is not configured when secretKey is set but secretName is not" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: vault CA is configured when both secretName and secretKey are set" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: vault tls annotations are set when tls is enabled" { - cd `chart_dir` - local cmd=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: vault agent annotations can be set" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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" ] -} - -#-------------------------------------------------------------------- -# telemetryCollector.cloud - -@test "telemetryCollector/Deployment: success with all cloud bits set" { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'global.cloud.enabled=true' \ - --set 'global.cloud.clientSecret.secretName=client-secret-name' \ - --set 'global.cloud.clientSecret.secretKey=client-secret-key' \ - --set 'global.cloud.clientId.secretName=client-id-name' \ - --set 'global.cloud.clientId.secretKey=client-id-key' \ - --set 'global.cloud.resourceId.secretName=client-resource-id-name' \ - --set 'global.cloud.resourceId.secretKey=client-resource-id-key' \ - . -} - -@test "telemetryCollector/Deployment: fails when telemetryCollector.cloud.clientId is set and global.cloud.resourceId is not set or global.cloud.clientSecret.secretName is not set" { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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 "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --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." ]] -} - -@test "telemetryCollector/Deployment: fails when telemetryCollector.cloud.clientId.secretName is set but telemetryCollector.cloud.clientId.secretKey is not set." { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.cloud.clientId.secretName=client-id-name' \ - --set 'telemetryCollector.clientSecret.secretName=client-secret-id-name' \ - --set 'telemetryCollector.clientSecret.secretKey=client-secret-id-key' \ - --set 'global.resourceId.secretName=resource-id-name' \ - --set 'global.resourceId.secretKey=resource-id-key' \ - . - [ "$status" -eq 1 ] - - [[ "$output" =~ "When telemetryCollector.cloud.clientId.secretName is set, global.cloud.resourceId.secretName, telemetryCollector.cloud.clientSecret.secretName must also be set." ]] -} - -@test "telemetryCollector/Deployment: fails when telemetryCollector.cloud.clientId.secretKey is set but telemetryCollector.cloud.clientId.secretName is not set." { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.cloud.clientId.secretName=client-id-name' \ - --set 'telemetryCollector.cloud.clientId.secretKey=client-id-key' \ - --set 'telemetryCollector.clientSecret.secretName=client-secret-id-name' \ - --set 'global.resourceId.secretName=resource-id-name' \ - --set 'global.resourceId.secretKey=resource-id-key' \ - . - [ "$status" -eq 1 ] - - [[ "$output" =~ "When telemetryCollector.cloud.clientId.secretName is set, global.cloud.resourceId.secretName, telemetryCollector.cloud.clientSecret.secretName must also be set." ]] -} - -@test "telemetryCollector/Deployment: fails when telemetryCollector.cloud.clientSecret.secretName is set but telemetryCollector.cloud.clientId.secretName is not set." { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.cloud.clientId.secretName=client-id-name' \ - --set 'telemetryCollector.cloud.clientId.secretKey=client-id-key' \ - --set 'telemetryCollector.clientSecret.secretName=client-secret-id-name' \ - --set 'telemetryCollector.clientSecret.secretKey=client-secret-key-name' \ - . - [ "$status" -eq 1 ] - - [[ "$output" =~ "When telemetryCollector.cloud.clientId.secretName is set, global.cloud.resourceId.secretName, telemetryCollector.cloud.clientSecret.secretName must also be set." ]] -} - -@test "telemetryCollector/Deployment: fails when telemetryCollector.cloud.clientId.secretName is set but telemetry.cloud.clientId.secretKey is not set." { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.cloud.clientId.secretName=client-id-name' \ - --set 'telemetryCollector.cloud.clientSecret.secretName=client-secret-name' \ - --set 'global.cloud.resourceId.secretName=resource-id-name' \ - . - [ "$status" -eq 1 ] - - [[ "$output" =~ "When either telemetryCollector.cloud.clientId.secretName or telemetryCollector.cloud.clientId.secretKey is defined, both must be set." ]] -} - -@test "telemetryCollector/Deployment: fails when telemetryCollector.cloud.clientSecret.secretName is set but telemetry.cloud.clientSecret.secretKey is not set." { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.cloud.clientId.secretName=client-id-name' \ - --set 'telemetryCollector.cloud.clientId.secretKey=client-id-key' \ - --set 'telemetryCollector.cloud.clientSecret.secretName=client-secret-name' \ - --set 'global.cloud.resourceId.secretName=resource-id-name' \ - . - [ "$status" -eq 1 ] - - [[ "$output" =~ "When either telemetryCollector.cloud.clientSecret.secretName or telemetryCollector.cloud.clientSecret.secretKey is defined, both must be set." ]] -} - -@test "telemetryCollector/Deployment: fails when telemetryCollector.cloud.clientId and telemetryCollector.cloud.clientSecret is set but global.cloud.resourceId.secretKey is not set." { - cd `chart_dir` - run helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.cloud.clientId.secretName=client-id-name' \ - --set 'telemetryCollector.cloud.clientId.secretKey=client-id-key' \ - --set 'telemetryCollector.cloud.clientSecret.secretName=client-secret-name' \ - --set 'telemetryCollector.cloud.clientSecret.secretKey=client-secret-key' \ - --set 'global.cloud.resourceId.secretName=resource-id-name' \ - . - [ "$status" -eq 1 ] - - [[ "$output" =~ "When telemetryCollector has clientId and clientSecret .global.cloud.resourceId.secretKey must be set" ]] -} - -#-------------------------------------------------------------------- -# global.tls.enabled - -@test "telemetryCollector/Deployment: sets -tls-disabled args when when not using TLS." { - cd `chart_dir` - - local flags=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'global.tls.enabled=false' \ - . | yq -r .spec.template.spec.containers[1].args) - - local actual=$(echo $flags | yq -r '. | any(contains("-tls-disabled"))') - [ "${actual}" = 'true' ] - -} - -@test "telemetryCollector/Deployment: -ca-certs set correctly when using TLS." { - cd `chart_dir` - local flags=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'global.tls.enabled=true' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[1].args' | tee /dev/stderr) - - local actual=$(echo $flags | yq -r '. | any(contains("-ca-certs=/consul/tls/ca/tls.crt"))' | tee /dev/stderr) - [ "${actual}" = 'true' ] -} - -#-------------------------------------------------------------------- -# External Server - -@test "telemetryCollector/Deployment: sets external server args when global.tls.enabled and externalServers.enabled" { - cd `chart_dir` - local flags=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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=foo.tls.server' \ - --set 'externalServers.useSystemRoots=true' \ - --set 'server.enabled=false' \ - --set 'client.enabled=false' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[1].args' | tee /dev/stderr) - - local actual=$(echo $flags | yq -r '. | any(contains("-ca-certs=/consul/tls/ca/tls.crt"))' | tee /dev/stderr) - [ "${actual}" = 'false' ] - - local actual=$(echo $flags | yq -r '. | any(contains("-tls-server-name=foo.tls.server"))' | tee /dev/stderr) - [ "${actual}" = 'true' ] - - local actual=$(echo $flags | jq -r '. | any(contains("-addresses=external-consul.host"))' | tee /dev/stderr) - [ "${actual}" = 'true' ] -} - -#-------------------------------------------------------------------- -# Admin Partitions - -@test "telemetryCollector/Deployment: partition flags are set when using admin partitions" { - cd `chart_dir` - local flags=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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[1].args' | tee /dev/stderr) - - local actual=$(echo $flags | jq -r '. | any(contains("-login-partition=hashi"))' | tee /dev/stderr) - [ "${actual}" = 'true' ] - - local actual=$(echo $flags | jq -r '. | any(contains("-service-partition=hashi"))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/Deployment: consul-ca-cert volume mount is not set when using externalServers and useSystemRoots" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: config volume mount is set when config exists" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.customExporterConfig="foo"' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "config") | .name' | tee /dev/stderr) - [ "${actual}" = "config" ] -} - -@test "telemetryCollector/Deployment: config flag is set when config exists" { - cd `chart_dir` - local flags=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - --set 'telemetryCollector.customExporterConfig="foo"' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command') - - local actual=$(echo $flags | yq -r '. | any(contains("-config-file-path /consul/config/config.json"))') - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/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/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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}" = "" ] -} -#-------------------------------------------------------------------- -# trustedCAs - -@test "telemetryCollector/Deployment: trustedCAs: if trustedCAs is set command is modified correctly" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0].command[2] | contains("cat < /trusted-cas/custom-ca-0.pem")' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/Deployment: trustedCAs: if multiple Trusted cas were set" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - --set 'global.trustedCAs[1]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0]' | tee /dev/stderr) - - - local actual=$(echo $object | jq '.command[2] | contains("cat < /trusted-cas/custom-ca-0.pem")' | tee /dev/stderr) - [ "${actual}" = "true" ] - local actual=$(echo $object | jq '.command[2] | contains("cat < /trusted-cas/custom-ca-1.pem")' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/Deployment: trustedCAs: if trustedCAs is set /trusted-cas volumeMount is added" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | yq -r '.spec.template.spec' | tee /dev/stderr) - local actual=$(echo $object | jq -r '.volumes[] | select(.name == "trusted-cas") | .name' | tee /dev/stderr) - [ "${actual}" = "trusted-cas" ] -} - - -@test "telemetryCollector/Deployment: trustedCAs: if trustedCAs is set SSL_CERT_DIR env var is set" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.trustedCAs[0]=-----BEGIN CERTIFICATE----- -MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ - . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env[] | select(.name == "SSL_CERT_DIR")' | tee /dev/stderr) - - local actual=$(echo $object | jq -r '.name' | tee /dev/stderr) - [ "${actual}" = "SSL_CERT_DIR" ] - local actual=$(echo $object | jq -r '.value' | tee /dev/stderr) - [ "${actual}" = "/etc/ssl/certs:/trusted-cas" ] -} - -#-------------------------------------------------------------------- -# extraLabels - -@test "telemetryCollector/Deployment: no extra labels defined by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.image=bar' \ - . | tee /dev/stderr | - yq -r '.spec.template.metadata.labels | del(."app") | del(."chart") | del(."release") | del(."component") | del(."consul.hashicorp.com/connect-inject-managed-by")' \ - | tee /dev/stderr) - [ "${actual}" = "{}" ] -} - -@test "telemetryCollector/Deployment: extra global labels can be set" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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 "telemetryCollector/Deployment: multiple global extra labels can be set" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.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" ] -} - -#-------------------------------------------------------------------- -# extraEnvironmentVariables - -@test "telemetryCollector/Deployment: extra environment variables" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.extraEnvironmentVars.HCP_AUTH_TLS=insecure' \ - --set 'telemetryCollector.extraEnvironmentVars.foo=bar' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - - local actual=$(echo $object | - yq -r 'map(select(.name == "HCP_AUTH_TLS")) | .[0].value' | tee /dev/stderr) - [ "${actual}" = "insecure" ] - - local actual=$(echo $object | - yq -r 'map(select(.name == "foo")) | .[0].value' | tee /dev/stderr) - [ "${actual}" = "bar" ] -} - -#-------------------------------------------------------------------- -# logLevel - -@test "telemetryCollector/Deployment: use global.logLevel by default" { - cd `chart_dir` - local cmd=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers[0].command' | tee /dev/stderr) - - local actual=$(echo "$cmd" | - yq 'any(contains("-log-level=info"))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/Deployment: override global.logLevel when telemetryCollector.logLevel is set" { - cd `chart_dir` - local cmd=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.logLevel=warn' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers[0].command' | tee /dev/stderr) - - local actual=$(echo "$cmd" | - yq 'any(contains("-log-level=warn"))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/Deployment: use global.logLevel by default for dataplane container" { - cd `chart_dir` - local cmd=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[1].args' | tee /dev/stderr) - - local actual=$(echo "$cmd" | - yq 'any(contains("-log-level=info"))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/Deployment: override global.logLevel when telemetryCollector.logLevel is set for dataplane container" { - cd `chart_dir` - local cmd=$(helm template \ - -s templates/telemetry-collector-deployment.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'telemetryCollector.logLevel=debug' \ - . | tee /dev/stderr | - yq -r '.spec.template.spec.containers[1].args' | tee /dev/stderr) - - local actual=$(echo "$cmd" | - yq 'any(contains("-log-level=debug"))' | tee /dev/stderr) - [ "${actual}" = "true" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/telemetry-collector-podsecuritypolicy.bats b/charts/consul/test/unit/telemetry-collector-podsecuritypolicy.bats deleted file mode 100644 index 90c494eca5..0000000000 --- a/charts/consul/test/unit/telemetry-collector-podsecuritypolicy.bats +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "telemetryCollector/PodSecurityPolicy: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-podsecuritypolicy.yaml \ - . -} - -@test "telemetryCollector/PodSecurityPolicy: enabled with telemetryCollector and global.enablePodSecurityPolicies=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-podsecuritypolicy.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.enablePodSecurityPolicies=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/telemetry-collector-role.bats b/charts/consul/test/unit/telemetry-collector-role.bats deleted file mode 100644 index 8fa209ef4b..0000000000 --- a/charts/consul/test/unit/telemetry-collector-role.bats +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "telemetryCollector/Role: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-role.yaml \ - . -} - -@test "telemetryCollector/Role: enabled with telemetryCollector and global.enablePodSecurityPolicies=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-role.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.enablePodSecurityPolicies=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/telemetry-collector-rolebinding.bats b/charts/consul/test/unit/telemetry-collector-rolebinding.bats deleted file mode 100644 index 454c2569fb..0000000000 --- a/charts/consul/test/unit/telemetry-collector-rolebinding.bats +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "telemetryCollector/RoleBinding: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-rolebinding.yaml \ - . -} - -@test "telemetryCollector/RoleBinding: enabled with telemetryCollector and global.enablePodSecurityPolicies=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-rolebinding.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'global.enablePodSecurityPolicies=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/telemetry-collector-service.bats b/charts/consul/test/unit/telemetry-collector-service.bats deleted file mode 100755 index c5406b8124..0000000000 --- a/charts/consul/test/unit/telemetry-collector-service.bats +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "telemetryCollector/Service: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-service.yaml \ - . -} - -@test "telemetryCollector/Service: enabled by default with telemetryCollector, connectInject enabled" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-service.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "telemetryCollector/Service: enabled with telemetryCollector.enabled=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-service.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -#-------------------------------------------------------------------- -# consul.name - -@test "telemetryCollector/Service: name is constant regardless of consul name" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-service.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'consul.name=foobar' \ - . | tee /dev/stderr | - yq -r '.metadata.name' | tee /dev/stderr) - [ "${actual}" = "consul-telemetry-collector" ] -} - -#-------------------------------------------------------------------- -# annotations - -@test "telemetryCollector/Service: no annotations by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-service.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq -r '.metadata.annotations' | tee /dev/stderr) - [ "${actual}" = "null" ] -} - -@test "telemetryCollector/Service: can set annotations" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-service.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - --set 'telemetryCollector.service.annotations=key: value' \ - . | tee /dev/stderr | - yq -r '.metadata.annotations.key' | tee /dev/stderr) - [ "${actual}" = "value" ] -} - -#-------------------------------------------------------------------- -# port - -@test "telemetryCollector/Service: has default port" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-service.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq -r '.spec.ports[0].port' | tee /dev/stderr) - [ "${actual}" = "9356" ] -} \ No newline at end of file diff --git a/charts/consul/test/unit/telemetry-collector-serviceaccount.bats b/charts/consul/test/unit/telemetry-collector-serviceaccount.bats deleted file mode 100644 index 589632d5b5..0000000000 --- a/charts/consul/test/unit/telemetry-collector-serviceaccount.bats +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "telemetryCollector/ServiceAccount: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/telemetry-collector-serviceaccount.yaml \ - . -} - -@test "telemetryCollector/ServiceAccount: enabled with telemetryCollector, connectInject enabled" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-serviceaccount.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -#-------------------------------------------------------------------- -# global.imagePullSecrets - -@test "telemetryCollector/ServiceAccount: can set image pull secrets" { - cd `chart_dir` - local object=$(helm template \ - -s templates/telemetry-collector-serviceaccount.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - --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" ] -} - -#-------------------------------------------------------------------- -# telemetryCollector.serviceAccount.annotations - -@test "telemetryCollector/ServiceAccount: no annotations by default" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-serviceaccount.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - . | tee /dev/stderr | - yq '.metadata.annotations | length > 0' | tee /dev/stderr) - [ "${actual}" = "false" ] -} - -@test "telemetryCollector/ServiceAccount: annotations when enabled" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-serviceaccount.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'connectInject.enabled=true' \ - --set "telemetryCollector.serviceAccount.annotations=foo: bar" \ - . | tee /dev/stderr | - yq -r '.metadata.annotations.foo' | tee /dev/stderr) - [ "${actual}" = "bar" ] -} - - -#-------------------------------------------------------------------- -# consul.name - -@test "telemetryCollector/ServiceAccount: name is constant regardless of consul name" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/telemetry-collector-serviceaccount.yaml \ - --set 'telemetryCollector.enabled=true' \ - --set 'consul.name=foobar' \ - . | tee /dev/stderr | - yq -r '.metadata.name' | tee /dev/stderr) - [ "${actual}" = "consul-telemetry-collector" ] -} diff --git a/charts/consul/test/unit/webhook-cert-manager-clusterrole.bats b/charts/consul/test/unit/webhook-cert-manager-clusterrole.bats index 4d1a4abdd2..d58ce20928 100644 --- a/charts/consul/test/unit/webhook-cert-manager-clusterrole.bats +++ b/charts/consul/test/unit/webhook-cert-manager-clusterrole.bats @@ -130,7 +130,7 @@ load _helpers #-------------------------------------------------------------------- # Vault -@test "webhookCertManager/ClusterRole: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, and global.secretsBackend.vault.connectInject.caCert.secretName" { +@test "webhookCertManager/ClusterRole: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and .global.secretsBackend.vault.controller.caCert.secretName" { cd `chart_dir` assert_empty helm template \ -s templates/webhook-cert-manager-clusterrole.yaml \ @@ -142,6 +142,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ diff --git a/charts/consul/test/unit/webhook-cert-manager-clusterrolebinding.bats b/charts/consul/test/unit/webhook-cert-manager-clusterrolebinding.bats index 2e507d279d..89a60a0ef3 100644 --- a/charts/consul/test/unit/webhook-cert-manager-clusterrolebinding.bats +++ b/charts/consul/test/unit/webhook-cert-manager-clusterrolebinding.bats @@ -24,7 +24,7 @@ load _helpers #-------------------------------------------------------------------- # Vault -@test "webhookCertManager/ClusterRoleBinding: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, and global.secretsBackend.vault.connectInject.caCert.secretName" { +@test "webhookCertManager/ClusterRoleBinding: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and .global.secretsBackend.vault.controller.caCert.secretName" { cd `chart_dir` assert_empty helm template \ -s templates/webhook-cert-manager-clusterrolebinding.yaml \ @@ -36,6 +36,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ diff --git a/charts/consul/test/unit/webhook-cert-manager-configmap.bats b/charts/consul/test/unit/webhook-cert-manager-configmap.bats index 196da220d4..774ada21d1 100644 --- a/charts/consul/test/unit/webhook-cert-manager-configmap.bats +++ b/charts/consul/test/unit/webhook-cert-manager-configmap.bats @@ -24,7 +24,7 @@ load _helpers #-------------------------------------------------------------------- # Vault -@test "webhookCertManager/Configmap: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, and global.secretsBackend.vault.connectInject.caCert.secretName" { +@test "webhookCertManager/Configmap: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and .global.secretsBackend.vault.controller.caCert.secretName" { cd `chart_dir` assert_empty helm template \ -s templates/webhook-cert-manager-configmap.yaml \ @@ -36,6 +36,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ diff --git a/charts/consul/test/unit/webhook-cert-manager-deployment.bats b/charts/consul/test/unit/webhook-cert-manager-deployment.bats index 7d1a028d20..c0e54ccd25 100644 --- a/charts/consul/test/unit/webhook-cert-manager-deployment.bats +++ b/charts/consul/test/unit/webhook-cert-manager-deployment.bats @@ -66,7 +66,7 @@ load _helpers #-------------------------------------------------------------------- # Vault -@test "webhookCertManager/Deployment: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, and global.secretsBackend.vault.connectInject.caCert.secretName" { +@test "webhookCertManager/Deployment: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and .global.secretsBackend.vault.controller.caCert.secretName" { cd `chart_dir` assert_empty helm template \ -s templates/webhook-cert-manager-deployment.yaml \ @@ -78,6 +78,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ diff --git a/charts/consul/test/unit/webhook-cert-manager-podsecuritypolicy.bats b/charts/consul/test/unit/webhook-cert-manager-podsecuritypolicy.bats index d8e16f867c..820be91404 100644 --- a/charts/consul/test/unit/webhook-cert-manager-podsecuritypolicy.bats +++ b/charts/consul/test/unit/webhook-cert-manager-podsecuritypolicy.bats @@ -35,7 +35,7 @@ load _helpers #-------------------------------------------------------------------- # Vault -@test "webhookCertManager/PodSecurityPolicy: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, and global.secretsBackend.vault.connectInject.caCert.secretName" { +@test "webhookCertManager/PodSecurityPolicy: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and .global.secretsBackend.vault.controller.caCert.secretName" { cd `chart_dir` assert_empty helm template \ -s templates/webhook-cert-manager-podsecuritypolicy.yaml \ @@ -48,6 +48,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ diff --git a/charts/consul/test/unit/webhook-cert-manager-serviceaccount.bats b/charts/consul/test/unit/webhook-cert-manager-serviceaccount.bats index f420e7319c..766d20fb66 100644 --- a/charts/consul/test/unit/webhook-cert-manager-serviceaccount.bats +++ b/charts/consul/test/unit/webhook-cert-manager-serviceaccount.bats @@ -45,7 +45,7 @@ load _helpers #-------------------------------------------------------------------- # Vault -@test "webhookCertManager/ServiceAccount: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, and global.secretsBackend.vault.connectInject.caCert.secretName" { +@test "webhookCertManager/ServiceAccount: disabled when the following are configured - global.secretsBackend.vault.enabled, global.secretsBackend.vault.connectInjectRole, global.secretsBackend.vault.connectInject.tlsCert.secretName, global.secretsBackend.vault.connectInject.caCert.secretName, global.secretsBackend.vault.controllerRole, global.secretsBackend.vault.controller.tlsCert.secretName, and .global.secretsBackend.vault.controller.caCert.secretName" { cd `chart_dir` assert_empty helm template \ -s templates/webhook-cert-manager-serviceaccount.yaml \ @@ -57,6 +57,9 @@ load _helpers --set 'global.secretsBackend.vault.connectInjectRole=inject-ca-role' \ --set 'global.secretsBackend.vault.connectInject.tlsCert.secretName=pki/issue/connect-webhook-cert-dc1' \ --set 'global.secretsBackend.vault.connectInject.caCert.secretName=pki/issue/connect-webhook-cert-dc1' \ + --set 'global.secretsBackend.vault.controllerRole=test' \ + --set 'global.secretsBackend.vault.controller.caCert.secretName=foo/ca' \ + --set 'global.secretsBackend.vault.controller.tlsCert.secretName=foo/tls' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ --set 'global.secretsBackend.vault.consulCARole=test2' \ diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 6f98d05d35..7d0379d6f4 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.17-dev + image: docker.mirror.hashicorp.services/hashicorppreview/consul:1.14-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,7 +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.3.0-dev + imageK8S: docker.mirror.hashicorp.services/hashicorppreview/consul-k8s-control-plane:1.0.10-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 @@ -164,6 +164,12 @@ global: # and check the name of `metadata.name`. adminPartitionsRole: "" + # The Vault role to read Consul controller's webhook's + # CA and issue a certificate and private key. + # A Vault policy must be created which grants issue capabilities to + # `global.secretsBackend.vault.controller.tlsCert.secretName`. + controllerRole: "" + # The Vault role to read Consul connect-injector webhook's CA # and issue a certificate and private key. # A Vault policy must be created which grants issue capabilities to @@ -239,6 +245,25 @@ global: additionalConfig: | {} + controller: + # Configuration to the Vault Secret that Kubernetes will use on + # Kubernetes CRD creation, deletion, and update, to get TLS certificates + # used issued from vault to send webhooks to the controller. + tlsCert: + # The Vault secret path that issues TLS certificates for controller + # webhooks. + # @type: string + secretName: null + + # Configuration to the Vault Secret that Kubernetes will use on + # Kubernetes CRD creation, deletion, and update, to get CA certificates + # used issued from vault to send webhooks to the controller. + caCert: + # The Vault secret path that contains the CA certificate for controller + # webhooks. + # @type: string + secretName: null + connectInject: # Configuration to the Vault Secret that Kubernetes uses on # Kubernetes pod creation, deletion, and update, to get CA certificates @@ -289,7 +314,7 @@ global: # The key within the Kubernetes secret or Vault secret key that holds the gossip # encryption key. secretKey: "" - # Override global log verbosity level for gossip-encryption-autogenerate-job pods. One of "trace", "debug", "info", "warn", or "error". + # Override global log verbosity level for `gossip-encryption-autogenerate-job` pods. One of "trace", "debug", "info", "warn", or "error". # @type: string logLevel: "" @@ -387,7 +412,7 @@ global: secretKey: null # This value defines additional annotations for - # tls init jobs. This should be formatted as a multi-line string. + # tls init jobs. Format this value as a multi-line string. # # ```yaml # annotations: | @@ -416,21 +441,15 @@ global: # Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". # @type: string logLevel: "" - - # A Kubernetes or Vault secret containing the bootstrap token to use for creating policies and - # tokens for all Consul and consul-k8s-control-plane components. If `secretName` and `secretKey` - # are unset, a default secret name and secret key are used. If the secret is populated, then - # we will skip ACL bootstrapping of the servers and will only initialize ACLs for the Consul - # clients and consul-k8s-control-plane system components. - # If the secret is empty, then we will bootstrap ACLs on the Consul servers, and write the - # bootstrap token to this secret. If ACLs are already bootstrapped on the servers, then the - # secret must contain the bootstrap token. + + # A Kubernetes or Vault secret containing the bootstrap token to use for + # creating policies and tokens for all Consul and consul-k8s-control-plane components. + # If set, we will skip ACL bootstrapping of the servers and will only + # initialize ACLs for the Consul clients and consul-k8s-control-plane system components. bootstrapToken: # The name of the Kubernetes or Vault secret that holds the bootstrap token. - # If unset, this defaults to `{{ global.name }}-bootstrap-acl-token`. secretName: null # The key within the Kubernetes or Vault secret that holds the bootstrap token. - # If unset, this defaults to `token`. secretKey: null # If true, an ACL token will be created that can be used in secondary @@ -453,7 +472,7 @@ global: # @type: string secretKey: null - # The resource requests (CPU, memory, etc.) for the server-acl-init and server-acl-init-cleanup pods. + # The resource requests (CPU, memory, etc.) for the server-acl-init and server-acl-init-cleanup pods. # This should be a YAML map corresponding to a Kubernetes # [`ResourceRequirements``](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#resourcerequirements-v1-core) # object. @@ -513,7 +532,7 @@ global: nodeSelector: null # This value defines additional annotations for - # acl init jobs. This should be formatted as a multi-line string. + # acl init jobs. Format this value as a multi-line string. # # ```yaml # annotations: | @@ -589,7 +608,7 @@ global: # @type: string k8sAuthMethodHost: null - # Override global log verbosity level for the create-federation-secret-job pods. One of "trace", "debug", "info", "warn", or "error". + # Override global log verbosity level for the `create-federation-secret-job` pods. One of "trace", "debug", "info", "warn", or "error". # @type: string logLevel: "" @@ -619,15 +638,10 @@ global: # @type: boolean enableGatewayMetrics: true - # Configures the Helm chart’s components to forward envoy metrics for the Consul service mesh to the - # consul-telemetry-collector. This includes gateway metrics and sidecar metrics. - # @type: boolean - enableTelemetryCollector: false - # 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.3-dev + imageConsulDataplane: docker.mirror.hashicorp.services/hashicorppreview/consul-dataplane:1.1-dev # Configuration for running this Helm chart on the Red Hat OpenShift platform. # This Helm chart currently supports OpenShift v4.x+. @@ -720,39 +734,6 @@ global: # @type: map extraLabels: {} - # Optional PEM-encoded CA certificates that will be added to trusted system CAs. - # - # Example: - # - # ```yaml - # trustedCAs: [ - # | - # -----BEGIN CERTIFICATE----- - # MIIC7jCCApSgAwIBAgIRAIq2zQEVexqxvtxP6J0bXAwwCgYIKoZIzj0EAwIwgbkx - # ... - # ] - # ``` - # @type: array - trustedCAs: [ ] - - # Consul feature flags that will be enabled across components. - # Supported feature flags: - # * `resource-apis`: - # _**Danger**_! 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. - # - # Example: - # - # ```yaml - # experiments: [ "resource-apis" ] - # ``` - # @type: array - experiments: [ ] - - # Server, when enabled, configures a server cluster to run. This should # be disabled if you plan on connecting to a Consul cluster external to # the Kube cluster. @@ -1244,7 +1225,7 @@ server: # @type: string caCert: null - # [Enterprise Only] Added in Consul 1.8, the audit object allow users to enable auditing + # [Enterprise Only] Added in Consul 1.8, the audit object allow users to enable auditing # and configure a sink and filters for their audit logs. Please refer to # [audit logs](https://developer.hashicorp.com/consul/docs/enterprise/audit-logging) documentation # for further information. @@ -1253,7 +1234,7 @@ server: # global.acls.manageSystemACLs must be enabled to use this feature. enabled: false - # A single entry of the sink object provides configuration for the destination to which Consul + # A single entry of the sink object provides configuration for the destination to which Consul # will log auditing events. # # Example: @@ -1268,7 +1249,7 @@ server: # rotate_duration: 24h # rotate_max_files: 15 # rotate_bytes: 25165824 - # + # # ``` # # The sink object supports the following keys: @@ -1298,43 +1279,6 @@ server: # @type: array sinks: [] - # Settings for potentially limiting timeouts, rate limiting on clients as well - # as servers, and other settings to limit exposure too many requests, requests - # waiting for too long, and other runtime considerations. - limits: - # This object specifies configurations that limit the rate of RPC and gRPC - # requests on the Consul server. Limiting the rate of gRPC and RPC requests - # also limits HTTP requests to the Consul server. - # https://developer.hashicorp.com/consul/docs/agent/config/config-files#request_limits - requestLimits: - # Setting for disabling or enabling rate limiting. If not disabled, it - # enforces the action that will occur when RequestLimitsReadRate - # or RequestLimitsWriteRate is exceeded. The default value of "disabled" will - # prevent any rate limiting from occuring. A value of "enforce" will block - # the request from processings by returning an error. A value of - # "permissive" will not block the request and will allow the request to - # continue processing. - # @type: string - mode: "disabled" - - # Setting that controls how frequently RPC, gRPC, and HTTP - # queries are allowed to happen. In any large enough time interval, rate - # limiter limits the rate to RequestLimitsReadRate tokens per second. - # - # See https://en.wikipedia.org/wiki/Token_bucket for more about token - # buckets. - # @type: integer - readRate: -1 - - # Setting that controls how frequently RPC, gRPC, and HTTP - # writes are allowed to happen. In any large enough time interval, rate - # limiter limits the rate to RequestLimitsWriteRate tokens per second. - # - # See https://en.wikipedia.org/wiki/Token_bucket for more about token - # buckets. - # @type: integer - writeRate: -1 - # Configuration for Consul servers when the servers are running outside of Kubernetes. # When running external servers, configuring these values is recommended # if setting `global.tls.enableAutoEncrypt` to true @@ -2165,96 +2109,6 @@ connectInject: # @type: integer minAvailable: null - # Configuration settings for the Consul API Gateway integration. - apiGateway: - # Enables Consul on Kubernetes to manage the CRDs used for Gateway API. - # Setting this to true will install the CRDs used for the Gateway API when Consul on Kubernetes is installed. - # These CRDs can clash with existing Gateway API CRDs if they are already installed in your cluster. - # If this setting is false, you will need to install the Gateway API CRDs manually. - manageExternalCRDs: true - - # Configuration settings for the GatewayClass installed by Consul on Kubernetes. - managedGatewayClass: - # 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 - - # 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 - - # The resource settings for Pods handling traffic for Gateway API. - # @recurse: false - # @type: map - resources: - requests: - memory: "100Mi" - cpu: "100m" - limits: - memory: "100Mi" - cpu: "100m" - - # 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 - deployment: - defaultInstances: 1 - maxInstances: 1 - minInstances: 1 - - # The name of the OpenShift SecurityContextConstraints resource to use for Gateways. - # Only applicable if `global.openshift.enabled` is true. - # @type: string - openshiftSCCName: "restricted-v2" - - # This value defines the amount we will add to privileged container ports on gateways that use this class. - # This is useful if you don't want to give your containers extra permissions to run privileged ports. - # Example: The gateway listener is defined on port 80, but the underlying value of the port on the container - # will be the 80 + the number defined below. - mapPrivilegedContainerPorts: 0 - - # 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 - # Configures consul-cni plugin for Consul Service mesh services cni: # If true, then all traffic redirection setup uses the consul-cni plugin. @@ -2655,16 +2509,16 @@ connectInject: # - `consul.hashicorp.com/sidecar-proxy-lifecycle-graceful-shutdown-path` # @type: map lifecycle: - # @type: boolean - defaultEnabled: true - # @type: boolean - defaultEnableShutdownDrainListeners: true - # @type: integer - defaultShutdownGracePeriodSeconds: 30 - # @type: integer - defaultGracefulPort: 20600 - # @type: string - defaultGracefulShutdownPath: "/graceful_shutdown" + # @type: boolean + defaultEnabled: true + # @type: boolean + defaultEnableShutdownDrainListeners: true + # @type: integer + defaultShutdownGracePeriodSeconds: 30 + # @type: integer + defaultGracefulPort: 20600 + # @type: string + defaultGracefulShutdownPath: "/graceful_shutdown" # The resource settings for the Connect injected init container. If null, the resources # won't be set for the initContainer. The defaults are optimized for developer instances of @@ -2695,7 +2549,7 @@ meshGateway: # Requirements: consul 1.6.0+ if using `global.acls.manageSystemACLs``. enabled: false - # Override global log verbosity level for mesh-gateway-deployment pods. One of "trace", "debug", "info", "warn", or "error". + # Override global log verbosity level for `mesh-gateway-deployment` pods. One of "trace", "debug", "info", "warn", or "error". # @type: string logLevel: "" @@ -2908,10 +2762,11 @@ meshGateway: # for a specific gateway. # Requirements: consul >= 1.8.0 ingressGateways: - # Enable ingress gateway deployment. Requires `connectInject.enabled=true`. + # Enable ingress gateway deployment. Requires `connectInject.enabled=true` + # and `client.enabled=true`. enabled: false - # Override global log verbosity level for ingress-gateways-deployment pods. One of "trace", "debug", "info", "warn", or "error". + # Override global log verbosity level for `ingress-gateways-deployment` pods. One of "trace", "debug", "info", "warn", or "error". # @type: string logLevel: "" @@ -3078,7 +2933,8 @@ ingressGateways: # for a specific gateway. # Requirements: consul >= 1.8.0 terminatingGateways: - # Enable terminating gateway deployment. Requires `connectInject.enabled=true`. + # Enable terminating gateway deployment. Requires `connectInject.enabled=true` + # and `client.enabled=true`. enabled: false # Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". @@ -3215,7 +3071,6 @@ terminatingGateways: gateways: - name: terminating-gateway -# [DEPRECATED] Use connectInject.apiGateway instead. This stanza will be removed with the release of Consul 1.17 # Configuration settings for the Consul API Gateway integration apiGateway: # When true the helm chart will install the Consul API Gateway controller @@ -3230,7 +3085,7 @@ apiGateway: # 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.1" + imageEnvoy: "envoyproxy/envoy:v1.24.10" # Override global log verbosity level for api-gateway-controller pods. One of "debug", "info", "warn", or "error". # @type: string @@ -3417,97 +3272,3 @@ prometheus: # is only useful when running helm template. tests: enabled: true - -telemetryCollector: - # Enables the consul-telemetry-collector deployment - # @type: boolean - enabled: false - - # Override global log verbosity level. One of "trace", "debug", "info", "warn", or "error". - # @type: string - logLevel: "" - - # The name of the Docker image (including any tag) for the containers running - # the consul-telemetry-collector - # @type: string - image: "hashicorp/consul-telemetry-collector:0.0.1" - - # The resource settings for consul-telemetry-collector pods. - # @recurse: false - # @type: map - resources: - requests: - memory: "512Mi" - cpu: "1000m" - limits: - memory: "512Mi" - cpu: "1000m" - - # This value sets the number of consul-telemetry-collector replicas to deploy. - replicas: 1 - - # This value defines additional configuration for the telemetry collector. It should be formatted as a multi-line - # json blob string - # - # ```yaml - # customExporterConfig: | - # {"http_collector_endpoint": "other-otel-collector"} - # ``` - # - # @type: string - customExporterConfig: null - - service: - # This value defines additional annotations for the server service account. This should be formatted as a multi-line - # string. - # - # ```yaml - # annotations: | - # "sample/annotation1": "foo" - # "sample/annotation2": "bar" - # ``` - # - # @type: string - annotations: null - - serviceAccount: - # This value defines additional annotations for the telemetry-collector's service account. This should be formatted - # as a multi-line string. - # - # ```yaml - # annotations: | - # "sample/annotation1": "foo" - # "sample/annotation2": "bar" - # ``` - # - # @type: string - annotations: null - - cloud: - clientId: - secretName: null - secretKey: null - clientSecret: - secretName: null - secretKey: null - - initContainer: - # The resource settings for consul-telemetry-collector initContainer. - # @recurse: false - # @type: map - resources: {} - - # Optional YAML string to specify a nodeSelector config. - # @type: string - nodeSelector: null - - # Optional priorityClassName. - # @type: string - priorityClassName: "" - - # A list of extra environment variables to set within the stateful set. - # These could be used to include proxy settings required for cloud auto-join - # feature, in case kubernetes cluster is behind egress http proxies. Additionally, - # it could be used to configure custom consul parameters. - # @type: map - extraEnvironmentVars: { } diff --git a/charts/demo/Chart.yaml b/charts/demo/Chart.yaml index ffd518082f..82fc51d2df 100644 --- a/charts/demo/Chart.yaml +++ b/charts/demo/Chart.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v2 name: consul-demo description: A Helm chart for Consul demo app diff --git a/charts/demo/templates/frontend.yaml b/charts/demo/templates/frontend.yaml index f64aaa24a8..38d466e87e 100644 --- a/charts/demo/templates/frontend.yaml +++ b/charts/demo/templates/frontend.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Service metadata: diff --git a/charts/demo/templates/intentions.yaml b/charts/demo/templates/intentions.yaml index ef36025b16..e0a0a0a5b1 100644 --- a/charts/demo/templates/intentions.yaml +++ b/charts/demo/templates/intentions.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceIntentions metadata: @@ -58,17 +55,6 @@ spec: --- apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceIntentions -metadata: - name: consul-telemetry-collector -spec: - destination: - name: 'consul-telemetry-collector' - sources: - - name: '*' - action: allow ---- -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceIntentions metadata: name: deny-all spec: diff --git a/charts/demo/templates/nginx.yaml b/charts/demo/templates/nginx.yaml index 3d37535733..ebca16f2a0 100644 --- a/charts/demo/templates/nginx.yaml +++ b/charts/demo/templates/nginx.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: v1 kind: Service diff --git a/charts/demo/templates/payments.yaml b/charts/demo/templates/payments.yaml index af36c62fb4..362a7ec1e1 100644 --- a/charts/demo/templates/payments.yaml +++ b/charts/demo/templates/payments.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: v1 kind: Service diff --git a/charts/demo/templates/postgres.yaml b/charts/demo/templates/postgres.yaml index 033a6724d8..5c7c903b7c 100644 --- a/charts/demo/templates/postgres.yaml +++ b/charts/demo/templates/postgres.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: v1 kind: Service diff --git a/charts/demo/templates/products-api.yaml b/charts/demo/templates/products-api.yaml index 22119f86d5..4e2fc4bea8 100644 --- a/charts/demo/templates/products-api.yaml +++ b/charts/demo/templates/products-api.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: v1 kind: Service diff --git a/charts/demo/templates/public-api.yaml b/charts/demo/templates/public-api.yaml index a397ddad35..14d4369ff8 100644 --- a/charts/demo/templates/public-api.yaml +++ b/charts/demo/templates/public-api.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - apiVersion: v1 kind: Service metadata: diff --git a/charts/demo/values.yaml b/charts/demo/values.yaml index 4509c555cb..2dd99602c7 100644 --- a/charts/demo/values.yaml +++ b/charts/demo/values.yaml @@ -1,4 +1 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # Default values for demo. diff --git a/charts/embed_chart.go b/charts/embed_chart.go index 8e36abba23..29e7e9635e 100644 --- a/charts/embed_chart.go +++ b/charts/embed_chart.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package charts import "embed" @@ -15,7 +12,6 @@ import "embed" // // The embed directive does not include files with underscores unless explicitly listed, which is why _helpers.tpl is // explicitly embedded. - //go:embed consul/Chart.yaml consul/values.yaml consul/templates consul/templates/_helpers.tpl var ConsulHelmChart embed.FS diff --git a/charts/go.mod b/charts/go.mod index f76282d756..cdb23e46b0 100644 --- a/charts/go.mod +++ b/charts/go.mod @@ -1,3 +1,3 @@ module github.com/hashicorp/consul-k8s/charts -go 1.20 +go 1.19 diff --git a/cli/cmd/config/command.go b/cli/cmd/config/command.go index 302b054bd9..5e44677ff6 100644 --- a/cli/cmd/config/command.go +++ b/cli/cmd/config/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config import ( diff --git a/cli/cmd/config/read/command.go b/cli/cmd/config/read/command.go index 0565294bd0..e2258bd013 100644 --- a/cli/cmd/config/read/command.go +++ b/cli/cmd/config/read/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( diff --git a/cli/cmd/config/read/command_test.go b/cli/cmd/config/read/command_test.go index 07275f872a..a3716cf3c1 100644 --- a/cli/cmd/config/read/command_test.go +++ b/cli/cmd/config/read/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index f3d4671c6e..7b5d5bb31c 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package install import ( @@ -592,7 +589,7 @@ func (c *Command) validateFlags(args []string) error { return fmt.Errorf("cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset) } if ok := slices.Contains(preset.Presets, c.flagPreset); c.flagPreset != defaultPreset && !ok { - return fmt.Errorf("'%s' is not a valid preset (valid presets: %s)", c.flagPreset, strings.Join(preset.Presets, ", ")) + return fmt.Errorf("'%s' is not a valid preset", c.flagPreset) } if !common.IsValidLabel(c.flagNamespace) { return fmt.Errorf("'%s' is an invalid namespace. Namespaces follow the RFC 1123 label convention and must "+ diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index c34eac9ac3..04c250b1e4 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package install import ( @@ -165,45 +162,39 @@ func TestValidateFlags(t *testing.T) { testCases := []struct { description string input []string - expErr string }{ { "Should disallow non-flag arguments.", []string{"foo", "-auto-approve"}, - "should have no non-flag arguments", }, { "Should disallow specifying both values file AND presets.", []string{"-f='f.txt'", "-preset=demo"}, - "cannot set both -config-file and -preset", }, { "Should error on invalid presets.", []string{"-preset=foo"}, - "'foo' is not a valid preset (valid presets: cloud, quickstart, secure)", }, { "Should error on invalid timeout.", []string{"-timeout=invalid-timeout"}, - "unable to parse -timeout: time: invalid duration \"invalid-timeout\"", }, { "Should error on an invalid namespace. If this failed, TestValidLabel() probably did too.", []string{"-namespace=\" nsWithSpace\""}, - "'\" nsWithSpace\"' is an invalid namespace. Namespaces follow the RFC 1123 label convention and must consist of a lower case alphanumeric character or '-' and must start/end with an alphanumeric character", }, { - "Should have errored on a non-existent file.", + "Should have errored on a non-existant file.", []string{"-f=\"does_not_exist.txt\""}, - "file '\"does_not_exist.txt\"' does not exist", }, } for _, testCase := range testCases { c := getInitializedCommand(t, nil) t.Run(testCase.description, func(t *testing.T) { - err := c.validateFlags(testCase.input) - require.EqualError(t, err, testCase.expErr) + if err := c.validateFlags(testCase.input); err == nil { + t.Errorf("Test case should have failed.") + } }) } } @@ -567,7 +558,7 @@ func TestInstall(t *testing.T) { }, messages: []string{ "\n==> Checking if Consul can be installed\n ✓ No existing Consul installations found.\n ✓ No existing Consul persistent volume claims found\n ✓ No existing Consul secrets found.\n", - "\n==> Consul Installation Summary\n Name: consul\n Namespace: consul\n \n Helm value overrides\n --------------------\n connectInject:\n enabled: true\n metrics:\n defaultEnableMerging: true\n defaultEnabled: true\n enableGatewayMetrics: true\n global:\n metrics:\n enableAgentMetrics: true\n enabled: true\n name: consul\n prometheus:\n enabled: true\n server:\n replicas: 1\n ui:\n enabled: true\n service:\n enabled: true\n \n", + "\n==> Consul Installation Summary\n Name: consul\n Namespace: consul\n \n Helm value overrides\n --------------------\n connectInject:\n enabled: true\n metrics:\n defaultEnableMerging: true\n defaultEnabled: true\n enableGatewayMetrics: true\n controller:\n enabled: true\n global:\n metrics:\n enableAgentMetrics: true\n enabled: true\n name: consul\n prometheus:\n enabled: true\n server:\n replicas: 1\n ui:\n enabled: true\n service:\n enabled: true\n \n", "\n==> Installing Consul\n ✓ Downloaded charts.\n ✓ Consul installed in namespace \"consul\".\n", }, helmActionsRunner: &helm.MockActionRunner{}, @@ -583,7 +574,7 @@ func TestInstall(t *testing.T) { }, messages: []string{ "\n==> Checking if Consul can be installed\n ✓ No existing Consul installations found.\n ✓ No existing Consul persistent volume claims found\n ✓ No existing Consul secrets found.\n", - "\n==> Consul Installation Summary\n Name: consul\n Namespace: consul\n \n Helm value overrides\n --------------------\n connectInject:\n enabled: true\n global:\n acls:\n manageSystemACLs: true\n gossipEncryption:\n autoGenerate: true\n name: consul\n tls:\n enableAutoEncrypt: true\n enabled: true\n server:\n replicas: 1\n \n", + "\n==> Consul Installation Summary\n Name: consul\n Namespace: consul\n \n Helm value overrides\n --------------------\n connectInject:\n enabled: true\n controller:\n enabled: true\n global:\n acls:\n manageSystemACLs: true\n gossipEncryption:\n autoGenerate: true\n name: consul\n tls:\n enableAutoEncrypt: true\n enabled: true\n server:\n replicas: 1\n \n", "\n==> Installing Consul\n ✓ Downloaded charts.\n ✓ Consul installed in namespace \"consul\".\n", }, helmActionsRunner: &helm.MockActionRunner{}, diff --git a/cli/cmd/proxy/command.go b/cli/cmd/proxy/command.go index e15469fb37..bc55ee0312 100644 --- a/cli/cmd/proxy/command.go +++ b/cli/cmd/proxy/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package proxy import ( diff --git a/cli/cmd/proxy/list/command.go b/cli/cmd/proxy/list/command.go index f427049de6..cbecda79a1 100644 --- a/cli/cmd/proxy/list/command.go +++ b/cli/cmd/proxy/list/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package list import ( diff --git a/cli/cmd/proxy/list/command_test.go b/cli/cmd/proxy/list/command_test.go index 3df205d3ca..b2c2cb6043 100644 --- a/cli/cmd/proxy/list/command_test.go +++ b/cli/cmd/proxy/list/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package list import ( diff --git a/cli/cmd/proxy/loglevel/command.go b/cli/cmd/proxy/loglevel/command.go deleted file mode 100644 index caf67d61de..0000000000 --- a/cli/cmd/proxy/loglevel/command.go +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package loglevel - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - - "github.com/posener/complete" - helmCLI "helm.sh/helm/v3/pkg/cli" - "k8s.io/apimachinery/pkg/api/validation" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/envoy" - "github.com/hashicorp/consul-k8s/cli/common/flag" - "github.com/hashicorp/consul-k8s/cli/common/terminal" -) - -const ( - defaultAdminPort = 19000 - flagNameNamespace = "namespace" - flagNameUpdateLevel = "update-level" - flagNameReset = "reset" - flagNameKubeConfig = "kubeconfig" - flagNameKubeContext = "context" -) - -var ErrIncorrectArgFormat = errors.New("Exactly one positional argument is required: ") - -type LoggerConfig map[string]string - -var levelToColor = map[string]string{ - "trace": terminal.Green, - "debug": terminal.HiWhite, - "info": terminal.Blue, - "warning": terminal.Yellow, - "error": terminal.Red, - "critical": terminal.Magenta, - "off": "", -} - -type LogLevelCommand struct { - *common.BaseCommand - - kubernetes kubernetes.Interface - set *flag.Sets - - // Command Flags - podName string - namespace string - level string - reset bool - kubeConfig string - kubeContext string - - once sync.Once - help string - restConfig *rest.Config - envoyLoggingCaller func(context.Context, common.PortForwarder, *envoy.LoggerParams) (map[string]string, error) -} - -func (l *LogLevelCommand) init() { - l.Log.ResetNamed("loglevel") - l.set = flag.NewSets() - f := l.set.NewSet("Command Options") - f.StringVar(&flag.StringVar{ - Name: flagNameNamespace, - Target: &l.namespace, - Usage: "The namespace where the target Pod can be found.", - Aliases: []string{"n"}, - }) - - f.StringVar(&flag.StringVar{ - Name: flagNameUpdateLevel, - Target: &l.level, - Usage: "Update the level for the logger. Can be either `-update-level warning` to change all loggers to warning, or a comma delineated list of loggers with level can be passed like `-update-level grpc:warning,http:info` to only modify specific loggers.", - Aliases: []string{"u"}, - }) - - f.BoolVar(&flag.BoolVar{ - Name: flagNameReset, - Target: &l.reset, - Usage: "Reset the log level for all loggers in a pod to the Envoy default (info).", - Aliases: []string{"r"}, - }) - - f = l.set.NewSet("Global Options") - f.StringVar(&flag.StringVar{ - Name: flagNameKubeConfig, - Aliases: []string{"c"}, - Target: &l.kubeConfig, - Usage: "Set the path to kubeconfig file.", - }) - f.StringVar(&flag.StringVar{ - Name: flagNameKubeContext, - Target: &l.kubeContext, - Usage: "Set the Kubernetes context to use.", - }) - - l.help = l.set.Help() -} - -func (l *LogLevelCommand) Run(args []string) int { - l.once.Do(l.init) - defer common.CloseWithError(l.BaseCommand) - - err := l.parseFlags(args) - if err != nil { - return l.logOutputAndDie(err) - } - err = l.validateFlags() - if err != nil { - return l.logOutputAndDie(err) - } - - // if we're resetting the default log level for envoy is info: https://www.envoyproxy.io/docs/envoy/latest/start/quick-start/run-envoy#debugging-envoy - if l.reset { - l.level = "info" - } - - if l.envoyLoggingCaller == nil { - l.envoyLoggingCaller = envoy.CallLoggingEndpoint - } - - err = l.initKubernetes() - if err != nil { - return l.logOutputAndDie(err) - } - - adminPorts, err := l.fetchAdminPorts() - if err != nil { - return l.logOutputAndDie(err) - } - - err = l.fetchOrSetLogLevels(adminPorts) - if err != nil { - return l.logOutputAndDie(err) - } - - return 0 -} - -func (l *LogLevelCommand) parseFlags(args []string) error { - if len(args) == 0 { - return ErrIncorrectArgFormat - } - - positional := []string{} - // Separate positional args from keyed args - for _, arg := range args { - if strings.HasPrefix(arg, "-") { - break - } - positional = append(positional, arg) - } - keyed := args[len(positional):] - - if len(positional) != 1 { - return ErrIncorrectArgFormat - } - - l.podName = positional[0] - - err := l.set.Parse(keyed) - if err != nil { - return err - } - - return nil -} - -func (l *LogLevelCommand) validateFlags() error { - if l.level != "" && l.reset { - return fmt.Errorf("cannot set log level to %q and reset to 'info' at the same time", l.level) - } - if l.namespace == "" { - return nil - } - - errs := validation.ValidateNamespaceName(l.namespace, false) - if len(errs) > 0 { - return fmt.Errorf("invalid namespace name passed for -namespace/-n: %v", strings.Join(errs, "; ")) - } - - return nil -} - -func (l *LogLevelCommand) initKubernetes() error { - settings := helmCLI.New() - var err error - - if l.kubeConfig != "" { - settings.KubeConfig = l.kubeConfig - } - - if l.kubeContext != "" { - settings.KubeContext = l.kubeContext - } - - if l.restConfig == nil { - l.restConfig, err = settings.RESTClientGetter().ToRESTConfig() - if err != nil { - return fmt.Errorf("error creating Kubernetes REST config %v", err) - } - - } - - if l.kubernetes == nil { - l.kubernetes, err = kubernetes.NewForConfig(l.restConfig) - if err != nil { - return fmt.Errorf("error creating Kubernetes client %v", err) - } - } - if l.namespace == "" { - l.namespace = settings.Namespace() - } - - return nil -} - -// fetchAdminPorts retrieves all admin ports for Envoy Proxies running in a pod given namespace. -func (l *LogLevelCommand) fetchAdminPorts() (map[string]int, error) { - adminPorts := make(map[string]int, 0) - pod, err := l.kubernetes.CoreV1().Pods(l.namespace).Get(l.Ctx, l.podName, metav1.GetOptions{}) - if err != nil { - return adminPorts, err - } - - connectService, isMultiport := pod.Annotations["consul.hashicorp.com/connect-service"] - - if !isMultiport { - // Return the default port configuration. - adminPorts[l.podName] = defaultAdminPort - return adminPorts, nil - } - - for idx, svc := range strings.Split(connectService, ",") { - adminPorts[svc] = defaultAdminPort + idx - } - - return adminPorts, nil -} - -func (l *LogLevelCommand) fetchOrSetLogLevels(adminPorts map[string]int) error { - loggers := make(map[string]LoggerConfig, 0) - - for name, port := range adminPorts { - pf := common.PortForward{ - Namespace: l.namespace, - PodName: l.podName, - RemotePort: port, - KubeClient: l.kubernetes, - RestConfig: l.restConfig, - } - params, err := parseParams(l.level) - if err != nil { - return err - } - logLevels, err := l.envoyLoggingCaller(l.Ctx, &pf, params) - if err != nil { - return err - } - loggers[name] = logLevels - } - - l.outputLevels(loggers) - return nil -} - -func parseParams(params string) (*envoy.LoggerParams, error) { - loggerParams := envoy.NewLoggerParams() - if len(params) == 0 { - return loggerParams, nil - } - - // contains global log level change - if !strings.Contains(params, ":") { - err := loggerParams.SetGlobalLoggerLevel(params) - if err != nil { - return nil, err - } - return loggerParams, nil - } - - // contains changes to at least 1 specific log level - loggerChanges := strings.Split(params, ",") - - for _, logger := range loggerChanges { - levelValues := strings.Split(logger, ":") - err := loggerParams.SetLoggerLevel(levelValues[0], levelValues[1]) - if err != nil { - return nil, err - } - } - return loggerParams, nil -} - -func (l *LogLevelCommand) outputLevels(logLevels map[string]LoggerConfig) { - l.UI.Output(fmt.Sprintf("Envoy log configuration for %s in namespace default:", l.podName)) - for n, levels := range logLevels { - l.UI.Output(fmt.Sprintf("Log Levels for %s", n), terminal.WithHeaderStyle()) - table := terminal.NewTable("Name", "Level") - for name, level := range levels { - table.AddRow([]string{name, level}, []string{"", levelToColor[level]}) - } - l.UI.Table(table) - l.UI.Output("") - } -} - -func (l *LogLevelCommand) Help() string { - l.once.Do(l.init) - return fmt.Sprintf("%s\n\nUsage: consul-k8s proxy log [flags]\n\n%s", l.Synopsis(), l.help) -} - -func (l *LogLevelCommand) Synopsis() string { - return "Inspect and Modify the Envoy Log configuration for a given Pod." -} - -// AutocompleteFlags returns a mapping of supported flags and autocomplete -// options for this command. The map key for the Flags map should be the -// complete flag such as "-foo" or "--foo". -func (l *LogLevelCommand) AutocompleteFlags() complete.Flags { - return complete.Flags{ - fmt.Sprintf("-%s", flagNameNamespace): complete.PredictNothing, - fmt.Sprintf("-%s", flagNameKubeConfig): complete.PredictFiles("*"), - fmt.Sprintf("-%s", flagNameKubeContext): complete.PredictNothing, - } -} - -// AutocompleteArgs returns the argument predictor for this command. -// Since argument completion is not supported, this will return -// complete.PredictNothing. -func (l *LogLevelCommand) AutocompleteArgs() complete.Predictor { - return complete.PredictNothing -} - -func (l *LogLevelCommand) logOutputAndDie(err error) int { - l.UI.Output(err.Error(), terminal.WithErrorStyle()) - l.UI.Output(fmt.Sprintf("\n%s", l.Help())) - return 1 -} diff --git a/cli/cmd/proxy/loglevel/command_test.go b/cli/cmd/proxy/loglevel/command_test.go deleted file mode 100644 index 87e0355c1e..0000000000 --- a/cli/cmd/proxy/loglevel/command_test.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package loglevel - -import ( - "bytes" - "context" - "fmt" - "io" - "os" - "regexp" - "testing" - - "github.com/stretchr/testify/require" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/fake" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/envoy" - "github.com/hashicorp/consul-k8s/cli/common/terminal" - "github.com/hashicorp/go-hclog" -) - -func TestFlagParsingFails(t *testing.T) { - t.Parallel() - testCases := map[string]struct { - args []string - out int - }{ - "No args": { - args: []string{}, - out: 1, - }, - "Multiple podnames passed": { - args: []string{"podname", "podname2"}, - out: 1, - }, - "Nonexistent flag passed, -foo bar": { - args: []string{"podName", "-foo", "bar"}, - out: 1, - }, - "Invalid argument passed, -namespace YOLO": { - args: []string{"podName", "-namespace", "YOLO"}, - out: 1, - }, - } - podName := "now-this-is-pod-racing" - fakePod := v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: podName, - Namespace: "default", - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - c := setupCommand(bytes.NewBuffer([]byte{})) - c.kubernetes = fake.NewSimpleClientset(&v1.PodList{Items: []v1.Pod{fakePod}}) - c.envoyLoggingCaller = func(context.Context, common.PortForwarder, *envoy.LoggerParams) (map[string]string, error) { - return testLogConfig, nil - } - - out := c.Run(tc.args) - require.Equal(t, tc.out, out) - }) - } -} - -func TestFlagParsingSucceeds(t *testing.T) { - t.Parallel() - podName := "now-this-is-pod-racing" - testCases := map[string]struct { - args []string - podNamespace string - out int - }{ - "With single pod name": { - args: []string{podName}, - podNamespace: "default", - out: 0, - }, - "With single pod name and namespace": { - args: []string{podName, "-n", "another"}, - podNamespace: "another", - out: 0, - }, - "With single pod name and blanket level": { - args: []string{podName, "-u", "warning"}, - podNamespace: "default", - out: 0, - }, - "With single pod name and single level": { - args: []string{podName, "-u", "grpc:warning"}, - podNamespace: "default", - out: 0, - }, - "With single pod name and multiple levels": { - args: []string{podName, "-u", "grpc:warning,http:info"}, - podNamespace: "default", - out: 0, - }, - "With single pod name and blanket level full flag": { - args: []string{podName, "-update-level", "warning"}, - podNamespace: "default", - out: 0, - }, - "With single pod name and single level full flag": { - args: []string{podName, "-update-level", "grpc:warning"}, - podNamespace: "default", - out: 0, - }, - "With single pod name and multiple levels full flag": { - args: []string{podName, "-update-level", "grpc:warning,http:info"}, - podNamespace: "default", - out: 0, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - fakePod := v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: podName, - Namespace: tc.podNamespace, - }, - } - - c := setupCommand(bytes.NewBuffer([]byte{})) - c.kubernetes = fake.NewSimpleClientset(&v1.PodList{Items: []v1.Pod{fakePod}}) - c.envoyLoggingCaller = func(context.Context, common.PortForwarder, *envoy.LoggerParams) (map[string]string, error) { - return testLogConfig, nil - } - - out := c.Run(tc.args) - require.Equal(t, tc.out, out) - }) - } -} - -func TestOutputForGettingLogLevels(t *testing.T) { - t.Parallel() - podName := "now-this-is-pod-racing" - expectedHeader := fmt.Sprintf("Envoy log configuration for %s in namespace default:", podName) - fakePod := v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: podName, - Namespace: "default", - }, - } - - buf := bytes.NewBuffer([]byte{}) - c := setupCommand(buf) - newLogLevel := "warning" - config := make(map[string]string, len(testLogConfig)) - for logger := range testLogConfig { - config[logger] = newLogLevel - } - - c.envoyLoggingCaller = func(context.Context, common.PortForwarder, *envoy.LoggerParams) (map[string]string, error) { - return config, nil - } - c.kubernetes = fake.NewSimpleClientset(&v1.PodList{Items: []v1.Pod{fakePod}}) - - args := []string{podName, "-u", newLogLevel} - out := c.Run(args) - require.Equal(t, 0, out) - - actual := buf.String() - - require.Regexp(t, expectedHeader, actual) - require.Regexp(t, "Log Levels for now-this-is-pod-racing", actual) - for logger, level := range config { - require.Regexp(t, regexp.MustCompile(logger+`.*`+level), actual) - } -} - -func TestOutputForSettingLogLevels(t *testing.T) { - t.Parallel() - podName := "now-this-is-pod-racing" - expectedHeader := fmt.Sprintf("Envoy log configuration for %s in namespace default:", podName) - fakePod := v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: podName, - Namespace: "default", - }, - } - - buf := bytes.NewBuffer([]byte{}) - c := setupCommand(buf) - c.envoyLoggingCaller = func(context.Context, common.PortForwarder, *envoy.LoggerParams) (map[string]string, error) { - return testLogConfig, nil - } - c.kubernetes = fake.NewSimpleClientset(&v1.PodList{Items: []v1.Pod{fakePod}}) - - args := []string{podName, "-u", "warning"} - out := c.Run(args) - require.Equal(t, 0, out) - - actual := buf.String() - - require.Regexp(t, expectedHeader, actual) - require.Regexp(t, "Log Levels for now-this-is-pod-racing", actual) - for logger, level := range testLogConfig { - require.Regexp(t, regexp.MustCompile(logger+`.*`+level), actual) - } -} - -func TestHelp(t *testing.T) { - t.Parallel() - buf := bytes.NewBuffer([]byte{}) - c := setupCommand(buf) - expectedSynposis := "Inspect and Modify the Envoy Log configuration for a given Pod." - expectedUsage := `Usage: consul-k8s proxy log \[flags\]` - actual := c.Help() - require.Regexp(t, expectedSynposis, actual) - require.Regexp(t, expectedUsage, actual) -} - -func setupCommand(buf io.Writer) *LogLevelCommand { - log := hclog.New(&hclog.LoggerOptions{ - Name: "test", - Level: hclog.Debug, - Output: os.Stdout, - }) - - command := &LogLevelCommand{ - BaseCommand: &common.BaseCommand{ - Log: log, - UI: terminal.NewUI(context.Background(), buf), - }, - } - command.init() - return command -} - -var testLogConfig = map[string]string{ - "admin": "debug", - "alternate_protocols_cache": "debug", - "aws": "debug", - "assert": "debug", - "backtrace": "debug", - "cache_filter": "debug", - "client": "debug", - "config": "debug", - "connection": "debug", - "conn_handler": "debug", - "decompression": "debug", - "dns": "debug", - "dubbo": "debug", - "envoy_bug": "debug", - "ext_authz": "debug", - "ext_proc": "debug", - "rocketmq": "debug", - "file": "debug", - "filter": "debug", - "forward_proxy": "debug", - "grpc": "debug", - "happy_eyeballs": "debug", - "hc": "debug", - "health_checker": "debug", - "http": "debug", - "http2": "debug", - "hystrix": "debug", - "init": "debug", - "io": "debug", - "jwt": "debug", - "kafka": "debug", - "key_value_store": "debug", - "lua": "debug", - "main": "debug", - "matcher": "debug", - "misc": "debug", - "mongo": "debug", - "multi_connection": "debug", - "oauth2": "debug", - "quic": "debug", - "quic_stream": "debug", - "pool": "debug", - "rbac": "debug", - "rds": "debug", - "redis": "debug", - "router": "debug", - "runtime": "debug", - "stats": "debug", - "secret": "debug", - "tap": "debug", - "testing": "debug", - "thrift": "debug", - "tracing": "debug", - "upstream": "debug", - "udp": "debug", - "wasm": "debug", - "websocket": "debug", -} diff --git a/cli/cmd/proxy/read/command.go b/cli/cmd/proxy/read/command.go index 26ca33b045..ad2bb96303 100644 --- a/cli/cmd/proxy/read/command.go +++ b/cli/cmd/proxy/read/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( @@ -10,6 +7,9 @@ import ( "strings" "sync" + "github.com/hashicorp/consul-k8s/cli/common" + "github.com/hashicorp/consul-k8s/cli/common/flag" + "github.com/hashicorp/consul-k8s/cli/common/terminal" "github.com/posener/complete" helmCLI "helm.sh/helm/v3/pkg/cli" "k8s.io/apimachinery/pkg/api/validation" @@ -17,11 +17,6 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/utils/strings/slices" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/envoy" - "github.com/hashicorp/consul-k8s/cli/common/flag" - "github.com/hashicorp/consul-k8s/cli/common/terminal" ) // defaultAdminPort is the port where the Envoy admin API is exposed. @@ -72,7 +67,7 @@ type ReadCommand struct { flagKubeConfig string flagKubeContext string - fetchConfig func(context.Context, common.PortForwarder) (*envoy.EnvoyConfig, error) + fetchConfig func(context.Context, common.PortForwarder) (*EnvoyConfig, error) restConfig *rest.Config @@ -82,7 +77,7 @@ type ReadCommand struct { func (c *ReadCommand) init() { if c.fetchConfig == nil { - c.fetchConfig = envoy.FetchConfig + c.fetchConfig = FetchConfig } c.set = flag.NewSets() @@ -325,8 +320,8 @@ func (c *ReadCommand) fetchAdminPorts() (map[string]int, error) { return adminPorts, nil } -func (c *ReadCommand) fetchConfigs(adminPorts map[string]int) (map[string]*envoy.EnvoyConfig, error) { - configs := make(map[string]*envoy.EnvoyConfig, 0) +func (c *ReadCommand) fetchConfigs(adminPorts map[string]int) (map[string]*EnvoyConfig, error) { + configs := make(map[string]*EnvoyConfig, 0) for name, adminPort := range adminPorts { pf := common.PortForward{ @@ -348,7 +343,7 @@ func (c *ReadCommand) fetchConfigs(adminPorts map[string]int) (map[string]*envoy return configs, nil } -func (c *ReadCommand) outputConfigs(configs map[string]*envoy.EnvoyConfig) error { +func (c *ReadCommand) outputConfigs(configs map[string]*EnvoyConfig) error { switch c.flagOutput { case Table: return c.outputTables(configs) @@ -401,7 +396,7 @@ func (c *ReadCommand) filterWarnings() []string { return warnings } -func (c *ReadCommand) outputTables(configs map[string]*envoy.EnvoyConfig) error { +func (c *ReadCommand) outputTables(configs map[string]*EnvoyConfig) error { if c.flagFQDN != "" || c.flagAddress != "" || c.flagPort != -1 { c.UI.Output("Filters applied", terminal.WithHeaderStyle()) @@ -436,7 +431,7 @@ func (c *ReadCommand) outputTables(configs map[string]*envoy.EnvoyConfig) error return nil } -func (c *ReadCommand) outputJSON(configs map[string]*envoy.EnvoyConfig) error { +func (c *ReadCommand) outputJSON(configs map[string]*EnvoyConfig) error { cfgs := make(map[string]interface{}) for name, config := range configs { cfg := make(map[string]interface{}) @@ -472,11 +467,11 @@ func (c *ReadCommand) outputJSON(configs map[string]*envoy.EnvoyConfig) error { return nil } -func (c *ReadCommand) outputRaw(configs map[string]*envoy.EnvoyConfig) error { +func (c *ReadCommand) outputRaw(configs map[string]*EnvoyConfig) error { cfgs := make(map[string]interface{}, 0) for name, config := range configs { var cfg interface{} - if err := json.Unmarshal(config.RawCfg, &cfg); err != nil { + if err := json.Unmarshal(config.rawCfg, &cfg); err != nil { return err } @@ -493,7 +488,7 @@ func (c *ReadCommand) outputRaw(configs map[string]*envoy.EnvoyConfig) error { return nil } -func (c *ReadCommand) outputClustersTable(clusters []envoy.Cluster) { +func (c *ReadCommand) outputClustersTable(clusters []Cluster) { if !c.shouldPrintTable(c.flagClusters) { return } @@ -501,16 +496,14 @@ func (c *ReadCommand) outputClustersTable(clusters []envoy.Cluster) { c.UI.Output(fmt.Sprintf("Clusters (%d)", len(clusters)), terminal.WithHeaderStyle()) table := terminal.NewTable("Name", "FQDN", "Endpoints", "Type", "Last Updated") for _, cluster := range clusters { - table.AddRow([]string{ - cluster.Name, cluster.FullyQualifiedDomainName, strings.Join(cluster.Endpoints, ", "), - cluster.Type, cluster.LastUpdated, - }, []string{}) + table.AddRow([]string{cluster.Name, cluster.FullyQualifiedDomainName, strings.Join(cluster.Endpoints, ", "), + cluster.Type, cluster.LastUpdated}, []string{}) } c.UI.Table(table) c.UI.Output("") } -func (c *ReadCommand) outputEndpointsTable(endpoints []envoy.Endpoint) { +func (c *ReadCommand) outputEndpointsTable(endpoints []Endpoint) { if !c.shouldPrintTable(c.flagEndpoints) { return } @@ -519,7 +512,7 @@ func (c *ReadCommand) outputEndpointsTable(endpoints []envoy.Endpoint) { c.UI.Table(formatEndpoints(endpoints)) } -func (c *ReadCommand) outputListenersTable(listeners []envoy.Listener) { +func (c *ReadCommand) outputListenersTable(listeners []Listener) { if !c.shouldPrintTable(c.flagListeners) { return } @@ -528,7 +521,7 @@ func (c *ReadCommand) outputListenersTable(listeners []envoy.Listener) { c.UI.Table(formatListeners(listeners)) } -func (c *ReadCommand) outputRoutesTable(routes []envoy.Route) { +func (c *ReadCommand) outputRoutesTable(routes []Route) { if !c.shouldPrintTable(c.flagRoutes) { return } @@ -537,7 +530,7 @@ func (c *ReadCommand) outputRoutesTable(routes []envoy.Route) { c.UI.Table(formatRoutes(routes)) } -func (c *ReadCommand) outputSecretsTable(secrets []envoy.Secret) { +func (c *ReadCommand) outputSecretsTable(secrets []Secret) { if !c.shouldPrintTable(c.flagSecrets) { return } diff --git a/cli/cmd/proxy/read/command_test.go b/cli/cmd/proxy/read/command_test.go index 992a9a3909..27f19e7370 100644 --- a/cli/cmd/proxy/read/command_test.go +++ b/cli/cmd/proxy/read/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( @@ -12,18 +9,16 @@ import ( "os" "testing" + "github.com/hashicorp/consul-k8s/cli/common" + cmnFlag "github.com/hashicorp/consul-k8s/cli/common/flag" + "github.com/hashicorp/consul-k8s/cli/common/terminal" + "github.com/hashicorp/go-hclog" "github.com/posener/complete" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/envoy" - cmnFlag "github.com/hashicorp/consul-k8s/cli/common/flag" - "github.com/hashicorp/consul-k8s/cli/common/terminal" - "github.com/hashicorp/go-hclog" ) func TestFlagParsing(t *testing.T) { @@ -70,48 +65,38 @@ func TestReadCommandOutput(t *testing.T) { // These regular expressions must be present in the output. expectedHeader := fmt.Sprintf("Envoy configuration for %s in namespace default:", podName) expected := map[string][]string{ - "-clusters": { - "==> Clusters \\(5\\)", + "-clusters": {"==> Clusters \\(5\\)", "Name.*FQDN.*Endpoints.*Type.*Last Updated", "local_agent.*192\\.168\\.79\\.187:8502.*STATIC.*2022-05-13T04:22:39\\.553Z", "local_app.*127\\.0\\.0\\.1:8080.*STATIC.*2022-05-13T04:22:39\\.655Z", "client.*client\\.default\\.dc1\\.internal\\.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00\\.consul.*EDS", "frontend.*frontend\\.default\\.dc1\\.internal\\.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00\\.consul", - "original-destination.*ORIGINAL_DST", - }, + "original-destination.*ORIGINAL_DST"}, - "-endpoints": { - "==> Endpoints \\(6\\)", + "-endpoints": {"==> Endpoints \\(6\\)", "Address:Port.*Cluster.*Weight.*Status", "192.168.79.187:8502.*local_agent.*1.00.*HEALTHY", "127.0.0.1:8080.*local_app.*1.00.*HEALTHY", "192.168.18.110:20000.*client.*1.00.*HEALTHY", "192.168.52.101:20000.*client.*1.00.*HEALTHY", "192.168.65.131:20000.*client.*1.00.*HEALTHY", - "192.168.63.120:20000.*frontend.*1.00.*HEALTHY", - }, + "192.168.63.120:20000.*frontend.*1.00.*HEALTHY"}, - "-listeners": { - "==> Listeners \\(2\\)", + "-listeners": {"==> Listeners \\(2\\)", "Name.*Address:Port.*Direction.*Filter Chain Match.*Filters.*Last Updated", "public_listener.*192\\.168\\.69\\.179:20000.*INBOUND.*Any.*\\* -> local_app/", "outbound_listener.*127.0.0.1:15001.*OUTBOUND.*10\\.100\\.134\\.173/32, 240\\.0\\.0\\.3/32.*TCP: -> client", "10\\.100\\.31\\.2/32, 240\\.0\\.0\\.5/32.*TCP: -> frontend", - "Any.*TCP: -> original-destination", - }, + "Any.*TCP: -> original-destination"}, - "-routes": { - "==> Routes \\(1\\)", + "-routes": {"==> Routes \\(1\\)", "Name.*Destination Cluster.*Last Updated", - "public_listener.*local_app/", - }, + "public_listener.*local_app/"}, - "-secrets": { - "==> Secrets \\(2\\)", + "-secrets": {"==> Secrets \\(2\\)", "Name.*Type.*Last Updated", "default.*Dynamic Active", - "ROOTCA.*Dynamic Warming", - }, + "ROOTCA.*Dynamic Warming"}, } cases := map[string][]string{ @@ -137,7 +122,7 @@ func TestReadCommandOutput(t *testing.T) { c.kubernetes = fake.NewSimpleClientset(&v1.PodList{Items: []v1.Pod{fakePod}}) // A fetchConfig function that just returns the test Envoy config. - c.fetchConfig = func(context.Context, common.PortForwarder) (*envoy.EnvoyConfig, error) { + c.fetchConfig = func(context.Context, common.PortForwarder) (*EnvoyConfig, error) { return testEnvoyConfig, nil } @@ -245,7 +230,7 @@ func TestFilterWarnings(t *testing.T) { buf := new(bytes.Buffer) c := setupCommand(buf) c.kubernetes = fake.NewSimpleClientset(&v1.PodList{Items: []v1.Pod{fakePod}}) - c.fetchConfig = func(context.Context, common.PortForwarder) (*envoy.EnvoyConfig, error) { + c.fetchConfig = func(context.Context, common.PortForwarder) (*EnvoyConfig, error) { return testEnvoyConfig, nil } @@ -310,73 +295,3 @@ func TestTaskCreateCommand_AutocompleteArgs(t *testing.T) { c := cmd.AutocompleteArgs() assert.Equal(t, complete.PredictNothing, c) } - -// testEnvoyConfig is what we expect the config at `test_config_dump.json` to be. - -var testEnvoyConfig = &envoy.EnvoyConfig{ - Clusters: []envoy.Cluster{ - {Name: "local_agent", FullyQualifiedDomainName: "local_agent", Endpoints: []string{"192.168.79.187:8502"}, Type: "STATIC", LastUpdated: "2022-05-13T04:22:39.553Z"}, - - {Name: "client", FullyQualifiedDomainName: "client.default.dc1.internal.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00.consul", Endpoints: []string{"192.168.18.110:20000", "192.168.52.101:20000", "192.168.65.131:20000"}, Type: "EDS", LastUpdated: "2022-08-10T12:30:32.326Z"}, - - {Name: "frontend", FullyQualifiedDomainName: "frontend.default.dc1.internal.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00.consul", Endpoints: []string{"192.168.63.120:20000"}, Type: "EDS", LastUpdated: "2022-08-10T12:30:32.233Z"}, - - {Name: "local_app", FullyQualifiedDomainName: "local_app", Endpoints: []string{"127.0.0.1:8080"}, Type: "STATIC", LastUpdated: "2022-05-13T04:22:39.655Z"}, - - {Name: "original-destination", FullyQualifiedDomainName: "original-destination", Endpoints: []string{}, Type: "ORIGINAL_DST", LastUpdated: "2022-05-13T04:22:39.743Z"}, - }, - - Endpoints: []envoy.Endpoint{ - {Address: "192.168.79.187:8502", Cluster: "local_agent", Weight: 1, Status: "HEALTHY"}, - - {Address: "192.168.18.110:20000", Cluster: "client", Weight: 1, Status: "HEALTHY"}, - - {Address: "192.168.52.101:20000", Cluster: "client", Weight: 1, Status: "HEALTHY"}, - - {Address: "192.168.65.131:20000", Cluster: "client", Weight: 1, Status: "HEALTHY"}, - - {Address: "192.168.63.120:20000", Cluster: "frontend", Weight: 1, Status: "HEALTHY"}, - - {Address: "127.0.0.1:8080", Cluster: "local_app", Weight: 1, Status: "HEALTHY"}, - }, - - Listeners: []envoy.Listener{ - {Name: "public_listener", Address: "192.168.69.179:20000", FilterChain: []envoy.FilterChain{{Filters: []string{"HTTP: * -> local_app/"}, FilterChainMatch: "Any"}}, Direction: "INBOUND", LastUpdated: "2022-08-10T12:30:47.142Z"}, - - {Name: "outbound_listener", Address: "127.0.0.1:15001", FilterChain: []envoy.FilterChain{ - {Filters: []string{"TCP: -> client"}, FilterChainMatch: "10.100.134.173/32, 240.0.0.3/32"}, - - {Filters: []string{"TCP: -> frontend"}, FilterChainMatch: "10.100.31.2/32, 240.0.0.5/32"}, - - {Filters: []string{"TCP: -> original-destination"}, FilterChainMatch: "Any"}, - }, Direction: "OUTBOUND", LastUpdated: "2022-07-18T15:31:03.246Z"}, - }, - - Routes: []envoy.Route{ - { - Name: "public_listener", - - DestinationCluster: "local_app/", - - LastUpdated: "2022-08-10T12:30:47.141Z", - }, - }, - - Secrets: []envoy.Secret{ - { - Name: "default", - - Type: "Dynamic Active", - - LastUpdated: "2022-05-24T17:41:59.078Z", - }, - - { - Name: "ROOTCA", - - Type: "Dynamic Warming", - - LastUpdated: "2022-03-15T05:14:22.868Z", - }, - }, -} diff --git a/cli/common/envoy/http.go b/cli/cmd/proxy/read/config.go similarity index 90% rename from cli/common/envoy/http.go rename to cli/cmd/proxy/read/config.go index 39c58df530..e7e6bcad34 100644 --- a/cli/common/envoy/http.go +++ b/cli/cmd/proxy/read/config.go @@ -1,13 +1,8 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package envoy +package read import ( - "bytes" "context" "encoding/json" - "errors" "fmt" "io" "net" @@ -17,13 +12,11 @@ import ( "github.com/hashicorp/consul-k8s/cli/common" ) -var ErrNoLoggersReturned = errors.New("No loggers were returned from Envoy") - // EnvoyConfig represents the configuration retrieved from a config dump at the // admin endpoint. It wraps the Envoy ConfigDump struct to give us convenient // access to the different sections of the config. type EnvoyConfig struct { - RawCfg []byte + rawCfg []byte Clusters []Cluster Endpoints []Endpoint Listeners []Listener @@ -76,54 +69,6 @@ type Secret struct { LastUpdated string } -// CallLoggingEndpoint requests the logging endpoint from Envoy Admin Interface for a given port -// This is used to both read and update the logging levels (the envoy admin interface uses the same endpoint for both) -// more can be read about that endpoint https://www.envoyproxy.io/docs/envoy/latest/operations/admin#post--logging -func CallLoggingEndpoint(ctx context.Context, portForward common.PortForwarder, params *LoggerParams) (map[string]string, error) { - endpoint, err := portForward.Open(ctx) - if err != nil { - return nil, err - } - - defer portForward.Close() - - // this endpoint does not support returning json, so we've gotta parse the plain text - response, err := http.Post(fmt.Sprintf("http://%s/logging%s", endpoint, params), "text/plain", bytes.NewBuffer([]byte{})) - if err != nil { - return nil, err - } - - body, err := io.ReadAll(response.Body) - if err != nil { - return nil, fmt.Errorf("failed to reach envoy: %v", err) - } - - if response.StatusCode >= 400 { - return nil, fmt.Errorf("call to envoy failed with status code: %d, and message: %s", response.StatusCode, body) - } - - loggers := strings.Split(string(body), "\n") - if len(loggers) == 0 { - return nil, ErrNoLoggersReturned - } - - logLevels := make(map[string]string) - var name string - var level string - - // the first line here is just a header - for _, logger := range loggers[1:] { - if len(logger) == 0 { - continue - } - fmt.Sscanf(logger, "%s %s", &name, &level) - name = strings.TrimRight(name, ":") - logLevels[name] = level - } - - return logLevels, nil -} - // FetchConfig opens a port forward to the Envoy admin API and fetches the // configuration from the config dump endpoint. func FetchConfig(ctx context.Context, portForward common.PortForwarder) (*EnvoyConfig, error) { @@ -172,7 +117,7 @@ func FetchConfig(ctx context.Context, portForward common.PortForwarder) (*EnvoyC // JSON returns the original JSON Envoy config dump data which was used to create // the Config object. func (c *EnvoyConfig) JSON() []byte { - return c.RawCfg + return c.rawCfg } // UnmarshalJSON implements the json.Unmarshaler interface to unmarshal the raw @@ -181,7 +126,7 @@ func (c *EnvoyConfig) JSON() []byte { func (c *EnvoyConfig) UnmarshalJSON(b []byte) error { // Save the original config dump bytes for marshalling. We should treat this // struct as immutable so this should be safe. - c.RawCfg = b + c.rawCfg = b var root root err := json.Unmarshal(b, &root) diff --git a/cli/common/envoy/http_test.go b/cli/cmd/proxy/read/config_test.go similarity index 92% rename from cli/common/envoy/http_test.go rename to cli/cmd/proxy/read/config_test.go index 961046100e..6b0e425794 100644 --- a/cli/common/envoy/http_test.go +++ b/cli/cmd/proxy/read/config_test.go @@ -1,41 +1,21 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package envoy +package read import ( "bytes" "context" + "embed" "encoding/json" "fmt" "net/http" "net/http/httptest" - "os" "strings" "testing" "github.com/stretchr/testify/require" ) -func TestCallLoggingEndpoint(t *testing.T) { - t.Parallel() - rawLogLevels, err := os.ReadFile("testdata/fetch_debug_levels.txt") - require.NoError(t, err) - mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write(rawLogLevels) - })) - - defer mockServer.Close() - - mpf := &mockPortForwarder{ - openBehavior: func(ctx context.Context) (string, error) { - return strings.Replace(mockServer.URL, "http://", "", 1), nil - }, - } - logLevels, err := CallLoggingEndpoint(context.Background(), mpf, NewLoggerParams()) - require.NoError(t, err) - require.Equal(t, testLogConfig(), logLevels) -} +//go:embed test_config_dump.json test_clusters.json +var fs embed.FS const ( testConfigDump = "test_config_dump.json" @@ -55,7 +35,7 @@ func TestUnmarshaling(t *testing.T) { } func TestJSON(t *testing.T) { - raw, err := os.ReadFile(fmt.Sprintf("testdata/%s", testConfigDump)) + raw, err := fs.ReadFile(testConfigDump) require.NoError(t, err) expected := bytes.TrimSpace(raw) @@ -69,10 +49,10 @@ func TestJSON(t *testing.T) { } func TestFetchConfig(t *testing.T) { - configDump, err := os.ReadFile(fmt.Sprintf("testdata/%s", testConfigDump)) + configDump, err := fs.ReadFile(testConfigDump) require.NoError(t, err) - clusters, err := os.ReadFile(fmt.Sprintf("testdata/%s", testClusters)) + clusters, err := fs.ReadFile(testClusters) require.NoError(t, err) mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -466,11 +446,18 @@ func TestClusterParsingEndpoints(t *testing.T) { require.Equal(t, expected, actual) } +type mockPortForwarder struct { + openBehavior func(context.Context) (string, error) +} + +func (m *mockPortForwarder) Open(ctx context.Context) (string, error) { return m.openBehavior(ctx) } +func (m *mockPortForwarder) Close() {} + func rawEnvoyConfig(t *testing.T) []byte { - configDump, err := os.ReadFile(fmt.Sprintf("testdata/%s", testConfigDump)) + configDump, err := fs.ReadFile(testConfigDump) require.NoError(t, err) - clusters, err := os.ReadFile(fmt.Sprintf("testdata/%s", testClusters)) + clusters, err := fs.ReadFile(testClusters) require.NoError(t, err) return []byte(fmt.Sprintf("{\n\"config_dump\":%s,\n\"clusters\":%s}", string(configDump), string(clusters))) @@ -521,18 +508,3 @@ var testEnvoyConfig = &EnvoyConfig{ }, }, } - -type mockPortForwarder struct { - openBehavior func(context.Context) (string, error) -} - -func (m *mockPortForwarder) Open(ctx context.Context) (string, error) { return m.openBehavior(ctx) } -func (m *mockPortForwarder) Close() {} - -func testLogConfig() map[string]string { - cfg := make(map[string]string, len(EnvoyLoggers)) - for k := range EnvoyLoggers { - cfg[k] = "debug" - } - return cfg -} diff --git a/cli/common/envoy/types.go b/cli/cmd/proxy/read/envoy_types.go similarity index 99% rename from cli/common/envoy/types.go rename to cli/cmd/proxy/read/envoy_types.go index 8923eee271..cc1ffcf7e2 100644 --- a/cli/common/envoy/types.go +++ b/cli/cmd/proxy/read/envoy_types.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package envoy +package read /* Envoy Types These types are based on the JSON returned from the Envoy Config Dump API on the diff --git a/cli/cmd/proxy/read/filters.go b/cli/cmd/proxy/read/filters.go index 3c02102df8..dc65172f32 100644 --- a/cli/cmd/proxy/read/filters.go +++ b/cli/cmd/proxy/read/filters.go @@ -1,13 +1,8 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( "strconv" "strings" - - "github.com/hashicorp/consul-k8s/cli/common/envoy" ) // FilterClusters takes a slice of clusters along with parameters for filtering @@ -22,7 +17,7 @@ import ( // // The filters are applied in combination such that a cluster must adhere to // all of the filtering values which are passed in. -func FilterClusters(clusters []envoy.Cluster, fqdn, address string, port int) []envoy.Cluster { +func FilterClusters(clusters []Cluster, fqdn, address string, port int) []Cluster { // No filtering no-op. if fqdn == "" && address == "" && port == -1 { return clusters @@ -30,7 +25,7 @@ func FilterClusters(clusters []envoy.Cluster, fqdn, address string, port int) [] portStr := ":" + strconv.Itoa(port) - filtered := make([]envoy.Cluster, 0) + filtered := make([]Cluster, 0) for _, cluster := range clusters { if !strings.Contains(cluster.FullyQualifiedDomainName, fqdn) { continue @@ -63,14 +58,14 @@ func FilterClusters(clusters []envoy.Cluster, fqdn, address string, port int) [] // // The filters are applied in combination such that an endpoint must adhere to // all of the filtering values which are passed in. -func FilterEndpoints(endpoints []envoy.Endpoint, address string, port int) []envoy.Endpoint { +func FilterEndpoints(endpoints []Endpoint, address string, port int) []Endpoint { if address == "" && port == -1 { return endpoints } portStr := ":" + strconv.Itoa(port) - filtered := make([]envoy.Endpoint, 0) + filtered := make([]Endpoint, 0) for _, endpoint := range endpoints { if strings.Contains(endpoint.Address, address) && (port == -1 || strings.Contains(endpoint.Address, portStr)) { filtered = append(filtered, endpoint) @@ -90,14 +85,14 @@ func FilterEndpoints(endpoints []envoy.Endpoint, address string, port int) []env // // The filters are applied in combination such that an listener must adhere to // all of the filtering values which are passed in. -func FilterListeners(listeners []envoy.Listener, address string, port int) []envoy.Listener { +func FilterListeners(listeners []Listener, address string, port int) []Listener { if address == "" && port == -1 { return listeners } portStr := ":" + strconv.Itoa(port) - filtered := make([]envoy.Listener, 0) + filtered := make([]Listener, 0) for _, listener := range listeners { if strings.Contains(listener.Address, address) && (port == -1 || strings.Contains(listener.Address, portStr)) { filtered = append(filtered, listener) diff --git a/cli/cmd/proxy/read/filters_test.go b/cli/cmd/proxy/read/filters_test.go index 5d998e6a7c..48ff3a97da 100644 --- a/cli/cmd/proxy/read/filters_test.go +++ b/cli/cmd/proxy/read/filters_test.go @@ -1,18 +1,13 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( "testing" "github.com/stretchr/testify/require" - - "github.com/hashicorp/consul-k8s/cli/common/envoy" ) func TestFilterClusters(t *testing.T) { - given := []envoy.Cluster{ + given := []Cluster{ { FullyQualifiedDomainName: "local_agent", Endpoints: []string{"192.168.79.187:8502"}, @@ -47,13 +42,13 @@ func TestFilterClusters(t *testing.T) { fqdn string address string port int - expected []envoy.Cluster + expected []Cluster }{ "No filter": { fqdn: "", address: "", port: -1, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "local_agent", Endpoints: []string{"192.168.79.187:8502"}, @@ -88,7 +83,7 @@ func TestFilterClusters(t *testing.T) { fqdn: "default", address: "", port: -1, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "client.default.dc1.internal.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00.consul", Endpoints: []string{}, @@ -107,7 +102,7 @@ func TestFilterClusters(t *testing.T) { fqdn: "", address: "127.0.", port: -1, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "local_app", Endpoints: []string{"127.0.0.1:8080"}, @@ -122,7 +117,7 @@ func TestFilterClusters(t *testing.T) { fqdn: "", address: "", port: 8080, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "local_app", Endpoints: []string{"127.0.0.1:8080"}, @@ -137,7 +132,7 @@ func TestFilterClusters(t *testing.T) { fqdn: "local", address: "127.0.0.1", port: -1, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "local_app", Endpoints: []string{"127.0.0.1:8080"}, @@ -152,7 +147,7 @@ func TestFilterClusters(t *testing.T) { fqdn: "local", address: "", port: 8080, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "local_app", Endpoints: []string{"127.0.0.1:8080"}, @@ -163,7 +158,7 @@ func TestFilterClusters(t *testing.T) { fqdn: "", address: "127.0.0.1", port: 8080, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "local_app", Endpoints: []string{"127.0.0.1:8080"}, @@ -174,7 +169,7 @@ func TestFilterClusters(t *testing.T) { fqdn: "local", address: "192.168.79.187", port: 8502, - expected: []envoy.Cluster{ + expected: []Cluster{ { FullyQualifiedDomainName: "local_agent", Endpoints: []string{"192.168.79.187:8502"}, @@ -192,7 +187,7 @@ func TestFilterClusters(t *testing.T) { } func TestFilterEndpoints(t *testing.T) { - given := []envoy.Endpoint{ + given := []Endpoint{ { Address: "192.168.79.187:8502", }, @@ -213,12 +208,12 @@ func TestFilterEndpoints(t *testing.T) { cases := map[string]struct { address string port int - expected []envoy.Endpoint + expected []Endpoint }{ "No filter": { address: "", port: -1, - expected: []envoy.Endpoint{ + expected: []Endpoint{ { Address: "192.168.79.187:8502", }, @@ -239,7 +234,7 @@ func TestFilterEndpoints(t *testing.T) { "Filter address": { address: "127.0.0.1", port: -1, - expected: []envoy.Endpoint{ + expected: []Endpoint{ { Address: "127.0.0.1:8080", }, @@ -248,7 +243,7 @@ func TestFilterEndpoints(t *testing.T) { "Filter port": { address: "", port: 20000, - expected: []envoy.Endpoint{ + expected: []Endpoint{ { Address: "192.168.31.201:20000", }, @@ -263,7 +258,7 @@ func TestFilterEndpoints(t *testing.T) { "Filter address and port": { address: "235", port: 20000, - expected: []envoy.Endpoint{ + expected: []Endpoint{ { Address: "192.168.47.235:20000", }, @@ -280,7 +275,7 @@ func TestFilterEndpoints(t *testing.T) { } func TestFilterListeners(t *testing.T) { - given := []envoy.Listener{ + given := []Listener{ { Address: "192.168.69.179:20000", }, @@ -292,12 +287,12 @@ func TestFilterListeners(t *testing.T) { cases := map[string]struct { address string port int - expected []envoy.Listener + expected []Listener }{ "No filter": { address: "", port: -1, - expected: []envoy.Listener{ + expected: []Listener{ { Address: "192.168.69.179:20000", }, @@ -309,7 +304,7 @@ func TestFilterListeners(t *testing.T) { "Filter address": { address: "127.0.0.1", port: -1, - expected: []envoy.Listener{ + expected: []Listener{ { Address: "127.0.0.1:15001", }, @@ -318,7 +313,7 @@ func TestFilterListeners(t *testing.T) { "Filter port": { address: "", port: 20000, - expected: []envoy.Listener{ + expected: []Listener{ { Address: "192.168.69.179:20000", }, @@ -327,7 +322,7 @@ func TestFilterListeners(t *testing.T) { "Filter address and port": { address: "192.168.69.179", port: 20000, - expected: []envoy.Listener{ + expected: []Listener{ { Address: "192.168.69.179:20000", }, diff --git a/cli/cmd/proxy/read/format.go b/cli/cmd/proxy/read/format.go index 596a6254f4..97d5ada86a 100644 --- a/cli/cmd/proxy/read/format.go +++ b/cli/cmd/proxy/read/format.go @@ -1,29 +1,23 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( "fmt" "strings" - "github.com/hashicorp/consul-k8s/cli/common/envoy" "github.com/hashicorp/consul-k8s/cli/common/terminal" ) -func formatClusters(clusters []envoy.Cluster) *terminal.Table { +func formatClusters(clusters []Cluster) *terminal.Table { table := terminal.NewTable("Name", "FQDN", "Endpoints", "Type", "Last Updated") for _, cluster := range clusters { - table.AddRow([]string{ - cluster.Name, cluster.FullyQualifiedDomainName, strings.Join(cluster.Endpoints, ", "), - cluster.Type, cluster.LastUpdated, - }, []string{}) + table.AddRow([]string{cluster.Name, cluster.FullyQualifiedDomainName, strings.Join(cluster.Endpoints, ", "), + cluster.Type, cluster.LastUpdated}, []string{}) } return table } -func formatEndpoints(endpoints []envoy.Endpoint) *terminal.Table { +func formatEndpoints(endpoints []Endpoint) *terminal.Table { table := terminal.NewTable("Address:Port", "Cluster", "Weight", "Status") for _, endpoint := range endpoints { var statusColor string @@ -41,7 +35,7 @@ func formatEndpoints(endpoints []envoy.Endpoint) *terminal.Table { return table } -func formatListeners(listeners []envoy.Listener) *terminal.Table { +func formatListeners(listeners []Listener) *terminal.Table { table := terminal.NewTable("Name", "Address:Port", "Direction", "Filter Chain Match", "Filters", "Last Updated") for _, listener := range listeners { for index, filter := range listener.FilterChain { @@ -63,7 +57,7 @@ func formatListeners(listeners []envoy.Listener) *terminal.Table { return table } -func formatRoutes(routes []envoy.Route) *terminal.Table { +func formatRoutes(routes []Route) *terminal.Table { table := terminal.NewTable("Name", "Destination Cluster", "Last Updated") for _, route := range routes { table.AddRow([]string{route.Name, route.DestinationCluster, route.LastUpdated}, []string{}) @@ -72,7 +66,7 @@ func formatRoutes(routes []envoy.Route) *terminal.Table { return table } -func formatSecrets(secrets []envoy.Secret) *terminal.Table { +func formatSecrets(secrets []Secret) *terminal.Table { table := terminal.NewTable("Name", "Type", "Last Updated") for _, secret := range secrets { table.AddRow([]string{secret.Name, secret.Type, secret.LastUpdated}, []string{}) diff --git a/cli/cmd/proxy/read/format_test.go b/cli/cmd/proxy/read/format_test.go index bac72df862..7d6f975d39 100644 --- a/cli/cmd/proxy/read/format_test.go +++ b/cli/cmd/proxy/read/format_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package read import ( @@ -8,10 +5,8 @@ import ( "context" "testing" - "github.com/stretchr/testify/require" - - "github.com/hashicorp/consul-k8s/cli/common/envoy" "github.com/hashicorp/consul-k8s/cli/common/terminal" + "github.com/stretchr/testify/require" ) func TestFormatClusters(t *testing.T) { @@ -26,7 +21,7 @@ func TestFormatClusters(t *testing.T) { "server.*server.default.dc1.internal.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00.consul.*EDS.*2022-06-09T00:39:12\\.754Z", } - given := []envoy.Cluster{ + given := []Cluster{ { Name: "local_agent", FullyQualifiedDomainName: "local_agent", @@ -102,7 +97,7 @@ func TestFormatEndpoints(t *testing.T) { "192.168.65.131:20000.*1.00.*HEALTHY", } - given := []envoy.Endpoint{ + given := []Endpoint{ { Address: "192.168.79.187:8502", Cluster: "local_agent", @@ -179,11 +174,11 @@ func TestFormatListeners(t *testing.T) { "Any.*-> original-destination", } - given := []envoy.Listener{ + given := []Listener{ { Name: "public_listener", Address: "192.168.69.179:20000", - FilterChain: []envoy.FilterChain{ + FilterChain: []FilterChain{ { FilterChainMatch: "Any", Filters: []string{"* -> local_app/"}, @@ -195,7 +190,7 @@ func TestFormatListeners(t *testing.T) { { Name: "outbound_listener", Address: "127.0.0.1:15001", - FilterChain: []envoy.FilterChain{ + FilterChain: []FilterChain{ { FilterChainMatch: "10.100.134.173/32, 240.0.0.3/32", Filters: []string{"-> client.default.dc1.internal.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00.consul"}, @@ -250,7 +245,7 @@ func TestFormatRoutes(t *testing.T) { "server.*server\\.default\\.dc1\\.internal\\.bc3815c2-1a0f-f3ff-a2e9-20d791f08d00\\.consul/.*2022-05-24T17:41:59\\.078Z", } - given := []envoy.Route{ + given := []Route{ { Name: "public_listener", DestinationCluster: "local_app/", @@ -287,7 +282,7 @@ func TestFormatSecrets(t *testing.T) { "ROOTCA.*Dynamic Warming.*2022-03-15T05:14:22.868Z", } - given := []envoy.Secret{ + given := []Secret{ { Name: "default", Type: "Dynamic Active", diff --git a/cli/common/envoy/testdata/test_clusters.json b/cli/cmd/proxy/read/test_clusters.json similarity index 100% rename from cli/common/envoy/testdata/test_clusters.json rename to cli/cmd/proxy/read/test_clusters.json diff --git a/cli/common/envoy/testdata/test_config_dump.json b/cli/cmd/proxy/read/test_config_dump.json similarity index 100% rename from cli/common/envoy/testdata/test_config_dump.json rename to cli/cmd/proxy/read/test_config_dump.json diff --git a/cli/cmd/status/status.go b/cli/cmd/status/status.go index ebe60528f2..c2108cc631 100644 --- a/cli/cmd/status/status.go +++ b/cli/cmd/status/status.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package status import ( diff --git a/cli/cmd/status/status_test.go b/cli/cmd/status/status_test.go index 7984415c43..8666fd8493 100644 --- a/cli/cmd/status/status_test.go +++ b/cli/cmd/status/status_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package status import ( diff --git a/cli/cmd/troubleshoot/command.go b/cli/cmd/troubleshoot/command.go deleted file mode 100644 index 723088a134..0000000000 --- a/cli/cmd/troubleshoot/command.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package troubleshoot - -import ( - "fmt" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/mitchellh/cli" -) - -// TroubleshootCommand provides a synopsis for the troubleshoot subcommands (e.g. proxy, upstreams). -type TroubleshootCommand struct { - *common.BaseCommand -} - -// Run prints out information about the subcommands. -func (c *TroubleshootCommand) Run([]string) int { - return cli.RunResultHelp -} - -func (c *TroubleshootCommand) Help() string { - return fmt.Sprintf("%s\n\nUsage: consul-k8s troubleshoot ", c.Synopsis()) -} - -func (c *TroubleshootCommand) Synopsis() string { - return "Troubleshoot network and security configurations." -} diff --git a/cli/cmd/troubleshoot/proxy/proxy.go b/cli/cmd/troubleshoot/proxy/proxy.go deleted file mode 100644 index cd8362bf28..0000000000 --- a/cli/cmd/troubleshoot/proxy/proxy.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package proxy - -import ( - "fmt" - "net" - "strings" - "sync" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/flag" - "github.com/hashicorp/consul-k8s/cli/common/terminal" - troubleshoot "github.com/hashicorp/consul/troubleshoot/proxy" - "github.com/posener/complete" - helmCLI "helm.sh/helm/v3/pkg/cli" - "k8s.io/apimachinery/pkg/api/validation" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" -) - -const ( - defaultAdminPort int = 19000 - flagNameKubeConfig = "kubeconfig" - flagNameKubeContext = "context" - flagNameNamespace = "namespace" - flagNamePod = "pod" - flagNameUpstreamEnvoyID = "upstream-envoy-id" - flagNameUpstreamIP = "upstream-ip" - DebugColor = "\033[0;36m%s\033[0m" -) - -type ProxyCommand struct { - *common.BaseCommand - - kubernetes kubernetes.Interface - - set *flag.Sets - - flagKubeConfig string - flagKubeContext string - flagNamespace string - - flagPod string - flagUpstreamEnvoyID string - flagUpstreamIP string - - restConfig *rest.Config - - once sync.Once - help string -} - -// init sets up flags and help text for the command. -func (c *ProxyCommand) init() { - c.set = flag.NewSets() - f := c.set.NewSet("Command Options") - - f.StringVar(&flag.StringVar{ - Name: flagNamePod, - Target: &c.flagPod, - Usage: "The pod to port-forward to.", - Aliases: []string{"p"}, - }) - - f.StringVar(&flag.StringVar{ - Name: flagNameUpstreamEnvoyID, - Target: &c.flagUpstreamEnvoyID, - Usage: "The envoy identifier of the upstream service that receives the communication. (explicit upstreams only)", - Aliases: []string{"id"}, - }) - - f.StringVar(&flag.StringVar{ - Name: flagNameUpstreamIP, - Target: &c.flagUpstreamIP, - Usage: "The IP address of the upstream service that receives the communication. (transparent proxy only)", - Aliases: []string{"ip"}, - }) - - f = c.set.NewSet("Global Options") - f.StringVar(&flag.StringVar{ - Name: flagNameKubeConfig, - Aliases: []string{"c"}, - Target: &c.flagKubeConfig, - Default: "", - Usage: "Set the path to kubeconfig file.", - }) - f.StringVar(&flag.StringVar{ - Name: flagNameKubeContext, - Target: &c.flagKubeContext, - Default: "", - Usage: "Set the Kubernetes context to use.", - }) - - f.StringVar(&flag.StringVar{ - Name: flagNameNamespace, - Target: &c.flagNamespace, - Usage: "The namespace the pod is in.", - Aliases: []string{"n"}, - }) - - c.help = c.set.Help() -} - -// Run executes the list command. -func (c *ProxyCommand) Run(args []string) int { - c.once.Do(c.init) - c.Log.ResetNamed("list") - defer common.CloseWithError(c.BaseCommand) - - // Parse the command line flags. - if err := c.set.Parse(args); err != nil { - c.UI.Output("Error parsing arguments: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - - // Validate the command line flags. - if err := c.validateFlags(); err != nil { - c.UI.Output("Invalid argument: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - - if c.kubernetes == nil { - if err := c.initKubernetes(); err != nil { - c.UI.Output("Error initializing Kubernetes client: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - } - - if err := c.Troubleshoot(); err != nil { - c.UI.Output("Error running troubleshoot: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - - return 0 -} - -// validateFlags ensures that the flags passed in by the can be used. -func (c *ProxyCommand) validateFlags() error { - - if (c.flagUpstreamEnvoyID == "" && c.flagUpstreamIP == "") || (c.flagUpstreamEnvoyID != "" && c.flagUpstreamIP != "") { - return fmt.Errorf("-upstream-envoy-id OR -upstream-ip is required.\n Please run `consul troubleshoot upstreams` to find the corresponding upstream.") - } - - if c.flagPod == "" { - return fmt.Errorf("-pod flag is required") - } - - if errs := validation.ValidateNamespaceName(c.flagNamespace, false); c.flagNamespace != "" && len(errs) > 0 { - return fmt.Errorf("invalid namespace name passed for -namespace/-n: %v", strings.Join(errs, "; ")) - } - - return nil -} - -// initKubernetes initializes the Kubernetes client. -func (c *ProxyCommand) initKubernetes() (err error) { - settings := helmCLI.New() - - if c.flagKubeConfig != "" { - settings.KubeConfig = c.flagKubeConfig - } - - if c.flagKubeContext != "" { - settings.KubeContext = c.flagKubeContext - } - - if c.restConfig == nil { - if c.restConfig, err = settings.RESTClientGetter().ToRESTConfig(); err != nil { - return fmt.Errorf("error creating Kubernetes REST config %v", err) - } - } - - if c.kubernetes == nil { - if c.kubernetes, err = kubernetes.NewForConfig(c.restConfig); err != nil { - return fmt.Errorf("error creating Kubernetes client %v", err) - } - } - - if c.flagNamespace == "" { - c.flagNamespace = settings.Namespace() - } - - return nil -} - -func (c *ProxyCommand) Troubleshoot() error { - pf := common.PortForward{ - Namespace: c.flagNamespace, - PodName: c.flagPod, - RemotePort: defaultAdminPort, - KubeClient: c.kubernetes, - RestConfig: c.restConfig, - } - - endpoint, err := pf.Open(c.Ctx) - if err != nil { - return err - } - defer pf.Close() - - adminAddr, adminPort, err := net.SplitHostPort(endpoint) - if err != nil { - return err - } - - adminAddrIP, err := net.ResolveIPAddr("ip", adminAddr) - if err != nil { - return err - } - - t, err := troubleshoot.NewTroubleshoot(adminAddrIP, adminPort) - if err != nil { - return err - } - - // err = t.GetEnvoyConfigDump() - // if err != nil { - // return err - // } - - messages, err := t.RunAllTests(c.flagUpstreamEnvoyID, c.flagUpstreamIP) - if err != nil { - return err - } - - c.UI.Output("Validation", terminal.WithHeaderStyle()) - for _, o := range messages { - if o.Success { - c.UI.Output(o.Message, terminal.WithSuccessStyle()) - } else { - c.UI.Output(o.Message, terminal.WithErrorStyle()) - for _, action := range o.PossibleActions { - c.UI.Output(fmt.Sprintf("-> %s", action), terminal.WithInfoStyle()) - } - } - } - - return nil -} - -// AutocompleteFlags returns a mapping of supported flags and autocomplete -// options for this command. The map key for the Flags map should be the -// complete flag such as "-foo" or "--foo". -func (c *ProxyCommand) AutocompleteFlags() complete.Flags { - return complete.Flags{ - fmt.Sprintf("-%s", flagNameNamespace): complete.PredictNothing, - fmt.Sprintf("-%s", flagNameKubeConfig): complete.PredictFiles("*"), - fmt.Sprintf("-%s", flagNameKubeContext): complete.PredictNothing, - } -} - -// AutocompleteArgs returns the argument predictor for this command. -// Since argument completion is not supported, this will return -// complete.PredictNothing. -func (c *ProxyCommand) AutocompleteArgs() complete.Predictor { - return complete.PredictNothing -} - -func (c *ProxyCommand) Synopsis() string { - return synopsis -} - -func (c *ProxyCommand) Help() string { - return help -} - -const ( - synopsis = "Troubleshoots service mesh issues." - help = ` -Usage: consul-k8s troubleshoot proxy [options] - - Connect to a pod with a proxy and troubleshoots service mesh communication issues. - - Requires a pod and upstream service SNI. - - Examples: - $ consul-k8s troubleshoot proxy -pod pod1 -upstream foo - - where 'pod1' is the pod running a consul proxy and 'foo' is the upstream envoy ID which - can be obtained by running: - $ consul-k8s troubleshoot upstreams [options] -` -) diff --git a/cli/cmd/troubleshoot/proxy/proxy_test.go b/cli/cmd/troubleshoot/proxy/proxy_test.go deleted file mode 100644 index e018878bf5..0000000000 --- a/cli/cmd/troubleshoot/proxy/proxy_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package proxy - -import ( - "bytes" - "context" - "io" - "os" - "testing" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/terminal" - "github.com/hashicorp/go-hclog" - "github.com/stretchr/testify/require" - "k8s.io/client-go/kubernetes/fake" -) - -func TestFlagParsing(t *testing.T) { - cases := map[string]struct { - args []string - out int - }{ - "No args, should fail": { - args: []string{}, - out: 1, - }, - "Nonexistent flag passed, -foo bar, should fail": { - args: []string{"-foo", "bar"}, - out: 1, - }, - "Invalid argument passed, -namespace notaname, should fail": { - args: []string{"-namespace", "notaname"}, - out: 1, - }, - "Cannot pass both -upstream-envoy-id and -upstream-ip flags, should fail": { - args: []string{"-upstream-envoy-id", "1234", "-upstream-ip", "127.0.0.1"}, - out: 1, - }, - "Cannot pass empty -upstream-envoy-id and -upstream-ip flags, should fail": { - args: []string{"-upstream-envoy-id", "-upstream-ip"}, - out: 1, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - c := setupCommand(new(bytes.Buffer)) - c.kubernetes = fake.NewSimpleClientset() - out := c.Run(tc.args) - require.Equal(t, tc.out, out) - }) - } -} - -func setupCommand(buf io.Writer) *ProxyCommand { - // Log at a test level to standard out. - log := hclog.New(&hclog.LoggerOptions{ - Name: "test", - Level: hclog.Debug, - Output: os.Stdout, - }) - - // Setup and initialize the command struct - command := &ProxyCommand{ - BaseCommand: &common.BaseCommand{ - Log: log, - UI: terminal.NewUI(context.Background(), buf), - }, - } - command.init() - - return command -} diff --git a/cli/cmd/troubleshoot/upstreams/upstreams.go b/cli/cmd/troubleshoot/upstreams/upstreams.go deleted file mode 100644 index abc3235cd5..0000000000 --- a/cli/cmd/troubleshoot/upstreams/upstreams.go +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package upstreams - -import ( - "fmt" - "net" - "sort" - "strconv" - "strings" - "sync" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/flag" - "github.com/hashicorp/consul-k8s/cli/common/terminal" - troubleshoot "github.com/hashicorp/consul/troubleshoot/proxy" - "github.com/posener/complete" - helmCLI "helm.sh/helm/v3/pkg/cli" - "k8s.io/apimachinery/pkg/api/validation" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" -) - -const ( - defaultAdminPort int = 19000 - flagNameKubeConfig = "kubeconfig" - flagNameKubeContext = "context" - flagNameNamespace = "namespace" - flagNamePod = "pod" -) - -type UpstreamsCommand struct { - *common.BaseCommand - - kubernetes kubernetes.Interface - - set *flag.Sets - - flagKubeConfig string - flagKubeContext string - flagNamespace string - - flagPod string - - restConfig *rest.Config - - once sync.Once - help string -} - -// init sets up flags and help text for the command. -func (c *UpstreamsCommand) init() { - c.set = flag.NewSets() - f := c.set.NewSet("Command Options") - - f.StringVar(&flag.StringVar{ - Name: flagNamePod, - Target: &c.flagPod, - Usage: "The pod to port-forward to.", - Aliases: []string{"p"}, - }) - - f = c.set.NewSet("Global Options") - f.StringVar(&flag.StringVar{ - Name: flagNameKubeConfig, - Aliases: []string{"c"}, - Target: &c.flagKubeConfig, - Default: "", - Usage: "Set the path to kubeconfig file.", - }) - f.StringVar(&flag.StringVar{ - Name: flagNameKubeContext, - Target: &c.flagKubeContext, - Default: "", - Usage: "Set the Kubernetes context to use.", - }) - - f.StringVar(&flag.StringVar{ - Name: flagNameNamespace, - Target: &c.flagNamespace, - Usage: "The namespace the pod is in.", - Aliases: []string{"n"}, - }) - - c.help = c.set.Help() -} - -// Run executes the list command. -func (c *UpstreamsCommand) Run(args []string) int { - c.once.Do(c.init) - c.Log.ResetNamed("list") - defer common.CloseWithError(c.BaseCommand) - - // Parse the command line flags. - if err := c.set.Parse(args); err != nil { - c.UI.Output("Error parsing arguments: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - - // Validate the command line flags. - if err := c.validateFlags(); err != nil { - c.UI.Output("Invalid argument: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - - if c.kubernetes == nil { - if err := c.initKubernetes(); err != nil { - c.UI.Output("Error initializing Kubernetes client: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - } - - if err := c.Troubleshoot(); err != nil { - c.UI.Output("Error running troubleshoot: %v", err.Error(), terminal.WithErrorStyle()) - return 1 - } - - return 0 -} - -// validateFlags ensures that the flags passed in by the can be used. -func (c *UpstreamsCommand) validateFlags() error { - - if c.flagPod == "" { - return fmt.Errorf("-pod flag is required") - } - - if errs := validation.ValidateNamespaceName(c.flagNamespace, false); c.flagNamespace != "" && len(errs) > 0 { - return fmt.Errorf("invalid namespace name passed for -namespace/-n: %v", strings.Join(errs, "; ")) - } - - return nil -} - -// initKubernetes initializes the Kubernetes client. -func (c *UpstreamsCommand) initKubernetes() (err error) { - settings := helmCLI.New() - - if c.flagKubeConfig != "" { - settings.KubeConfig = c.flagKubeConfig - } - - if c.flagKubeContext != "" { - settings.KubeContext = c.flagKubeContext - } - - if c.restConfig == nil { - if c.restConfig, err = settings.RESTClientGetter().ToRESTConfig(); err != nil { - return fmt.Errorf("error creating Kubernetes REST config %v", err) - } - } - - if c.kubernetes == nil { - if c.kubernetes, err = kubernetes.NewForConfig(c.restConfig); err != nil { - return fmt.Errorf("error creating Kubernetes client %v", err) - } - } - - if c.flagNamespace == "" { - c.flagNamespace = settings.Namespace() - } - - return nil -} - -func (c *UpstreamsCommand) Troubleshoot() error { - pf := common.PortForward{ - Namespace: c.flagNamespace, - PodName: c.flagPod, - RemotePort: defaultAdminPort, - KubeClient: c.kubernetes, - RestConfig: c.restConfig, - } - - endpoint, err := pf.Open(c.Ctx) - if err != nil { - return fmt.Errorf("error opening endpoint: %v", err) - } - defer pf.Close() - - adminAddr, adminPort, err := net.SplitHostPort(endpoint) - if err != nil { - return fmt.Errorf("error splitting hostport: %v", err) - } - - adminAddrIP, err := net.ResolveIPAddr("ip", adminAddr) - if err != nil { - return fmt.Errorf("error resolving ip address: %v", err) - } - - t, err := troubleshoot.NewTroubleshoot(adminAddrIP, adminPort) - if err != nil { - return fmt.Errorf("error creating new troubleshoot: %v", err) - } - - envoyIDs, upstreamIPs, err := t.GetUpstreams() - if err != nil { - return fmt.Errorf("error getting upstreams: %v", err) - } - - c.UI.Output(fmt.Sprintf("Upstreams (explicit upstreams only) (%v)", len(envoyIDs)), terminal.WithHeaderStyle()) - for _, e := range envoyIDs { - c.UI.Output(e) - } - - c.UI.Output(fmt.Sprintf("Upstream IPs (transparent proxy only) (%v)", len(upstreamIPs)), terminal.WithHeaderStyle()) - table := terminal.NewTable("IPs ", "Virtual ", "Cluster Names") - for _, u := range upstreamIPs { - table.AddRow([]string{formatIPs(u.IPs), strconv.FormatBool(u.IsVirtual), formatClusterNames(u.ClusterNames)}, []string{}) - } - c.UI.Table(table) - - c.UI.Output("\nIf you cannot find the upstream address or cluster for a transparent proxy upstream:", terminal.WithInfoStyle()) - c.UI.Output("-> Check intentions: Transparent proxy upstreams are configured based on intentions. Make sure you "+ - "have configured intentions to allow traffic to your upstream.", terminal.WithInfoStyle()) - c.UI.Output("-> To check that the right cluster is being dialed, run a DNS lookup "+ - "for the upstream you are dialing. For example, run `dig backend.svc.consul` to return the IP address for the `backend` service. If the address you get from that is missing "+ - "from the upstream IPs, it means that your proxy may be misconfigured.", terminal.WithInfoStyle()) - - return nil -} - -// AutocompleteFlags returns a mapping of supported flags and autocomplete -// options for this command. The map key for the Flags map should be the -// complete flag such as "-foo" or "--foo". -func (c *UpstreamsCommand) AutocompleteFlags() complete.Flags { - return complete.Flags{ - fmt.Sprintf("-%s", flagNameNamespace): complete.PredictNothing, - fmt.Sprintf("-%s", flagNameKubeConfig): complete.PredictFiles("*"), - fmt.Sprintf("-%s", flagNameKubeContext): complete.PredictNothing, - } -} - -// AutocompleteArgs returns the argument predictor for this command. -// Since argument completion is not supported, this will return -// complete.PredictNothing. -func (c *UpstreamsCommand) AutocompleteArgs() complete.Predictor { - return complete.PredictNothing -} - -func (c *UpstreamsCommand) Synopsis() string { - return synopsis -} - -func (c *UpstreamsCommand) Help() string { - return help -} - -func formatIPs(ips []string) string { - return strings.Join(ips, ", ") -} - -func formatClusterNames(names map[string]struct{}) string { - var out []string - for k := range names { - out = append(out, k) - } - sort.Strings(out) - return strings.Join(out, ", ") -} - -const ( - synopsis = "Connect to a pod with a proxy and gather upstream services." - help = ` -Usage: consul-k8s troubleshoot upstreams [options] - - Connect to a pod with a proxy and gather upstream services. - - Requires a pod. - - Examples: - $ consul-k8s troubleshoot upstreams -pod pod1 - - where 'pod1' is the pod running a consul proxy -` -) diff --git a/cli/cmd/troubleshoot/upstreams/upstreams_test.go b/cli/cmd/troubleshoot/upstreams/upstreams_test.go deleted file mode 100644 index 595c480a35..0000000000 --- a/cli/cmd/troubleshoot/upstreams/upstreams_test.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package upstreams - -import ( - "bytes" - "context" - "io" - "os" - "testing" - - "github.com/hashicorp/consul-k8s/cli/common" - "github.com/hashicorp/consul-k8s/cli/common/terminal" - "github.com/hashicorp/go-hclog" - "github.com/stretchr/testify/require" - "k8s.io/client-go/kubernetes/fake" -) - -func TestFlagParsing(t *testing.T) { - cases := map[string]struct { - args []string - out int - }{ - "No args, should fail": { - args: []string{}, - out: 1, - }, - "Nonexistent flag passed, -foo bar, should fail": { - args: []string{"-foo", "bar"}, - out: 1, - }, - "Invalid argument passed, -namespace notaname, should fail": { - args: []string{"-namespace", "notaname"}, - out: 1, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - c := setupCommand(new(bytes.Buffer)) - c.kubernetes = fake.NewSimpleClientset() - out := c.Run(tc.args) - require.Equal(t, tc.out, out) - }) - } -} - -func TestFormatIPs(t *testing.T) { - t.Parallel() - - cases := []struct { - name string - actual []string - expected string - }{ - { - name: "single IPs", - actual: []string{"1.1.1.1"}, - expected: "1.1.1.1", - }, - - { - name: "several IPs", - actual: []string{"1.1.1.1", "2.2.2.2"}, - expected: "1.1.1.1, 2.2.2.2", - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - got := formatIPs(c.actual) - if c.expected != got { - t.Errorf("expected %v, got %v", c.expected, got) - } - }) - } -} - -func TestFormatClusterNames(t *testing.T) { - cases := []struct { - name string - actual map[string]struct{} - expected string - }{ - { - name: "single cluster", - actual: map[string]struct{}{ - "cluster1": {}, - }, - expected: "cluster1", - }, - { - name: "several clusters", - actual: map[string]struct{}{ - "cluster1": {}, - "cluster2": {}, - "cluster3": {}, - }, - expected: "cluster1, cluster2, cluster3", - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - got := formatClusterNames(c.actual) - if c.expected != got { - t.Errorf("expected %v, got %v", c.expected, got) - } - }) - } -} - -func setupCommand(buf io.Writer) *UpstreamsCommand { - // Log at a test level to standard out. - log := hclog.New(&hclog.LoggerOptions{ - Name: "test", - Level: hclog.Debug, - Output: os.Stdout, - }) - - // Setup and initialize the command struct - command := &UpstreamsCommand{ - BaseCommand: &common.BaseCommand{ - Log: log, - UI: terminal.NewUI(context.Background(), buf), - }, - } - command.init() - - return command -} diff --git a/cli/cmd/uninstall/uninstall.go b/cli/cmd/uninstall/uninstall.go index caaaa2f0fa..06bf4a19b3 100644 --- a/cli/cmd/uninstall/uninstall.go +++ b/cli/cmd/uninstall/uninstall.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package uninstall import ( diff --git a/cli/cmd/uninstall/uninstall_test.go b/cli/cmd/uninstall/uninstall_test.go index 1d3fffc2c1..2adc0960ab 100644 --- a/cli/cmd/uninstall/uninstall_test.go +++ b/cli/cmd/uninstall/uninstall_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package uninstall import ( diff --git a/cli/cmd/upgrade/upgrade.go b/cli/cmd/upgrade/upgrade.go index a7e79d2239..4c962c47b5 100644 --- a/cli/cmd/upgrade/upgrade.go +++ b/cli/cmd/upgrade/upgrade.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package upgrade import ( @@ -20,6 +17,7 @@ import ( "github.com/hashicorp/consul-k8s/cli/helm" "github.com/hashicorp/consul-k8s/cli/preset" "github.com/posener/complete" + helmCLI "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v3/pkg/getter" @@ -427,7 +425,7 @@ func (c *Command) validateFlags(args []string) error { return fmt.Errorf("cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset) } if ok := slices.Contains(preset.Presets, c.flagPreset); c.flagPreset != defaultPreset && !ok { - return fmt.Errorf("'%s' is not a valid preset (valid presets: %s)", c.flagPreset, strings.Join(preset.Presets, ", ")) + return fmt.Errorf("'%s' is not a valid preset", c.flagPreset) } if _, err := time.ParseDuration(c.flagTimeout); err != nil { return fmt.Errorf("unable to parse -%s: %s", flagNameTimeout, err) diff --git a/cli/cmd/upgrade/upgrade_test.go b/cli/cmd/upgrade/upgrade_test.go index f8421296a7..809cac1034 100644 --- a/cli/cmd/upgrade/upgrade_test.go +++ b/cli/cmd/upgrade/upgrade_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package upgrade import ( @@ -455,7 +452,7 @@ func TestUpgrade(t *testing.T) { messages: []string{ "\n==> Checking if Consul can be upgraded\n ✓ Existing Consul installation found to be upgraded.\n Name: consul\n Namespace: consul\n", "\n==> Checking if Consul demo application can be upgraded\n No existing Consul demo application installation found.\n", - "\n==> Consul Upgrade Summary\n ✓ Downloaded charts.\n \n Difference between user overrides for current and upgraded charts\n -----------------------------------------------------------------\n + connectInject:\n + enabled: true\n + metrics:\n + defaultEnableMerging: true\n + defaultEnabled: true\n + enableGatewayMetrics: true\n + global:\n + metrics:\n + enableAgentMetrics: true\n + enabled: true\n + name: consul\n + prometheus:\n + enabled: true\n + server:\n + replicas: 1\n + ui:\n + enabled: true\n + service:\n + enabled: true\n \n", + "\n==> Consul Upgrade Summary\n ✓ Downloaded charts.\n \n Difference between user overrides for current and upgraded charts\n -----------------------------------------------------------------\n + connectInject:\n + enabled: true\n + metrics:\n + defaultEnableMerging: true\n + defaultEnabled: true\n + enableGatewayMetrics: true\n + controller:\n + enabled: true\n + global:\n + metrics:\n + enableAgentMetrics: true\n + enabled: true\n + name: consul\n + prometheus:\n + enabled: true\n + server:\n + replicas: 1\n + ui:\n + enabled: true\n + service:\n + enabled: true\n \n", "\n==> Upgrading Consul\n ✓ Consul upgraded in namespace \"consul\".\n", }, helmActionsRunner: &helm.MockActionRunner{ @@ -480,7 +477,7 @@ func TestUpgrade(t *testing.T) { messages: []string{ "\n==> Checking if Consul can be upgraded\n ✓ Existing Consul installation found to be upgraded.\n Name: consul\n Namespace: consul\n", "\n==> Checking if Consul demo application can be upgraded\n No existing Consul demo application installation found.\n", - "\n==> Consul Upgrade Summary\n ✓ Downloaded charts.\n \n Difference between user overrides for current and upgraded charts\n -----------------------------------------------------------------\n + connectInject:\n + enabled: true\n + global:\n + acls:\n + manageSystemACLs: true\n + gossipEncryption:\n + autoGenerate: true\n + name: consul\n + tls:\n + enableAutoEncrypt: true\n + enabled: true\n + server:\n + replicas: 1\n \n", + "\n==> Consul Upgrade Summary\n ✓ Downloaded charts.\n \n Difference between user overrides for current and upgraded charts\n -----------------------------------------------------------------\n + connectInject:\n + enabled: true\n + controller:\n + enabled: true\n + global:\n + acls:\n + manageSystemACLs: true\n + gossipEncryption:\n + autoGenerate: true\n + name: consul\n + tls:\n + enableAutoEncrypt: true\n + enabled: true\n + server:\n + replicas: 1\n \n", "\n==> Upgrading Consul\n ✓ Consul upgraded in namespace \"consul\".\n", }, helmActionsRunner: &helm.MockActionRunner{ diff --git a/cli/cmd/version/version.go b/cli/cmd/version/version.go index cab5cbc34d..f31fa711f1 100644 --- a/cli/cmd/version/version.go +++ b/cli/cmd/version/version.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package version import ( diff --git a/cli/commands.go b/cli/commands.go index 1c58e75cf8..fdb581decd 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( @@ -11,12 +8,8 @@ import ( "github.com/hashicorp/consul-k8s/cli/cmd/install" "github.com/hashicorp/consul-k8s/cli/cmd/proxy" "github.com/hashicorp/consul-k8s/cli/cmd/proxy/list" - "github.com/hashicorp/consul-k8s/cli/cmd/proxy/loglevel" "github.com/hashicorp/consul-k8s/cli/cmd/proxy/read" "github.com/hashicorp/consul-k8s/cli/cmd/status" - "github.com/hashicorp/consul-k8s/cli/cmd/troubleshoot" - troubleshoot_proxy "github.com/hashicorp/consul-k8s/cli/cmd/troubleshoot/proxy" - "github.com/hashicorp/consul-k8s/cli/cmd/troubleshoot/upstreams" "github.com/hashicorp/consul-k8s/cli/cmd/uninstall" "github.com/hashicorp/consul-k8s/cli/cmd/upgrade" cmdversion "github.com/hashicorp/consul-k8s/cli/cmd/version" @@ -28,6 +21,7 @@ import ( ) func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseCommand, map[string]cli.CommandFactory) { + baseCommand := &common.BaseCommand{ Ctx: ctx, Log: log, @@ -71,11 +65,6 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, - "proxy log": func() (cli.Command, error) { - return &loglevel.LogLevelCommand{ - BaseCommand: baseCommand, - }, nil - }, "proxy read": func() (cli.Command, error) { return &read.ReadCommand{ BaseCommand: baseCommand, @@ -91,21 +80,6 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, - "troubleshoot": func() (cli.Command, error) { - return &troubleshoot.TroubleshootCommand{ - BaseCommand: baseCommand, - }, nil - }, - "troubleshoot proxy": func() (cli.Command, error) { - return &troubleshoot_proxy.ProxyCommand{ - BaseCommand: baseCommand, - }, nil - }, - "troubleshoot upstreams": func() (cli.Command, error) { - return &upstreams.UpstreamsCommand{ - BaseCommand: baseCommand, - }, nil - }, } return baseCommand, commands diff --git a/cli/common/base.go b/cli/common/base.go index 126e52ab07..2237b66f84 100644 --- a/cli/common/base.go +++ b/cli/common/base.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/common/diff.go b/cli/common/diff.go index c11f4f8c78..30d03e2968 100644 --- a/cli/common/diff.go +++ b/cli/common/diff.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/common/diff_test.go b/cli/common/diff_test.go index 83bc4a59ab..31563e0b6b 100644 --- a/cli/common/diff_test.go +++ b/cli/common/diff_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/common/envoy/logger_params.go b/cli/common/envoy/logger_params.go deleted file mode 100644 index ce18e727c3..0000000000 --- a/cli/common/envoy/logger_params.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package envoy - -import ( - "fmt" - "strings" -) - -type logLevel struct { - name string - level string -} - -type LoggerParams struct { - globalLevel string - individualLevels []logLevel -} - -func NewLoggerParams() *LoggerParams { - return &LoggerParams{ - individualLevels: make([]logLevel, 0), - } -} - -func (l *LoggerParams) SetLoggerLevel(name, level string) error { - err := validateLoggerName(name) - if err != nil { - return err - } - err = validateLogLevel(level) - if err != nil { - return err - } - - l.individualLevels = append(l.individualLevels, logLevel{name: name, level: level}) - return nil -} - -func (l *LoggerParams) SetGlobalLoggerLevel(level string) error { - err := validateLogLevel(level) - if err != nil { - return err - } - l.globalLevel = level - return nil -} - -func validateLogLevel(level string) error { - if _, ok := envoyLevels[level]; !ok { - logLevels := []string{} - for levelName := range envoyLevels { - logLevels = append(logLevels, levelName) - } - return fmt.Errorf("Unknown log level %s, available log levels are %q", level, strings.Join(logLevels, ", ")) - } - return nil -} - -func validateLoggerName(name string) error { - if _, ok := EnvoyLoggers[name]; !ok { - loggers := []string{} - for loggerName := range envoyLevels { - loggers = append(loggers, loggerName) - } - return fmt.Errorf("Unknown logger %s, available loggers are %q", name, strings.Join(loggers, ", ")) - - } - return nil -} - -func (l *LoggerParams) String() string { - switch { - // Global log level change is set - case l.globalLevel != "": - return fmt.Sprintf("?level=%s", l.globalLevel) - - // only one specific logger is changed - case len(l.individualLevels) == 1: - params := fmt.Sprintf("?%s=%s", l.individualLevels[0].name, l.individualLevels[0].level) - return params - - // multiple specific loggers are changed - case len(l.individualLevels) > 1: - logParams := make([]string, 0, len(l.individualLevels)) - for _, logger := range l.individualLevels { - logParams = append(logParams, fmt.Sprintf("%s:%s", logger.name, logger.level)) - } - - params := fmt.Sprintf("?paths=%s", strings.Join(logParams, ",")) - return params - default: - - // default path, this is hit if there are no params - return "" - } -} - -// trace debug info warning error critical off. -var envoyLevels = map[string]struct{}{ - "trace": {}, - "debug": {}, - "info": {}, - "warning": {}, - "error": {}, - "critical": {}, - "off": {}, -} - -var EnvoyLoggers = map[string]struct{}{ - "admin": {}, - "alternate_protocols_cache": {}, - "aws": {}, - "assert": {}, - "backtrace": {}, - "cache_filter": {}, - "client": {}, - "config": {}, - "connection": {}, - "conn_handler": {}, - "decompression": {}, - "dns": {}, - "dubbo": {}, - "envoy_bug": {}, - "ext_authz": {}, - "ext_proc": {}, - "rocketmq": {}, - "file": {}, - "filter": {}, - "forward_proxy": {}, - "grpc": {}, - "happy_eyeballs": {}, - "hc": {}, - "health_checker": {}, - "http": {}, - "http2": {}, - "hystrix": {}, - "init": {}, - "io": {}, - "jwt": {}, - "kafka": {}, - "key_value_store": {}, - "lua": {}, - "main": {}, - "matcher": {}, - "misc": {}, - "mongo": {}, - "multi_connection": {}, - "oauth2": {}, - "quic": {}, - "quic_stream": {}, - "pool": {}, - "rbac": {}, - "rds": {}, - "redis": {}, - "router": {}, - "runtime": {}, - "stats": {}, - "secret": {}, - "tap": {}, - "testing": {}, - "thrift": {}, - "tracing": {}, - "upstream": {}, - "udp": {}, - "wasm": {}, - "websocket": {}, -} diff --git a/cli/common/envoy/logger_params_test.go b/cli/common/envoy/logger_params_test.go deleted file mode 100644 index 1d1779e267..0000000000 --- a/cli/common/envoy/logger_params_test.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package envoy - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestSetLoggerLevelSucceeds(t *testing.T) { - t.Parallel() - testCases := map[string]struct { - levelsToSet [][]string - expectedIndividualLevels []logLevel - }{ - "single log level change trace": { - levelsToSet: [][]string{ - {"admin", "trace"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "trace"}, - }, - }, - "single log level change debug": { - levelsToSet: [][]string{ - {"admin", "debug"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "debug"}, - }, - }, - "single log level change info": { - levelsToSet: [][]string{ - {"admin", "info"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "info"}, - }, - }, - "single log level change warning": { - levelsToSet: [][]string{ - {"admin", "warning"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "warning"}, - }, - }, - "single log level change error": { - levelsToSet: [][]string{ - {"admin", "error"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "error"}, - }, - }, - "single log level change critical": { - levelsToSet: [][]string{ - {"admin", "critical"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "critical"}, - }, - }, - "single log level change off": { - levelsToSet: [][]string{ - {"admin", "off"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "off"}, - }, - }, - "multiple log level change": { - levelsToSet: [][]string{ - {"admin", "info"}, - {"grpc", "debug"}, - }, - expectedIndividualLevels: []logLevel{ - {name: "admin", level: "info"}, - {name: "grpc", level: "debug"}, - }, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - loggerParams := NewLoggerParams() - for _, loggerLevel := range tc.levelsToSet { - logger, level := loggerLevel[0], loggerLevel[1] - err := loggerParams.SetLoggerLevel(logger, level) - require.NoError(t, err) - } - require.Equal(t, loggerParams.individualLevels, tc.expectedIndividualLevels) - }) - } -} - -func TestSetLoggerLevelFails(t *testing.T) { - t.Parallel() - testCases := map[string]struct { - loggerName string - loggerLevel string - }{ - "invalid logger name": { - loggerName: "this is not the logger you're looking for", - loggerLevel: "info", - }, - "invalid logger level": { - loggerName: "grpc", - loggerLevel: "this is also incorrect", - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - loggerParams := NewLoggerParams() - err := loggerParams.SetLoggerLevel(tc.loggerName, tc.loggerLevel) - require.Error(t, err) - }) - } -} - -func TestSetGlobalLoggerLevel(t *testing.T) { - t.Parallel() - for level := range envoyLevels { - loggerParams := NewLoggerParams() - err := loggerParams.SetGlobalLoggerLevel(level) - require.NoError(t, err) - } -} - -func TestSetGlobalLoggerLevelFails(t *testing.T) { - t.Parallel() - loggerParams := NewLoggerParams() - err := loggerParams.SetGlobalLoggerLevel("not a valid level") - require.Error(t, err) -} - -func TestString(t *testing.T) { - t.Parallel() - testCases := map[string]struct { - subject *LoggerParams - expectedOutput string - }{ - "when global level is set": { - subject: &LoggerParams{globalLevel: "warn"}, - expectedOutput: "?level=warn", - }, - "when one specific log level is set": { - subject: &LoggerParams{ - individualLevels: []logLevel{ - {name: "grpc", level: "warn"}, - }, - }, - expectedOutput: "?grpc=warn", - }, - "when multiple specific log levels are set": { - subject: &LoggerParams{ - individualLevels: []logLevel{ - {name: "grpc", level: "warn"}, - {name: "http", level: "info"}, - }, - }, - expectedOutput: "?paths=grpc:warn,http:info", - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - actual := tc.subject.String() - require.Equal(t, actual, tc.expectedOutput) - }) - } -} diff --git a/cli/common/envoy/testdata/fetch_debug_levels.txt b/cli/common/envoy/testdata/fetch_debug_levels.txt deleted file mode 100644 index 6b059dc1aa..0000000000 --- a/cli/common/envoy/testdata/fetch_debug_levels.txt +++ /dev/null @@ -1,59 +0,0 @@ -active loggers: - admin: debug - alternate_protocols_cache: debug - aws: debug - assert: debug - backtrace: debug - cache_filter: debug - client: debug - config: debug - connection: debug - conn_handler: debug - decompression: debug - dns: debug - dubbo: debug - envoy_bug: debug - ext_authz: debug - ext_proc: debug - rocketmq: debug - file: debug - filter: debug - forward_proxy: debug - grpc: debug - happy_eyeballs: debug - hc: debug - health_checker: debug - http: debug - http2: debug - hystrix: debug - init: debug - io: debug - jwt: debug - kafka: debug - key_value_store: debug - lua: debug - main: debug - matcher: debug - misc: debug - mongo: debug - multi_connection: debug - oauth2: debug - quic: debug - quic_stream: debug - pool: debug - rbac: debug - rds: debug - redis: debug - router: debug - runtime: debug - stats: debug - secret: debug - tap: debug - testing: debug - thrift: debug - tracing: debug - upstream: debug - udp: debug - wasm: debug - websocket: debug - diff --git a/cli/common/error.go b/cli/common/error.go index bbdd4087ff..3d8e3deb51 100644 --- a/cli/common/error.go +++ b/cli/common/error.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common // DanglingResourceError should be used when a request was made to remove diff --git a/cli/common/flag/doc.go b/cli/common/flag/doc.go index 90d2b46ffa..1e40f0742c 100644 --- a/cli/common/flag/doc.go +++ b/cli/common/flag/doc.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package flag is a thin layer over the stdlib flag package that provides // some minimal features such as aliasing, autocompletion handling, improved // defaults, etc. It was created for mitchellh/cli but can work as a standalone diff --git a/cli/common/flag/flag.go b/cli/common/flag/flag.go index 471ff86dcf..a0ccf2b239 100644 --- a/cli/common/flag/flag.go +++ b/cli/common/flag/flag.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_bool.go b/cli/common/flag/flag_bool.go index 2800c84495..2862c2fe40 100644 --- a/cli/common/flag/flag_bool.go +++ b/cli/common/flag/flag_bool.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_enum.go b/cli/common/flag/flag_enum.go index a5612ccdb3..ac9ecaedc1 100644 --- a/cli/common/flag/flag_enum.go +++ b/cli/common/flag/flag_enum.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_enum_single.go b/cli/common/flag/flag_enum_single.go index 0165689c76..ddef52796b 100644 --- a/cli/common/flag/flag_enum_single.go +++ b/cli/common/flag/flag_enum_single.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_float.go b/cli/common/flag/flag_float.go index a27be881c8..1f7fcfad67 100644 --- a/cli/common/flag/flag_float.go +++ b/cli/common/flag/flag_float.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_int.go b/cli/common/flag/flag_int.go index fc6b880ac8..41ce1c19ab 100644 --- a/cli/common/flag/flag_int.go +++ b/cli/common/flag/flag_int.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_string.go b/cli/common/flag/flag_string.go index b79b44c6ed..b16a1be16d 100644 --- a/cli/common/flag/flag_string.go +++ b/cli/common/flag/flag_string.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_string_map.go b/cli/common/flag/flag_string_map.go index dfa54da656..5314a66655 100644 --- a/cli/common/flag/flag_string_map.go +++ b/cli/common/flag/flag_string_map.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_string_slice.go b/cli/common/flag/flag_string_slice.go index 93d3483f5b..b567c64936 100644 --- a/cli/common/flag/flag_string_slice.go +++ b/cli/common/flag/flag_string_slice.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_string_slice_test.go b/cli/common/flag/flag_string_slice_test.go index 87a5790db0..5bea43386f 100644 --- a/cli/common/flag/flag_string_slice_test.go +++ b/cli/common/flag/flag_string_slice_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_time.go b/cli/common/flag/flag_time.go index 062c558c1a..45dc297f3d 100644 --- a/cli/common/flag/flag_time.go +++ b/cli/common/flag/flag_time.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/flag_var.go b/cli/common/flag/flag_var.go index 69e2a46675..1b4114f16f 100644 --- a/cli/common/flag/flag_var.go +++ b/cli/common/flag/flag_var.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/set.go b/cli/common/flag/set.go index 8c97313f98..03ee353f80 100644 --- a/cli/common/flag/set.go +++ b/cli/common/flag/set.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/flag/set_test.go b/cli/common/flag/set_test.go index 46e195430c..9bb4ef4a7a 100644 --- a/cli/common/flag/set_test.go +++ b/cli/common/flag/set_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flag import ( diff --git a/cli/common/portforward.go b/cli/common/portforward.go index 79536706d9..4cca979ac6 100644 --- a/cli/common/portforward.go +++ b/cli/common/portforward.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/common/portforward_test.go b/cli/common/portforward_test.go index e4dad39e5a..9bf7cf8e9d 100644 --- a/cli/common/portforward_test.go +++ b/cli/common/portforward_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/common/terminal/basic.go b/cli/common/terminal/basic.go index 4aba11f9f6..e8866415bc 100644 --- a/cli/common/terminal/basic.go +++ b/cli/common/terminal/basic.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminal import ( diff --git a/cli/common/terminal/doc.go b/cli/common/terminal/doc.go index 975bb416ec..2935fa9db5 100644 --- a/cli/common/terminal/doc.go +++ b/cli/common/terminal/doc.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package terminal is a modified version of // https://github.com/hashicorp/waypoint-plugin-sdk/tree/74d9328929293551499078da388b8d057f3b2341/terminal. // diff --git a/cli/common/terminal/table.go b/cli/common/terminal/table.go index 7768a48bce..67278931a4 100644 --- a/cli/common/terminal/table.go +++ b/cli/common/terminal/table.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminal import ( @@ -8,21 +5,15 @@ import ( ) const ( - Yellow = "yellow" - Green = "green" - Red = "red" - Blue = "blue" - Magenta = "magenta" - HiWhite = "hiwhite" + Yellow = "yellow" + Green = "green" + Red = "red" ) var colorMapping = map[string]int{ - Green: tablewriter.FgGreenColor, - Yellow: tablewriter.FgYellowColor, - Red: tablewriter.FgRedColor, - Blue: tablewriter.FgBlueColor, - Magenta: tablewriter.FgMagentaColor, - HiWhite: tablewriter.FgHiWhiteColor, + Green: tablewriter.FgGreenColor, + Yellow: tablewriter.FgYellowColor, + Red: tablewriter.FgRedColor, } // Passed to UI.Table to provide a nicely formatted table. diff --git a/cli/common/terminal/ui.go b/cli/common/terminal/ui.go index b371e95654..dde5d532ba 100644 --- a/cli/common/terminal/ui.go +++ b/cli/common/terminal/ui.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package terminal import ( diff --git a/cli/common/usage.go b/cli/common/usage.go index 6b09950b3e..b4b4cdf780 100644 --- a/cli/common/usage.go +++ b/cli/common/usage.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/common/utils.go b/cli/common/utils.go index 43a94a38ea..b2e9714a9d 100644 --- a/cli/common/utils.go +++ b/cli/common/utils.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/common/utils_test.go b/cli/common/utils_test.go index 9001aba79e..c15397e4a3 100644 --- a/cli/common/utils_test.go +++ b/cli/common/utils_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/cli/config/config.go b/cli/config/config.go index 6bda5b702a..d964bc3b5c 100644 --- a/cli/config/config.go +++ b/cli/config/config.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config import "sigs.k8s.io/yaml" diff --git a/cli/go.mod b/cli/go.mod index 3e92113d18..020192cf0a 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -1,22 +1,21 @@ module github.com/hashicorp/consul-k8s/cli -go 1.20 +go 1.19 require ( github.com/bgentry/speakeasy v0.1.0 github.com/cenkalti/backoff v2.2.1+incompatible - github.com/fatih/color v1.14.1 - github.com/google/go-cmp v0.5.9 + github.com/fatih/color v1.13.0 + github.com/google/go-cmp v0.5.8 github.com/hashicorp/consul-k8s/charts v0.0.0-00010101000000-000000000000 - github.com/hashicorp/consul/troubleshoot v0.3.0-rc1 - github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/go-hclog v0.16.2 github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc github.com/kr/text v0.2.0 - github.com/mattn/go-isatty v0.0.17 + github.com/mattn/go-isatty v0.0.14 github.com/mitchellh/cli v1.1.2 github.com/olekukonko/tablewriter v0.0.5 github.com/posener/complete v1.2.3 - github.com/stretchr/testify v1.8.3 + github.com/stretchr/testify v1.7.2 golang.org/x/text v0.11.0 helm.sh/helm/v3 v3.9.4 k8s.io/api v0.25.0 @@ -28,11 +27,8 @@ require ( sigs.k8s.io/yaml v1.3.0 ) -require go.opentelemetry.io/proto/otlp v0.19.0 // indirect - require ( - cloud.google.com/go/compute v1.19.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go v0.99.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.27 // indirect @@ -50,17 +46,14 @@ require ( github.com/Masterminds/squirrel v1.5.3 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/armon/go-metrics v0.4.1 // indirect github.com/armon/go-radix v1.0.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect + github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect - github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 // indirect github.com/containerd/containerd v1.6.6 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/cli v20.10.17+incompatible // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v20.10.17+incompatible // indirect @@ -69,50 +62,41 @@ require ( github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/emicklei/go-restful/v3 v3.8.0 // indirect - github.com/envoyproxy/go-control-plane v0.11.0 // indirect - github.com/envoyproxy/go-control-plane/xdsmatcher v0.0.0-20230524161521-aaaacbfbe53e // indirect - github.com/envoyproxy/protoc-gen-validate v0.10.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/go-errors/errors v1.0.1 // indirect - github.com/go-gorp/gorp/v3 v3.1.0 // indirect + github.com/go-gorp/gorp/v3 v3.0.2 // indirect github.com/go-logr/logr v1.2.3 // indirect - github.com/go-openapi/analysis v0.21.2 // indirect + github.com/go-openapi/analysis v0.20.0 // indirect github.com/go-openapi/errors v0.20.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect - github.com/go-openapi/loads v0.21.1 // indirect - github.com/go-openapi/runtime v0.24.1 // indirect - github.com/go-openapi/spec v0.20.4 // indirect - github.com/go-openapi/strfmt v0.21.3 // indirect - github.com/go-openapi/swag v0.21.1 // indirect - github.com/go-openapi/validate v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/loads v0.20.2 // indirect + github.com/go-openapi/runtime v0.19.24 // indirect + github.com/go-openapi/spec v0.20.3 // indirect + github.com/go-openapi/strfmt v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-openapi/validate v0.20.2 // indirect github.com/go-ozzo/ozzo-validation v3.6.0+incompatible // indirect + github.com/go-stack/stack v1.8.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.2.0 // indirect github.com/gorilla/mux v1.8.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.22.0-rc1 // indirect - github.com/hashicorp/consul/envoyextensions v0.3.0-rc1 // 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 + github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-version v1.2.1 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/serf v0.10.1 // indirect github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -120,17 +104,16 @@ require ( github.com/klauspost/compress v1.13.6 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect - github.com/lib/pq v1.10.7 // indirect + github.com/lib/pq v1.10.6 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect @@ -140,16 +123,14 @@ require ( github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/oklog/ulid v1.3.1 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.12.2 // indirect - github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/rubenv/sql-migrate v1.1.1 // indirect @@ -164,20 +145,19 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect - go.mongodb.org/mongo-driver v1.11.1 // indirect - go.starlark.net v0.0.0-20230128213706-3f75dec8e403 // indirect + go.mongodb.org/mongo-driver v1.4.6 // indirect + go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/net v0.13.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/sync v0.2.0 // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect + google.golang.org/grpc v1.47.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/cli/go.sum b/cli/go.sum index 6b54e646b2..48969abfef 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -18,16 +18,21 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -66,7 +71,6 @@ github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -86,30 +90,34 @@ github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6 github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= -github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -127,31 +135,24 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXe github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/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= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4= github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0= github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= @@ -166,9 +167,8 @@ github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269 h1:hbCT8ZPPMqefiAWD2ZKjn7ypokIGViTvBBg/ExLSdCk= @@ -185,6 +185,7 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= @@ -202,14 +203,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= -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/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -217,10 +212,8 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwC github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -232,14 +225,15 @@ github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmV github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4= github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY= -github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= -github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -252,45 +246,104 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= -github.com/go-openapi/analysis v0.21.2 h1:hXFrOYFHUAMQdu6zwAiKKJHJQ8kqZs1ux/ru1P1wLJU= -github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= +github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk= +github.com/go-openapi/analysis v0.20.0 h1:UN09o0kNhleunxW7LR+KnltD0YrJ8FF03pSqvAN3Vro= +github.com/go-openapi/analysis v0.20.0/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxlOmQr9FBZk+Og= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/loads v0.21.1 h1:Wb3nVZpdEzDTcly8S4HMkey6fjARRzb7iEaySimlDW0= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/runtime v0.24.1 h1:Sml5cgQKGYQHF+M7yYSHaH1eOjvTykrddTE/KtQVjqo= -github.com/go-openapi/runtime v0.24.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= -github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= +github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= +github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= +github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= +github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4= +github.com/go-openapi/loads v0.20.2 h1:z5p5Xf5wujMxS1y8aP+vxwW5qYT2zdJBbXKmQUG3lcc= +github.com/go-openapi/loads v0.20.2/go.mod h1:hTVUotJ+UonAMMZsvakEgmWKgtulweO9vYP2bQYKA/o= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= +github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= +github.com/go-openapi/runtime v0.19.24 h1:TqagMVlRAOTwllE/7hNKx6rQ10O6T8ZzeJdMjSTKaD4= +github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/spec v0.20.1/go.mod h1:93x7oh+d+FQsmsieroS4cmR3u0p/ywH649a3qwC9OsQ= +github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ= +github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= +github.com/go-openapi/strfmt v0.20.0 h1:l2omNtmNbMc39IGptl9BuXBEKcZfS8zjrTsPKTiJiDM= +github.com/go-openapi/strfmt v0.20.0/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= +github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/validate v0.21.0 h1:+Wqk39yKOhfpLqNLEC0/eViCkzM5FVXVqrvt526+wcI= -github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= +github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= +github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= +github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= +github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= +github.com/go-openapi/validate v0.20.2 h1:AhqDegYV3J3iQkMPJSXkvzymHKMTw0BST3RK3hTT4ts= +github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZIVCbJBpTUoY0= github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE= github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= @@ -334,7 +387,6 @@ github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8 github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -348,6 +400,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -364,10 +417,10 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -388,8 +441,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -397,6 +450,7 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -408,15 +462,21 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -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/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= @@ -428,63 +488,35 @@ github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16 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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.22.0-rc1 h1:ePmGqndeMgaI38KUbSA/CqTzeEAIogXyWnfNJzglo70= -github.com/hashicorp/consul/api v1.22.0-rc1/go.mod h1:wtduXtbAqSGtBdi3tyA5SSAYGAG51rBejV9SEUBciMY= -github.com/hashicorp/consul/envoyextensions v0.3.0-rc1 h1:weclrwjvLeX+vxPOyo4b4dCDxSpnDl60Z9K16nnCVnI= -github.com/hashicorp/consul/envoyextensions v0.3.0-rc1/go.mod h1:ckxoPHMiWXAe6dhyxmKsX1XqO4KTV64KWIyTu44z8UI= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.14.0-rc1 h1:PuETOfN0uxl28i0Pq6rK7TBCrIl7psMbL0YTSje4KvM= -github.com/hashicorp/consul/troubleshoot v0.3.0-rc1 h1:Z6ZUEKILsf85wA/zXK3XMop6IGtjui4ZZ0bAu+JIAz4= -github.com/hashicorp/consul/troubleshoot v0.3.0-rc1/go.mod h1:2WfcYZ8M4vpLtTv9M5Dp3egqSPZ16l5XsqMpO9QUYxc= 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= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -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/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -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-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc h1:on26TCKYnX7JzZCtwkR/LWHSqMu40PoZ6h/0e6Pq8ug= github.com/hashicorp/hcp-sdk-go v0.23.1-0.20220921131124-49168300a7dc/go.mod h1:/9UoDY2FYYA8lFaKBb2HmM/jKYZGANmf65q9QRc/cVw= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= -github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= @@ -493,10 +525,12 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= @@ -506,7 +540,6 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -520,8 +553,10 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -532,9 +567,10 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -544,18 +580,20 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= @@ -565,35 +603,27 @@ github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= @@ -602,8 +632,6 @@ github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFW github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -612,11 +640,11 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -649,8 +677,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= @@ -669,11 +695,9 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= @@ -685,18 +709,16 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1 h1:oL4IBbcqwhhNWh31bjOX8C/OCy0zs9906d/VUru+bqg= github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU= -github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= @@ -705,12 +727,10 @@ github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrb 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.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 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= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= @@ -718,7 +738,6 @@ github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= @@ -727,7 +746,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rubenv/sql-migrate v1.1.1 h1:haR5Hn8hbW9/SpAICrXoZqXnywS7Q5WijwkQENPeNWY= github.com/rubenv/sql-migrate v1.1.1/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMHQPT4FWdnbQ= @@ -736,8 +754,8 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= @@ -773,29 +791,22 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -804,7 +815,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -815,24 +825,27 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8= -go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.6 h1:rh7GdYmDrb8AQSkF8yteAus8qYOgOASWDOv1BWqBXkU= +go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= @@ -844,11 +857,9 @@ go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= -go.starlark.net v0.0.0-20230128213706-3f75dec8e403 h1:jPeC7Exc+m8OBJUlWbBLh0O5UZPM7yU5W4adnhhbG4U= -go.starlark.net v0.0.0-20230128213706-3f75dec8e403/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.starlark.net v0.0.0-20200707032745-474f21a9602d h1:uFqwFYlX7d5ZSp+IqhXxct0SybXrTzEBDvb2CkEhPBs= +go.starlark.net v0.0.0-20200707032745-474f21a9602d/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -857,23 +868,23 @@ go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -886,8 +897,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -917,12 +926,14 @@ golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -932,7 +943,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -945,19 +955,21 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -978,9 +990,11 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -993,8 +1007,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1004,6 +1018,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1012,15 +1027,15 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1052,36 +1067,34 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1102,7 +1115,9 @@ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= golang.org/x/time v0.0.0-20220609170525-579cf78fd858/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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1116,11 +1131,12 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1160,7 +1176,10 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= @@ -1190,6 +1209,15 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1239,11 +1267,27 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 h1:hrbNEivu7Zn1pxvHk6MBrq9iE22woVILTHqexqBxe6I= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1264,11 +1308,15 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1282,8 +1330,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1311,7 +1359,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= diff --git a/cli/helm/action.go b/cli/helm/action.go index 4afe1ba9d8..d71014c762 100644 --- a/cli/helm/action.go +++ b/cli/helm/action.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( diff --git a/cli/helm/chart.go b/cli/helm/chart.go index c57d9220bc..f679ca591d 100644 --- a/cli/helm/chart.go +++ b/cli/helm/chart.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( @@ -65,7 +62,7 @@ func readChartFiles(chart embed.FS, chartDirName string) ([]*loader.BufferedFile // filepath.* functions, then Go on Windows will try to use `\` delimiters to access // the embedded filesystem, which will then fail. - // Load Chart.yaml and values.yaml. + // Load Chart.yaml and values.yaml first. for _, f := range []string{chartFileName, valuesFileName} { file, err := readFile(chart, path.Join(chartDirName, f), chartDirName) if err != nil { @@ -74,7 +71,7 @@ func readChartFiles(chart embed.FS, chartDirName string) ([]*loader.BufferedFile chartFiles = append(chartFiles, file) } - // Load everything under templates/. + // Now load everything under templates/. dirs, err := chart.ReadDir(path.Join(chartDirName, templatesDirName)) if err != nil { return nil, err diff --git a/cli/helm/chart_test.go b/cli/helm/chart_test.go index f0e33e092b..9ed48d50a5 100644 --- a/cli/helm/chart_test.go +++ b/cli/helm/chart_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( @@ -38,10 +35,10 @@ func TestLoadChart(t *testing.T) { func TestReadChartFiles(t *testing.T) { directory := "test_fixtures/consul" expectedFiles := map[string]string{ - "Chart.yaml": "# Copyright (c) HashiCorp, Inc.\n# SPDX-License-Identifier: MPL-2.0\n\n# This is a mock Helm Chart.yaml file used for testing.\napiVersion: v2\nname: Foo\nversion: 0.1.0\ndescription: Mock Helm Chart for testing.", - "values.yaml": "# Copyright (c) HashiCorp, Inc.\n# SPDX-License-Identifier: MPL-2.0\n\n# This is a mock Helm values.yaml file used for testing.\nkey: value", + "Chart.yaml": "# This is a mock Helm Chart.yaml file used for testing.\napiVersion: v2\nname: Foo\nversion: 0.1.0\ndescription: Mock Helm Chart for testing.", + "values.yaml": "# This is a mock Helm values.yaml file used for testing.\nkey: value", "templates/_helpers.tpl": "helpers", - "templates/foo.yaml": "# Copyright (c) HashiCorp, Inc.\n# SPDX-License-Identifier: MPL-2.0\n\nfoo: bar\n", + "templates/foo.yaml": "foo: bar\n", } files, err := readChartFiles(testChartFiles, directory) diff --git a/cli/helm/install.go b/cli/helm/install.go index c19dd9dff3..1e0a83b8b8 100644 --- a/cli/helm/install.go +++ b/cli/helm/install.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( diff --git a/cli/helm/install_test.go b/cli/helm/install_test.go index 7b154f6975..6458a06e54 100644 --- a/cli/helm/install_test.go +++ b/cli/helm/install_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( diff --git a/cli/helm/mock.go b/cli/helm/mock.go index ce0793ef01..05d3b6edb4 100644 --- a/cli/helm/mock.go +++ b/cli/helm/mock.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( diff --git a/cli/helm/test_fixtures/consul/Chart.yaml b/cli/helm/test_fixtures/consul/Chart.yaml index 488e2da2a7..72cdfea793 100644 --- a/cli/helm/test_fixtures/consul/Chart.yaml +++ b/cli/helm/test_fixtures/consul/Chart.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # This is a mock Helm Chart.yaml file used for testing. apiVersion: v2 name: Foo diff --git a/cli/helm/test_fixtures/consul/templates/foo.yaml b/cli/helm/test_fixtures/consul/templates/foo.yaml index b17972509f..20e9ff3fea 100644 --- a/cli/helm/test_fixtures/consul/templates/foo.yaml +++ b/cli/helm/test_fixtures/consul/templates/foo.yaml @@ -1,4 +1 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - foo: bar diff --git a/cli/helm/test_fixtures/consul/values.yaml b/cli/helm/test_fixtures/consul/values.yaml index a0b3ab57b1..e8062923bc 100644 --- a/cli/helm/test_fixtures/consul/values.yaml +++ b/cli/helm/test_fixtures/consul/values.yaml @@ -1,5 +1,2 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # This is a mock Helm values.yaml file used for testing. key: value \ No newline at end of file diff --git a/cli/helm/upgrade.go b/cli/helm/upgrade.go index 8c0072c345..e9d4545652 100644 --- a/cli/helm/upgrade.go +++ b/cli/helm/upgrade.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( diff --git a/cli/helm/upgrade_test.go b/cli/helm/upgrade_test.go index 750c903d33..4ae09bb36f 100644 --- a/cli/helm/upgrade_test.go +++ b/cli/helm/upgrade_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm import ( diff --git a/cli/helm/values.go b/cli/helm/values.go index 19e19d8d05..1f55ecfdf3 100644 --- a/cli/helm/values.go +++ b/cli/helm/values.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package helm // HACK this is a temporary hard-coded struct. We should actually generate this from our `values.yaml` file. @@ -576,13 +573,11 @@ type CopyAnnotations struct { } type ManagedGatewayClass struct { - Enabled bool `yaml:"enabled"` - NodeSelector interface{} `yaml:"nodeSelector"` - ServiceType string `yaml:"serviceType"` - UseHostPorts bool `yaml:"useHostPorts"` - CopyAnnotations CopyAnnotations `yaml:"copyAnnotations"` - OpenshiftSCCName string `yaml:"openshiftSCCName"` - MapPrivilegedContainerPorts int `yaml:"mapPrivilegedContainerPorts"` + Enabled bool `yaml:"enabled"` + NodeSelector interface{} `yaml:"nodeSelector"` + ServiceType string `yaml:"serviceType"` + UseHostPorts bool `yaml:"useHostPorts"` + CopyAnnotations CopyAnnotations `yaml:"copyAnnotations"` } type Service struct { diff --git a/cli/main.go b/cli/main.go index 133e2a28a8..0ffd03328c 100644 --- a/cli/main.go +++ b/cli/main.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( diff --git a/cli/preset/cloud_preset.go b/cli/preset/cloud_preset.go index cbc335ae17..95219cb378 100644 --- a/cli/preset/cloud_preset.go +++ b/cli/preset/cloud_preset.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package preset import ( @@ -8,7 +5,6 @@ import ( "encoding/json" "fmt" "net/http" - "strings" "github.com/hashicorp/consul-k8s/cli/common" "github.com/hashicorp/consul-k8s/cli/common/terminal" @@ -202,8 +198,6 @@ global: bootstrapToken: secretName: %s secretKey: %s - metrics: - enableTelemetryCollector: true cloud: enabled: true resourceId: @@ -218,15 +212,6 @@ global: %s %s %s -telemetryCollector: - enabled: true - cloud: - clientId: - secretName: %s - secretKey: %s - clientSecret: - secretName: %s - secretKey: %s server: replicas: %d affinity: null @@ -236,15 +221,13 @@ connectInject: enabled: true controller: enabled: true -`, strings.ToLower(cfg.BootstrapResponse.Cluster.ID), secretNameServerCA, corev1.TLSCertKey, +`, cfg.BootstrapResponse.Cluster.ID, secretNameServerCA, corev1.TLSCertKey, secretNameGossipKey, secretKeyGossipKey, secretNameBootstrapToken, secretKeyBootstrapToken, secretNameHCPResourceID, secretKeyHCPResourceID, secretNameHCPClientID, secretKeyHCPClientID, secretNameHCPClientSecret, secretKeyHCPClientSecret, apiHostCfg, authURLCfg, scadaAddressCfg, - secretNameHCPClientID, secretKeyHCPClientID, - secretNameHCPClientSecret, secretKeyHCPClientSecret, cfg.BootstrapResponse.Cluster.BootstrapExpect, secretNameServerCert) valuesMap := config.ConvertToMap(values) return valuesMap diff --git a/cli/preset/cloud_preset_test.go b/cli/preset/cloud_preset_test.go index d905cb4088..946e1ca158 100644 --- a/cli/preset/cloud_preset_test.go +++ b/cli/preset/cloud_preset_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package preset import ( @@ -43,7 +40,7 @@ const ( { "cluster": { - "id": "Dc1", + "id": "dc1", "bootstrap_expect" : 3 }, "bootstrap": @@ -63,7 +60,7 @@ const ( var validBootstrapReponse *models.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse = &models.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse{ Bootstrap: &models.HashicorpCloudGlobalNetworkManager20220215ClusterBootstrap{ - ID: "Dc1", + ID: "dc1", GossipKey: "Wa6/XFAnYy0f9iqVH2iiG+yore3CqHSemUy4AIVTa/w=", BootstrapExpect: 3, ServerTLS: &models.HashicorpCloudGlobalNetworkManager20220215ServerTLS{ @@ -483,8 +480,6 @@ global: gossipEncryption: secretKey: key secretName: consul-gossip-key - metrics: - enableTelemetryCollector: true tls: caCert: secretKey: tls.crt @@ -496,15 +491,6 @@ server: replicas: 3 serverCert: secretName: consul-server-cert -telemetryCollector: - cloud: - clientId: - secretKey: client-id - secretName: consul-hcp-client-id - clientSecret: - secretKey: client-secret - secretName: consul-hcp-client-secret - enabled: true ` const expectedWithoutOptional = `connectInject: @@ -532,8 +518,6 @@ global: gossipEncryption: secretKey: key secretName: consul-gossip-key - metrics: - enableTelemetryCollector: true tls: caCert: secretKey: tls.crt @@ -545,43 +529,16 @@ server: replicas: 3 serverCert: secretName: consul-server-cert -telemetryCollector: - cloud: - clientId: - secretKey: client-id - secretName: consul-hcp-client-id - clientSecret: - secretKey: client-secret - secretName: consul-hcp-client-secret - enabled: true ` cloudPreset := &CloudPreset{} - testCases := map[string]struct { + testCases := []struct { + description string config *CloudBootstrapConfig expectedYaml string }{ - "Config_including_optional_parameters_with_mixedcase_DC": { - &CloudBootstrapConfig{ - BootstrapResponse: &models.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse{ - Cluster: &models.HashicorpCloudGlobalNetworkManager20220215Cluster{ - BootstrapExpect: 3, - ID: "Dc1", - }, - }, - HCPConfig: HCPConfig{ - ResourceID: "consul-hcp-resource-id", - ClientID: "consul-hcp-client-id", - ClientSecret: "consul-hcp-client-secret", - AuthURL: "consul-hcp-auth-url", - APIHostname: "consul-hcp-api-host", - ScadaAddress: "consul-hcp-scada-address", - }, - }, - expectedFull, - }, - "Config_including_optional_parameters": { + {"Config including optional parameters", &CloudBootstrapConfig{ BootstrapResponse: &models.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse{ Cluster: &models.HashicorpCloudGlobalNetworkManager20220215Cluster{ @@ -600,7 +557,7 @@ telemetryCollector: }, expectedFull, }, - "Config_without_optional_parameters": { + {"Config without optional parameters", &CloudBootstrapConfig{ BootstrapResponse: &models.HashicorpCloudGlobalNetworkManager20220215AgentBootstrapResponse{ Cluster: &models.HashicorpCloudGlobalNetworkManager20220215Cluster{ @@ -617,8 +574,8 @@ telemetryCollector: expectedWithoutOptional, }, } - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { cloudHelmValues := cloudPreset.getHelmConfigWithMapSecretNames(tc.config) require.NotNil(t, cloudHelmValues) valuesYaml, err := yaml.Marshal(cloudHelmValues) diff --git a/cli/preset/demo.go b/cli/preset/demo.go index 5e011904fa..bf6c0bb122 100644 --- a/cli/preset/demo.go +++ b/cli/preset/demo.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package preset import "github.com/hashicorp/consul-k8s/cli/config" @@ -32,6 +29,8 @@ connectInject: enableGatewayMetrics: true server: replicas: 1 +controller: + enabled: true ui: enabled: true service: diff --git a/cli/preset/preset.go b/cli/preset/preset.go index 1b53dd021f..2eb2c94bc4 100644 --- a/cli/preset/preset.go +++ b/cli/preset/preset.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package preset import ( diff --git a/cli/preset/preset_test.go b/cli/preset/preset_test.go index 53b95b56e6..c39c11e80f 100644 --- a/cli/preset/preset_test.go +++ b/cli/preset/preset_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package preset import ( diff --git a/cli/preset/quickstart.go b/cli/preset/quickstart.go index 1e16a1e9c3..52b3f000b1 100644 --- a/cli/preset/quickstart.go +++ b/cli/preset/quickstart.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package preset import "github.com/hashicorp/consul-k8s/cli/config" @@ -32,6 +29,8 @@ connectInject: enableGatewayMetrics: true server: replicas: 1 +controller: + enabled: true ui: enabled: true service: diff --git a/cli/preset/secure.go b/cli/preset/secure.go index 62727273be..ded436804c 100644 --- a/cli/preset/secure.go +++ b/cli/preset/secure.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package preset import "github.com/hashicorp/consul-k8s/cli/config" @@ -32,6 +29,8 @@ server: replicas: 1 connectInject: enabled: true +controller: + enabled: true ` return config.ConvertToMap(values), nil diff --git a/cli/release/release.go b/cli/release/release.go index 9b973f080f..e1590f9057 100644 --- a/cli/release/release.go +++ b/cli/release/release.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package release import ( diff --git a/cli/release/release_test.go b/cli/release/release_test.go index f65c67ac05..a6f1c28994 100644 --- a/cli/release/release_test.go +++ b/cli/release/release_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package release import ( diff --git a/cli/validation/kubernetes.go b/cli/validation/kubernetes.go index 8a7d77ed5b..99dc8af6f7 100644 --- a/cli/validation/kubernetes.go +++ b/cli/validation/kubernetes.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package validation import ( diff --git a/cli/validation/kubernetes_test.go b/cli/validation/kubernetes_test.go index 90a5c6c298..60d7ec243b 100644 --- a/cli/validation/kubernetes_test.go +++ b/cli/validation/kubernetes_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package validation import ( diff --git a/cli/version/fips_build.go b/cli/version/fips_build.go deleted file mode 100644 index 63e0e68883..0000000000 --- a/cli/version/fips_build.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -//go:build fips - -package version - -// This validates during compilation that we are being built with a FIPS enabled go toolchain -import ( - _ "crypto/tls/fipsonly" - "runtime" - "strings" -) - -// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode. -func IsFIPS() bool { - return true -} - -func GetFIPSInfo() string { - str := "Enabled" - // Try to get the crypto module name - gover := strings.Split(runtime.Version(), "X:") - if len(gover) >= 2 { - gover_last := gover[len(gover)-1] - // Able to find crypto module name; add that to status string. - str = "FIPS 140-2 Enabled, crypto module " + gover_last - } - return str -} diff --git a/cli/version/non_fips_build.go b/cli/version/non_fips_build.go deleted file mode 100644 index ce99575d2c..0000000000 --- a/cli/version/non_fips_build.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -//go:build !fips - -package version - -// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode. -func IsFIPS() bool { - return false -} - -func GetFIPSInfo() string { - return "" -} diff --git a/cli/version/version.go b/cli/version/version.go index 952cd9ca81..c17eb5d89e 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package version import ( @@ -17,7 +14,7 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "1.3.0" + Version = "1.0.10" // 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 @@ -39,12 +36,8 @@ func GetHumanVersion() string { release = "dev" } - if IsFIPS() { - version += "+fips1402" - } - if release != "" { - if !strings.Contains(version, "-"+release) { + if !strings.HasSuffix(version, "-"+release) { // if we tagged a prerelease version then the release is in the version already version += fmt.Sprintf("-%s", release) } diff --git a/control-plane/Dockerfile b/control-plane/Dockerfile index c09f5ecf80..773db0b0e9 100644 --- a/control-plane/Dockerfile +++ b/control-plane/Dockerfile @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # This Dockerfile contains multiple targets. # Use 'docker build --target= .' to build one. # @@ -16,7 +13,7 @@ # go-discover builds the discover binary (which we don't currently publish # either). -FROM golang:1.19.2-alpine as go-discover +FROM golang:1.19.9-alpine as go-discover RUN CGO_ENABLED=0 go install github.com/hashicorp/go-discover/cmd/discover@214571b6a5309addf3db7775f4ee8cf4d264fd5f # dev copies the binary from a local build @@ -92,11 +89,7 @@ LABEL name=${BIN_NAME} \ ENV BIN_NAME=${BIN_NAME} ENV VERSION=${PRODUCT_VERSION} -RUN apk add --no-cache ca-certificates libcap openssl su-exec iputils gcompat libc6-compat libstdc++ iptables - -# for FIPS CGO glibc compatibility in alpine -# see https://github.com/golang/go/issues/59305 -RUN ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 +RUN apk add --no-cache ca-certificates libcap openssl su-exec iputils libc6-compat iptables # TARGETOS and TARGETARCH are set automatically when --platform is provided. ARG TARGETOS @@ -113,9 +106,6 @@ COPY dist/cni/${TARGETOS}/${TARGETARCH}/${CNI_BIN_NAME} /bin/ USER 100 CMD /bin/${BIN_NAME} -# Duplicate target for FIPS builds -FROM release-default AS release-default-fips - # ----------------------------------- # Dockerfile target for consul-k8s with UBI as its base image. Used for running on # OpenShift. @@ -178,8 +168,6 @@ COPY dist/cni/${TARGETOS}/${TARGETARCH}/${CNI_BIN_NAME} /bin/ USER 100 CMD /bin/${BIN_NAME} -# Duplicate target for FIPS builds -FROM ubi AS ubi-fips # =================================== # # Set default target to 'dev'. diff --git a/control-plane/PROJECT b/control-plane/PROJECT index 5a4e24d0f8..c11e857849 100644 --- a/control-plane/PROJECT +++ b/control-plane/PROJECT @@ -1,7 +1,3 @@ -# Code generated by tool. DO NOT EDIT. -# This file is used to track the info used to scaffold your project -# and allow the plugins properly work. -# More info: https://book.kubebuilder.io/reference/project-config.html domain: hashicorp.com layout: - go.kubebuilder.io/v2 @@ -81,49 +77,4 @@ resources: kind: PeeringDialer path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 version: v1alpha1 -- api: - crdVersion: v1beta1 - namespaced: true - controller: true - domain: hashicorp.com - group: consul - kind: SamenessGroup - path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1beta1 - namespaced: true - controller: true - domain: hashicorp.com - group: consul - kind: JWTProvider - path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1beta1 - namespaced: true - controller: true - domain: hashicorp.com - group: consul - kind: ControlPlaneRequestLimit - path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1beta1 - namespaced: true - controller: true - domain: hashicorp.com - group: consul - kind: RouteRetryFilter - path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1beta1 - namespaced: true - controller: true - domain: hashicorp.com - group: consul - kind: RouteTimeoutFilter - path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 - version: v1alpha1 version: "3" diff --git a/control-plane/api-gateway/binding/annotations.go b/control-plane/api-gateway/binding/annotations.go deleted file mode 100644 index 2bd4d0db15..0000000000 --- a/control-plane/api-gateway/binding/annotations.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "encoding/json" - - 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" -) - -func serializeGatewayClassConfig(gw *gwv1beta1.Gateway, gwcc *v1alpha1.GatewayClassConfig) (*v1alpha1.GatewayClassConfig, bool) { - if gwcc == nil { - return nil, false - } - - if gw.Annotations == nil { - gw.Annotations = make(map[string]string) - } - - if annotatedConfig, ok := gw.Annotations[common.AnnotationGatewayClassConfig]; ok { - var config v1alpha1.GatewayClassConfig - if err := json.Unmarshal([]byte(annotatedConfig), &config.Spec); err == nil { - // if we can unmarshal the gateway, return it - return &config, false - } - } - - // otherwise if we failed to unmarshal or there was no annotation, marshal it onto - // the gateway - marshaled, _ := json.Marshal(gwcc.Spec) - gw.Annotations[common.AnnotationGatewayClassConfig] = string(marshaled) - return gwcc, true -} diff --git a/control-plane/api-gateway/binding/annotations_test.go b/control-plane/api-gateway/binding/annotations_test.go deleted file mode 100644 index edb44ccfb4..0000000000 --- a/control-plane/api-gateway/binding/annotations_test.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "encoding/json" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - 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" -) - -func TestSerializeGatewayClassConfig_HappyPath(t *testing.T) { - t.Parallel() - - type args struct { - gw *gwv1beta1.Gateway - gwcc *v1alpha1.GatewayClassConfig - } - tests := []struct { - name string - args args - expectedDidUpdate bool - }{ - { - name: "when gateway has not been annotated yet and annotations are nil", - args: args{ - gw: &gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-gw", - }, - Spec: gwv1beta1.GatewaySpec{}, - Status: gwv1beta1.GatewayStatus{}, - }, - gwcc: &v1alpha1.GatewayClassConfig{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "the config", - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - ServiceType: common.PointerTo(corev1.ServiceType("serviceType")), - NodeSelector: map[string]string{ - "selector": "of node", - }, - Tolerations: []v1.Toleration{ - { - Key: "key", - Operator: "op", - Value: "120", - Effect: "to the moon", - TolerationSeconds: new(int64), - }, - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{ - Service: []string{"service"}, - }, - }, - }, - }, - expectedDidUpdate: true, - }, - { - name: "when gateway has not been annotated yet but annotations are empty", - args: args{ - gw: &gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-gw", - Annotations: make(map[string]string), - }, - Spec: gwv1beta1.GatewaySpec{}, - Status: gwv1beta1.GatewayStatus{}, - }, - gwcc: &v1alpha1.GatewayClassConfig{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "the config", - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - ServiceType: common.PointerTo(corev1.ServiceType("serviceType")), - NodeSelector: map[string]string{ - "selector": "of node", - }, - Tolerations: []v1.Toleration{ - { - Key: "key", - Operator: "op", - Value: "120", - Effect: "to the moon", - TolerationSeconds: new(int64), - }, - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{ - Service: []string{"service"}, - }, - }, - }, - }, - expectedDidUpdate: true, - }, - { - name: "when gateway has been annotated", - args: args{ - gw: &gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-gw", - Annotations: map[string]string{ - common.AnnotationGatewayClassConfig: `{"serviceType":"serviceType","nodeSelector":{"selector":"of node"},"tolerations":[{"key":"key","operator":"op","value":"120","effect":"to the moon","tolerationSeconds":0}],"copyAnnotations":{"service":["service"]}}`, - }, - }, - Spec: gwv1beta1.GatewaySpec{}, - Status: gwv1beta1.GatewayStatus{}, - }, - gwcc: &v1alpha1.GatewayClassConfig{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "the config", - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - ServiceType: common.PointerTo(corev1.ServiceType("serviceType")), - NodeSelector: map[string]string{ - "selector": "of node", - }, - Tolerations: []v1.Toleration{ - { - Key: "key", - Operator: "op", - Value: "120", - Effect: "to the moon", - TolerationSeconds: new(int64), - }, - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{ - Service: []string{"service"}, - }, - }, - }, - }, - expectedDidUpdate: false, - }, - { - name: "when gateway has been annotated but the serialization was invalid", - args: args{ - gw: &gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-gw", - Annotations: map[string]string{ - // we remove the opening brace to make unmarshalling fail - common.AnnotationGatewayClassConfig: `"serviceType":"serviceType","nodeSelector":{"selector":"of node"},"tolerations":[{"key":"key","operator":"op","value":"120","effect":"to the moon","tolerationSeconds":0}],"copyAnnotations":{"service":["service"]}}`, - }, - }, - Spec: gwv1beta1.GatewaySpec{}, - Status: gwv1beta1.GatewayStatus{}, - }, - gwcc: &v1alpha1.GatewayClassConfig{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "the config", - }, - Spec: v1alpha1.GatewayClassConfigSpec{ - ServiceType: common.PointerTo(corev1.ServiceType("serviceType")), - NodeSelector: map[string]string{ - "selector": "of node", - }, - Tolerations: []v1.Toleration{ - { - Key: "key", - Operator: "op", - Value: "120", - Effect: "to the moon", - TolerationSeconds: new(int64), - }, - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{ - Service: []string{"service"}, - }, - }, - }, - }, - expectedDidUpdate: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, actualDidUpdate := serializeGatewayClassConfig(tt.args.gw, tt.args.gwcc) - - if actualDidUpdate != tt.expectedDidUpdate { - t.Errorf("SerializeGatewayClassConfig() = %v, want %v", actualDidUpdate, tt.expectedDidUpdate) - } - - var config v1alpha1.GatewayClassConfig - err := json.Unmarshal([]byte(tt.args.gw.Annotations[common.AnnotationGatewayClassConfig]), &config.Spec) - require.NoError(t, err) - - if diff := cmp.Diff(config.Spec, tt.args.gwcc.Spec); diff != "" { - t.Errorf("Expected gwconfig spec to match serialized version (-want,+got):\n%s", diff) - } - }) - } -} diff --git a/control-plane/api-gateway/binding/binder.go b/control-plane/api-gateway/binding/binder.go deleted file mode 100644 index 7798a6b49c..0000000000 --- a/control-plane/api-gateway/binding/binder.go +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - mapset "github.com/deckarep/golang-set" - "github.com/go-logr/logr" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul/api" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -// BinderConfig configures a binder instance with all of the information -// that it needs to know to generate a snapshot of bound state. -type BinderConfig struct { - // Logger for any internal logs - Logger logr.Logger - // Translator instance initialized with proper name/namespace translation - // configuration from helm. - Translator common.ResourceTranslator - // ControllerName is the name of the controller used in determining which - // gateways we control, also leveraged for setting route statuses. - ControllerName string - - // Namespaces is a map of all namespaces in Kubernetes indexed by their names for looking up labels - // for AllowedRoutes matching purposes. - Namespaces map[string]corev1.Namespace - // GatewayClassConfig is the configuration corresponding to the given - // GatewayClass -- if it is nil we should treat the gateway as deleted - // since the gateway is now pointing to an invalid gateway class - GatewayClassConfig *v1alpha1.GatewayClassConfig - // GatewayClass is the GatewayClass corresponding to the Gateway we want to - // bind routes to. It is passed as a pointer because it could be nil. If no - // GatewayClass corresponds to a Gateway, we ought to clean up any sort of - // state that we may have set on the Gateway, its corresponding Routes or in - // Consul, because we should no longer be managing the Gateway (its association - // to our controller is through a parameter on the GatewayClass). - GatewayClass *gwv1beta1.GatewayClass - // Gateway is the Gateway being reconciled that we want to bind routes to. - Gateway gwv1beta1.Gateway - // HTTPRoutes is a list of HTTPRoute objects that ought to be bound to the Gateway. - HTTPRoutes []gwv1beta1.HTTPRoute - // TCPRoutes is a list of TCPRoute objects that ought to be bound to the Gateway. - TCPRoutes []gwv1alpha2.TCPRoute - // Pods are any pods that are part of the Gateway deployment. - Pods []corev1.Pod - // Service is the deployed service associated with the Gateway deployment. - Service *corev1.Service - - // ConsulGateway is the config entry we've created in Consul. - ConsulGateway *api.APIGatewayConfigEntry - // GatewayServices are the services associated with the Gateway - ConsulGatewayServices []api.CatalogService - - // Resources is a map containing all service targets to verify - // against the routing backends. - Resources *common.ResourceMap -} - -// Binder is used for generating a Snapshot of all operations that should occur both -// in Kubernetes and Consul as a result of binding routes to a Gateway. -type Binder struct { - statusSetter *setter - key types.NamespacedName - nonNormalizedConsulKey api.ResourceReference - normalizedConsulKey api.ResourceReference - config BinderConfig -} - -// NewBinder creates a Binder object with the given configuration. -func NewBinder(config BinderConfig) *Binder { - id := client.ObjectKeyFromObject(&config.Gateway) - - return &Binder{ - config: config, - statusSetter: newSetter(config.ControllerName), - key: id, - nonNormalizedConsulKey: config.Translator.NonNormalizedConfigEntryReference(api.APIGateway, id), - normalizedConsulKey: config.Translator.ConfigEntryReference(api.APIGateway, id), - } -} - -// isGatewayDeleted returns whether we should treat the given gateway as a deleted object. -// This is true if the gateway has a deleted timestamp, if its GatewayClass does not match -// our controller name, or if the GatewayClass it references doesn't exist. -func (b *Binder) isGatewayDeleted() bool { - gatewayClassMismatch := b.config.GatewayClass == nil || b.config.ControllerName != string(b.config.GatewayClass.Spec.ControllerName) - isGatewayDeleted := isDeleted(&b.config.Gateway) || gatewayClassMismatch || b.config.GatewayClassConfig == nil - return isGatewayDeleted -} - -// Snapshot generates a snapshot of operations that need to occur in Kubernetes and Consul -// in order for a Gateway to be reconciled. -func (b *Binder) Snapshot() *Snapshot { - // at this point we assume all tcp routes and http routes - // actually reference this gateway - snapshot := NewSnapshot() - - registrationPods := []corev1.Pod{} - // filter out any pod that is being deleted - for _, pod := range b.config.Pods { - if !isDeleted(&pod) { - registrationPods = append(registrationPods, pod) - } - } - - gatewayClassConfig := b.config.GatewayClassConfig - - isGatewayDeleted := b.isGatewayDeleted() - - var gatewayValidation gatewayValidationResult - var listenerValidation listenerValidationResults - - if !isGatewayDeleted { - var updated bool - - gatewayClassConfig, updated = serializeGatewayClassConfig(&b.config.Gateway, gatewayClassConfig) - - // we don't have a deletion but if we add a finalizer for the gateway, then just add it and return - // otherwise try and resolve as much as possible - if common.EnsureFinalizer(&b.config.Gateway) || updated { - // if we've added the finalizer or serialized the class config, then update - snapshot.Kubernetes.Updates.Add(&b.config.Gateway) - return snapshot - } - - // calculate the status for the gateway - gatewayValidation = validateGateway(b.config.Gateway, registrationPods, b.config.ConsulGateway) - listenerValidation = validateListeners(b.config.Gateway, b.config.Gateway.Spec.Listeners, b.config.Resources, b.config.GatewayClassConfig) - } - - // used for tracking how many routes have successfully bound to which listeners - // on a gateway for reporting the number of bound routes in a gateway listener's - // status - boundCounts := make(map[gwv1beta1.SectionName]int) - - // attempt to bind all routes - - for _, r := range b.config.HTTPRoutes { - b.bindRoute(common.PointerTo(r), boundCounts, snapshot) - } - - for _, r := range b.config.TCPRoutes { - b.bindRoute(common.PointerTo(r), boundCounts, snapshot) - } - - // process secrets - gatewaySecrets := secretsForGateway(b.config.Gateway, b.config.Resources) - if !isGatewayDeleted { - // we only do this if the gateway isn't going to be deleted so that the - // resources can get GC'd - 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 - if err := b.config.Resources.TranslateInlineCertificate(secret.(types.NamespacedName)); err != nil { - b.config.Logger.Error(err, "error parsing referenced secret, ignoring") - continue - } - } - } - - // now cleanup any routes or certificates that we haven't already processed - - snapshot.Consul.Deletions = b.config.Resources.ResourcesToGC(b.key) - snapshot.Consul.Updates = b.config.Resources.Mutations() - - // finally, handle the gateway itself - - // we only want to upsert the gateway into Consul or update its status - // if the gateway hasn't been marked for deletion - if !isGatewayDeleted { - snapshot.GatewayClassConfig = gatewayClassConfig - snapshot.UpsertGatewayDeployment = true - - var consulStatus api.ConfigEntryStatus - if b.config.ConsulGateway != nil { - consulStatus = b.config.ConsulGateway.Status - } - entry := b.config.Translator.ToAPIGateway(b.config.Gateway, b.config.Resources, gatewayClassConfig) - snapshot.Consul.Updates = append(snapshot.Consul.Updates, &common.ConsulUpdateOperation{ - Entry: entry, - OnUpdate: b.handleGatewaySyncStatus(snapshot, &b.config.Gateway, consulStatus), - }) - - registrations := registrationsForPods(entry.Namespace, b.config.Gateway, registrationPods) - snapshot.Consul.Registrations = registrations - - // deregister any not explicitly registered service - for _, service := range b.config.ConsulGatewayServices { - found := false - for _, registration := range registrations { - if service.ServiceID == registration.Service.ID { - found = true - break - } - } - if !found { - // we didn't register the service instance, so drop it - snapshot.Consul.Deregistrations = append(snapshot.Consul.Deregistrations, api.CatalogDeregistration{ - Node: service.Node, - ServiceID: service.ServiceID, - Namespace: service.Namespace, - }) - } - } - - // calculate the status for the gateway - var status gwv1beta1.GatewayStatus - for i, listener := range b.config.Gateway.Spec.Listeners { - status.Listeners = append(status.Listeners, gwv1beta1.ListenerStatus{ - Name: listener.Name, - SupportedKinds: supportedKinds(listener), - AttachedRoutes: int32(boundCounts[listener.Name]), - Conditions: listenerValidation.Conditions(b.config.Gateway.Generation, i), - }) - } - status.Conditions = b.config.Gateway.Status.Conditions - - // we do this loop to not accidentally override any additional statuses that - // have been set anywhere outside of validation. - for _, condition := range gatewayValidation.Conditions(b.config.Gateway.Generation, listenerValidation.Invalid()) { - status.Conditions, _ = setCondition(status.Conditions, condition) - } - status.Addresses = addressesForGateway(b.config.Service, registrationPods) - - // only mark the gateway as needing a status update if there's a diff with its old - // status, this keeps the controller from infinitely reconciling - if !common.GatewayStatusesEqual(status, b.config.Gateway.Status) { - b.config.Gateway.Status = status - snapshot.Kubernetes.StatusUpdates.Add(&b.config.Gateway) - } - } else { - // if the gateway has been deleted, unset whatever we've set on it - snapshot.Consul.Deletions = append(snapshot.Consul.Deletions, b.nonNormalizedConsulKey) - for _, service := range b.config.ConsulGatewayServices { - // deregister all gateways - snapshot.Consul.Deregistrations = append(snapshot.Consul.Deregistrations, api.CatalogDeregistration{ - Node: service.Node, - ServiceID: service.ServiceID, - Namespace: service.Namespace, - }) - } - if common.RemoveFinalizer(&b.config.Gateway) { - snapshot.Kubernetes.Updates.Add(&b.config.Gateway) - } - } - - return snapshot -} - -func secretsForGateway(gateway gwv1beta1.Gateway, resources *common.ResourceMap) mapset.Set { - set := mapset.NewSet() - - for _, listener := range gateway.Spec.Listeners { - if listener.TLS == nil { - continue - } - - for _, cert := range listener.TLS.CertificateRefs { - if resources.GatewayCanReferenceSecret(gateway, cert) { - if common.NilOrEqual(cert.Group, "") && common.NilOrEqual(cert.Kind, common.KindSecret) { - key := common.IndexedNamespacedNameWithDefault(cert.Name, cert.Namespace, gateway.Namespace) - set.Add(key) - } - } - } - } - - return set -} - -func addressesForGateway(service *corev1.Service, pods []corev1.Pod) []gwv1beta1.GatewayAddress { - if service == nil { - return addressesFromPods(pods) - } - - switch service.Spec.Type { - case corev1.ServiceTypeLoadBalancer: - return addressesFromLoadBalancer(service) - case corev1.ServiceTypeClusterIP: - return addressesFromClusterIP(service) - case corev1.ServiceTypeNodePort: - /* For serviceType: NodePort, there isn't a consistent way to guarantee access to the - * service from outside the k8s cluster. For now, we're putting the IP address of the - * nodes that the gateway pods are running on. - * The practitioner will have to understand that they may need to port forward into the - * cluster (in the case of Kind) or open firewall rules (in the case of GKE) in order to - * access the gateway from outside the cluster. - */ - return addressesFromPodHosts(pods) - } - - return []gwv1beta1.GatewayAddress{} -} - -func addressesFromLoadBalancer(service *corev1.Service) []gwv1beta1.GatewayAddress { - addresses := []gwv1beta1.GatewayAddress{} - - for _, ingress := range service.Status.LoadBalancer.Ingress { - if ingress.IP != "" { - addresses = append(addresses, gwv1beta1.GatewayAddress{ - Type: common.PointerTo(gwv1beta1.IPAddressType), - Value: ingress.IP, - }) - } - if ingress.Hostname != "" { - addresses = append(addresses, gwv1beta1.GatewayAddress{ - Type: common.PointerTo(gwv1beta1.HostnameAddressType), - Value: ingress.Hostname, - }) - } - } - - return addresses -} - -func addressesFromClusterIP(service *corev1.Service) []gwv1beta1.GatewayAddress { - addresses := []gwv1beta1.GatewayAddress{} - - if service.Spec.ClusterIP != "" { - addresses = append(addresses, gwv1beta1.GatewayAddress{ - Type: common.PointerTo(gwv1beta1.IPAddressType), - Value: service.Spec.ClusterIP, - }) - } - - return addresses -} - -func addressesFromPods(pods []corev1.Pod) []gwv1beta1.GatewayAddress { - addresses := []gwv1beta1.GatewayAddress{} - seenIPs := make(map[string]struct{}) - - for _, pod := range pods { - if pod.Status.PodIP != "" { - if _, found := seenIPs[pod.Status.PodIP]; !found { - addresses = append(addresses, gwv1beta1.GatewayAddress{ - Type: common.PointerTo(gwv1beta1.IPAddressType), - Value: pod.Status.PodIP, - }) - seenIPs[pod.Status.PodIP] = struct{}{} - } - } - } - - return addresses -} - -func addressesFromPodHosts(pods []corev1.Pod) []gwv1beta1.GatewayAddress { - addresses := []gwv1beta1.GatewayAddress{} - seenIPs := make(map[string]struct{}) - - for _, pod := range pods { - if pod.Status.HostIP != "" { - if _, found := seenIPs[pod.Status.HostIP]; !found { - addresses = append(addresses, gwv1beta1.GatewayAddress{ - Type: common.PointerTo(gwv1beta1.IPAddressType), - Value: pod.Status.HostIP, - }) - seenIPs[pod.Status.HostIP] = struct{}{} - } - } - } - - return addresses -} - -// isDeleted checks if the deletion timestamp is set for an object. -func isDeleted(object client.Object) bool { - return !object.GetDeletionTimestamp().IsZero() -} - -func supportedKinds(listener gwv1beta1.Listener) []gwv1beta1.RouteGroupKind { - if listener.AllowedRoutes != nil && listener.AllowedRoutes.Kinds != nil { - return common.Filter(listener.AllowedRoutes.Kinds, func(kind gwv1beta1.RouteGroupKind) bool { - if _, ok := allSupportedRouteKinds[kind.Kind]; !ok { - return true - } - return !common.NilOrEqual(kind.Group, gwv1beta1.GroupVersion.Group) - }) - } - return supportedKindsForProtocol[listener.Protocol] -} diff --git a/control-plane/api-gateway/binding/binder_test.go b/control-plane/api-gateway/binding/binder_test.go deleted file mode 100644 index 7366d1a164..0000000000 --- a/control-plane/api-gateway/binding/binder_test.go +++ /dev/null @@ -1,2384 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "math/big" - "testing" - "time" - - logrtest "github.com/go-logr/logr/testing" - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - 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" - "github.com/hashicorp/consul/api" -) - -func init() { - timeFunc = func() metav1.Time { - return metav1.Time{} - } -} - -const ( - testGatewayClassName = "gateway-class" - testControllerName = "test-controller" -) - -var ( - testGatewayClassObjectName = gwv1beta1.ObjectName(testGatewayClassName) - deletionTimestamp = common.PointerTo(metav1.Now()) - - testGatewayClass = &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Name: testGatewayClassName, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: gwv1beta1.GatewayController(testControllerName), - }, - } -) - -type resourceMapResources struct { - grants []gwv1beta1.ReferenceGrant - secrets []corev1.Secret - gateways []gwv1beta1.Gateway - httpRoutes []gwv1beta1.HTTPRoute - tcpRoutes []gwv1alpha2.TCPRoute - meshServices []v1alpha1.MeshService - services []types.NamespacedName - consulInlineCertificates []api.InlineCertificateConfigEntry - consulHTTPRoutes []api.HTTPRouteConfigEntry - consulTCPRoutes []api.TCPRouteConfigEntry -} - -func newTestResourceMap(t *testing.T, resources resourceMapResources) *common.ResourceMap { - resourceMap := common.NewResourceMap(common.ResourceTranslator{}, NewReferenceValidator(resources.grants), logrtest.NewTestLogger(t)) - - for _, s := range resources.services { - resourceMap.AddService(s, s.Name) - } - for _, s := range resources.meshServices { - resourceMap.AddMeshService(s) - } - for _, s := range resources.secrets { - resourceMap.ReferenceCountCertificate(s) - } - for _, g := range resources.gateways { - resourceMap.ReferenceCountGateway(g) - } - for _, r := range resources.httpRoutes { - resourceMap.ReferenceCountHTTPRoute(r) - } - for _, r := range resources.tcpRoutes { - resourceMap.ReferenceCountTCPRoute(r) - } - for _, r := range resources.consulHTTPRoutes { - resourceMap.ReferenceCountConsulHTTPRoute(r) - } - for _, r := range resources.consulTCPRoutes { - resourceMap.ReferenceCountConsulTCPRoute(r) - } - return resourceMap -} - -func TestBinder_Lifecycle(t *testing.T) { - t.Parallel() - - certificateOne, secretOne := generateTestCertificate(t, "default", "secret-one") - certificateTwo, secretTwo := generateTestCertificate(t, "default", "secret-two") - - for name, tt := range map[string]struct { - resources resourceMapResources - config BinderConfig - expectedStatusUpdates []client.Object - expectedUpdates []client.Object - expectedConsulDeletions []api.ResourceReference - expectedConsulUpdates []api.ConfigEntry - }{ - "no gateway class and empty routes": { - config: BinderConfig{ - Gateway: gwv1beta1.Gateway{}, - }, - expectedConsulDeletions: []api.ResourceReference{{ - Kind: api.APIGateway, - }}, - }, - "no gateway class and empty routes remove finalizer": { - config: BinderConfig{ - Gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Finalizers: []string{common.GatewayFinalizer}, - }, - }, - }, - expectedUpdates: []client.Object{ - addClassConfig(gwv1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{}}}), - }, - expectedConsulDeletions: []api.ResourceReference{ - {Kind: api.APIGateway}, - }, - }, - "deleting gateway empty routes": { - config: BinderConfig{ - ControllerName: testControllerName, - GatewayClass: testGatewayClass, - Gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - DeletionTimestamp: deletionTimestamp, - Finalizers: []string{common.GatewayFinalizer}, - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: testGatewayClassObjectName, - }, - }, - }, - expectedUpdates: []client.Object{ - addClassConfig(gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: deletionTimestamp, Finalizers: []string{}}, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: testGatewayClassObjectName, - }, - }), - }, - expectedConsulDeletions: []api.ResourceReference{ - {Kind: api.APIGateway}, - }, - }, - "basic gateway no finalizer": { - config: BinderConfig{ - ControllerName: testControllerName, - GatewayClass: testGatewayClass, - Gateway: gwv1beta1.Gateway{ - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: testGatewayClassObjectName, - }, - }, - }, - expectedUpdates: []client.Object{ - addClassConfig(gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{Finalizers: []string{common.GatewayFinalizer}}, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: testGatewayClassObjectName, - }, - }), - }, - }, - "basic gateway": { - config: controlledBinder(BinderConfig{ - Gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{{ - Protocol: gwv1beta1.HTTPSProtocolType, - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "secret-one"}, - }, - Mode: common.PointerTo(gwv1beta1.TLSModeTerminate), - }, - }}, - }), - }), - resources: resourceMapResources{ - secrets: []corev1.Secret{ - secretOne, - }, - }, - expectedStatusUpdates: []client.Object{ - addClassConfig(gatewayWithFinalizerStatus( - gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{{ - Protocol: gwv1beta1.HTTPSProtocolType, - TLS: &gwv1beta1.GatewayTLSConfig{ - Mode: common.PointerTo(gwv1beta1.TLSModeTerminate), - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "secret-one"}, - }, - }, - }}, - }, - gwv1beta1.GatewayStatus{ - Addresses: []gwv1beta1.GatewayAddress{}, - Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "gateway accepted", - }, { - Type: "Programmed", - Status: metav1.ConditionFalse, - Reason: "Pending", - Message: "gateway pods are still being scheduled", - }, - }, - Listeners: []gwv1beta1.ListenerStatus{{ - SupportedKinds: supportedKindsForProtocol[gwv1beta1.HTTPSProtocolType], - Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "listener accepted", - }, { - Type: "Programmed", - Status: metav1.ConditionTrue, - Reason: "Programmed", - Message: "listener programmed", - }, { - Type: "Conflicted", - Status: metav1.ConditionFalse, - Reason: "NoConflicts", - Message: "listener has no conflicts", - }, { - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved certificate references", - }, - }, - }}, - }), - ), - }, - expectedConsulUpdates: []api.ConfigEntry{ - certificateOne, - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "gateway", - Meta: map[string]string{ - "k8s-name": "gateway", - "k8s-namespace": "default", - }, - Listeners: []api.APIGatewayListener{{ - Protocol: "http", - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{{ - Kind: api.InlineCertificate, - Name: "secret-one", - }}, - }, - }}, - }, - }, - }, - "gateway http route no finalizer": { - config: controlledBinder(BinderConfig{ - Gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - HTTPRoutes: []gwv1beta1.HTTPRoute{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "HTTPRoute", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "route", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{{ - Name: "gateway", - }}, - }, - }, - }, - }, - }), - expectedUpdates: []client.Object{ - common.PointerTo(testHTTPRoute("route", []string{"gateway"}, nil)), - }, - expectedStatusUpdates: []client.Object{ - addClassConfig(gatewayWithFinalizerStatus(gwv1beta1.GatewaySpec{}, gwv1beta1.GatewayStatus{ - Addresses: []gwv1beta1.GatewayAddress{}, - Conditions: []metav1.Condition{{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "gateway accepted", - }, { - Type: "Programmed", - Status: metav1.ConditionFalse, - Reason: "Pending", - Message: "gateway pods are still being scheduled", - }}, - })), - }, - expectedConsulUpdates: []api.ConfigEntry{ - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "gateway", - Meta: map[string]string{ - "k8s-name": "gateway", - "k8s-namespace": "default", - }, - Listeners: []api.APIGatewayListener{}, - }, - }, - }, - "gateway http route deleting": { - config: controlledBinder(BinderConfig{ - Gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - HTTPRoutes: []gwv1beta1.HTTPRoute{{ - ObjectMeta: metav1.ObjectMeta{ - Name: "route", - DeletionTimestamp: deletionTimestamp, - Finalizers: []string{common.GatewayFinalizer}, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{{ - Name: "gateway", - }}, - }, - }, - }}, - }), - resources: resourceMapResources{ - consulHTTPRoutes: []api.HTTPRouteConfigEntry{{ - Kind: api.HTTPRoute, - Name: "route", - Parents: []api.ResourceReference{ - {Kind: api.APIGateway, Name: "gateway"}, - }, - }}, - }, - expectedUpdates: []client.Object{ - &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "route", - DeletionTimestamp: deletionTimestamp, - Finalizers: []string{}, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{{ - Name: "gateway", - }}, - }, - }, - }, - }, - expectedStatusUpdates: []client.Object{ - addClassConfig(gatewayWithFinalizerStatus(gwv1beta1.GatewaySpec{}, gwv1beta1.GatewayStatus{ - Addresses: []gwv1beta1.GatewayAddress{}, - Conditions: []metav1.Condition{{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "gateway accepted", - }, { - Type: "Programmed", - Status: metav1.ConditionFalse, - Reason: "Pending", - Message: "gateway pods are still being scheduled", - }}, - })), - }, - expectedConsulUpdates: []api.ConfigEntry{ - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "gateway", - Meta: map[string]string{ - "k8s-name": "gateway", - "k8s-namespace": "default", - }, - Listeners: []api.APIGatewayListener{}, - }, - }, - expectedConsulDeletions: []api.ResourceReference{ - {Kind: api.HTTPRoute, Name: "route"}, - }, - }, - "gateway tcp route no finalizer": { - config: controlledBinder(BinderConfig{ - Gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - TCPRoutes: []gwv1alpha2.TCPRoute{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "TCPRoute", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "route", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{{ - Name: "gateway", - }}, - }, - }, - }, - }, - }), - expectedUpdates: []client.Object{ - common.PointerTo(testTCPRoute("route", []string{"gateway"}, nil)), - }, - expectedStatusUpdates: []client.Object{ - addClassConfig(gatewayWithFinalizerStatus(gwv1beta1.GatewaySpec{}, gwv1beta1.GatewayStatus{ - Addresses: []gwv1beta1.GatewayAddress{}, - Conditions: []metav1.Condition{{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "gateway accepted", - }, { - Type: "Programmed", - Status: metav1.ConditionFalse, - Reason: "Pending", - Message: "gateway pods are still being scheduled", - }}, - })), - }, - expectedConsulUpdates: []api.ConfigEntry{ - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "gateway", - Meta: map[string]string{ - "k8s-name": "gateway", - "k8s-namespace": "default", - }, - Listeners: []api.APIGatewayListener{}, - }, - }, - }, - "gateway tcp route deleting": { - config: controlledBinder(BinderConfig{ - Gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - TCPRoutes: []gwv1alpha2.TCPRoute{{ - ObjectMeta: metav1.ObjectMeta{ - Name: "route", - DeletionTimestamp: deletionTimestamp, - Finalizers: []string{common.GatewayFinalizer}, - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{{ - Name: "gateway", - }}, - }, - }, - }}, - }), - resources: resourceMapResources{ - consulTCPRoutes: []api.TCPRouteConfigEntry{{ - Kind: api.TCPRoute, - Name: "route", - Parents: []api.ResourceReference{ - {Kind: api.APIGateway, Name: "gateway"}, - }, - }}, - }, - expectedUpdates: []client.Object{ - &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "route", - DeletionTimestamp: deletionTimestamp, - Finalizers: []string{}, - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{{ - Name: "gateway", - }}, - }, - }, - }, - }, - expectedStatusUpdates: []client.Object{ - addClassConfig(gatewayWithFinalizerStatus(gwv1beta1.GatewaySpec{}, gwv1beta1.GatewayStatus{ - Addresses: []gwv1beta1.GatewayAddress{}, - Conditions: []metav1.Condition{{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "gateway accepted", - }, { - Type: "Programmed", - Status: metav1.ConditionFalse, - Reason: "Pending", - Message: "gateway pods are still being scheduled", - }}, - })), - }, - expectedConsulUpdates: []api.ConfigEntry{ - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "gateway", - Meta: map[string]string{ - "k8s-name": "gateway", - "k8s-namespace": "default", - }, - Listeners: []api.APIGatewayListener{}, - }, - }, - expectedConsulDeletions: []api.ResourceReference{ - {Kind: api.TCPRoute, Name: "route"}, - }, - }, - "gateway deletion routes and secrets": { - config: controlledBinder(BinderConfig{ - Gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gateway-deleted", - DeletionTimestamp: deletionTimestamp, - Finalizers: []string{common.GatewayFinalizer}, - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: testGatewayClassName, - Listeners: []gwv1beta1.Listener{{ - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "secret-one"}, - {Name: "secret-two"}, - }, - }, - }}, - }, - }, - HTTPRoutes: []gwv1beta1.HTTPRoute{ - testHTTPRoute("http-route-one", []string{"gateway-deleted"}, nil), - testHTTPRouteStatus("http-route-two", nil, []gwv1alpha2.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway-deleted"}, ControllerName: testControllerName, Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - }, - }}, - {ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, ControllerName: testControllerName, Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - }, - }}, - }), - }, - TCPRoutes: []gwv1alpha2.TCPRoute{ - testTCPRoute("tcp-route-one", []string{"gateway-deleted"}, nil), - testTCPRouteStatus("tcp-route-two", nil, []gwv1alpha2.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway-deleted"}, ControllerName: testControllerName, Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - }, - }}, - {ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, ControllerName: testControllerName, Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - }, - }}, - }), - }, - }), - resources: resourceMapResources{ - consulHTTPRoutes: []api.HTTPRouteConfigEntry{ - { - Kind: api.HTTPRoute, Name: "http-route-two", Meta: map[string]string{ - "k8s-name": "http-route-two", - "k8s-namespace": "", - }, - Parents: []api.ResourceReference{ - {Kind: api.APIGateway, Name: "gateway-deleted"}, - {Kind: api.APIGateway, Name: "gateway"}, - }, - }, - { - Kind: api.HTTPRoute, Name: "http-route-one", Meta: map[string]string{ - "k8s-name": "http-route-one", - "k8s-namespace": "", - }, - Parents: []api.ResourceReference{ - {Kind: api.APIGateway, Name: "gateway-deleted"}, - }, - }, - }, - consulTCPRoutes: []api.TCPRouteConfigEntry{ - { - Kind: api.TCPRoute, Name: "tcp-route-two", - Meta: map[string]string{ - "k8s-name": "tcp-route-two", - "k8s-namespace": "", - }, - Parents: []api.ResourceReference{ - {Kind: api.APIGateway, Name: "gateway-deleted"}, - {Kind: api.APIGateway, Name: "gateway"}, - }, - }, - { - Kind: api.TCPRoute, Name: "tcp-route-one", - Meta: map[string]string{ - "k8s-name": "tcp-route-one", - "k8s-namespace": "", - }, - Parents: []api.ResourceReference{ - {Kind: api.APIGateway, Name: "gateway-deleted"}, - }, - }, - }, - consulInlineCertificates: []api.InlineCertificateConfigEntry{ - *certificateOne, - *certificateTwo, - }, - secrets: []corev1.Secret{ - secretOne, - secretTwo, - }, - gateways: []gwv1beta1.Gateway{ - gatewayWithFinalizer(gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{{ - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "secret-one"}, - {Name: "secret-three"}, - }, - }, - }}, - }), - }, - }, - expectedStatusUpdates: []client.Object{ - common.PointerTo(testHTTPRouteStatus("http-route-two", nil, []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, ControllerName: testControllerName, Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - }, - }}, - }, "gateway-deleted")), - common.PointerTo(testTCPRouteStatus("tcp-route-two", nil, []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, ControllerName: testControllerName, Conditions: []metav1.Condition{ - { - Type: "Accepted", - Status: metav1.ConditionTrue, - }, - }}, - }, "gateway-deleted")), - }, - expectedUpdates: []client.Object{ - &gwv1beta1.HTTPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "HTTPRoute", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "http-route-one", - // removing a finalizer - Finalizers: []string{}, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway-deleted"}, - }, - }, - }, - Status: gwv1beta1.HTTPRouteStatus{RouteStatus: gwv1beta1.RouteStatus{Parents: []gwv1alpha2.RouteParentStatus{}}}, - }, - &gwv1alpha2.TCPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "TCPRoute", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-route-one", - Finalizers: []string{}, - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway-deleted"}, - }, - }, - }, - Status: gwv1alpha2.TCPRouteStatus{RouteStatus: gwv1beta1.RouteStatus{Parents: []gwv1alpha2.RouteParentStatus{}}}, - }, - addClassConfig(gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gateway-deleted", - DeletionTimestamp: deletionTimestamp, - Finalizers: []string{}, - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: testGatewayClassName, - Listeners: []gwv1beta1.Listener{{ - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "secret-one"}, - {Name: "secret-two"}, - }, - }, - }}, - }, - }), - }, - expectedConsulUpdates: []api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "http-route-two", - Meta: map[string]string{ - "k8s-name": "http-route-two", - "k8s-namespace": "", - }, - // dropped ref to gateway - Parents: []api.ResourceReference{{ - Kind: api.APIGateway, - Name: "gateway", - }}, - }, - &api.TCPRouteConfigEntry{ - Kind: api.TCPRoute, - Name: "tcp-route-two", - Meta: map[string]string{ - "k8s-name": "tcp-route-two", - "k8s-namespace": "", - }, - // dropped ref to gateway - Parents: []api.ResourceReference{{ - Kind: api.APIGateway, - Name: "gateway", - }}, - }, - }, - expectedConsulDeletions: []api.ResourceReference{ - {Kind: api.HTTPRoute, Name: "http-route-one"}, - {Kind: api.TCPRoute, Name: "tcp-route-one"}, - {Kind: api.InlineCertificate, Name: "secret-two"}, - {Kind: api.APIGateway, Name: "gateway-deleted"}, - }, - }, - } { - t.Run(name, func(t *testing.T) { - tt.resources.gateways = append(tt.resources.gateways, tt.config.Gateway) - tt.resources.httpRoutes = append(tt.resources.httpRoutes, tt.config.HTTPRoutes...) - tt.resources.tcpRoutes = append(tt.resources.tcpRoutes, tt.config.TCPRoutes...) - - tt.config.Resources = newTestResourceMap(t, tt.resources) - tt.config.ControllerName = testControllerName - tt.config.Logger = logrtest.NewTestLogger(t) - tt.config.GatewayClassConfig = &v1alpha1.GatewayClassConfig{} - serializeGatewayClassConfig(&tt.config.Gateway, tt.config.GatewayClassConfig) - - binder := NewBinder(tt.config) - actual := binder.Snapshot() - - actualConsulUpdates := common.ConvertSliceFunc(actual.Consul.Updates, func(op *common.ConsulUpdateOperation) api.ConfigEntry { - return op.Entry - }) - - require.ElementsMatch(t, tt.expectedConsulUpdates, actualConsulUpdates, "consul updates differ", cmp.Diff(tt.expectedConsulUpdates, actualConsulUpdates)) - require.ElementsMatch(t, tt.expectedConsulDeletions, actual.Consul.Deletions, "consul deletions differ") - require.ElementsMatch(t, tt.expectedStatusUpdates, actual.Kubernetes.StatusUpdates.Operations(), "kubernetes statuses differ", cmp.Diff(tt.expectedStatusUpdates, actual.Kubernetes.StatusUpdates.Operations())) - require.ElementsMatch(t, tt.expectedUpdates, actual.Kubernetes.Updates.Operations(), "kubernetes updates differ", cmp.Diff(tt.expectedUpdates, actual.Kubernetes.Updates.Operations())) - }) - } -} - -func TestBinder_Registrations(t *testing.T) { - t.Parallel() - - setDeleted := func(gateway gwv1beta1.Gateway) gwv1beta1.Gateway { - gateway.DeletionTimestamp = deletionTimestamp - return gateway - } - - for name, tt := range map[string]struct { - config BinderConfig - resources resourceMapResources - expectedRegistrations []string - expectedDeregistrations []api.CatalogDeregistration - }{ - "deleting gateway with consul services": { - config: controlledBinder(BinderConfig{ - Gateway: setDeleted(gatewayWithFinalizer(gwv1beta1.GatewaySpec{})), - ConsulGatewayServices: []api.CatalogService{ - {Node: "test", ServiceID: "pod1", Namespace: "namespace1"}, - {Node: "test", ServiceID: "pod2", Namespace: "namespace1"}, - {Node: "test", ServiceID: "pod3", Namespace: "namespace1"}, - }, - Pods: []corev1.Pod{ - { - ObjectMeta: metav1.ObjectMeta{Name: "pod1"}, - Status: corev1.PodStatus{ - Phase: corev1.PodRunning, - Conditions: []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionTrue}}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{Name: "pod2"}, - Status: corev1.PodStatus{ - Phase: corev1.PodRunning, - Conditions: []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionTrue}}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{Name: "pod3"}, - Status: corev1.PodStatus{ - Phase: corev1.PodRunning, - Conditions: []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionTrue}}, - }, - }, - }, - }), - expectedDeregistrations: []api.CatalogDeregistration{ - {Node: "test", ServiceID: "pod1", Namespace: "namespace1"}, - {Node: "test", ServiceID: "pod2", Namespace: "namespace1"}, - {Node: "test", ServiceID: "pod3", Namespace: "namespace1"}, - }, - }, - "gateway with consul services and mixed pods": { - config: controlledBinder(BinderConfig{ - Gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - Pods: []corev1.Pod{ - { - ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "namespace1"}, - Status: corev1.PodStatus{ - Phase: corev1.PodRunning, - Conditions: []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionTrue}}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{Name: "pod3", Namespace: "namespace1"}, - Status: corev1.PodStatus{ - Phase: corev1.PodFailed, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{Name: "pod4", Namespace: "namespace1"}, - Status: corev1.PodStatus{ - Phase: corev1.PodRunning, - Conditions: []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionTrue}}, - }, - }, - }, - ConsulGatewayServices: []api.CatalogService{ - {Node: "test", ServiceID: "pod1", Namespace: "namespace1"}, - {Node: "test", ServiceID: "pod2", Namespace: "namespace1"}, - {Node: "test", ServiceID: "pod3", Namespace: "namespace1"}, - }, - }), - expectedRegistrations: []string{"pod1", "pod3", "pod4"}, - expectedDeregistrations: []api.CatalogDeregistration{ - {Node: "test", ServiceID: "pod2", Namespace: "namespace1"}, - }, - }, - } { - t.Run(name, func(t *testing.T) { - tt.resources.gateways = append(tt.resources.gateways, tt.config.Gateway) - tt.resources.httpRoutes = append(tt.resources.httpRoutes, tt.config.HTTPRoutes...) - tt.resources.tcpRoutes = append(tt.resources.tcpRoutes, tt.config.TCPRoutes...) - - tt.config.Resources = newTestResourceMap(t, tt.resources) - tt.config.ControllerName = testControllerName - tt.config.Logger = logrtest.NewTestLogger(t) - tt.config.GatewayClassConfig = &v1alpha1.GatewayClassConfig{} - serializeGatewayClassConfig(&tt.config.Gateway, tt.config.GatewayClassConfig) - - binder := NewBinder(tt.config) - actual := binder.Snapshot() - - require.Len(t, actual.Consul.Registrations, len(tt.expectedRegistrations)) - for i := range actual.Consul.Registrations { - registration := actual.Consul.Registrations[i] - expected := tt.expectedRegistrations[i] - - require.EqualValues(t, expected, registration.Service.ID) - require.EqualValues(t, "gateway", registration.Service.Service) - } - - require.EqualValues(t, tt.expectedDeregistrations, actual.Consul.Deregistrations) - }) - } -} - -func TestBinder_BindingRulesKitchenSink(t *testing.T) { - t.Parallel() - - gateway := gatewayWithFinalizer(gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{{ - Name: "http-listener-default-same", - Protocol: gwv1beta1.HTTPProtocolType, - }, { - Name: "http-listener-hostname", - Protocol: gwv1beta1.HTTPProtocolType, - Hostname: common.PointerTo[gwv1beta1.Hostname]("host.name"), - }, { - Name: "http-listener-mismatched-kind-allowed", - Protocol: gwv1beta1.HTTPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Kinds: []gwv1beta1.RouteGroupKind{{ - Kind: "Foo", - }}, - }, - }, { - Name: "http-listener-explicit-all-allowed", - Protocol: gwv1beta1.HTTPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromAll), - }, - }, - }, { - Name: "http-listener-explicit-allowed-same", - Protocol: gwv1beta1.HTTPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromSame), - }, - }, - }, { - Name: "http-listener-allowed-selector", - Protocol: gwv1beta1.HTTPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromSelector), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "test": "foo", - }, - }, - }, - }, - }, { - Name: "http-listener-tls", - Protocol: gwv1beta1.HTTPSProtocolType, - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{{ - Name: "secret-one", - }}, - }, - }, { - Name: "tcp-listener-default-same", - Protocol: gwv1beta1.TCPProtocolType, - }, { - Name: "tcp-listener-mismatched-kind-allowed", - Protocol: gwv1beta1.TCPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Kinds: []gwv1beta1.RouteGroupKind{{ - Kind: "Foo", - }}, - }, - }, { - Name: "tcp-listener-explicit-all-allowed", - Protocol: gwv1beta1.TCPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromAll), - }, - }, - }, { - Name: "tcp-listener-explicit-allowed-same", - Protocol: gwv1beta1.TCPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromSame), - }, - }, - }, { - Name: "tcp-listener-allowed-selector", - Protocol: gwv1beta1.TCPProtocolType, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromSelector), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "test": "foo", - }, - }, - }, - }, - }, { - Name: "tcp-listener-tls", - Protocol: gwv1beta1.TCPProtocolType, - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{{ - Name: "secret-one", - }}, - }, - }}, - }) - - namespaces := map[string]corev1.Namespace{ - "default": { - ObjectMeta: metav1.ObjectMeta{ - Name: "default", - }, - }, - "test": { - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Labels: map[string]string{ - "test": "foo", - }, - }, - }, - } - - _, secretOne := generateTestCertificate(t, "", "secret-one") - - gateway.Namespace = "default" - defaultNamespacePointer := common.PointerTo[gwv1beta1.Namespace]("default") - - for name, tt := range map[string]struct { - httpRoute *gwv1beta1.HTTPRoute - tcpRoute *gwv1alpha2.TCPRoute - referenceGrants []gwv1beta1.ReferenceGrant - expectedStatusUpdates []client.Object - }{ - "untargeted http route same namespace": { - httpRoute: testHTTPRouteBackends("route", "default", nil, []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }), - expectedStatusUpdates: []client.Object{ - testHTTPRouteStatusBackends("route", "default", nil, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted http route same namespace missing backend": { - httpRoute: testHTTPRouteBackends("route", "default", []gwv1beta1.BackendObjectReference{ - {Name: gwv1beta1.ObjectName("backend")}, - }, []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }), - expectedStatusUpdates: []client.Object{ - testHTTPRouteStatusBackends("route", "default", []gwv1beta1.BackendObjectReference{ - {Name: gwv1beta1.ObjectName("backend")}, - }, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "BackendNotFound", - Message: "default/backend: backend not found", - }, - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted http route same namespace invalid backend type": { - httpRoute: testHTTPRouteBackends("route", "default", []gwv1beta1.BackendObjectReference{ - { - Name: gwv1beta1.ObjectName("backend"), - Group: common.PointerTo[gwv1beta1.Group]("invalid.foo.com"), - }, - }, []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }), - expectedStatusUpdates: []client.Object{ - testHTTPRouteStatusBackends("route", "default", []gwv1beta1.BackendObjectReference{ - { - Name: gwv1beta1.ObjectName("backend"), - Group: common.PointerTo[gwv1beta1.Group]("invalid.foo.com"), - }, - }, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "InvalidKind", - Message: "default/backend [Service.invalid.foo.com]: invalid backend kind", - }, - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted http route different namespace": { - httpRoute: testHTTPRouteBackends("route", "other", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - Namespace: defaultNamespacePointer, - }, - }), - expectedStatusUpdates: []client.Object{ - testHTTPRouteStatusBackends("route", "other", nil, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - }, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted http route different namespace and reference grants": { - httpRoute: testHTTPRouteBackends("route", "other", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - Namespace: defaultNamespacePointer, - }, - }), - referenceGrants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "HTTPRoute", Namespace: gwv1beta1.Namespace("other")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Group: gwv1beta1.GroupName, Kind: "Gateway"}, - }, - }}, - }, - expectedStatusUpdates: []client.Object{ - testHTTPRouteStatusBackends("route", "other", nil, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - }, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "targeted http route same namespace": { - httpRoute: testHTTPRouteBackends("route", "default", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - }), - expectedStatusUpdates: []client.Object{ - testHTTPRouteStatusBackends("route", "default", nil, []gwv1beta1.RouteParentStatus{ - { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-mismatched-kind-allowed: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-allowed-selector: listener does not allow binding routes from the given namespace", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "tcp-listener-explicit-all-allowed: listener does not support route protocol", - }}, - }, - }), - }, - }, - "targeted http route different namespace": { - referenceGrants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "HTTPRoute", Namespace: gwv1beta1.Namespace("test")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Group: gwv1beta1.GroupName, Kind: "Gateway"}, - }, - }}, - }, - httpRoute: testHTTPRouteBackends("route", "test", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - }), - expectedStatusUpdates: []client.Object{ - testHTTPRouteStatusBackends("route", "test", nil, []gwv1beta1.RouteParentStatus{ - { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-default-same: listener does not allow binding routes from the given namespace", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-hostname: listener does not allow binding routes from the given namespace", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-mismatched-kind-allowed: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-explicit-allowed-same: listener does not allow binding routes from the given namespace", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-tls: listener does not allow binding routes from the given namespace", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "tcp-listener-explicit-all-allowed: listener does not support route protocol", - }}, - }, - }), - }, - }, - "untargeted tcp route same namespace": { - tcpRoute: testTCPRouteBackends("route", "default", nil, []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }), - expectedStatusUpdates: []client.Object{ - testTCPRouteStatusBackends("route", "default", nil, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted tcp route same namespace missing backend": { - tcpRoute: testTCPRouteBackends("route", "default", []gwv1beta1.BackendObjectReference{ - {Name: gwv1beta1.ObjectName("backend")}, - }, []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }), - expectedStatusUpdates: []client.Object{ - testTCPRouteStatusBackends("route", "default", []gwv1beta1.BackendObjectReference{ - {Name: gwv1beta1.ObjectName("backend")}, - }, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "BackendNotFound", - Message: "default/backend: backend not found", - }, - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted tcp route same namespace invalid backend type": { - tcpRoute: testTCPRouteBackends("route", "default", []gwv1beta1.BackendObjectReference{ - { - Name: gwv1beta1.ObjectName("backend"), - Group: common.PointerTo[gwv1beta1.Group]("invalid.foo.com"), - }, - }, []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }), - expectedStatusUpdates: []client.Object{ - testTCPRouteStatusBackends("route", "default", []gwv1beta1.BackendObjectReference{ - { - Name: gwv1beta1.ObjectName("backend"), - Group: common.PointerTo[gwv1beta1.Group]("invalid.foo.com"), - }, - }, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{Name: "gateway"}, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "InvalidKind", - Message: "default/backend [Service.invalid.foo.com]: invalid backend kind", - }, - { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted tcp route different namespace": { - tcpRoute: testTCPRouteBackends("route", "other", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - Namespace: defaultNamespacePointer, - }, - }), - expectedStatusUpdates: []client.Object{ - testTCPRouteStatusBackends("route", "other", nil, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - }, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "untargeted tcp route different namespace and reference grants": { - tcpRoute: testTCPRouteBackends("route", "other", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - Namespace: defaultNamespacePointer, - }, - }), - referenceGrants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "TCPRoute", Namespace: gwv1beta1.Namespace("other")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Group: gwv1beta1.GroupName, Kind: "Gateway"}, - }, - }}, - }, - expectedStatusUpdates: []client.Object{ - testTCPRouteStatusBackends("route", "other", nil, []gwv1beta1.RouteParentStatus{ - {ControllerName: testControllerName, ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - }, Conditions: []metav1.Condition{ - { - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }, - }}, - }), - }, - }, - "targeted tcp route same namespace": { - tcpRoute: testTCPRouteBackends("route", "default", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, { - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - }), - expectedStatusUpdates: []client.Object{ - testTCPRouteStatusBackends("route", "default", nil, []gwv1beta1.RouteParentStatus{ - { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-default-same: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-hostname: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-mismatched-kind-allowed: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-explicit-all-allowed: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-explicit-allowed-same: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-allowed-selector: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-tls: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, - }), - }, - }, - "targeted tcp route different namespace": { - referenceGrants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "TCPRoute", Namespace: gwv1beta1.Namespace("test")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Group: gwv1beta1.GroupName, Kind: "Gateway"}, - }, - }}, - }, - tcpRoute: testTCPRouteBackends("route", "test", nil, []gwv1beta1.ParentReference{ - { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, { - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - }), - expectedStatusUpdates: []client.Object{ - testTCPRouteStatusBackends("route", "test", nil, []gwv1beta1.RouteParentStatus{ - { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-default-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-default-same: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-hostname"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-hostname: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-mismatched-kind-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-mismatched-kind-allowed: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-explicit-all-allowed: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-explicit-allowed-same"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-explicit-allowed-same: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-allowed-selector"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-allowed-selector: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("http-listener-tls"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "NotAllowedByListeners", - Message: "http-listener-tls: listener does not support route protocol", - }}, - }, { - ControllerName: testControllerName, - ParentRef: gwv1beta1.ParentReference{ - Name: "gateway", - Namespace: defaultNamespacePointer, - SectionName: common.PointerTo[gwv1beta1.SectionName]("tcp-listener-explicit-all-allowed"), - }, - Conditions: []metav1.Condition{{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - }, { - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - }}, - }, - }), - }, - }, - } { - t.Run(name, func(t *testing.T) { - g := *addClassConfig(gateway) - - resources := resourceMapResources{ - gateways: []gwv1beta1.Gateway{g}, - secrets: []corev1.Secret{ - secretOne, - }, - grants: tt.referenceGrants, - } - - if tt.httpRoute != nil { - resources.httpRoutes = append(resources.httpRoutes, *tt.httpRoute) - } - if tt.tcpRoute != nil { - resources.tcpRoutes = append(resources.tcpRoutes, *tt.tcpRoute) - } - - config := controlledBinder(BinderConfig{ - Gateway: g, - GatewayClassConfig: &v1alpha1.GatewayClassConfig{}, - Namespaces: namespaces, - Resources: newTestResourceMap(t, resources), - HTTPRoutes: resources.httpRoutes, - TCPRoutes: resources.tcpRoutes, - }) - - binder := NewBinder(config) - actual := binder.Snapshot() - - compareUpdates(t, tt.expectedStatusUpdates, actual.Kubernetes.StatusUpdates.Operations()) - }) - } -} - -func compareUpdates(t *testing.T, expected []client.Object, actual []client.Object) { - t.Helper() - - filtered := common.Filter(actual, func(o client.Object) bool { - if _, ok := o.(*gwv1beta1.HTTPRoute); ok { - return false - } - if _, ok := o.(*gwv1alpha2.TCPRoute); ok { - return false - } - return true - }) - - require.ElementsMatch(t, expected, filtered, "statuses don't match", cmp.Diff(expected, filtered)) -} - -func addClassConfig(g gwv1beta1.Gateway) *gwv1beta1.Gateway { - serializeGatewayClassConfig(&g, &v1alpha1.GatewayClassConfig{}) - return &g -} - -func gatewayWithFinalizer(spec gwv1beta1.GatewaySpec) gwv1beta1.Gateway { - spec.GatewayClassName = testGatewayClassObjectName - - typeMeta := metav1.TypeMeta{} - typeMeta.SetGroupVersionKind(gwv1beta1.SchemeGroupVersion.WithKind("Gateway")) - - return gwv1beta1.Gateway{ - TypeMeta: typeMeta, - ObjectMeta: metav1.ObjectMeta{ - Name: "gateway", - Namespace: "default", - Finalizers: []string{common.GatewayFinalizer}, - }, - Spec: spec, - } -} - -func gatewayWithFinalizerStatus(spec gwv1beta1.GatewaySpec, status gwv1beta1.GatewayStatus) gwv1beta1.Gateway { - g := gatewayWithFinalizer(spec) - g.Status = status - return g -} - -func testHTTPRoute(name string, parents []string, services []string) gwv1beta1.HTTPRoute { - var parentRefs []gwv1beta1.ParentReference - var rules []gwv1beta1.HTTPRouteRule - - for _, parent := range parents { - parentRefs = append(parentRefs, gwv1beta1.ParentReference{Name: gwv1beta1.ObjectName(parent)}) - } - - for _, service := range services { - rules = append(rules, gwv1beta1.HTTPRouteRule{ - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: gwv1beta1.ObjectName(service), - }, - }, - }, - }, - }) - } - - httpTypeMeta := metav1.TypeMeta{} - httpTypeMeta.SetGroupVersionKind(gwv1beta1.SchemeGroupVersion.WithKind("HTTPRoute")) - - return gwv1beta1.HTTPRoute{ - TypeMeta: httpTypeMeta, - ObjectMeta: metav1.ObjectMeta{Name: name, Finalizers: []string{common.GatewayFinalizer}}, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: parentRefs, - }, - Rules: rules, - }, - } -} - -func testHTTPRouteBackends(name, namespace string, services []gwv1beta1.BackendObjectReference, parents []gwv1beta1.ParentReference) *gwv1beta1.HTTPRoute { - var rules []gwv1beta1.HTTPRouteRule - for _, service := range services { - rules = append(rules, gwv1beta1.HTTPRouteRule{ - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: service, - }, - }, - }, - }) - } - - httpTypeMeta := metav1.TypeMeta{} - httpTypeMeta.SetGroupVersionKind(gwv1beta1.SchemeGroupVersion.WithKind("HTTPRoute")) - - return &gwv1beta1.HTTPRoute{ - TypeMeta: httpTypeMeta, - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, Finalizers: []string{common.GatewayFinalizer}}, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: parents, - }, - Rules: rules, - }, - } -} - -func testHTTPRouteStatusBackends(name, namespace string, services []gwv1beta1.BackendObjectReference, parentStatuses []gwv1beta1.RouteParentStatus) *gwv1beta1.HTTPRoute { - var parentRefs []gwv1beta1.ParentReference - - for _, parent := range parentStatuses { - parentRefs = append(parentRefs, parent.ParentRef) - } - - route := testHTTPRouteBackends(name, namespace, services, parentRefs) - route.Status.RouteStatus.Parents = parentStatuses - return route -} - -func testHTTPRouteStatus(name string, services []string, parentStatuses []gwv1beta1.RouteParentStatus, extraParents ...string) gwv1beta1.HTTPRoute { - parentRefs := extraParents - - for _, parent := range parentStatuses { - parentRefs = append(parentRefs, string(parent.ParentRef.Name)) - } - - route := testHTTPRoute(name, parentRefs, services) - route.Status.RouteStatus.Parents = parentStatuses - - return route -} - -func testTCPRoute(name string, parents []string, services []string) gwv1alpha2.TCPRoute { - var parentRefs []gwv1beta1.ParentReference - var rules []gwv1alpha2.TCPRouteRule - - for _, parent := range parents { - parentRefs = append(parentRefs, gwv1beta1.ParentReference{Name: gwv1beta1.ObjectName(parent)}) - } - - for _, service := range services { - rules = append(rules, gwv1alpha2.TCPRouteRule{ - BackendRefs: []gwv1beta1.BackendRef{ - { - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: gwv1beta1.ObjectName(service), - }, - }, - }, - }) - } - - tcpTypeMeta := metav1.TypeMeta{} - tcpTypeMeta.SetGroupVersionKind(gwv1beta1.SchemeGroupVersion.WithKind("TCPRoute")) - - return gwv1alpha2.TCPRoute{ - TypeMeta: tcpTypeMeta, - ObjectMeta: metav1.ObjectMeta{Name: name, Finalizers: []string{common.GatewayFinalizer}}, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: parentRefs, - }, - Rules: rules, - }, - } -} - -func testTCPRouteBackends(name, namespace string, services []gwv1beta1.BackendObjectReference, parents []gwv1beta1.ParentReference) *gwv1alpha2.TCPRoute { - var rules []gwv1alpha2.TCPRouteRule - for _, service := range services { - rules = append(rules, gwv1alpha2.TCPRouteRule{ - BackendRefs: []gwv1beta1.BackendRef{ - {BackendObjectReference: service}, - }, - }) - } - - tcpTypeMeta := metav1.TypeMeta{} - tcpTypeMeta.SetGroupVersionKind(gwv1beta1.SchemeGroupVersion.WithKind("TCPRoute")) - - return &gwv1alpha2.TCPRoute{ - TypeMeta: tcpTypeMeta, - ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, Finalizers: []string{common.GatewayFinalizer}}, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: parents, - }, - Rules: rules, - }, - } -} - -func testTCPRouteStatusBackends(name, namespace string, services []gwv1beta1.BackendObjectReference, parentStatuses []gwv1beta1.RouteParentStatus) *gwv1alpha2.TCPRoute { - var parentRefs []gwv1beta1.ParentReference - - for _, parent := range parentStatuses { - parentRefs = append(parentRefs, parent.ParentRef) - } - - route := testTCPRouteBackends(name, namespace, services, parentRefs) - route.Status.RouteStatus.Parents = parentStatuses - return route -} - -func testTCPRouteStatus(name string, services []string, parentStatuses []gwv1beta1.RouteParentStatus, extraParents ...string) gwv1alpha2.TCPRoute { - parentRefs := extraParents - - for _, parent := range parentStatuses { - parentRefs = append(parentRefs, string(parent.ParentRef.Name)) - } - - route := testTCPRoute(name, parentRefs, services) - route.Status.RouteStatus.Parents = parentStatuses - - return route -} - -func controlledBinder(config BinderConfig) BinderConfig { - config.ControllerName = testControllerName - config.GatewayClass = testGatewayClass - return config -} - -func generateTestCertificate(t *testing.T, namespace, name string) (*api.InlineCertificateConfigEntry, corev1.Secret) { - privateKey, err := rsa.GenerateKey(rand.Reader, common.MinKeyLength) - require.NoError(t, err) - - usage := x509.KeyUsageCertSign - expiration := time.Now().AddDate(10, 0, 0) - - cert := &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: "consul.test", - }, - IsCA: true, - 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 - caPrivateKey := 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), - }) - - secret := corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - }, - Data: map[string][]byte{ - corev1.TLSCertKey: certBytes, - corev1.TLSPrivateKeyKey: privateKeyBytes, - }, - } - - certificate, err := (common.ResourceTranslator{}).ToInlineCertificate(secret) - require.NoError(t, err) - - return certificate, secret -} diff --git a/control-plane/api-gateway/binding/reference_grant.go b/control-plane/api-gateway/binding/reference_grant.go deleted file mode 100644 index c2cc421a30..0000000000 --- a/control-plane/api-gateway/binding/reference_grant.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" -) - -type referenceValidator struct { - grants map[string]map[types.NamespacedName]gwv1beta1.ReferenceGrant -} - -func NewReferenceValidator(grants []gwv1beta1.ReferenceGrant) common.ReferenceValidator { - byNamespace := make(map[string]map[types.NamespacedName]gwv1beta1.ReferenceGrant) - for _, grant := range grants { - grantsForNamespace, ok := byNamespace[grant.Namespace] - if !ok { - grantsForNamespace = make(map[types.NamespacedName]gwv1beta1.ReferenceGrant) - } - grantsForNamespace[client.ObjectKeyFromObject(&grant)] = grant - byNamespace[grant.Namespace] = grantsForNamespace - } - return &referenceValidator{ - grants: byNamespace, - } -} - -func (rv *referenceValidator) GatewayCanReferenceSecret(gateway gwv1beta1.Gateway, secretRef gwv1beta1.SecretObjectReference) bool { - fromNS := gateway.GetNamespace() - fromGK := metav1.GroupKind{ - Group: gateway.GroupVersionKind().Group, - Kind: gateway.GroupVersionKind().Kind, - } - - // Kind should default to Secret if not set - // https://github.com/kubernetes-sigs/gateway-api/blob/v0.6.2/apis/v1beta1/object_reference_types.go#LL59C21-L59C21 - toNS, toGK := createValuesFromRef(secretRef.Namespace, secretRef.Group, secretRef.Kind, "", common.KindSecret) - - return rv.referenceAllowed(fromGK, fromNS, toGK, toNS, string(secretRef.Name)) -} - -func (rv *referenceValidator) HTTPRouteCanReferenceBackend(httproute gwv1beta1.HTTPRoute, backendRef gwv1beta1.BackendRef) bool { - fromNS := httproute.GetNamespace() - fromGK := metav1.GroupKind{ - Group: httproute.GroupVersionKind().Group, - Kind: httproute.GroupVersionKind().Kind, - } - - // Kind should default to Service if not set - // https://github.com/kubernetes-sigs/gateway-api/blob/v0.6.2/apis/v1beta1/object_reference_types.go#L106 - toNS, toGK := createValuesFromRef(backendRef.Namespace, backendRef.Group, backendRef.Kind, "", common.KindService) - - return rv.referenceAllowed(fromGK, fromNS, toGK, toNS, string(backendRef.Name)) -} - -func (rv *referenceValidator) TCPRouteCanReferenceBackend(tcpRoute gwv1alpha2.TCPRoute, backendRef gwv1beta1.BackendRef) bool { - fromNS := tcpRoute.GetNamespace() - fromGK := metav1.GroupKind{ - Group: tcpRoute.GroupVersionKind().Group, - Kind: tcpRoute.GroupVersionKind().Kind, - } - - // Kind should default to Service if not set - // https://github.com/kubernetes-sigs/gateway-api/blob/v0.6.2/apis/v1beta1/object_reference_types.go#L106 - toNS, toGK := createValuesFromRef(backendRef.Namespace, backendRef.Group, backendRef.Kind, common.BetaGroup, common.KindService) - - return rv.referenceAllowed(fromGK, fromNS, toGK, toNS, string(backendRef.Name)) -} - -func createValuesFromRef(ns *gwv1beta1.Namespace, group *gwv1beta1.Group, kind *gwv1beta1.Kind, defaultGroup, defaultKind string) (string, metav1.GroupKind) { - toNS := "" - if ns != nil { - toNS = string(*ns) - } - - gk := metav1.GroupKind{ - Kind: defaultKind, - Group: defaultGroup, - } - if group != nil { - gk.Group = string(*group) - } - if kind != nil { - gk.Kind = string(*kind) - } - - return toNS, gk -} - -// referenceAllowed checks to see if a reference between resources is allowed. -// In particular, references from one namespace to a resource in a different namespace -// require an applicable ReferenceGrant be found in the namespace containing the resource -// being referred to. -// -// For example, a Gateway in namespace "foo" may only reference a Secret in namespace "bar" -// if a ReferenceGrant in namespace "bar" allows references from namespace "foo". -func (rv *referenceValidator) referenceAllowed(fromGK metav1.GroupKind, fromNamespace string, toGK metav1.GroupKind, toNamespace, toName string) bool { - // Reference does not cross namespaces - if toNamespace == "" || toNamespace == fromNamespace { - return true - } - - // Fetch all ReferenceGrants in the referenced namespace - grants, ok := rv.grants[toNamespace] - if !ok { - return false - } - - for _, grant := range grants { - // Check for a From that applies - fromMatch := false - for _, from := range grant.Spec.From { - if fromGK.Group == string(from.Group) && fromGK.Kind == string(from.Kind) && fromNamespace == string(from.Namespace) { - fromMatch = true - break - } - } - - if !fromMatch { - continue - } - - // Check for a To that applies - for _, to := range grant.Spec.To { - if toGK.Group == string(to.Group) && toGK.Kind == string(to.Kind) { - if to.Name == nil || *to.Name == "" { - // No name specified is treated as a wildcard within the namespace - return true - } - - if gwv1beta1.ObjectName(toName) == *to.Name { - // The ReferenceGrant specifically targets this object - return true - } - } - } - } - - // No ReferenceGrant was found which allows this cross-namespace reference - return false -} diff --git a/control-plane/api-gateway/binding/reference_grant_test.go b/control-plane/api-gateway/binding/reference_grant_test.go deleted file mode 100644 index 12f01478fc..0000000000 --- a/control-plane/api-gateway/binding/reference_grant_test.go +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "context" - "testing" - - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - ToNamespace = "toNamespace" - FromNamespace = "fromNamespace" - InvalidNamespace = "invalidNamespace" - Group = "gateway.networking.k8s.io" - V1Beta1 = "/v1beta1" - V1Alpha2 = "/v1alpha2" - HTTPRouteKind = "HTTPRoute" - TCPRouteKind = "TCPRoute" - GatewayKind = "Gateway" - BackendRefKind = "Service" - SecretKind = "Secret" -) - -func TestGatewayCanReferenceSecret(t *testing.T) { - t.Parallel() - - objName := gwv1beta1.ObjectName("mysecret") - - basicValidReferenceGrant := gwv1beta1.ReferenceGrant{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: ToNamespace, - }, - Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - { - Group: Group, - Kind: GatewayKind, - Namespace: FromNamespace, - }, - }, - To: []gwv1beta1.ReferenceGrantTo{ - { - Group: Group, - Kind: SecretKind, - Name: &objName, - }, - }, - }, - } - - secretRefGroup := gwv1beta1.Group(Group) - secretRefKind := gwv1beta1.Kind(SecretKind) - secretRefNamespace := gwv1beta1.Namespace(ToNamespace) - - cases := map[string]struct { - canReference bool - err error - ctx context.Context - gateway gwv1beta1.Gateway - secret gwv1beta1.SecretObjectReference - k8sReferenceGrants []gwv1beta1.ReferenceGrant - }{ - "gateway allowed to secret": { - canReference: true, - err: nil, - ctx: context.TODO(), - gateway: gwv1beta1.Gateway{ - TypeMeta: metav1.TypeMeta{ - Kind: GatewayKind, - APIVersion: Group + V1Beta1, - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: FromNamespace, - }, - Spec: gwv1beta1.GatewaySpec{}, - Status: gwv1beta1.GatewayStatus{}, - }, - secret: gwv1beta1.SecretObjectReference{ - Group: &secretRefGroup, - Kind: &secretRefKind, - Namespace: &secretRefNamespace, - Name: objName, - }, - k8sReferenceGrants: []gwv1beta1.ReferenceGrant{ - basicValidReferenceGrant, - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - rv := NewReferenceValidator(tc.k8sReferenceGrants) - canReference := rv.GatewayCanReferenceSecret(tc.gateway, tc.secret) - - require.Equal(t, tc.canReference, canReference) - }) - } -} - -func TestHTTPRouteCanReferenceBackend(t *testing.T) { - t.Parallel() - - objName := gwv1beta1.ObjectName("myBackendRef") - - basicValidReferenceGrant := gwv1beta1.ReferenceGrant{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: ToNamespace, - }, - Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - { - Group: Group, - Kind: HTTPRouteKind, - Namespace: FromNamespace, - }, - }, - To: []gwv1beta1.ReferenceGrantTo{ - { - Group: Group, - Kind: BackendRefKind, - Name: &objName, - }, - }, - }, - } - - backendRefGroup := gwv1beta1.Group(Group) - backendRefKind := gwv1beta1.Kind(BackendRefKind) - backendRefNamespace := gwv1beta1.Namespace(ToNamespace) - - cases := map[string]struct { - canReference bool - err error - ctx context.Context - httpRoute gwv1beta1.HTTPRoute - backendRef gwv1beta1.BackendRef - k8sReferenceGrants []gwv1beta1.ReferenceGrant - }{ - "httproute allowed to gateway": { - canReference: true, - err: nil, - ctx: context.TODO(), - httpRoute: gwv1beta1.HTTPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: HTTPRouteKind, - APIVersion: Group + V1Beta1, - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: FromNamespace, - }, - Spec: gwv1beta1.HTTPRouteSpec{}, - Status: gwv1beta1.HTTPRouteStatus{}, - }, - backendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Group: &backendRefGroup, - Kind: &backendRefKind, - Name: objName, - Namespace: &backendRefNamespace, - Port: nil, - }, - Weight: nil, - }, - k8sReferenceGrants: []gwv1beta1.ReferenceGrant{ - basicValidReferenceGrant, - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - rv := NewReferenceValidator(tc.k8sReferenceGrants) - canReference := rv.HTTPRouteCanReferenceBackend(tc.httpRoute, tc.backendRef) - - require.Equal(t, tc.canReference, canReference) - }) - } -} - -func TestTCPRouteCanReferenceBackend(t *testing.T) { - t.Parallel() - - objName := gwv1beta1.ObjectName("myBackendRef") - - basicValidReferenceGrant := gwv1beta1.ReferenceGrant{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: ToNamespace, - }, - Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - { - Group: Group, - Kind: TCPRouteKind, - Namespace: FromNamespace, - }, - }, - To: []gwv1beta1.ReferenceGrantTo{ - { - Group: Group, - Kind: BackendRefKind, - Name: &objName, - }, - }, - }, - } - - backendRefGroup := gwv1beta1.Group(Group) - backendRefKind := gwv1beta1.Kind(BackendRefKind) - backendRefNamespace := gwv1beta1.Namespace(ToNamespace) - - cases := map[string]struct { - canReference bool - err error - ctx context.Context - tcpRoute gwv1alpha2.TCPRoute - backendRef gwv1beta1.BackendRef - k8sReferenceGrants []gwv1beta1.ReferenceGrant - }{ - "tcpRoute allowed to gateway": { - canReference: true, - err: nil, - ctx: context.TODO(), - tcpRoute: gwv1alpha2.TCPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: TCPRouteKind, - APIVersion: Group + V1Alpha2, - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: FromNamespace, - }, - Spec: gwv1alpha2.TCPRouteSpec{}, - Status: gwv1alpha2.TCPRouteStatus{}, - }, - backendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Group: &backendRefGroup, - Kind: &backendRefKind, - Name: objName, - Namespace: &backendRefNamespace, - Port: nil, - }, - Weight: nil, - }, - k8sReferenceGrants: []gwv1beta1.ReferenceGrant{ - basicValidReferenceGrant, - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - rv := NewReferenceValidator(tc.k8sReferenceGrants) - canReference := rv.TCPRouteCanReferenceBackend(tc.tcpRoute, tc.backendRef) - - require.Equal(t, tc.canReference, canReference) - }) - } -} - -func TestReferenceAllowed(t *testing.T) { - t.Parallel() - - objName := gwv1beta1.ObjectName("myObject") - - basicValidReferenceGrant := gwv1beta1.ReferenceGrant{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: ToNamespace, - }, - Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - { - Group: Group, - Kind: HTTPRouteKind, - Namespace: FromNamespace, - }, - }, - To: []gwv1beta1.ReferenceGrantTo{ - { - Group: Group, - Kind: GatewayKind, - Name: &objName, - }, - }, - }, - } - - cases := map[string]struct { - refAllowed bool - err error - ctx context.Context - fromGK metav1.GroupKind - fromNamespace string - toGK metav1.GroupKind - toNamespace string - toName string - k8sReferenceGrants []gwv1beta1.ReferenceGrant - }{ - "same namespace": { - refAllowed: true, - err: nil, - ctx: context.TODO(), - fromGK: metav1.GroupKind{ - Group: Group, - Kind: HTTPRouteKind, - }, - fromNamespace: FromNamespace, - toGK: metav1.GroupKind{ - Group: Group, - Kind: GatewayKind, - }, - toNamespace: FromNamespace, - toName: string(objName), - k8sReferenceGrants: []gwv1beta1.ReferenceGrant{ - { - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: FromNamespace, - }, - Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - { - Group: Group, - Kind: HTTPRouteKind, - Namespace: FromNamespace, - }, - }, - To: []gwv1beta1.ReferenceGrantTo{ - { - Group: Group, - Kind: GatewayKind, - Name: &objName, - }, - }, - }, - }, - }, - }, - "reference allowed": { - refAllowed: true, - err: nil, - ctx: context.TODO(), - fromGK: metav1.GroupKind{ - Group: Group, - Kind: HTTPRouteKind, - }, - fromNamespace: FromNamespace, - toGK: metav1.GroupKind{ - Group: Group, - Kind: GatewayKind, - }, - toNamespace: ToNamespace, - toName: string(objName), - k8sReferenceGrants: []gwv1beta1.ReferenceGrant{ - basicValidReferenceGrant, - }, - }, - "reference not allowed": { - refAllowed: false, - err: nil, - ctx: context.TODO(), - fromGK: metav1.GroupKind{ - Group: Group, - Kind: HTTPRouteKind, - }, - fromNamespace: InvalidNamespace, - toGK: metav1.GroupKind{ - Group: Group, - Kind: GatewayKind, - }, - toNamespace: ToNamespace, - toName: string(objName), - k8sReferenceGrants: []gwv1beta1.ReferenceGrant{ - basicValidReferenceGrant, - }, - }, - "no reference grant defined in namespace": { - refAllowed: false, - err: nil, - ctx: context.TODO(), - fromGK: metav1.GroupKind{ - Group: Group, - Kind: HTTPRouteKind, - }, - fromNamespace: FromNamespace, - toGK: metav1.GroupKind{ - Group: Group, - Kind: GatewayKind, - }, - toNamespace: ToNamespace, - toName: string(objName), - k8sReferenceGrants: nil, - }, - "reference allowed to all objects in namespace": { - refAllowed: true, - err: nil, - ctx: context.TODO(), - fromGK: metav1.GroupKind{ - Group: Group, - Kind: HTTPRouteKind, - }, - fromNamespace: FromNamespace, - toGK: metav1.GroupKind{ - Group: Group, - Kind: GatewayKind, - }, - toNamespace: ToNamespace, - toName: string(objName), - k8sReferenceGrants: []gwv1beta1.ReferenceGrant{ - { - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Namespace: ToNamespace, - }, - Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - { - Group: Group, - Kind: HTTPRouteKind, - Namespace: FromNamespace, - }, - }, - To: []gwv1beta1.ReferenceGrantTo{ - { - Group: Group, - Kind: GatewayKind, - Name: nil, - }, - }, - }, - }, - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - rv := NewReferenceValidator(tc.k8sReferenceGrants).(*referenceValidator) - refAllowed := rv.referenceAllowed(tc.fromGK, tc.fromNamespace, tc.toGK, tc.toNamespace, tc.toName) - - require.Equal(t, tc.refAllowed, refAllowed) - }) - } -} diff --git a/control-plane/api-gateway/binding/registration.go b/control-plane/api-gateway/binding/registration.go deleted file mode 100644 index ae26ab51f6..0000000000 --- a/control-plane/api-gateway/binding/registration.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "fmt" - - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul/api" - corev1 "k8s.io/api/core/v1" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -const ( - metaKeySyntheticNode = "synthetic-node" - kubernetesSuccessReasonMsg = "Kubernetes health checks passing" - - // consulKubernetesCheckType is the type of health check in Consul for Kubernetes readiness status. - consulKubernetesCheckType = "kubernetes-readiness" - - // consulKubernetesCheckName is the name of health check in Consul for Kubernetes readiness status. - consulKubernetesCheckName = "Kubernetes Readiness Check" -) - -func registrationsForPods(namespace string, gateway gwv1beta1.Gateway, pods []corev1.Pod) []api.CatalogRegistration { - registrations := []api.CatalogRegistration{} - for _, pod := range pods { - registrations = append(registrations, registrationForPod(namespace, gateway, pod)) - } - return registrations -} - -func registrationForPod(namespace string, gateway gwv1beta1.Gateway, pod corev1.Pod) api.CatalogRegistration { - healthStatus := api.HealthCritical - if isPodReady(pod) { - healthStatus = api.HealthPassing - } - - return api.CatalogRegistration{ - Node: common.ConsulNodeNameFromK8sNode(pod.Spec.NodeName), - Address: pod.Status.HostIP, - NodeMeta: map[string]string{ - metaKeySyntheticNode: "true", - }, - Service: &api.AgentService{ - Kind: api.ServiceKindAPIGateway, - ID: pod.Name, - Service: gateway.Name, - Address: pod.Status.PodIP, - Namespace: namespace, - Meta: map[string]string{ - constants.MetaKeyPodName: pod.Name, - constants.MetaKeyKubeNS: pod.Namespace, - constants.MetaKeyKubeServiceName: gateway.Name, - "external-source": "consul-api-gateway", - }, - }, - Check: &api.AgentCheck{ - CheckID: fmt.Sprintf("%s/%s", pod.Namespace, pod.Name), - Name: consulKubernetesCheckName, - Type: consulKubernetesCheckType, - Status: healthStatus, - ServiceID: pod.Name, - Output: getHealthCheckStatusReason(healthStatus, pod.Name, pod.Namespace), - Namespace: namespace, - }, - SkipNodeUpdate: true, - } -} - -func getHealthCheckStatusReason(healthCheckStatus, podName, podNamespace string) string { - if healthCheckStatus == api.HealthPassing { - return kubernetesSuccessReasonMsg - } - - return fmt.Sprintf("Pod \"%s/%s\" is not ready", podNamespace, podName) -} - -func isPodReady(pod corev1.Pod) bool { - if corev1.PodRunning != pod.Status.Phase { - return false - } - - for _, condition := range pod.Status.Conditions { - if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue { - return true - } - } - return false -} diff --git a/control-plane/api-gateway/binding/registration_test.go b/control-plane/api-gateway/binding/registration_test.go deleted file mode 100644 index 356915f9f7..0000000000 --- a/control-plane/api-gateway/binding/registration_test.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "testing" - - "github.com/hashicorp/consul/api" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestRegistrationsForPods_Health(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - consulNamespace string - gateway gwv1beta1.Gateway - pods []corev1.Pod - expected []string - }{ - "empty": { - consulNamespace: "", - gateway: gwv1beta1.Gateway{}, - pods: []corev1.Pod{}, - expected: []string{}, - }, - "mix": { - consulNamespace: "", - gateway: gwv1beta1.Gateway{}, - pods: []corev1.Pod{ - // Pods without a running status - {Status: corev1.PodStatus{Phase: corev1.PodFailed}}, - {Status: corev1.PodStatus{Phase: corev1.PodPending}}, - {Status: corev1.PodStatus{Phase: corev1.PodSucceeded}}, - {Status: corev1.PodStatus{Phase: corev1.PodUnknown}}, - // Running statuses that don't show readiness - {Status: corev1.PodStatus{Phase: corev1.PodRunning, Conditions: []corev1.PodCondition{ - {Type: corev1.PodScheduled, Status: corev1.ConditionTrue}, - }}}, - {Status: corev1.PodStatus{Phase: corev1.PodRunning, Conditions: []corev1.PodCondition{ - {Type: corev1.PodInitialized, Status: corev1.ConditionTrue}, - }}}, - {Status: corev1.PodStatus{Phase: corev1.PodRunning, Conditions: []corev1.PodCondition{ - {Type: corev1.DisruptionTarget, Status: corev1.ConditionTrue}, - }}}, - {Status: corev1.PodStatus{Phase: corev1.PodRunning, Conditions: []corev1.PodCondition{ - {Type: corev1.ContainersReady, Status: corev1.ConditionTrue}, - }}}, - // And finally, the successful check - {Status: corev1.PodStatus{Phase: corev1.PodRunning, Conditions: []corev1.PodCondition{ - {Type: corev1.PodReady, Status: corev1.ConditionTrue}, - }}}, - }, - expected: []string{ - api.HealthCritical, - api.HealthCritical, - api.HealthCritical, - api.HealthCritical, - api.HealthCritical, - api.HealthCritical, - api.HealthCritical, - api.HealthCritical, - api.HealthPassing, - }, - }, - } { - t.Run(name, func(t *testing.T) { - registrations := registrationsForPods(tt.consulNamespace, tt.gateway, tt.pods) - require.Len(t, registrations, len(tt.expected)) - - for i := range registrations { - registration := registrations[i] - expected := tt.expected[i] - - require.EqualValues(t, "Kubernetes Readiness Check", registration.Check.Name) - require.EqualValues(t, expected, registration.Check.Status) - } - }) - } -} diff --git a/control-plane/api-gateway/binding/result.go b/control-plane/api-gateway/binding/result.go deleted file mode 100644 index 0ba4a257fd..0000000000 --- a/control-plane/api-gateway/binding/result.go +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "errors" - "fmt" - "sort" - "strings" - - mapset "github.com/deckarep/golang-set" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" -) - -// override function for tests. -var timeFunc = metav1.Now - -// This is used for any error related to a lack of proper reference grant creation. -var errRefNotPermitted = errors.New("reference not permitted due to lack of ReferenceGrant") - -var ( - // Each of the below are specified in the Gateway spec under RouteConditionReason - // to the RouteConditionReason given in the spec. If a reason is overloaded and can - // be used with two different types of things (i.e. something is not found or it's not supported) - // then we distinguish those two usages with errRoute*_Usage. - errRouteNotAllowedByListeners_Namespace = errors.New("listener does not allow binding routes from the given namespace") - errRouteNotAllowedByListeners_Protocol = errors.New("listener does not support route protocol") - errRouteNoMatchingListenerHostname = errors.New("listener cannot bind route with a non-aligned hostname") - errRouteInvalidKind = errors.New("invalid backend kind") - errRouteBackendNotFound = errors.New("backend not found") - errRouteNoMatchingParent = errors.New("no matching parent") - errInvalidExternalRefType = errors.New("invalid externalref filter kind") - errExternalRefNotFound = errors.New("ref not found") -) - -// routeValidationResult holds the result of validating a route globally, in other -// words, for a particular backend reference without consideration to its particular -// gateway. Unfortunately, due to the fact that the spec requires a route status be -// associated with a parent reference, what it means is that anything that is global -// in nature, like this status will need to be duplicated for every parent reference -// on a given route status. -type routeValidationResult struct { - namespace string - backend gwv1beta1.BackendRef - err error -} - -// Type is used for error printing a backend reference type that we don't support on -// a validation error. -func (v routeValidationResult) Type() string { - return (&metav1.GroupKind{ - Group: common.ValueOr(v.backend.Group, ""), - Kind: common.ValueOr(v.backend.Kind, common.KindService), - }).String() -} - -// String is the namespace/name of the reference that has an error. -func (v routeValidationResult) String() string { - return (types.NamespacedName{Namespace: v.namespace, Name: string(v.backend.Name)}).String() -} - -// routeValidationResults contains a list of validation results for the backend references -// on a route. -type routeValidationResults []routeValidationResult - -// Condition returns the ResolvedRefs condition that gets duplicated across every relevant -// parent on a route's status. -func (e routeValidationResults) Condition() metav1.Condition { - // we only use the first error due to the way the spec is structured - // where you can only have a single condition - for _, v := range e { - err := v.err - if err != nil { - switch err { - case errRouteInvalidKind: - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "InvalidKind", - Message: fmt.Sprintf("%s [%s]: %s", v.String(), v.Type(), err.Error()), - } - case errRouteBackendNotFound: - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "BackendNotFound", - Message: fmt.Sprintf("%s: %s", v.String(), err.Error()), - } - case errRefNotPermitted: - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "RefNotPermitted", - Message: fmt.Sprintf("%s: %s", v.String(), err.Error()), - } - default: - // this should never happen - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "UnhandledValidationError", - Message: err.Error(), - } - } - } - } - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - Message: "resolved backend references", - } -} - -// bindResult holds the result of attempting to bind a route to a particular gateway listener -// an error value here means that the route did not bind successfully, no error means that -// the route should be considered bound. -type bindResult struct { - section gwv1beta1.SectionName - err error -} - -// bindResults holds the results of attempting to bind a route to a gateway, having a separate -// bindResult for each listener on the gateway. -type bindResults []bindResult - -// Error constructs a human readable error for bindResults, containing any errors that a route -// had in binding to a gateway. Note that this is only used if a route failed to bind to every -// listener it attempted to bind to. -func (b bindResults) Error() string { - messages := []string{} - for _, result := range b { - if result.err != nil { - message := result.err.Error() - if result.section != "" { - message = fmt.Sprintf("%s: %s", result.section, result.err.Error()) - } - messages = append(messages, message) - } - } - - sort.Strings(messages) - return strings.Join(messages, "; ") -} - -// DidBind returns whether a route successfully bound to any listener on a gateway. -func (b bindResults) DidBind() bool { - for _, result := range b { - if result.err == nil { - return true - } - } - return false -} - -// Condition constructs an Accepted condition for a route that will be scoped -// to the particular parent reference it's using to attempt binding. -func (b bindResults) Condition() metav1.Condition { - // if we bound to any listeners, say we're accepted - if b.DidBind() { - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - } - } - - // default to the most generic reason in the spec "NotAllowedByListeners" - reason := "NotAllowedByListeners" - - // if we only have a single binding error, we can get more specific - if len(b) == 1 { - for _, result := range b { - switch { - case errors.Is(result.err, errRouteNoMatchingListenerHostname): - // if we have a hostname mismatch error, then use the more specific reason - reason = "NoMatchingListenerHostname" - case errors.Is(result.err, errRefNotPermitted): - // or if we have a ref not permitted, then use that - reason = "RefNotPermitted" - case errors.Is(result.err, errRouteNoMatchingParent): - // or if the route declares a parent that we can't find - reason = "NoMatchingParent" - case errors.Is(result.err, errExternalRefNotFound): - reason = "FilterNotFound" - case errors.Is(result.err, errInvalidExternalRefType): - reason = "UnsupportedValue" - } - } - } - - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: reason, - Message: b.Error(), - } -} - -// parentBindResult associates a binding result with the given parent reference. -type parentBindResult struct { - parent gwv1beta1.ParentReference - results bindResults -} - -// parentBindResults contains the list of all results that occurred when this route -// attempted to bind to a gateway using its parent references. -type parentBindResults []parentBindResult - -func (p parentBindResults) boundSections() mapset.Set { - set := mapset.NewSet() - for _, result := range p { - for _, r := range result.results { - if r.err == nil { - set.Add(string(r.section)) - } - } - } - return set -} - -var ( - // Each of the below are specified in the Gateway spec under ListenerConditionReason. - // The general usage is that each error is specified as errListener* where * corresponds - // to the ListenerConditionReason given in the spec. If a reason is overloaded and can - // be used with two different types of things (i.e. something is not found or it's not supported) - // then we distinguish those two usages with errListener*_Usage. - errListenerUnsupportedProtocol = errors.New("listener protocol is unsupported") - errListenerPortUnavailable = errors.New("listener port is unavailable") - errListenerHostnameConflict = errors.New("listener hostname conflicts with another listener") - errListenerProtocolConflict = errors.New("listener protocol conflicts with another listener") - errListenerInvalidCertificateRef_NotFound = errors.New("certificate not found") - errListenerInvalidCertificateRef_NotSupported = errors.New("certificate type is not supported") - errListenerInvalidCertificateRef_InvalidData = errors.New("certificate is invalid or does not contain a supported server name") - errListenerInvalidCertificateRef_NonFIPSRSAKeyLen = errors.New("certificate has an invalid length: RSA Keys must be at least 2048-bit") - errListenerInvalidCertificateRef_FIPSRSAKeyLen = errors.New("certificate has an invalid length: RSA keys must be either 2048-bit, 3072-bit, or 4096-bit in FIPS mode") - errListenerInvalidRouteKinds = errors.New("allowed route kind is invalid") - errListenerProgrammed_Invalid = errors.New("listener cannot be programmed because it is invalid") - - // Below is where any custom generic listener validation errors should go. - // We map anything under here to a custom ListenerConditionReason of Invalid on - // an Accepted status type. - errListenerNoTLSPassthrough = errors.New("TLS passthrough is not supported") - errListenerTLSCipherSuiteNotConfigurable = errors.New("tls_min_version does not allow tls_cipher_suites configuration") - errListenerUnsupportedTLSCipherSuite = errors.New("unsupported cipher suite in tls_cipher_suites") - errListenerUnsupportedTLSMaxVersion = errors.New("unsupported tls_max_version") - errListenerUnsupportedTLSMinVersion = errors.New("unsupported tls_min_version") - - // This custom listener validation error is used to differentiate between an errListenerPortUnavailable because of - // direct port conflicts defined by the user (two listeners on the same port) vs a port conflict because we map - // privileged ports by adding the value passed into the gatewayClassConfig. - // (i.e. one listener on 80 with a privileged port mapping of 2000, and one listener on 2080 would conflict). - errListenerMappedToPrivilegedPortMapping = errors.New("listener conflicts with privileged port mapped by GatewayClassConfig privileged port mapping setting") -) - -// listenerValidationResult contains the result of internally validating a single listener -// as well as the result of validating it in relation to all its peers (via conflictedErr). -// an error set on any of its members corresponds to an error condition on the corresponding -// status type. -type listenerValidationResult struct { - // status type: Accepted - acceptedErr error - // status type: Conflicted - conflictedErr error - // status type: ResolvedRefs - refErr error - // status type: ResolvedRefs (but with internal validation) - routeKindErr error -} - -// programmedCondition constructs the condition for the Programmed status type. -// If there are no validation errors for the listener, we mark it as programmed. -// If there are validation errors for the listener, we mark it as invalid. -func (l listenerValidationResult) programmedCondition(generation int64) metav1.Condition { - now := timeFunc() - - switch { - case l.acceptedErr != nil, l.conflictedErr != nil, l.refErr != nil, l.routeKindErr != nil: - return metav1.Condition{ - Type: "Programmed", - Status: metav1.ConditionFalse, - Reason: "Invalid", - ObservedGeneration: generation, - Message: errListenerProgrammed_Invalid.Error(), - LastTransitionTime: now, - } - default: - return metav1.Condition{ - Type: "Programmed", - Status: metav1.ConditionTrue, - Reason: "Programmed", - ObservedGeneration: generation, - Message: "listener programmed", - LastTransitionTime: now, - } - } -} - -// acceptedCondition constructs the condition for the Accepted status type. -func (l listenerValidationResult) acceptedCondition(generation int64) metav1.Condition { - now := timeFunc() - switch l.acceptedErr { - case errListenerPortUnavailable, errListenerMappedToPrivilegedPortMapping: - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "PortUnavailable", - ObservedGeneration: generation, - Message: l.acceptedErr.Error(), - LastTransitionTime: now, - } - case errListenerUnsupportedProtocol: - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "UnsupportedProtocol", - ObservedGeneration: generation, - Message: l.acceptedErr.Error(), - LastTransitionTime: now, - } - case nil: - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - ObservedGeneration: generation, - Message: "listener accepted", - LastTransitionTime: now, - } - default: - // falback to invalid - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "Invalid", - ObservedGeneration: generation, - Message: l.acceptedErr.Error(), - LastTransitionTime: now, - } - } -} - -// conflictedCondition constructs the condition for the Conflicted status type. -func (l listenerValidationResult) conflictedCondition(generation int64) metav1.Condition { - now := timeFunc() - - switch l.conflictedErr { - case errListenerProtocolConflict: - return metav1.Condition{ - Type: "Conflicted", - Status: metav1.ConditionTrue, - Reason: "ProtocolConflict", - ObservedGeneration: generation, - Message: l.conflictedErr.Error(), - LastTransitionTime: now, - } - case errListenerHostnameConflict: - return metav1.Condition{ - Type: "Conflicted", - Status: metav1.ConditionTrue, - Reason: "HostnameConflict", - ObservedGeneration: generation, - Message: l.conflictedErr.Error(), - LastTransitionTime: now, - } - default: - return metav1.Condition{ - Type: "Conflicted", - Status: metav1.ConditionFalse, - Reason: "NoConflicts", - ObservedGeneration: generation, - Message: "listener has no conflicts", - LastTransitionTime: now, - } - } -} - -// acceptedCondition constructs the condition for the ResolvedRefs status type. -func (l listenerValidationResult) resolvedRefsCondition(generation int64) metav1.Condition { - now := timeFunc() - - if l.routeKindErr != nil { - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "InvalidRouteKinds", - ObservedGeneration: generation, - Message: l.routeKindErr.Error(), - LastTransitionTime: now, - } - } - - switch l.refErr { - case errListenerInvalidCertificateRef_NotFound, errListenerInvalidCertificateRef_NotSupported, errListenerInvalidCertificateRef_InvalidData, errListenerInvalidCertificateRef_NonFIPSRSAKeyLen, errListenerInvalidCertificateRef_FIPSRSAKeyLen: - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "InvalidCertificateRef", - ObservedGeneration: generation, - Message: l.refErr.Error(), - LastTransitionTime: now, - } - case errRefNotPermitted: - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionFalse, - Reason: "RefNotPermitted", - ObservedGeneration: generation, - Message: l.refErr.Error(), - LastTransitionTime: now, - } - default: - return metav1.Condition{ - Type: "ResolvedRefs", - Status: metav1.ConditionTrue, - Reason: "ResolvedRefs", - ObservedGeneration: generation, - Message: "resolved certificate references", - LastTransitionTime: now, - } - } -} - -// Conditions constructs the entire set of conditions for a given gateway listener. -func (l listenerValidationResult) Conditions(generation int64) []metav1.Condition { - return []metav1.Condition{ - l.acceptedCondition(generation), - l.programmedCondition(generation), - l.conflictedCondition(generation), - l.resolvedRefsCondition(generation), - } -} - -// listenerValidationResults holds all of the results for a gateway's listeners -// the index of each result needs to correspond exactly to the index of the listener -// on the gateway spec for which it is describing. -type listenerValidationResults []listenerValidationResult - -// Invalid returns whether or not there is any listener that is not "Accepted" -// this is used in constructing a gateway's status where the Accepted status -// at the top-level can have a GatewayConditionReason of ListenersNotValid. -func (l listenerValidationResults) Invalid() bool { - for _, r := range l { - if r.acceptedErr != nil { - return true - } - } - return false -} - -// Conditions returns the listener conditions at a given index. -func (l listenerValidationResults) Conditions(generation int64, index int) []metav1.Condition { - result := l[index] - return result.Conditions(generation) -} - -var ( - // Each of the below are specified in the Gateway spec under GatewayConditionReason - // the general usage is that each error is specified as errGateway* where * corresponds - // to the GatewayConditionReason given in the spec. - errGatewayUnsupportedAddress = errors.New("gateway does not support specifying addresses") - errGatewayListenersNotValid = errors.New("one or more listeners are invalid") - errGatewayPending_Pods = errors.New("gateway pods are still being scheduled") - errGatewayPending_Consul = errors.New("gateway configuration is not yet synced to Consul") -) - -// gatewayValidationResult contains the result of internally validating a gateway. -// An error set on any of its members corresponds to an error condition on the corresponding -// status type. -type gatewayValidationResult struct { - acceptedErr error - programmedErr error -} - -// programmedCondition returns a condition for the Programmed status type. -func (l gatewayValidationResult) programmedCondition(generation int64) metav1.Condition { - now := timeFunc() - - switch l.programmedErr { - case errGatewayPending_Pods, errGatewayPending_Consul: - return metav1.Condition{ - Type: "Programmed", - Status: metav1.ConditionFalse, - Reason: "Pending", - ObservedGeneration: generation, - Message: l.programmedErr.Error(), - LastTransitionTime: now, - } - default: - return metav1.Condition{ - Type: "Programmed", - Status: metav1.ConditionTrue, - Reason: "Programmed", - ObservedGeneration: generation, - Message: "gateway programmed", - LastTransitionTime: now, - } - } -} - -// acceptedCondition returns a condition for the Accepted status type. It takes a boolean argument -// for whether or not any of the gateway's listeners are invalid, if they are, it overrides whatever -// Reason is set as an error on the result and instead uses the ListenersNotValid reason. -func (l gatewayValidationResult) acceptedCondition(generation int64, listenersInvalid bool) metav1.Condition { - now := timeFunc() - - if l.acceptedErr == nil { - if listenersInvalid { - return metav1.Condition{ - Type: "Accepted", - // should one invalid listener cause the entire gateway to become invalid? - Status: metav1.ConditionFalse, - Reason: "ListenersNotValid", - ObservedGeneration: generation, - Message: errGatewayListenersNotValid.Error(), - LastTransitionTime: now, - } - } - - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - ObservedGeneration: generation, - Message: "gateway accepted", - LastTransitionTime: now, - } - } - - if l.acceptedErr == errGatewayUnsupportedAddress { - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "UnsupportedAddress", - ObservedGeneration: generation, - Message: l.acceptedErr.Error(), - LastTransitionTime: now, - } - } - - // fallback to Invalid reason - return metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionFalse, - Reason: "Invalid", - ObservedGeneration: generation, - Message: l.acceptedErr.Error(), - LastTransitionTime: now, - } -} - -// Conditions constructs the gateway conditions given whether its listeners are valid. -func (l gatewayValidationResult) Conditions(generation int64, listenersInvalid bool) []metav1.Condition { - return []metav1.Condition{ - l.acceptedCondition(generation, listenersInvalid), - l.programmedCondition(generation), - } -} diff --git a/control-plane/api-gateway/binding/result_test.go b/control-plane/api-gateway/binding/result_test.go deleted file mode 100644 index 6989bb09ab..0000000000 --- a/control-plane/api-gateway/binding/result_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "errors" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestBindResults_Condition(t *testing.T) { - testCases := []struct { - Name string - Results bindResults - Expected metav1.Condition - }{ - { - Name: "route successfully bound", - Results: bindResults{{section: "", err: nil}}, - Expected: metav1.Condition{Type: "Accepted", Status: "True", Reason: "Accepted", Message: "route accepted"}, - }, - { - Name: "multiple bind results", - Results: bindResults{ - {section: "abc", err: errRouteNoMatchingListenerHostname}, - {section: "def", err: errRouteNoMatchingParent}, - }, - Expected: metav1.Condition{Type: "Accepted", Status: "False", Reason: "NotAllowedByListeners", Message: "abc: listener cannot bind route with a non-aligned hostname; def: no matching parent"}, - }, - { - Name: "no matching listener hostname error", - Results: bindResults{{section: "abc", err: errRouteNoMatchingListenerHostname}}, - Expected: metav1.Condition{Type: "Accepted", Status: "False", Reason: "NoMatchingListenerHostname", Message: "abc: listener cannot bind route with a non-aligned hostname"}, - }, - { - Name: "ref not permitted error", - Results: bindResults{{section: "abc", err: errRefNotPermitted}}, - Expected: metav1.Condition{Type: "Accepted", Status: "False", Reason: "RefNotPermitted", Message: "abc: reference not permitted due to lack of ReferenceGrant"}, - }, - { - Name: "no matching parent error", - Results: bindResults{{section: "hello1", err: errRouteNoMatchingParent}}, - Expected: metav1.Condition{Type: "Accepted", Status: "False", Reason: "NoMatchingParent", Message: "hello1: no matching parent"}, - }, - { - Name: "bind result without section name", - Results: bindResults{{section: "", err: errRouteNoMatchingParent}}, - Expected: metav1.Condition{Type: "Accepted", Status: "False", Reason: "NoMatchingParent", Message: "no matching parent"}, - }, - { - Name: "unhandled error type", - Results: bindResults{{section: "abc", err: errors.New("you don't know me")}}, - Expected: metav1.Condition{Type: "Accepted", Status: "False", Reason: "NotAllowedByListeners", Message: "abc: you don't know me"}, - }, - } - - for _, tc := range testCases { - t.Run(fmt.Sprintf("%s_%s", t.Name(), tc.Name), func(t *testing.T) { - actual := tc.Results.Condition() - assert.Equalf(t, tc.Expected.Type, actual.Type, "expected condition with type %q but got %q", tc.Expected.Type, actual.Type) - assert.Equalf(t, tc.Expected.Status, actual.Status, "expected condition with status %q but got %q", tc.Expected.Status, actual.Status) - assert.Equalf(t, tc.Expected.Reason, actual.Reason, "expected condition with reason %q but got %q", tc.Expected.Reason, actual.Reason) - assert.Equalf(t, tc.Expected.Message, actual.Message, "expected condition with message %q but got %q", tc.Expected.Message, actual.Message) - }) - } -} diff --git a/control-plane/api-gateway/binding/route_binding.go b/control-plane/api-gateway/binding/route_binding.go deleted file mode 100644 index 75a70c2974..0000000000 --- a/control-plane/api-gateway/binding/route_binding.go +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - mapset "github.com/deckarep/golang-set" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul/api" -) - -// bindRoute contains the main logic for binding a route to a given gateway. -func (r *Binder) bindRoute(route client.Object, boundCount map[gwv1beta1.SectionName]int, snapshot *Snapshot) { - // use the non-normalized key since we can't write back enterprise metadata - // on non-enterprise installations - routeConsulKey := r.config.Translator.NonNormalizedConfigEntryReference(entryKind(route), client.ObjectKeyFromObject(route)) - filteredParents := filterParentRefs(r.key, route.GetNamespace(), getRouteParents(route)) - filteredParentStatuses := filterParentRefs(r.key, route.GetNamespace(), - common.ConvertSliceFunc(getRouteParentsStatus(route), func(parentStatus gwv1beta1.RouteParentStatus) gwv1beta1.ParentReference { - return parentStatus.ParentRef - }), - ) - - // flags to mark that some operation needs to occur - kubernetesNeedsUpdate := false - kubernetesNeedsStatusUpdate := false - - // we do this in a closure at the end to make sure we don't accidentally - // add something multiple times into the list of update/delete operations - // instead we just set a flag indicating that an update is needed and then - // append to the snapshot right before returning - defer func() { - if kubernetesNeedsUpdate { - snapshot.Kubernetes.Updates.Add(route) - } - if kubernetesNeedsStatusUpdate { - snapshot.Kubernetes.StatusUpdates.Add(route) - } - }() - - if isDeleted(route) { - // mark the route as needing to get cleaned up if we detect that it's being deleted - if common.RemoveFinalizer(route) { - kubernetesNeedsUpdate = true - } - return - } - - if r.isGatewayDeleted() { - if canGCOnUnbind(routeConsulKey, r.config.Resources) && common.RemoveFinalizer(route) { - kubernetesNeedsUpdate = true - } else { - // Remove the condition since we no longer know if we should - // control the route and drop any references for the Consul route. - // This only gets run if we can't GC the route at the end of this - // loop. - r.dropConsulRouteParent(snapshot, route, r.nonNormalizedConsulKey, r.config.Resources) - } - - // drop the status conditions - if r.statusSetter.removeRouteReferences(route, filteredParentStatuses) { - kubernetesNeedsStatusUpdate = true - } - if r.statusSetter.removeRouteReferences(route, filteredParents) { - kubernetesNeedsStatusUpdate = true - } - return - } - - if common.EnsureFinalizer(route) { - kubernetesNeedsUpdate = true - return - } - - validation := validateRefs(route, getRouteBackends(route), r.config.Resources) - // the spec is dumb and makes you set a parent for any status, even when the - // status is not with respect to a parent, as is the case of resolved refs - // so we need to set the status on all parents - for _, parent := range filteredParents { - if r.statusSetter.setRouteCondition(route, &parent, validation.Condition()) { - kubernetesNeedsStatusUpdate = true - } - } - // if we're orphaned from this gateway we'll - // always need a status update. - if len(filteredParents) == 0 { - // we already checked that these refs existed, so no need to check - // the return value here. - _ = r.statusSetter.removeRouteReferences(route, filteredParentStatuses) - kubernetesNeedsStatusUpdate = true - } - - namespace := r.config.Namespaces[route.GetNamespace()] - groupKind := route.GetObjectKind().GroupVersionKind().GroupKind() - - var results parentBindResults - - for _, ref := range filteredParents { - var result bindResults - - listeners := listenersFor(&r.config.Gateway, ref.SectionName) - - // If there are no matching listeners, then we failed to find the parent - if len(listeners) == 0 { - var sectionName gwv1beta1.SectionName - if ref.SectionName != nil { - sectionName = *ref.SectionName - } - - result = append(result, bindResult{ - section: sectionName, - err: errRouteNoMatchingParent, - }) - } - - for _, listener := range listeners { - if !routeKindIsAllowedForListener(supportedKindsForProtocol[listener.Protocol], groupKind) { - result = append(result, bindResult{ - section: listener.Name, - err: errRouteNotAllowedByListeners_Protocol, - }) - continue - } - - if !routeKindIsAllowedForListenerExplicit(listener.AllowedRoutes, groupKind) { - result = append(result, bindResult{ - section: listener.Name, - err: errRouteNotAllowedByListeners_Protocol, - }) - continue - } - - if !routeAllowedForListenerNamespaces(r.config.Gateway.Namespace, listener.AllowedRoutes, namespace) { - result = append(result, bindResult{ - section: listener.Name, - err: errRouteNotAllowedByListeners_Namespace, - }) - continue - } - - if !routeAllowedForListenerHostname(listener.Hostname, getRouteHostnames(route)) { - result = append(result, bindResult{ - section: listener.Name, - err: errRouteNoMatchingListenerHostname, - }) - continue - } - - result = append(result, bindResult{ - section: listener.Name, - }) - - boundCount[listener.Name]++ - } - - results = append(results, parentBindResult{ - parent: ref, - results: result, - }) - - httproute, ok := route.(*gwv1beta1.HTTPRoute) - if ok { - if !externalRefsOnRouteAllExist(httproute, r.config.Resources) { - results = append(results, parentBindResult{ - parent: ref, - results: []bindResult{ - { - err: errExternalRefNotFound, - }, - }, - }) - } - - if !externalRefsKindAllowedOnRoute(httproute) { - results = append(results, parentBindResult{ - parent: ref, - results: []bindResult{ - { - err: errInvalidExternalRefType, - }, - }, - }) - } - } - } - - updated := false - for _, result := range results { - if r.statusSetter.setRouteCondition(route, &result.parent, result.results.Condition()) { - updated = true - } - } - - if updated { - kubernetesNeedsStatusUpdate = true - } - - r.mutateRouteWithBindingResults(snapshot, route, r.nonNormalizedConsulKey, r.config.Resources, results) -} - -// filterParentRefs returns the subset of parent references on a route that point to the given gateway. -func filterParentRefs(gateway types.NamespacedName, namespace string, refs []gwv1beta1.ParentReference) []gwv1beta1.ParentReference { - references := []gwv1beta1.ParentReference{} - for _, ref := range refs { - if common.NilOrEqual(ref.Group, common.BetaGroup) && - common.NilOrEqual(ref.Kind, common.KindGateway) && - gateway.Namespace == common.ValueOr(ref.Namespace, namespace) && - gateway.Name == string(ref.Name) { - references = append(references, ref) - } - } - - return references -} - -// listenersFor returns the listeners corresponding to the given section name. If the section -// name is actually specified, the returned set will only contain the named listener. If it is -// unspecified, then all gateway listeners will be returned. -func listenersFor(gateway *gwv1beta1.Gateway, name *gwv1beta1.SectionName) []gwv1beta1.Listener { - listeners := []gwv1beta1.Listener{} - for _, listener := range gateway.Spec.Listeners { - if name == nil { - listeners = append(listeners, listener) - continue - } - if listener.Name == *name { - listeners = append(listeners, listener) - } - } - return listeners -} - -func consulParentMatches(namespace string, gatewayKey api.ResourceReference, parent api.ResourceReference) bool { - gatewayKey = common.NormalizeMeta(gatewayKey) - - if parent.Namespace == "" { - parent.Namespace = namespace - } - if parent.Kind == "" { - parent.Kind = api.APIGateway - } - - parent = common.NormalizeMeta(parent) - - return parent.Kind == api.APIGateway && - parent.Name == gatewayKey.Name && - parent.Namespace == gatewayKey.Namespace && - parent.Partition == gatewayKey.Partition -} - -func (r *Binder) dropConsulRouteParent(snapshot *Snapshot, object client.Object, gateway api.ResourceReference, resources *common.ResourceMap) { - switch object.(type) { - case *gwv1beta1.HTTPRoute: - resources.MutateHTTPRoute(client.ObjectKeyFromObject(object), r.handleRouteSyncStatus(snapshot, object), func(entry api.HTTPRouteConfigEntry) api.HTTPRouteConfigEntry { - entry.Parents = common.Filter(entry.Parents, func(parent api.ResourceReference) bool { - return consulParentMatches(entry.Namespace, gateway, parent) - }) - return entry - }) - case *gwv1alpha2.TCPRoute: - resources.MutateTCPRoute(client.ObjectKeyFromObject(object), r.handleRouteSyncStatus(snapshot, object), func(entry api.TCPRouteConfigEntry) api.TCPRouteConfigEntry { - entry.Parents = common.Filter(entry.Parents, func(parent api.ResourceReference) bool { - return consulParentMatches(entry.Namespace, gateway, parent) - }) - return entry - }) - } -} - -func (r *Binder) mutateRouteWithBindingResults(snapshot *Snapshot, object client.Object, gatewayConsulKey api.ResourceReference, resources *common.ResourceMap, results parentBindResults) { - if results.boundSections().Cardinality() == 0 { - r.dropConsulRouteParent(snapshot, object, r.nonNormalizedConsulKey, r.config.Resources) - return - } - - key := client.ObjectKeyFromObject(object) - - parents := mapset.NewSet() - // the normalized set keeps us from accidentally adding the same thing - // twice due to the Consul server normalizing our refs. - normalized := make(map[api.ResourceReference]api.ResourceReference) - for section := range results.boundSections().Iter() { - ref := api.ResourceReference{ - Kind: api.APIGateway, - Name: gatewayConsulKey.Name, - SectionName: section.(string), - Namespace: gatewayConsulKey.Namespace, - Partition: gatewayConsulKey.Partition, - } - parents.Add(ref) - normalized[common.NormalizeMeta(ref)] = ref - } - - switch object.(type) { - case *gwv1beta1.HTTPRoute: - resources.TranslateAndMutateHTTPRoute(key, r.handleRouteSyncStatus(snapshot, object), func(old *api.HTTPRouteConfigEntry, new api.HTTPRouteConfigEntry) api.HTTPRouteConfigEntry { - if old != nil { - for _, parent := range old.Parents { - // drop any references that already exist - if parents.Contains(parent) { - parents.Remove(parent) - } - if id, ok := normalized[parent]; ok { - parents.Remove(id) - } - } - - // set the old parent states - new.Parents = old.Parents - new.Status = old.Status - } - // and now add what is left - for parent := range parents.Iter() { - new.Parents = append(new.Parents, parent.(api.ResourceReference)) - } - - return new - }) - case *gwv1alpha2.TCPRoute: - resources.TranslateAndMutateTCPRoute(key, r.handleRouteSyncStatus(snapshot, object), func(old *api.TCPRouteConfigEntry, new api.TCPRouteConfigEntry) api.TCPRouteConfigEntry { - if old != nil { - for _, parent := range old.Parents { - // drop any references that already exist - if parents.Contains(parent) { - parents.Remove(parent) - } - } - - // set the old parent states - new.Parents = old.Parents - new.Status = old.Status - } - // and now add what is left - for parent := range parents.Iter() { - new.Parents = append(new.Parents, parent.(api.ResourceReference)) - } - return new - }) - } -} - -func entryKind(object client.Object) string { - switch object.(type) { - case *gwv1beta1.HTTPRoute: - return api.HTTPRoute - case *gwv1alpha2.TCPRoute: - return api.TCPRoute - } - return "" -} - -func canGCOnUnbind(id api.ResourceReference, resources *common.ResourceMap) bool { - switch id.Kind { - case api.HTTPRoute: - return resources.CanGCHTTPRouteOnUnbind(id) - case api.TCPRoute: - return resources.CanGCTCPRouteOnUnbind(id) - } - return true -} - -func getRouteHostnames(object client.Object) []gwv1beta1.Hostname { - switch v := object.(type) { - case *gwv1beta1.HTTPRoute: - return v.Spec.Hostnames - } - return nil -} - -func getRouteParents(object client.Object) []gwv1beta1.ParentReference { - switch v := object.(type) { - case *gwv1beta1.HTTPRoute: - return v.Spec.ParentRefs - case *gwv1alpha2.TCPRoute: - return v.Spec.ParentRefs - } - return nil -} - -func getRouteParentsStatus(object client.Object) []gwv1beta1.RouteParentStatus { - switch v := object.(type) { - case *gwv1beta1.HTTPRoute: - return v.Status.RouteStatus.Parents - case *gwv1alpha2.TCPRoute: - return v.Status.RouteStatus.Parents - } - return nil -} - -func setRouteParentsStatus(object client.Object, parents []gwv1beta1.RouteParentStatus) { - switch v := object.(type) { - case *gwv1beta1.HTTPRoute: - v.Status.RouteStatus.Parents = parents - case *gwv1alpha2.TCPRoute: - v.Status.RouteStatus.Parents = parents - } -} - -func getRouteBackends(object client.Object) []gwv1beta1.BackendRef { - switch v := object.(type) { - case *gwv1beta1.HTTPRoute: - return common.Flatten(common.ConvertSliceFunc(v.Spec.Rules, func(rule gwv1beta1.HTTPRouteRule) []gwv1beta1.BackendRef { - return common.ConvertSliceFunc(rule.BackendRefs, func(rule gwv1beta1.HTTPBackendRef) gwv1beta1.BackendRef { - return rule.BackendRef - }) - })) - case *gwv1alpha2.TCPRoute: - return common.Flatten(common.ConvertSliceFunc(v.Spec.Rules, func(rule gwv1alpha2.TCPRouteRule) []gwv1beta1.BackendRef { - return rule.BackendRefs - })) - } - return nil -} - -func canReferenceBackend(object client.Object, ref gwv1beta1.BackendRef, resources *common.ResourceMap) bool { - switch v := object.(type) { - case *gwv1beta1.HTTPRoute: - return resources.HTTPRouteCanReferenceBackend(*v, ref) - case *gwv1alpha2.TCPRoute: - return resources.TCPRouteCanReferenceBackend(*v, ref) - } - return false -} - -func (r *Binder) handleRouteSyncStatus(snapshot *Snapshot, object client.Object) func(error, api.ConfigEntryStatus) { - return func(err error, status api.ConfigEntryStatus) { - condition := metav1.Condition{ - Type: "Synced", - Status: metav1.ConditionTrue, - ObservedGeneration: object.GetGeneration(), - LastTransitionTime: timeFunc(), - Reason: "Synced", - Message: "route synced to Consul", - } - if err != nil { - condition = metav1.Condition{ - Type: "Synced", - Status: metav1.ConditionFalse, - ObservedGeneration: object.GetGeneration(), - LastTransitionTime: timeFunc(), - Reason: "SyncError", - Message: err.Error(), - } - } - if r.statusSetter.setRouteConditionOnAllRefs(object, condition) { - snapshot.Kubernetes.StatusUpdates.Add(object) - } - if consulCondition := consulCondition(object.GetGeneration(), status); consulCondition != nil { - if r.statusSetter.setRouteConditionOnAllRefs(object, *consulCondition) { - snapshot.Kubernetes.StatusUpdates.Add(object) - } - } - } -} - -func (r *Binder) handleGatewaySyncStatus(snapshot *Snapshot, gateway *gwv1beta1.Gateway, status api.ConfigEntryStatus) func(error) { - return func(err error) { - condition := metav1.Condition{ - Type: "Synced", - Status: metav1.ConditionTrue, - ObservedGeneration: gateway.Generation, - LastTransitionTime: timeFunc(), - Reason: "Synced", - Message: "gateway synced to Consul", - } - if err != nil { - condition = metav1.Condition{ - Type: "Synced", - Status: metav1.ConditionFalse, - ObservedGeneration: gateway.Generation, - LastTransitionTime: timeFunc(), - Reason: "SyncError", - Message: err.Error(), - } - } - - if conditions, updated := setCondition(gateway.Status.Conditions, condition); updated { - gateway.Status.Conditions = conditions - snapshot.Kubernetes.StatusUpdates.Add(gateway) - } - - if consulCondition := consulCondition(gateway.Generation, status); consulCondition != nil { - if conditions, updated := setCondition(gateway.Status.Conditions, *consulCondition); updated { - gateway.Status.Conditions = conditions - snapshot.Kubernetes.StatusUpdates.Add(gateway) - } - } - } -} - -func consulCondition(generation int64, status api.ConfigEntryStatus) *metav1.Condition { - for _, c := range status.Conditions { - // we only care about the top-level status that isn't in reference - // to a resource. - if c.Type == "Accepted" && (c.Resource == nil || c.Resource.Name == "") { - return &metav1.Condition{ - Type: "ConsulAccepted", - Reason: c.Reason, - Status: metav1.ConditionStatus(c.Status), - Message: c.Message, - ObservedGeneration: generation, - LastTransitionTime: timeFunc(), - } - } - } - return nil -} diff --git a/control-plane/api-gateway/binding/setter.go b/control-plane/api-gateway/binding/setter.go deleted file mode 100644 index 5b3a9096d6..0000000000 --- a/control-plane/api-gateway/binding/setter.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -// setter wraps the status setting logic for routes. -type setter struct { - controllerName string -} - -// newSetter constructs a status setter with the given controller name. -func newSetter(controllerName string) *setter { - return &setter{controllerName: controllerName} -} - -// removeRouteReferences removes the given parent reference sections from a routes's status. -func (s *setter) removeRouteReferences(route client.Object, refs []gwv1beta1.ParentReference) bool { - modified := false - for _, parent := range refs { - parents, removed := s.removeParentStatus(getRouteParentsStatus(route), parent) - setRouteParentsStatus(route, parents) - if removed { - modified = true - } - } - return modified -} - -// setRouteCondition sets an route condition on its status with the given parent. -func (s *setter) setRouteCondition(route client.Object, parent *gwv1beta1.ParentReference, condition metav1.Condition) bool { - condition.LastTransitionTime = timeFunc() - condition.ObservedGeneration = route.GetGeneration() - - parents := getRouteParentsStatus(route) - status := s.getParentStatus(parents, parent) - conditions, modified := setCondition(status.Conditions, condition) - if modified { - status.Conditions = conditions - setRouteParentsStatus(route, s.setParentStatus(parents, status)) - } - return modified -} - -// setRouteConditionOnAllRefs sets an route condition and its status on all parents. -func (s *setter) setRouteConditionOnAllRefs(route client.Object, condition metav1.Condition) bool { - condition.LastTransitionTime = timeFunc() - condition.ObservedGeneration = route.GetGeneration() - - parents := getRouteParentsStatus(route) - statuses := common.Filter(getRouteParentsStatus(route), func(status gwv1beta1.RouteParentStatus) bool { - return string(status.ControllerName) != s.controllerName - }) - - updated := false - for _, status := range statuses { - conditions, modified := setCondition(status.Conditions, condition) - if modified { - updated = true - status.Conditions = conditions - setRouteParentsStatus(route, s.setParentStatus(parents, status)) - } - } - return updated -} - -// getParentStatus returns the section of a status referenced by the given parent reference. -func (s *setter) getParentStatus(statuses []gwv1beta1.RouteParentStatus, parent *gwv1beta1.ParentReference) gwv1beta1.RouteParentStatus { - var parentRef gwv1beta1.ParentReference - if parent != nil { - parentRef = *parent - } - - for _, status := range statuses { - if common.ParentsEqual(status.ParentRef, parentRef) && string(status.ControllerName) == s.controllerName { - return status - } - } - return gwv1beta1.RouteParentStatus{ - ParentRef: parentRef, - ControllerName: gwv1beta1.GatewayController(s.controllerName), - } -} - -// removeParentStatus removes the section of a status referenced by the given parent reference. -func (s *setter) removeParentStatus(statuses []gwv1beta1.RouteParentStatus, parent gwv1beta1.ParentReference) ([]gwv1beta1.RouteParentStatus, bool) { - found := false - filtered := []gwv1beta1.RouteParentStatus{} - for _, status := range statuses { - if common.ParentsEqual(status.ParentRef, parent) && string(status.ControllerName) == s.controllerName { - found = true - continue - } - filtered = append(filtered, status) - } - return filtered, found -} - -// setCondition overrides or appends a condition to the list of conditions, returning if a modification -// to the condition set was made or not. Modifications only occur if a field other than the observation -// timestamp is modified. -func setCondition(conditions []metav1.Condition, condition metav1.Condition) ([]metav1.Condition, bool) { - for i, existing := range conditions { - if existing.Type == condition.Type { - // no-op if we have the exact same thing - if condition.Reason == existing.Reason && condition.Message == existing.Message && condition.ObservedGeneration == existing.ObservedGeneration { - return conditions, false - } - - conditions[i] = condition - return conditions, true - } - } - return append(conditions, condition), true -} - -// setParentStatus updates or inserts the set of parent statuses with the newly modified parent. -func (s *setter) setParentStatus(statuses []gwv1beta1.RouteParentStatus, parent gwv1beta1.RouteParentStatus) []gwv1beta1.RouteParentStatus { - for i, status := range statuses { - if common.ParentsEqual(status.ParentRef, parent.ParentRef) && status.ControllerName == parent.ControllerName { - statuses[i] = parent - return statuses - } - } - return append(statuses, parent) -} diff --git a/control-plane/api-gateway/binding/setter_test.go b/control-plane/api-gateway/binding/setter_test.go deleted file mode 100644 index 84d3ecc7d5..0000000000 --- a/control-plane/api-gateway/binding/setter_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "testing" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestSetter(t *testing.T) { - setter := newSetter("test") - parentRef := gwv1beta1.ParentReference{ - Name: "test", - } - parentRefDup := gwv1beta1.ParentReference{ - Name: "test", - } - condition := metav1.Condition{ - Type: "Accepted", - Status: metav1.ConditionTrue, - Reason: "Accepted", - Message: "route accepted", - } - route := &gwv1beta1.HTTPRoute{ - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{parentRef}, - }, - }, - } - require.True(t, setter.setRouteCondition(route, &parentRef, condition)) - require.False(t, setter.setRouteCondition(route, &parentRefDup, condition)) - require.False(t, setter.setRouteCondition(route, &parentRefDup, condition)) - require.False(t, setter.setRouteCondition(route, &parentRefDup, condition)) - - require.Len(t, route.Status.Parents, 1) - require.Len(t, route.Status.Parents[0].Conditions, 1) -} diff --git a/control-plane/api-gateway/binding/snapshot.go b/control-plane/api-gateway/binding/snapshot.go deleted file mode 100644 index 18888a6d46..0000000000 --- a/control-plane/api-gateway/binding/snapshot.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul/api" -) - -// KubernetesSnapshot contains all the operations -// required in Kubernetes to complete reconciliation. -type KubernetesSnapshot struct { - // Updates is the list of objects that need to have - // aspects of their metadata or spec updated in Kubernetes - // (i.e. for finalizers or annotations) - Updates *common.KubernetesUpdates - // StatusUpdates is the list of objects that need - // to have their statuses updated in Kubernetes - StatusUpdates *common.KubernetesUpdates -} - -// ConsulSnapshot contains all the operations required -// in Consul to complete reconciliation. -type ConsulSnapshot struct { - // Updates is the list of ConfigEntry objects that should - // either be updated or created in Consul - Updates []*common.ConsulUpdateOperation - // Deletions is a list of references that ought to be - // deleted in Consul - Deletions []api.ResourceReference - // Registrations is a list of Consul services to make sure - // are registered in Consul - Registrations []api.CatalogRegistration - // Deregistrations is a list of Consul services to make sure - // are no longer registered in Consul - Deregistrations []api.CatalogDeregistration -} - -// Snapshot contains all Kubernetes and Consul operations -// needed to complete reconciliation. -type Snapshot struct { - // Kubernetes holds the snapshot of required Kubernetes operations - Kubernetes *KubernetesSnapshot - // Consul holds the snapshot of required Consul operations - Consul *ConsulSnapshot - // GatewayClassConfig is the configuration to use for determining - // a Gateway deployment, if it is not set, a deployment should be - // deleted instead of updated - GatewayClassConfig *v1alpha1.GatewayClassConfig - - // UpsertGatewayDeployment determines whether the gateway deployment - // objects should be updated, i.e. deployments, roles, services - UpsertGatewayDeployment bool -} - -func NewSnapshot() *Snapshot { - return &Snapshot{ - Kubernetes: &KubernetesSnapshot{ - Updates: common.NewKubernetesUpdates(), - StatusUpdates: common.NewKubernetesUpdates(), - }, - Consul: &ConsulSnapshot{}, - } -} diff --git a/control-plane/api-gateway/binding/validation.go b/control-plane/api-gateway/binding/validation.go deleted file mode 100644 index a2726b8bb1..0000000000 --- a/control-plane/api-gateway/binding/validation.go +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "strings" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - klabels "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - 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" - "github.com/hashicorp/consul-k8s/control-plane/version" - "github.com/hashicorp/consul/api" -) - -var ( - // the list of kinds we can support by listener protocol. - supportedKindsForProtocol = map[gwv1beta1.ProtocolType][]gwv1beta1.RouteGroupKind{ - gwv1beta1.HTTPProtocolType: {{ - Group: (*gwv1beta1.Group)(&gwv1beta1.GroupVersion.Group), - Kind: "HTTPRoute", - }}, - gwv1beta1.HTTPSProtocolType: {{ - Group: (*gwv1beta1.Group)(&gwv1beta1.GroupVersion.Group), - Kind: "HTTPRoute", - }}, - gwv1beta1.TCPProtocolType: {{ - Group: (*gwv1alpha2.Group)(&gwv1alpha2.GroupVersion.Group), - Kind: "TCPRoute", - }}, - } - allSupportedRouteKinds = map[gwv1beta1.Kind]struct{}{ - gwv1beta1.Kind("HTTPRoute"): {}, - gwv1beta1.Kind("TCPRoute"): {}, - } - - allSupportedTLSVersions = map[string]struct{}{ - "TLS_AUTO": {}, - "TLSv1_0": {}, - "TLSv1_1": {}, - "TLSv1_2": {}, - "TLSv1_3": {}, - } - - allTLSVersionsWithConfigurableCipherSuites = map[string]struct{}{ - // Remove "" and "TLS_AUTO" if Envoy ever sets TLS 1.3 as default minimum - "": {}, - "TLS_AUTO": {}, - "TLSv1_0": {}, - "TLSv1_1": {}, - "TLSv1_2": {}, - } - - allSupportedTLSCipherSuites = map[string]struct{}{ - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": {}, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": {}, - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": {}, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": {}, - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": {}, - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": {}, - - // NOTE: the following cipher suites are currently supported by Envoy - // but have been identified as insecure and are pending removal - // https://github.com/envoyproxy/envoy/issues/5399 - "TLS_RSA_WITH_AES_128_GCM_SHA256": {}, - "TLS_RSA_WITH_AES_128_CBC_SHA": {}, - "TLS_RSA_WITH_AES_256_GCM_SHA384": {}, - "TLS_RSA_WITH_AES_256_CBC_SHA": {}, - // https://github.com/envoyproxy/envoy/issues/5400 - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": {}, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": {}, - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": {}, - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": {}, - } -) - -// validateRefs validates backend references for a route, determining whether or -// not they were found in the list of known connect-injected services. -func validateRefs(route client.Object, refs []gwv1beta1.BackendRef, resources *common.ResourceMap) routeValidationResults { - namespace := route.GetNamespace() - - var result routeValidationResults - for _, ref := range refs { - backendRef := ref.BackendObjectReference - - nsn := types.NamespacedName{ - Name: string(backendRef.Name), - Namespace: common.ValueOr(backendRef.Namespace, namespace), - } - - isServiceRef := common.NilOrEqual(backendRef.Group, "") && common.NilOrEqual(backendRef.Kind, common.KindService) - isMeshServiceRef := common.DerefEqual(backendRef.Group, v1alpha1.ConsulHashicorpGroup) && common.DerefEqual(backendRef.Kind, v1alpha1.MeshServiceKind) - - if !isServiceRef && !isMeshServiceRef { - result = append(result, routeValidationResult{ - namespace: nsn.Namespace, - backend: ref, - err: errRouteInvalidKind, - }) - continue - } - - if isServiceRef && !resources.HasService(nsn) { - result = append(result, routeValidationResult{ - namespace: nsn.Namespace, - backend: ref, - err: errRouteBackendNotFound, - }) - continue - } - - if isMeshServiceRef && !resources.HasMeshService(nsn) { - result = append(result, routeValidationResult{ - namespace: nsn.Namespace, - backend: ref, - err: errRouteBackendNotFound, - }) - continue - } - - if !canReferenceBackend(route, ref, resources) { - result = append(result, routeValidationResult{ - namespace: nsn.Namespace, - backend: ref, - err: errRefNotPermitted, - }) - continue - } - - result = append(result, routeValidationResult{ - namespace: nsn.Namespace, - backend: ref, - }) - } - return result -} - -// validateGateway validates that a gateway is semantically valid given -// the set of features that we support. -func validateGateway(gateway gwv1beta1.Gateway, pods []corev1.Pod, consulGateway *api.APIGatewayConfigEntry) gatewayValidationResult { - var result gatewayValidationResult - - if len(gateway.Spec.Addresses) > 0 { - result.acceptedErr = errGatewayUnsupportedAddress - } - - if len(pods) == 0 { - result.programmedErr = errGatewayPending_Pods - } else if consulGateway == nil { - result.programmedErr = errGatewayPending_Consul - } - - return result -} - -// mergedListener associates a listener with its indexed position -// in the gateway spec, it's used to re-associate a status with -// a listener after we merge compatible listeners together and then -// validate their conflicts. -type mergedListener struct { - index int - listener gwv1beta1.Listener -} - -// mergedListeners is a set of a listeners that are considered "merged" -// due to referencing the same listener port. -type mergedListeners []mergedListener - -// validateProtocol validates that the protocols used across all merged -// listeners are compatible. -func (m mergedListeners) validateProtocol() error { - var protocol *gwv1beta1.ProtocolType - for _, l := range m { - if protocol == nil { - protocol = common.PointerTo(l.listener.Protocol) - } - if *protocol != l.listener.Protocol { - return errListenerProtocolConflict - } - } - return nil -} - -// validateHostname validates that the merged listeners don't use the same -// hostnames as per the spec. -func (m mergedListeners) validateHostname(index int, listener gwv1beta1.Listener) error { - for _, l := range m { - if l.index == index { - continue - } - if common.BothNilOrEqual(listener.Hostname, l.listener.Hostname) { - return errListenerHostnameConflict - } - } - return nil -} - -// validateTLS validates that the TLS configuration for a given listener is valid and that -// the certificates that it references exist. -func validateTLS(gateway gwv1beta1.Gateway, tls *gwv1beta1.GatewayTLSConfig, resources *common.ResourceMap) (error, error) { - // If there's no TLS, there's nothing to validate - if tls == nil { - return nil, nil - } - - // Validate the certificate references and then return any error - // alongside any TLS configuration error that we find below. - refsErr := validateCertificateRefs(gateway, tls.CertificateRefs, resources) - - if tls.Mode != nil && *tls.Mode == gwv1beta1.TLSModePassthrough { - return errListenerNoTLSPassthrough, refsErr - } - - if err := validateTLSOptions(tls.Options); err != nil { - return err, refsErr - } - - return nil, refsErr -} - -func validateCertificateRefs(gateway gwv1beta1.Gateway, refs []gwv1beta1.SecretObjectReference, resources *common.ResourceMap) error { - for _, cert := range refs { - // Verify that the reference has a group and kind that we support - if !common.NilOrEqual(cert.Group, "") || !common.NilOrEqual(cert.Kind, common.KindSecret) { - return errListenerInvalidCertificateRef_NotSupported - } - - // Verify that the reference is within the namespace or, - // if cross-namespace, that it's allowed by a ReferenceGrant - if !resources.GatewayCanReferenceSecret(gateway, cert) { - return errRefNotPermitted - } - - // Verify that the referenced resource actually exists - key := common.IndexedNamespacedNameWithDefault(cert.Name, cert.Namespace, gateway.Namespace) - secret := resources.Certificate(key) - if secret == nil { - return errListenerInvalidCertificateRef_NotFound - } - - // Verify that the referenced resource contains the data shape that we expect - if err := validateCertificateData(*secret); err != nil { - return err - } - } - - return nil -} - -func validateTLSOptions(options map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue) error { - if options == nil { - return nil - } - - tlsMinVersionValue := string(options[common.TLSMinVersionAnnotationKey]) - if tlsMinVersionValue != "" { - if _, supported := allSupportedTLSVersions[tlsMinVersionValue]; !supported { - return errListenerUnsupportedTLSMinVersion - } - } - - tlsMaxVersionValue := string(options[common.TLSMaxVersionAnnotationKey]) - if tlsMaxVersionValue != "" { - if _, supported := allSupportedTLSVersions[tlsMaxVersionValue]; !supported { - return errListenerUnsupportedTLSMaxVersion - } - } - - tlsCipherSuitesValue := string(options[common.TLSCipherSuitesAnnotationKey]) - if tlsCipherSuitesValue != "" { - // If a minimum TLS version is configured, verify that it supports configuring cipher suites - if tlsMinVersionValue != "" { - if _, supported := allTLSVersionsWithConfigurableCipherSuites[tlsMinVersionValue]; !supported { - return errListenerTLSCipherSuiteNotConfigurable - } - } - - for _, tlsCipherSuiteValue := range strings.Split(tlsCipherSuitesValue, ",") { - tlsCipherSuite := strings.TrimSpace(tlsCipherSuiteValue) - if _, supported := allSupportedTLSCipherSuites[tlsCipherSuite]; !supported { - return errListenerUnsupportedTLSCipherSuite - } - } - } - - return nil -} - -func validateCertificateData(secret corev1.Secret) error { - _, privateKey, err := common.ParseCertificateData(secret) - if err != nil { - return errListenerInvalidCertificateRef_InvalidData - } - - err = common.ValidateKeyLength(privateKey) - if err != nil { - if version.IsFIPS() { - return errListenerInvalidCertificateRef_FIPSRSAKeyLen - } - - return errListenerInvalidCertificateRef_NonFIPSRSAKeyLen - } - - return nil -} - -// validateListeners validates the given listeners both internally and with respect to each -// other for purposes of setting "Conflicted" status conditions. -func validateListeners(gateway gwv1beta1.Gateway, listeners []gwv1beta1.Listener, resources *common.ResourceMap, gwcc *v1alpha1.GatewayClassConfig) listenerValidationResults { - var results listenerValidationResults - merged := make(map[gwv1beta1.PortNumber]mergedListeners) - for i, listener := range listeners { - merged[listener.Port] = append(merged[listener.Port], mergedListener{ - index: i, - listener: listener, - }) - } - // This list keeps track of port conflicts directly on gateways. i.e., two listeners on the same port as - // defined by the user. - seenListenerPorts := map[int]struct{}{} - // This list keeps track of port conflicts caused by privileged port mappings. - seenContainerPorts := map[int]struct{}{} - portMapping := int32(0) - if gwcc != nil { - portMapping = gwcc.Spec.MapPrivilegedContainerPorts - } - for i, listener := range listeners { - var result listenerValidationResult - - err, refErr := validateTLS(gateway, listener.TLS, resources) - result.refErr = refErr - if err != nil { - result.acceptedErr = err - } else { - _, supported := supportedKindsForProtocol[listener.Protocol] - if !supported { - result.acceptedErr = errListenerUnsupportedProtocol - } else if listener.Port == 20000 { // admin port - result.acceptedErr = errListenerPortUnavailable - } else if _, ok := seenListenerPorts[int(listener.Port)]; ok { - result.acceptedErr = errListenerPortUnavailable - } else if _, ok := seenContainerPorts[common.ToContainerPort(listener.Port, portMapping)]; ok { - result.acceptedErr = errListenerMappedToPrivilegedPortMapping - } - - result.routeKindErr = validateListenerAllowedRouteKinds(listener.AllowedRoutes) - } - - if err := merged[listener.Port].validateProtocol(); err != nil { - result.conflictedErr = err - } else { - result.conflictedErr = merged[listener.Port].validateHostname(i, listener) - } - - results = append(results, result) - - seenListenerPorts[int(listener.Port)] = struct{}{} - seenContainerPorts[common.ToContainerPort(listener.Port, portMapping)] = struct{}{} - } - return results -} - -func validateListenerAllowedRouteKinds(allowedRoutes *gwv1beta1.AllowedRoutes) error { - if allowedRoutes == nil { - return nil - } - for _, kind := range allowedRoutes.Kinds { - if _, ok := allSupportedRouteKinds[kind.Kind]; !ok { - return errListenerInvalidRouteKinds - } - if !common.NilOrEqual(kind.Group, gwv1beta1.GroupVersion.Group) { - return errListenerInvalidRouteKinds - } - } - return nil -} - -// routeAllowedForListenerNamespaces determines whether the route is allowed -// to bind to the Gateway based on the AllowedRoutes namespace selectors. -func routeAllowedForListenerNamespaces(gatewayNamespace string, allowedRoutes *gwv1beta1.AllowedRoutes, namespace corev1.Namespace) bool { - var namespaceSelector *gwv1beta1.RouteNamespaces - if allowedRoutes != nil { - // check gateway namespace - namespaceSelector = allowedRoutes.Namespaces - } - - // set default if namespace selector is nil - from := gwv1beta1.NamespacesFromSame - if namespaceSelector != nil && namespaceSelector.From != nil && *namespaceSelector.From != "" { - from = *namespaceSelector.From - } - - switch from { - case gwv1beta1.NamespacesFromAll: - return true - case gwv1beta1.NamespacesFromSame: - return gatewayNamespace == namespace.Name - case gwv1beta1.NamespacesFromSelector: - namespaceSelector, err := metav1.LabelSelectorAsSelector(namespaceSelector.Selector) - if err != nil { - // log the error here, the label selector is invalid - return false - } - - return namespaceSelector.Matches(toNamespaceSet(namespace.GetName(), namespace.GetLabels())) - default: - return false - } -} - -// routeAllowedForListenerHostname checks that a hostname specified on a route and the hostname specified -// on the gateway listener are compatible. -func routeAllowedForListenerHostname(hostname *gwv1beta1.Hostname, hostnames []gwv1beta1.Hostname) bool { - if hostname == nil || len(hostnames) == 0 { - return true - } - - for _, name := range hostnames { - if hostnamesMatch(name, *hostname) { - return true - } - } - return false -} - -// externalRefsOnRouteAllExist checks to make sure that all external filters referenced by the route exist in the resource map. -func externalRefsOnRouteAllExist(route *gwv1beta1.HTTPRoute, resources *common.ResourceMap) bool { - for _, rule := range route.Spec.Rules { - for _, filter := range rule.Filters { - if filter.Type != gwv1beta1.HTTPRouteFilterExtensionRef { - continue - } - - if !resources.ExternalFilterExists(*filter.ExtensionRef, route.Namespace) { - return false - } - - } - - for _, backendRef := range rule.BackendRefs { - for _, filter := range backendRef.Filters { - if filter.Type != gwv1beta1.HTTPRouteFilterExtensionRef { - continue - } - - if !resources.ExternalFilterExists(*filter.ExtensionRef, route.Namespace) { - return false - } - } - - } - } - - return true -} - -// externalRefsKindAllowedOnRoute makes sure that all externalRefs reference a kind supported by gatewaycontroller. -func externalRefsKindAllowedOnRoute(route *gwv1beta1.HTTPRoute) bool { - for _, rule := range route.Spec.Rules { - if !filtersAllAllowedType(rule.Filters) { - return false - } - - //same thing but for backendref - for _, backendRef := range rule.BackendRefs { - if !filtersAllAllowedType(backendRef.Filters) { - return false - } - } - } - return true -} - -func filtersAllAllowedType(filters []gwv1beta1.HTTPRouteFilter) bool { - for _, filter := range filters { - if filter.ExtensionRef == nil { - continue - } - - if !common.FilterIsExternalFilter(filter) { - return false - } - } - return true -} - -// hostnameMatch checks that an individual hostname matches another hostname for -// compatibility. -func hostnamesMatch(a gwv1alpha2.Hostname, b gwv1beta1.Hostname) bool { - if a == "" || a == "*" || b == "" || b == "*" { - // any wildcard always matches - return true - } - - if strings.HasPrefix(string(a), "*.") || strings.HasPrefix(string(b), "*.") { - aLabels, bLabels := strings.Split(string(a), "."), strings.Split(string(b), ".") - if len(aLabels) != len(bLabels) { - return false - } - - for i := 1; i < len(aLabels); i++ { - if !strings.EqualFold(aLabels[i], bLabels[i]) { - return false - } - } - return true - } - - return string(a) == string(b) -} - -// routeKindIsAllowedForListener checks that the given route kind is present in the allowed set. -func routeKindIsAllowedForListener(kinds []gwv1beta1.RouteGroupKind, gk schema.GroupKind) bool { - if kinds == nil { - return true - } - - for _, kind := range kinds { - if string(kind.Kind) == gk.Kind && common.NilOrEqual(kind.Group, gk.Group) { - return true - } - } - - return false -} - -// routeKindIsAllowedForListenerExplicit checks that a route is allowed by the kinds specified explicitly -// on the listener. -func routeKindIsAllowedForListenerExplicit(allowedRoutes *gwv1alpha2.AllowedRoutes, gk schema.GroupKind) bool { - if allowedRoutes == nil { - return true - } - - return routeKindIsAllowedForListener(allowedRoutes.Kinds, gk) -} - -// toNamespaceSet constructs a list of labels used to match a Namespace. -func toNamespaceSet(name string, labels map[string]string) klabels.Labels { - // If namespace label is not set, implicitly insert it to support older Kubernetes versions - if labels[common.NamespaceNameLabel] == name { - // Already set, avoid copies - return klabels.Set(labels) - } - // First we need a copy to not modify the underlying object - ret := make(map[string]string, len(labels)+1) - for k, v := range labels { - ret[k] = v - } - ret[common.NamespaceNameLabel] = name - return klabels.Set(ret) -} diff --git a/control-plane/api-gateway/binding/validation_test.go b/control-plane/api-gateway/binding/validation_test.go deleted file mode 100644 index 1f2b143387..0000000000 --- a/control-plane/api-gateway/binding/validation_test.go +++ /dev/null @@ -1,862 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package binding - -import ( - "testing" - - logrtest "github.com/go-logr/logr/testing" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestValidateRefs(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - route client.Object - services map[types.NamespacedName]corev1.Service - referenceGrants []gwv1beta1.ReferenceGrant - meshServices []v1alpha1.MeshService - expectedErrors []error - }{ - "all pass no namespaces": { - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{{Name: "1"}, {Name: "2"}}, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "test"}: {}, - {Name: "2", Namespace: "test"}: {}, - {Name: "3", Namespace: "test"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{nil, nil}, - }, - "all fails namespaces no reference grants": { - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - {Name: "2", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "other"}: {}, - {Name: "2", Namespace: "other"}: {}, - {Name: "3", Namespace: "other"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{errRefNotPermitted, errRefNotPermitted}, - }, - "all pass namespaces": { - referenceGrants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "other", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "HTTPRoute", Namespace: gwv1beta1.Namespace("test")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Service"}, - }, - }}, - }, - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - {Name: "2", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "other"}: {}, - {Name: "2", Namespace: "other"}: {}, - {Name: "3", Namespace: "other"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{nil, nil}, - }, - "some pass mixed missing reference grants": { - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - {Name: "2"}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "other"}: {}, - {Name: "2", Namespace: "test"}: {}, - {Name: "3", Namespace: "other"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{errRefNotPermitted, nil}, - }, - "all pass mixed": { - referenceGrants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "other", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "HTTPRoute", Namespace: gwv1beta1.Namespace("test")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Service"}, - }, - }}, - }, - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - {Name: "2"}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "other"}: {}, - {Name: "2", Namespace: "test"}: {}, - {Name: "3", Namespace: "other"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{nil, nil}, - }, - "all fail mixed": { - referenceGrants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "other", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "HTTPRoute", Namespace: gwv1beta1.Namespace("test")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Service"}, - }, - }}, - }, - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1"}, - {Name: "2", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "other"}: {}, - {Name: "2", Namespace: "test"}: {}, - {Name: "3", Namespace: "other"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{errRouteBackendNotFound, errRouteBackendNotFound}, - }, - "all fail no namespaces": { - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1"}, - {Name: "2"}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "other"}: {}, - {Name: "2", Namespace: "other"}: {}, - {Name: "3", Namespace: "other"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{errRouteBackendNotFound, errRouteBackendNotFound}, - }, - "all fail namespaces": { - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - {Name: "2", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "test"}: {}, - {Name: "2", Namespace: "test"}: {}, - {Name: "3", Namespace: "test"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{errRouteBackendNotFound, errRouteBackendNotFound}, - }, - "type failures": { - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - {Name: "1", Group: common.PointerTo[gwv1beta1.Group]("test")}, - {Name: "2"}, - }, nil), - services: map[types.NamespacedName]corev1.Service{ - {Name: "1", Namespace: "test"}: {}, - {Name: "2", Namespace: "test"}: {}, - {Name: "3", Namespace: "test"}: {}, - }, - meshServices: []v1alpha1.MeshService{}, - expectedErrors: []error{errRouteInvalidKind, nil}, - }, - "mesh services": { - route: testHTTPRouteBackends("route", "test", []gwv1beta1.BackendObjectReference{ - { - Name: "1", - Group: common.PointerTo(gwv1beta1.Group(v1alpha1.ConsulHashicorpGroup)), - Kind: common.PointerTo(gwv1beta1.Kind(v1alpha1.MeshServiceKind)), - }, - }, nil), - meshServices: []v1alpha1.MeshService{ - {ObjectMeta: metav1.ObjectMeta{Name: "1", Namespace: "test"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "2", Namespace: "test"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "3", Namespace: "test"}}, - }, - expectedErrors: []error{nil}, - }, - } { - t.Run(name, func(t *testing.T) { - refs := getRouteBackends(tt.route) - resources := common.NewResourceMap(common.ResourceTranslator{}, NewReferenceValidator(tt.referenceGrants), logrtest.NewTestLogger(t)) - for _, service := range tt.meshServices { - resources.AddMeshService(service) - } - for id := range tt.services { - resources.AddService(id, id.Name) - } - - actual := validateRefs(tt.route, refs, resources) - require.Equal(t, len(actual), len(tt.expectedErrors)) - for i, err := range tt.expectedErrors { - require.Equal(t, err, actual[i].err) - } - }) - } -} - -func TestValidateGateway(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - object gwv1beta1.Gateway - expected error - }{ - "valid": { - object: gwv1beta1.Gateway{}, - expected: nil, - }, - "invalid": { - object: gwv1beta1.Gateway{Spec: gwv1beta1.GatewaySpec{Addresses: []gwv1beta1.GatewayAddress{ - {Value: "1"}, - }}}, - expected: errGatewayUnsupportedAddress, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, validateGateway(tt.object, nil, nil).acceptedErr) - }) - } -} - -func TestMergedListeners_ValidateProtocol(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - mergedListeners mergedListeners - expected error - }{ - "valid": { - mergedListeners: []mergedListener{ - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - }, - expected: nil, - }, - "invalid": { - mergedListeners: []mergedListener{ - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.TCPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - }, - expected: errListenerProtocolConflict, - }, - "big list": { - mergedListeners: []mergedListener{ - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPSProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - {listener: gwv1beta1.Listener{Protocol: gwv1beta1.HTTPProtocolType}}, - }, - expected: errListenerProtocolConflict, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, tt.mergedListeners.validateProtocol()) - }) - } -} - -func TestMergedListeners_ValidateHostname(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - mergedListeners mergedListeners - expected error - }{ - "valid": { - mergedListeners: []mergedListener{ - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("1")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("2")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("3")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("4")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("5")}}, - {}, - }, - expected: nil, - }, - "invalid nil": { - mergedListeners: []mergedListener{ - {}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("1")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("2")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("3")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("4")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("5")}}, - {}, - }, - expected: errListenerHostnameConflict, - }, - "invalid set": { - mergedListeners: []mergedListener{ - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("1")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("2")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("3")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("4")}}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("5")}}, - {}, - {listener: gwv1beta1.Listener{Hostname: common.PointerTo[gwv1beta1.Hostname]("1")}}, - }, - expected: errListenerHostnameConflict, - }, - } { - t.Run(name, func(t *testing.T) { - for i, l := range tt.mergedListeners { - l.index = i - tt.mergedListeners[i] = l - } - - require.Equal(t, tt.expected, tt.mergedListeners.validateHostname(0, tt.mergedListeners[0].listener)) - }) - } -} - -func TestValidateTLS(t *testing.T) { - t.Parallel() - - _, secret := generateTestCertificate(t, "", "") - - for name, tt := range map[string]struct { - gateway gwv1beta1.Gateway - grants []gwv1beta1.ReferenceGrant - tls *gwv1beta1.GatewayTLSConfig - certificates []corev1.Secret - expectedResolvedRefsErr error - expectedAcceptedErr error - }{ - "no tls": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: nil, - certificates: nil, - expectedResolvedRefsErr: nil, - expectedAcceptedErr: nil, - }, - "not supported certificate": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "foo", Namespace: common.PointerTo[gwv1beta1.Namespace]("other"), Group: common.PointerTo[gwv1beta1.Group]("test")}, - }, - }, - certificates: []corev1.Secret{ - {ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "other"}}, - }, - expectedResolvedRefsErr: errListenerInvalidCertificateRef_NotSupported, - expectedAcceptedErr: nil, - }, - "not allowed certificate": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "foo", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - }, - }, - certificates: []corev1.Secret{ - {ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "other"}}, - }, - expectedResolvedRefsErr: errRefNotPermitted, - expectedAcceptedErr: nil, - }, - "not found certificate": { - grants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "other", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "Gateway", Namespace: gwv1beta1.Namespace("default")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Secret"}, - }, - }}, - }, - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "zoiks", Namespace: common.PointerTo[gwv1beta1.Namespace]("other")}, - }, - }, - certificates: []corev1.Secret{ - {ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "other"}}, - }, - expectedResolvedRefsErr: errListenerInvalidCertificateRef_NotFound, - expectedAcceptedErr: nil, - }, - "not found certificate mismatched namespace": { - grants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "Gateway", Namespace: gwv1beta1.Namespace("default")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Secret"}, - }, - }}, - }, - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "foo", Namespace: common.PointerTo[gwv1beta1.Namespace]("foo")}, - }, - }, - certificates: []corev1.Secret{ - {ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "other"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "other"}}, - }, - expectedResolvedRefsErr: errListenerInvalidCertificateRef_NotFound, - expectedAcceptedErr: nil, - }, - "passthrough mode": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - Mode: common.PointerTo(gwv1beta1.TLSModePassthrough), - }, - certificates: nil, - expectedResolvedRefsErr: nil, - expectedAcceptedErr: errListenerNoTLSPassthrough, - }, - "valid targeted namespace": { - grants: []gwv1beta1.ReferenceGrant{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "1", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "Gateway", Namespace: gwv1beta1.Namespace("default")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Secret"}, - }, - }}, - {ObjectMeta: metav1.ObjectMeta{Namespace: "2", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "Gateway", Namespace: gwv1beta1.Namespace("default")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Secret"}, - }, - }}, - {ObjectMeta: metav1.ObjectMeta{Namespace: "3", Name: "grant"}, Spec: gwv1beta1.ReferenceGrantSpec{ - From: []gwv1beta1.ReferenceGrantFrom{ - {Group: gwv1beta1.GroupName, Kind: "Gateway", Namespace: gwv1beta1.Namespace("default")}, - }, - To: []gwv1beta1.ReferenceGrantTo{ - {Kind: "Secret"}, - }, - }}, - }, - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "foo", Namespace: common.PointerTo[gwv1beta1.Namespace]("1")}, - {Name: "bar", Namespace: common.PointerTo[gwv1beta1.Namespace]("2")}, - {Name: "baz", Namespace: common.PointerTo[gwv1beta1.Namespace]("3")}, - }, - }, - certificates: []corev1.Secret{ - {ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "1"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "2"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "3"}}, - }, - expectedResolvedRefsErr: nil, - expectedAcceptedErr: nil, - }, - "valid same namespace": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "foo"}, - {Name: "bar"}, - {Name: "baz"}, - }, - }, - certificates: []corev1.Secret{ - {ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "default"}}, - {ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "default"}}, - }, - expectedResolvedRefsErr: nil, - expectedAcceptedErr: nil, - }, - "valid empty certs": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{}, - certificates: nil, - expectedResolvedRefsErr: nil, - expectedAcceptedErr: nil, - }, - "invalid cipher suite": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - Options: map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue{ - common.TLSCipherSuitesAnnotationKey: "invalid", - }, - }, - certificates: nil, - expectedAcceptedErr: errListenerUnsupportedTLSCipherSuite, - }, - "cipher suite not configurable": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - Options: map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue{ - common.TLSMinVersionAnnotationKey: "TLSv1_3", - common.TLSCipherSuitesAnnotationKey: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - }, - }, - certificates: nil, - expectedAcceptedErr: errListenerTLSCipherSuiteNotConfigurable, - }, - "invalid max version": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - Options: map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue{ - common.TLSMaxVersionAnnotationKey: "invalid", - }, - }, - certificates: nil, - expectedAcceptedErr: errListenerUnsupportedTLSMaxVersion, - }, - "invalid min version": { - gateway: gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), - tls: &gwv1beta1.GatewayTLSConfig{ - Options: map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue{ - common.TLSMinVersionAnnotationKey: "invalid", - }, - }, - certificates: nil, - expectedAcceptedErr: errListenerUnsupportedTLSMinVersion, - }, - } { - t.Run(name, func(t *testing.T) { - resources := common.NewResourceMap(common.ResourceTranslator{}, NewReferenceValidator(tt.grants), logrtest.NewTestLogger(t)) - for _, certificate := range tt.certificates { - // make the data valid - certificate.Data = secret.Data - resources.ReferenceCountCertificate(certificate) - } - - actualAcceptedError, actualResolvedRefsError := validateTLS(tt.gateway, tt.tls, resources) - require.Equal(t, tt.expectedResolvedRefsErr, actualResolvedRefsError) - require.Equal(t, tt.expectedAcceptedErr, actualAcceptedError) - }) - } -} - -func TestValidateListeners(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - listeners []gwv1beta1.Listener - expectedAcceptedErr error - listenerIndexToTest int - mapPrivilegedContainerPorts int32 - }{ - "valid protocol HTTP": { - listeners: []gwv1beta1.Listener{ - {Protocol: gwv1beta1.HTTPProtocolType}, - }, - expectedAcceptedErr: nil, - }, - "valid protocol HTTPS": { - listeners: []gwv1beta1.Listener{ - {Protocol: gwv1beta1.HTTPSProtocolType}, - }, - expectedAcceptedErr: nil, - }, - "valid protocol TCP": { - listeners: []gwv1beta1.Listener{ - {Protocol: gwv1beta1.TCPProtocolType}, - }, - expectedAcceptedErr: nil, - }, - "invalid protocol UDP": { - listeners: []gwv1beta1.Listener{ - {Protocol: gwv1beta1.UDPProtocolType}, - }, - expectedAcceptedErr: errListenerUnsupportedProtocol, - }, - "invalid port": { - listeners: []gwv1beta1.Listener{ - {Protocol: gwv1beta1.TCPProtocolType, Port: 20000}, - }, - expectedAcceptedErr: errListenerPortUnavailable, - }, - "conflicted port": { - listeners: []gwv1beta1.Listener{ - {Protocol: gwv1beta1.TCPProtocolType, Port: 80}, - {Protocol: gwv1beta1.TCPProtocolType, Port: 80}, - }, - expectedAcceptedErr: errListenerPortUnavailable, - listenerIndexToTest: 1, - }, - "conflicted mapped port": { - listeners: []gwv1beta1.Listener{ - {Protocol: gwv1beta1.TCPProtocolType, Port: 80}, - {Protocol: gwv1beta1.TCPProtocolType, Port: 2080}, - }, - expectedAcceptedErr: errListenerMappedToPrivilegedPortMapping, - listenerIndexToTest: 1, - mapPrivilegedContainerPorts: 2000, - }, - } { - t.Run(name, func(t *testing.T) { - gwcc := &v1alpha1.GatewayClassConfig{ - Spec: v1alpha1.GatewayClassConfigSpec{ - MapPrivilegedContainerPorts: tt.mapPrivilegedContainerPorts, - }, - } - - require.Equal(t, tt.expectedAcceptedErr, validateListeners(gatewayWithFinalizer(gwv1beta1.GatewaySpec{}), tt.listeners, nil, gwcc)[tt.listenerIndexToTest].acceptedErr) - }) - } -} - -func TestRouteAllowedForListenerNamespaces(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - allowedRoutes *gwv1beta1.AllowedRoutes - gatewayNamespace string - routeNamespace corev1.Namespace - expected bool - }{ - "default same namespace allowed": { - allowedRoutes: nil, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test"}}, - expected: true, - }, - "default same namespace not allowed": { - allowedRoutes: nil, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "other"}}, - expected: false, - }, - "explicit same namespace allowed": { - allowedRoutes: &gwv1beta1.AllowedRoutes{Namespaces: &gwv1beta1.RouteNamespaces{From: common.PointerTo(gwv1beta1.NamespacesFromSame)}}, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test"}}, - expected: true, - }, - "explicit same namespace not allowed": { - allowedRoutes: &gwv1beta1.AllowedRoutes{Namespaces: &gwv1beta1.RouteNamespaces{From: common.PointerTo(gwv1beta1.NamespacesFromSame)}}, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "other"}}, - expected: false, - }, - "all namespace allowed": { - allowedRoutes: &gwv1beta1.AllowedRoutes{Namespaces: &gwv1beta1.RouteNamespaces{From: common.PointerTo(gwv1beta1.NamespacesFromAll)}}, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "other"}}, - expected: true, - }, - "invalid namespace from not allowed": { - allowedRoutes: &gwv1beta1.AllowedRoutes{Namespaces: &gwv1beta1.RouteNamespaces{From: common.PointerTo[gwv1beta1.FromNamespaces]("other")}}, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test"}}, - expected: false, - }, - "labeled namespace allowed": { - allowedRoutes: &gwv1beta1.AllowedRoutes{Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromSelector), - Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, - }}, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "other", Labels: map[string]string{ - "foo": "bar", - }}}, - expected: true, - }, - "labeled namespace not allowed": { - allowedRoutes: &gwv1beta1.AllowedRoutes{Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromSelector), - Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, - }}, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "other", Labels: map[string]string{ - "foo": "baz", - }}}, - expected: false, - }, - "invalid labeled namespace": { - allowedRoutes: &gwv1beta1.AllowedRoutes{Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.NamespacesFromSelector), - Selector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{ - {Key: "foo", Operator: "junk", Values: []string{"1"}}, - }}, - }}, - gatewayNamespace: "test", - routeNamespace: corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "other", Labels: map[string]string{ - "foo": "bar", - }}}, - expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, routeAllowedForListenerNamespaces(tt.gatewayNamespace, tt.allowedRoutes, tt.routeNamespace)) - }) - } -} - -func TestRouteAllowedForListenerHostname(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - hostname *gwv1beta1.Hostname - hostnames []gwv1beta1.Hostname - expected bool - }{ - "empty hostnames": { - hostname: nil, - hostnames: []gwv1beta1.Hostname{"foo", "bar"}, - expected: true, - }, - "empty hostname": { - hostname: common.PointerTo[gwv1beta1.Hostname]("foo"), - hostnames: nil, - expected: true, - }, - "any hostname match": { - hostname: common.PointerTo[gwv1beta1.Hostname]("foo"), - hostnames: []gwv1beta1.Hostname{"foo", "bar"}, - expected: true, - }, - "no match": { - hostname: common.PointerTo[gwv1beta1.Hostname]("foo"), - hostnames: []gwv1beta1.Hostname{"bar"}, - expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, routeAllowedForListenerHostname(tt.hostname, tt.hostnames)) - }) - } -} - -func TestHostnamesMatch(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - one gwv1beta1.Hostname - two gwv1beta1.Hostname - expected bool - }{ - "wildcard one": { - one: "*", - two: "foo", - expected: true, - }, - "wildcard two": { - one: "foo", - two: "*", - expected: true, - }, - "empty one": { - one: "", - two: "foo", - expected: true, - }, - "empty two": { - one: "foo", - two: "", - expected: true, - }, - "subdomain one": { - one: "*.foo", - two: "sub.foo", - expected: true, - }, - "subdomain two": { - one: "sub.foo", - two: "*.foo", - expected: true, - }, - "exact match": { - one: "foo", - two: "foo", - expected: true, - }, - "no match": { - one: "foo", - two: "bar", - expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, hostnamesMatch(tt.one, tt.two)) - }) - } -} - -func TestRouteKindIsAllowedForListener(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - kinds []gwv1beta1.RouteGroupKind - gk schema.GroupKind - expected bool - }{ - "empty kinds": { - kinds: nil, - gk: schema.GroupKind{Group: "a", Kind: "b"}, - expected: true, - }, - "group specified": { - kinds: []gwv1beta1.RouteGroupKind{ - {Group: common.PointerTo[gwv1beta1.Group]("a"), Kind: "b"}, - }, - gk: schema.GroupKind{Group: "a", Kind: "b"}, - expected: true, - }, - "group unspecified": { - kinds: []gwv1beta1.RouteGroupKind{ - {Kind: "b"}, - }, - gk: schema.GroupKind{Group: "a", Kind: "b"}, - expected: true, - }, - "kind mismatch": { - kinds: []gwv1beta1.RouteGroupKind{ - {Kind: "b"}, - }, - gk: schema.GroupKind{Group: "a", Kind: "c"}, - expected: false, - }, - "group mismatch": { - kinds: []gwv1beta1.RouteGroupKind{ - {Group: common.PointerTo[gwv1beta1.Group]("a"), Kind: "b"}, - }, - gk: schema.GroupKind{Group: "d", Kind: "b"}, - expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, routeKindIsAllowedForListener(tt.kinds, tt.gk)) - }) - } -} diff --git a/control-plane/api-gateway/cache/consul.go b/control-plane/api-gateway/cache/consul.go deleted file mode 100644 index 7737e80d57..0000000000 --- a/control-plane/api-gateway/cache/consul.go +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cache - -import ( - "bytes" - "context" - "fmt" - "strings" - "sync" - "text/template" - "time" - - "github.com/go-logr/logr" - "golang.org/x/exp/slices" - "sigs.k8s.io/controller-runtime/pkg/event" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" - "github.com/hashicorp/consul/api" -) - -func init() { - gatewayTpl = template.Must(template.New("root").Parse(strings.TrimSpace(gatewayRulesTpl))) -} - -type templateArgs struct { - EnableNamespaces bool -} - -var ( - gatewayTpl *template.Template - gatewayRulesTpl = ` -mesh = "read" -{{- if .EnableNamespaces }} - namespace_prefix "" { -{{- end }} - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "write" - } -{{- if .EnableNamespaces }} - } -{{- end }} -` -) - -const ( - namespaceWildcard = "*" - apiTimeout = 5 * time.Minute -) - -var Kinds = []string{api.APIGateway, api.HTTPRoute, api.TCPRoute, api.InlineCertificate} - -type Config struct { - ConsulClientConfig *consul.Config - ConsulServerConnMgr consul.ServerConnectionManager - NamespacesEnabled bool - Datacenter string - CrossNamespaceACLPolicy string - Logger logr.Logger -} - -// Cache subscribes to and caches Consul objects, it also responsible for mainting subscriptions to -// resources that it caches. -type Cache struct { - config *consul.Config - serverMgr consul.ServerConnectionManager - logger logr.Logger - - cache map[string]*common.ReferenceMap - cacheMutex *sync.Mutex - - subscribers map[string][]*Subscription - subscriberMutex *sync.Mutex - - namespacesEnabled bool - crossNamespaceACLPolicy string - - synced chan struct{} - - kinds []string - - datacenter string -} - -func New(config Config) *Cache { - cache := make(map[string]*common.ReferenceMap, len(Kinds)) - for _, kind := range Kinds { - cache[kind] = common.NewReferenceMap() - } - config.ConsulClientConfig.APITimeout = apiTimeout - - return &Cache{ - config: config.ConsulClientConfig, - serverMgr: config.ConsulServerConnMgr, - namespacesEnabled: config.NamespacesEnabled, - cache: cache, - cacheMutex: &sync.Mutex{}, - subscribers: make(map[string][]*Subscription), - subscriberMutex: &sync.Mutex{}, - kinds: Kinds, - synced: make(chan struct{}, len(Kinds)), - logger: config.Logger, - crossNamespaceACLPolicy: config.CrossNamespaceACLPolicy, - datacenter: config.Datacenter, - } -} - -// WaitSynced is used to coordinate with the caller when the cache is initially filled. -func (c *Cache) WaitSynced(ctx context.Context) { - for range c.kinds { - select { - case <-c.synced: - case <-ctx.Done(): - return - } - } -} - -// Subscribe handles adding a new subscription for resources of a given kind. -func (c *Cache) Subscribe(ctx context.Context, kind string, translator TranslatorFn) *Subscription { - c.subscriberMutex.Lock() - defer c.subscriberMutex.Unlock() - - // check that kind is registered with cache - if !slices.Contains(c.kinds, kind) { - return &Subscription{} - } - - subscribers, ok := c.subscribers[kind] - if !ok { - subscribers = []*Subscription{} - } - - ctx, cancel := context.WithCancel(ctx) - events := make(chan event.GenericEvent) - sub := &Subscription{ - translator: translator, - ctx: ctx, - cancelCtx: cancel, - events: events, - } - - subscribers = append(subscribers, sub) - - c.subscribers[kind] = subscribers - - return sub -} - -// Run starts the cache watch cycle, on the first call it will fill the cache with existing resources. -func (c *Cache) Run(ctx context.Context) { - wg := &sync.WaitGroup{} - - for i := range c.kinds { - kind := c.kinds[i] - - wg.Add(1) - go func() { - defer wg.Done() - c.subscribeToConsul(ctx, kind) - }() - } - - wg.Wait() -} - -func (c *Cache) subscribeToConsul(ctx context.Context, kind string) { - once := &sync.Once{} - - opts := &api.QueryOptions{} - if c.namespacesEnabled { - opts.Namespace = namespaceWildcard - } - - for { - select { - case <-ctx.Done(): - return - default: - } - - client, err := consul.NewClientFromConnMgr(c.config, c.serverMgr) - if err != nil { - c.logger.Error(err, "error initializing consul client") - continue - } - - entries, meta, err := client.ConfigEntries().List(kind, 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") { - c.logger.Error(err, fmt.Sprintf("error fetching config entries for kind: %s", kind)) - } - continue - } - - opts.WaitIndex = meta.LastIndex - - c.updateAndNotify(ctx, once, kind, entries) - - select { - case <-ctx.Done(): - return - default: - continue - } - } -} - -func (c *Cache) updateAndNotify(ctx context.Context, once *sync.Once, kind string, entries []api.ConfigEntry) { - c.cacheMutex.Lock() - - cache := common.NewReferenceMap() - - for _, entry := range entries { - meta := entry.GetMeta() - if meta[constants.MetaKeyKubeName] == "" || meta[constants.MetaKeyDatacenter] != c.datacenter { - // Don't process things that don't belong to us. The main reason - // for this is so that we don't garbage collect config entries that - // are either user-created or that another controller running in a - // federated datacenter creates. While we still allow for competing controllers - // syncing/overriding each other due to conflicting Kubernetes objects in - // two federated clusters (which is what the rest of the controllers also allow - // for), we don't want to delete a config entry just because we don't have - // its corresponding Kubernetes object if we know it belongs to another datacenter. - continue - } - - cache.Set(common.EntryToReference(entry), entry) - } - - diffs := c.cache[kind].Diff(cache) - - c.cache[kind] = cache - - // we run this the first time the cache is filled to notify the waiter - once.Do(func() { - c.logger.Info("sync mark for " + kind) - c.synced <- struct{}{} - }) - - c.cacheMutex.Unlock() - - // now notify all subscribers - c.notifySubscribers(ctx, kind, diffs) -} - -// notifySubscribers notifies each subscriber for a given kind on changes to a config entry of that kind. It also -// handles removing any subscribers that have marked themselves as done. -func (c *Cache) notifySubscribers(ctx context.Context, kind string, entries []api.ConfigEntry) { - c.subscriberMutex.Lock() - defer c.subscriberMutex.Unlock() - - for _, entry := range entries { - // this will hold the new list of current subscribers after we finish notifying - subscribers := make([]*Subscription, 0, len(c.subscribers[kind])) - for _, subscriber := range c.subscribers[kind] { - addSubscriber := false - - for _, namespaceName := range subscriber.translator(entry) { - event := event.GenericEvent{ - Object: newConfigEntryObject(namespaceName), - } - - select { - case <-ctx.Done(): - return - case <-subscriber.ctx.Done(): - // don't add this subscriber to current list because it is done - addSubscriber = false - case subscriber.events <- event: - // keep this one since we can send events to it - addSubscriber = true - } - } - - if addSubscriber { - subscribers = append(subscribers, subscriber) - } - } - c.subscribers[kind] = subscribers - } -} - -// Write handles writing the config entry back to Consul, if the current reference of the -// config entry is stale then it returns an error. -func (c *Cache) Write(ctx context.Context, entry api.ConfigEntry) error { - c.cacheMutex.Lock() - defer c.cacheMutex.Unlock() - - entryMap, ok := c.cache[entry.GetKind()] - if !ok { - return nil - } - - ref := common.EntryToReference(entry) - - old := entryMap.Get(ref) - if old != nil && common.EntriesEqual(old, entry) { - return nil - } - - client, err := consul.NewClientFromConnMgr(c.config, c.serverMgr) - if err != nil { - return err - } - - if c.namespacesEnabled { - if _, err := namespaces.EnsureExists(client, entry.GetNamespace(), c.crossNamespaceACLPolicy); err != nil { - return err - } - } - - options := &api.WriteOptions{} - - _, _, err = client.ConfigEntries().Set(entry, options.WithContext(ctx)) - if err != nil { - return err - } - - return nil -} - -func (c *Cache) ensurePolicy(client *api.Client) (string, error) { - policy := c.gatewayPolicy() - - created, _, err := client.ACL().PolicyCreate(&policy, &api.WriteOptions{}) - - if isPolicyExistsErr(err, policy.Name) { - existing, _, err := client.ACL().PolicyReadByName(policy.Name, &api.QueryOptions{}) - if err != nil { - return "", err - } - return existing.ID, nil - } - if err != nil { - return "", err - } - return created.ID, nil -} - -func (c *Cache) ensureRole(client *api.Client) (string, error) { - policyID, err := c.ensurePolicy(client) - if err != nil { - return "", err - } - - aclRoleName := "managed-gateway-acl-role" - - aclRole, _, err := client.ACL().RoleReadByName(aclRoleName, &api.QueryOptions{}) - if err != nil { - return "", err - } - if aclRole != nil { - return aclRoleName, nil - } - - role := &api.ACLRole{ - Name: aclRoleName, - Description: "ACL Role for Managed API Gateways", - Policies: []*api.ACLLink{{ID: policyID}}, - } - - _, _, err = client.ACL().RoleCreate(role, &api.WriteOptions{}) - return aclRoleName, err -} - -func (c *Cache) gatewayPolicy() api.ACLPolicy { - var data bytes.Buffer - if err := gatewayTpl.Execute(&data, templateArgs{ - EnableNamespaces: c.namespacesEnabled, - }); err != nil { - // just panic if we can't compile the simple template - // as it means something else is going severly wrong. - panic(err) - } - - return api.ACLPolicy{ - Name: "api-gateway-token-policy", - Description: "API Gateway token Policy", - Rules: data.String(), - } -} - -// Get returns a config entry from the cache that corresponds to the given resource reference. -func (c *Cache) Get(ref api.ResourceReference) api.ConfigEntry { - c.cacheMutex.Lock() - defer c.cacheMutex.Unlock() - - entryMap, ok := c.cache[ref.Kind] - if !ok { - return nil - } - - return entryMap.Get(ref) -} - -// Delete handles deleting the config entry from consul, if the current reference of the config entry is stale then -// it returns an error. -func (c *Cache) Delete(ctx context.Context, ref api.ResourceReference) error { - c.cacheMutex.Lock() - defer c.cacheMutex.Unlock() - - entryMap, ok := c.cache[ref.Kind] - if !ok { - return nil - } - - if entryMap.Get(ref) == nil { - c.logger.Info("cached object not found, not deleting") - return nil - } - - client, err := consul.NewClientFromConnMgr(c.config, c.serverMgr) - if err != nil { - return err - } - - options := &api.WriteOptions{} - - _, err = client.ConfigEntries().Delete(ref.Kind, ref.Name, options.WithContext(ctx)) - return err -} - -// List returns a list of config entries from the cache that corresponds to the given kind. -func (c *Cache) List(kind string) []api.ConfigEntry { - c.cacheMutex.Lock() - defer c.cacheMutex.Unlock() - - refMap, ok := c.cache[kind] - if !ok { - return nil - } - - return refMap.Entries() -} - -func (c *Cache) EnsureRoleBinding(authMethod, service, namespace string) error { - client, err := consul.NewClientFromConnMgr(c.config, c.serverMgr) - if err != nil { - return err - } - - role, err := c.ensureRole(client) - if err != nil { - return ignoreACLsDisabled(err) - } - - bindingRule := &api.ACLBindingRule{ - Description: fmt.Sprintf("Binding Rule for %s/%s", namespace, service), - AuthMethod: authMethod, - Selector: fmt.Sprintf("serviceaccount.name==%q and serviceaccount.namespace==%q", service, namespace), - BindType: api.BindingRuleBindTypeRole, - BindName: role, - } - - existingRules, _, err := client.ACL().BindingRuleList(authMethod, &api.QueryOptions{}) - if err != nil { - return err - } - - for _, existingRule := range existingRules { - if existingRule.BindName == bindingRule.BindName && existingRule.Description == bindingRule.Description { - bindingRule.ID = existingRule.ID - } - } - - if bindingRule.ID == "" { - _, _, err := client.ACL().BindingRuleCreate(bindingRule, &api.WriteOptions{}) - return err - } - _, _, err = client.ACL().BindingRuleUpdate(bindingRule, &api.WriteOptions{}) - return err -} - -// Register registers a service in Consul. -func (c *Cache) Register(ctx context.Context, registration api.CatalogRegistration) error { - client, err := consul.NewClientFromConnMgr(c.config, c.serverMgr) - if err != nil { - return err - } - - options := &api.WriteOptions{} - - _, err = client.Catalog().Register(®istration, options.WithContext(ctx)) - return err -} - -// Deregister deregisters a service in Consul. -func (c *Cache) Deregister(ctx context.Context, deregistration api.CatalogDeregistration) error { - client, err := consul.NewClientFromConnMgr(c.config, c.serverMgr) - if err != nil { - return err - } - - options := &api.WriteOptions{} - - _, err = client.Catalog().Deregister(&deregistration, options.WithContext(ctx)) - return err -} - -func ignoreACLsDisabled(err error) error { - if err == nil { - return nil - } - if err.Error() == "Unexpected response code: 401 (ACL support disabled)" { - return nil - } - 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 err != nil && - strings.Contains(err.Error(), "Unexpected response code: 500") && - strings.Contains(err.Error(), fmt.Sprintf("Invalid Policy: A Policy with Name %q already exists", policyName)) -} diff --git a/control-plane/api-gateway/cache/consul_test.go b/control-plane/api-gateway/cache/consul_test.go deleted file mode 100644 index 59570e532f..0000000000 --- a/control-plane/api-gateway/cache/consul_test.go +++ /dev/null @@ -1,2027 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cache - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "strconv" - "testing" - - "github.com/go-logr/logr" - 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" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/event" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/helper/test" - "github.com/hashicorp/consul/api" -) - -func Test_resourceCache_diff(t *testing.T) { - t.Parallel() - type args struct { - newCache *common.ReferenceMap - } - tests := []struct { - name string - oldCache *common.ReferenceMap - args args - want []api.ConfigEntry - }{ - { - name: "no difference", - oldCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - args: args{ - newCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - }, - want: []api.ConfigEntry{}, - }, - { - name: "resource exists in old cache but not new one", - oldCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route 2", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-2", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - args: args{ - newCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - }, - want: []api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route 2", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-2", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - }, - }, - { - name: "resource exists in new cache but not old one", - oldCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - args: args{ - newCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route 2", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-2", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - }, - want: []api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route 2", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-2", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - }, - }, - { - name: "same ref new cache has a greater modify index", - oldCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - ModifyIndex: 1, - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - args: args{ - newCache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - ModifyIndex: 10, - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - })[api.HTTPRoute], - }, - want: []api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - ModifyIndex: 10, - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - }, - }, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - got := tt.oldCache.Diff(tt.args.newCache) - if diff := cmp.Diff(got, tt.want); diff != "" { - t.Errorf("resourceCache.diff mismatch (-want +got):\n%s", diff) - } - }) - } -} - -func TestCache_Subscribe(t *testing.T) { - t.Parallel() - type args struct { - ctx context.Context - kind string - translator TranslatorFn - } - tests := []struct { - name string - args args - subscribers map[string][]*Subscription - subscriberChange int - }{ - { - name: "new subscription added when there are no other subscribers of the same kind", - args: args{ - ctx: context.Background(), - kind: api.HTTPRoute, - translator: func(api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{} - }, - }, - subscriberChange: 1, - }, - { - name: "new subscription added when there are existing subscribers of the same kind", - args: args{ - ctx: context.Background(), - kind: api.HTTPRoute, - translator: func(api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{} - }, - }, - subscribers: map[string][]*Subscription{ - api.HTTPRoute: { - { - translator: func(api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{} - }, - ctx: context.Background(), - cancelCtx: func() { - }, - events: make(chan event.GenericEvent), - }, - }, - }, - subscriberChange: 1, - }, - { - name: "subscription for kind that does not exist does not change any subscriber counts", - args: args{ - ctx: context.Background(), - kind: "UnknownKind", - translator: func(api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{} - }, - }, - subscriberChange: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := New(Config{ - ConsulClientConfig: &consul.Config{ - APIClientConfig: &api.Config{}, - HTTPPort: 0, - GRPCPort: 0, - APITimeout: 0, - }, - ConsulServerConnMgr: consul.NewMockServerConnectionManager(t), - NamespacesEnabled: false, - Logger: logr.Logger{}, - }) - - if len(tt.subscribers) > 0 { - c.subscribers = tt.subscribers - } - - kindSubscriberCounts := make(map[string]int) - for kind, subscribers := range c.subscribers { - kindSubscriberCounts[kind] = len(subscribers) - } - - c.Subscribe(tt.args.ctx, tt.args.kind, tt.args.translator) - - for kind, subscribers := range c.subscribers { - expectedSubscriberCount := kindSubscriberCounts[kind] - if kind == tt.args.kind { - expectedSubscriberCount += tt.subscriberChange - } - actualSubscriberCount := len(subscribers) - - if expectedSubscriberCount != actualSubscriberCount { - t.Errorf("Expected there to be %d subscribers, there were %d", expectedSubscriberCount, actualSubscriberCount) - } - } - }) - } -} - -func TestCache_Write(t *testing.T) { - t.Parallel() - testCases := []struct { - name string - responseFn func(w http.ResponseWriter) - expectedErr error - }{ - { - name: "write is successful", - responseFn: func(w http.ResponseWriter) { - w.WriteHeader(200) - fmt.Fprintln(w, `{updated: true}`) - }, - expectedErr: nil, - }, - } - - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - consulServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/v1/config": - tt.responseFn(w) - case "/v1/catalog/services": - fmt.Fprintln(w, `{}`) - 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 := New(Config{ - ConsulClientConfig: &consul.Config{ - APIClientConfig: &api.Config{}, - HTTPPort: port, - GRPCPort: port, - APITimeout: 0, - }, - ConsulServerConnMgr: test.MockConnMgrForIPAndPort(serverURL.Hostname(), port), - NamespacesEnabled: false, - Logger: logrtest.NewTestLogger(t), - }) - - entry := &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - } - - err = c.Write(context.Background(), entry) - require.Equal(t, err, tt.expectedErr) - }) - } -} - -func TestCache_Get(t *testing.T) { - t.Parallel() - type args struct { - ref api.ResourceReference - } - tests := []struct { - name string - args args - want api.ConfigEntry - cache map[string]*common.ReferenceMap - }{ - { - name: "entry exists", - args: args{ - ref: api.ResourceReference{ - Kind: api.APIGateway, - Name: "api-gw", - }, - }, - want: &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "api-gw", - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - }, - cache: loadedReferenceMaps([]api.ConfigEntry{ - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "api-gw", - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - }, - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "api-gw-2", - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - }, - }), - }, - { - name: "entry does not exist", - args: args{ - ref: api.ResourceReference{ - Kind: api.APIGateway, - Name: "api-gw-4", - }, - }, - want: nil, - cache: loadedReferenceMaps([]api.ConfigEntry{ - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "api-gw", - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - }, - &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "api-gw-2", - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - }, - }), - }, - { - name: "kind key does not exist", - args: args{ - ref: api.ResourceReference{ - Kind: api.APIGateway, - Name: "api-gw-4", - }, - }, - want: nil, - cache: loadedReferenceMaps([]api.ConfigEntry{ - &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "route", - Meta: map[string]string{ - constants.MetaKeyKubeName: "name", - }, - }, - }), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := New(Config{ - ConsulClientConfig: &consul.Config{ - APIClientConfig: &api.Config{}, - }, - }) - c.cache = tt.cache - - got := c.Get(tt.args.ref) - - if diff := cmp.Diff(got, tt.want); diff != "" { - t.Errorf("Cache.Get mismatch (-want +got):\n%s", diff) - } - }) - } -} - -func Test_Run(t *testing.T) { - t.Parallel() - // setup httproutes - httpRouteOne, httpRouteTwo := setupHTTPRoutes() - httpRoutes := []*api.HTTPRouteConfigEntry{httpRouteOne, httpRouteTwo} - - // setup gateway - gw := setupGateway() - gateways := []*api.APIGatewayConfigEntry{gw} - - // setup TCPRoutes - tcpRoute := setupTCPRoute() - tcpRoutes := []*api.TCPRouteConfigEntry{tcpRoute} - - // setup inline certs - inlineCert := setupInlineCertificate() - certs := []*api.InlineCertificateConfigEntry{inlineCert} - - consulServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/v1/config/http-route": - val, err := json.Marshal(httpRoutes) - if err != nil { - w.WriteHeader(500) - fmt.Fprintln(w, err) - return - } - fmt.Fprintln(w, string(val)) - case "/v1/config/api-gateway": - val, err := json.Marshal(gateways) - if err != nil { - w.WriteHeader(500) - fmt.Fprintln(w, err) - return - } - fmt.Fprintln(w, string(val)) - case "/v1/config/tcp-route": - val, err := json.Marshal(tcpRoutes) - if err != nil { - w.WriteHeader(500) - fmt.Fprintln(w, err) - return - } - fmt.Fprintln(w, string(val)) - case "/v1/config/inline-certificate": - val, err := json.Marshal(certs) - if err != nil { - w.WriteHeader(500) - fmt.Fprintln(w, err) - return - } - fmt.Fprintln(w, string(val)) - case "/v1/catalog/services": - fmt.Fprintln(w, `{}`) - case "/v1/peerings": - fmt.Fprintln(w, `[]`) - 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 := New(Config{ - ConsulClientConfig: &consul.Config{ - APIClientConfig: &api.Config{}, - HTTPPort: port, - GRPCPort: port, - APITimeout: 0, - }, - ConsulServerConnMgr: test.MockConnMgrForIPAndPort(serverURL.Hostname(), port), - NamespacesEnabled: false, - Logger: logrtest.NewTestLogger(t), - }) - prevCache := make(map[string]*common.ReferenceMap) - for kind, cache := range c.cache { - resCache := common.NewReferenceMap() - for _, entry := range cache.Entries() { - resCache.Set(common.EntryToReference(entry), entry) - } - prevCache[kind] = resCache - } - - expectedCache := loadedReferenceMaps([]api.ConfigEntry{ - gw, tcpRoute, httpRouteOne, httpRouteTwo, inlineCert, - }) - - ctx, cancelFn := context.WithCancel(context.Background()) - - httpRouteOneNsn := types.NamespacedName{ - Name: httpRouteOne.Name, - Namespace: httpRouteOne.Namespace, - } - - httpRouteTwoNsn := types.NamespacedName{ - Name: httpRouteTwo.Name, - Namespace: httpRouteTwo.Namespace, - } - - httpRouteSubscriber := c.Subscribe(ctx, api.HTTPRoute, func(cfe api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{ - {Name: cfe.GetName(), Namespace: cfe.GetNamespace()}, - } - }) - - canceledSub := c.Subscribe(ctx, api.HTTPRoute, func(cfe api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{ - {Name: cfe.GetName(), Namespace: cfe.GetNamespace()}, - } - }) - - gwNsn := types.NamespacedName{ - Name: gw.Name, - Namespace: gw.Namespace, - } - - gwSubscriber := c.Subscribe(ctx, api.APIGateway, func(cfe api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{ - {Name: cfe.GetName(), Namespace: cfe.GetNamespace()}, - } - }) - - tcpRouteNsn := types.NamespacedName{ - Name: tcpRoute.Name, - Namespace: tcpRoute.Namespace, - } - - tcpRouteSubscriber := c.Subscribe(ctx, api.TCPRoute, func(cfe api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{ - {Name: cfe.GetName(), Namespace: cfe.GetNamespace()}, - } - }) - - certNsn := types.NamespacedName{ - Name: inlineCert.Name, - Namespace: inlineCert.Namespace, - } - - certSubscriber := c.Subscribe(ctx, api.InlineCertificate, func(cfe api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{ - {Name: cfe.GetName(), Namespace: cfe.GetNamespace()}, - } - }) - - // mark this subscription as ended - canceledSub.Cancel() - - go c.Run(ctx) - - // Check subscribers - httpRouteExpectedEvents := []event.GenericEvent{{Object: newConfigEntryObject(httpRouteOneNsn)}, {Object: newConfigEntryObject(httpRouteTwoNsn)}} - gwExpectedEvent := event.GenericEvent{Object: newConfigEntryObject(gwNsn)} - tcpExpectedEvent := event.GenericEvent{Object: newConfigEntryObject(tcpRouteNsn)} - certExpectedEvent := event.GenericEvent{Object: newConfigEntryObject(certNsn)} - - // 2 http routes + 1 gw + 1 tcp route + 1 cert = 5 - i := 5 - for { - if i == 0 { - break - } - select { - case actualHTTPRouteEvent := <-httpRouteSubscriber.Events(): - require.Contains(t, httpRouteExpectedEvents, actualHTTPRouteEvent) - case actualGWEvent := <-gwSubscriber.Events(): - require.Equal(t, gwExpectedEvent, actualGWEvent) - case actualTCPRouteEvent := <-tcpRouteSubscriber.Events(): - require.Equal(t, tcpExpectedEvent, actualTCPRouteEvent) - case actualCertExpectedEvent := <-certSubscriber.Events(): - require.Equal(t, certExpectedEvent, actualCertExpectedEvent) - } - i -= 1 - } - - // the canceled Subscription should not receive any events - require.Zero(t, len(canceledSub.Events())) - c.WaitSynced(ctx) - - // cancel the context so the Run function exits - cancelFn() - - sorter := func(x, y api.ConfigEntry) bool { - return x.GetName() < y.GetName() - } - // Check cache - // expect the cache to have changed - for _, kind := range Kinds { - if diff := cmp.Diff(prevCache[kind].Entries(), c.cache[kind].Entries(), cmpopts.SortSlices(sorter)); diff == "" { - t.Error("Expect cache to have changed but it did not") - } - - if diff := cmp.Diff(expectedCache[kind].Entries(), c.cache[kind].Entries(), cmpopts.SortSlices(sorter)); diff != "" { - t.Errorf("Cache.cache mismatch (-want +got):\n%s", diff) - } - } -} - -func setupHTTPRoutes() (*api.HTTPRouteConfigEntry, *api.HTTPRouteConfigEntry) { - routeOne := &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-1", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - "metaKey": "metaVal", - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - } - routeTwo := &api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "my route 2", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener-2", - Namespace: "ns", - }, - }, - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{"hostname.com"}, - Meta: map[string]string{ - "metakey": "meta val", - constants.MetaKeyKubeName: "name", - }, - } - return routeOne, routeTwo -} - -func setupGateway() *api.APIGatewayConfigEntry { - return &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: "api-gw", - Meta: map[string]string{ - "metakey": "meta val", - constants.MetaKeyKubeName: "name", - }, - Listeners: []api.APIGatewayListener{ - { - Name: "listener one", - Hostname: "hostname.com", - Port: 3350, - Protocol: "https", - TLS: api.APIGatewayTLSConfiguration{}, - }, - }, - } -} - -func setupTCPRoute() *api.TCPRouteConfigEntry { - return &api.TCPRouteConfigEntry{ - Kind: api.TCPRoute, - Name: "tcp route", - Parents: []api.ResourceReference{ - { - Kind: api.APIGateway, - Name: "api-gw", - SectionName: "listener two", - }, - }, - Services: []api.TCPService{ - { - Name: "tcp service", - }, - }, - Meta: map[string]string{ - "metakey": "meta val", - constants.MetaKeyKubeName: "name", - }, - Status: api.ConfigEntryStatus{}, - } -} - -func setupInlineCertificate() *api.InlineCertificateConfigEntry { - return &api.InlineCertificateConfigEntry{ - Kind: api.InlineCertificate, - Name: "inline-cert", - Certificate: "cert", - PrivateKey: "super secret", - Meta: map[string]string{ - "metaKey": "meta val", - constants.MetaKeyKubeName: "name", - }, - } -} - -func TestCache_Delete(t *testing.T) { - t.Parallel() - testCases := []struct { - name string - responseFn func(w http.ResponseWriter) - expectedErr error - }{ - { - name: "delete is successful", - responseFn: func(w http.ResponseWriter) { - w.WriteHeader(200) - fmt.Fprintln(w, `{deleted: true}`) - }, - expectedErr: nil, - }, - } - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - ref := api.ResourceReference{ - Name: "my-route", - Kind: api.HTTPRoute, - } - consulServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case fmt.Sprintf("/v1/config/%s/%s", ref.Kind, ref.Name): - tt.responseFn(w) - 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 := New(Config{ - ConsulClientConfig: &consul.Config{ - APIClientConfig: &api.Config{}, - HTTPPort: port, - GRPCPort: port, - APITimeout: 0, - }, - ConsulServerConnMgr: test.MockConnMgrForIPAndPort(serverURL.Hostname(), port), - NamespacesEnabled: false, - Logger: logrtest.NewTestLogger(t), - }) - - err = c.Delete(context.Background(), ref) - require.ErrorIs(t, err, tt.expectedErr) - }) - } -} - -func loadedReferenceMaps(entries []api.ConfigEntry) map[string]*common.ReferenceMap { - refs := make(map[string]*common.ReferenceMap) - - for _, entry := range entries { - refMap, ok := refs[entry.GetKind()] - if !ok { - refMap = common.NewReferenceMap() - } - refMap.Set(common.EntryToReference(entry), entry) - refs[entry.GetKind()] = refMap - } - return refs -} diff --git a/control-plane/api-gateway/cache/gateway.go b/control-plane/api-gateway/cache/gateway.go deleted file mode 100644 index 0d79542eec..0000000000 --- a/control-plane/api-gateway/cache/gateway.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cache - -import ( - "context" - "fmt" - "sync" - - "github.com/cenkalti/backoff" - "github.com/go-logr/logr" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul/api" - "k8s.io/apimachinery/pkg/types" -) - -type GatewayCache struct { - config Config - serverMgr consul.ServerConnectionManager - logger logr.Logger - - data map[api.ResourceReference][]api.CatalogService - dataMutex sync.RWMutex - - subscribedGateways map[api.ResourceReference]context.CancelFunc - mutex sync.RWMutex - - ctx context.Context -} - -func NewGatewayCache(ctx context.Context, config Config) *GatewayCache { - return &GatewayCache{ - config: config, - serverMgr: config.ConsulServerConnMgr, - logger: config.Logger, - data: make(map[api.ResourceReference][]api.CatalogService), - subscribedGateways: make(map[api.ResourceReference]context.CancelFunc), - ctx: ctx, - } -} - -func (r *GatewayCache) ServicesFor(ref api.ResourceReference) []api.CatalogService { - r.dataMutex.RLock() - defer r.dataMutex.RUnlock() - - return r.data[common.NormalizeMeta(ref)] -} - -func (r *GatewayCache) FetchServicesFor(ctx context.Context, ref api.ResourceReference) ([]api.CatalogService, error) { - client, err := consul.NewClientFromConnMgr(r.config.ConsulClientConfig, r.serverMgr) - if err != nil { - return nil, err - } - - opts := &api.QueryOptions{} - if r.config.NamespacesEnabled && ref.Namespace != "" { - opts.Namespace = ref.Namespace - } - - services, _, err := client.Catalog().Service(ref.Name, "", opts.WithContext(ctx)) - if err != nil { - return nil, err - } - return common.DerefAll(services), nil -} - -func (r *GatewayCache) EnsureSubscribed(ref api.ResourceReference, resource types.NamespacedName) { - r.mutex.Lock() - defer r.mutex.Unlock() - - if _, exists := r.subscribedGateways[common.NormalizeMeta(ref)]; exists { - return - } - - ctx, cancel := context.WithCancel(r.ctx) - r.subscribedGateways[common.NormalizeMeta(ref)] = cancel - go r.subscribeToGateway(ctx, ref, resource) -} - -func (r *GatewayCache) RemoveSubscription(ref api.ResourceReference) { - r.mutex.Lock() - defer r.mutex.Unlock() - - if cancel, exists := r.subscribedGateways[common.NormalizeMeta(ref)]; exists { - cancel() - delete(r.subscribedGateways, common.NormalizeMeta(ref)) - } -} - -func (r *GatewayCache) subscribeToGateway(ctx context.Context, ref api.ResourceReference, resource types.NamespacedName) { - opts := &api.QueryOptions{} - if r.config.NamespacesEnabled && ref.Namespace != "" { - opts.Namespace = ref.Namespace - } - - var ( - services []*api.CatalogService - meta *api.QueryMeta - ) - - for { - select { - case <-ctx.Done(): - r.dataMutex.Lock() - delete(r.data, ref) - r.dataMutex.Unlock() - return - default: - } - - retryBackoff := backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 10) - - if err := backoff.Retry(func() error { - client, err := consul.NewClientFromConnMgr(r.config.ConsulClientConfig, r.serverMgr) - if err != nil { - return err - } - - services, meta, err = client.Catalog().Service(ref.Name, "", opts.WithContext(ctx)) - if err != nil { - return err - } - - return nil - }, backoff.WithContext(retryBackoff, ctx)); err != nil { - r.logger.Error(err, fmt.Sprintf("unable to fetch config entry for gateway: %s/%s", ref.Namespace, ref.Name)) - continue - } - - opts.WaitIndex = meta.LastIndex - - derefed := common.DerefAll(services) - - r.dataMutex.Lock() - r.data[common.NormalizeMeta(ref)] = derefed - r.dataMutex.Unlock() - } -} diff --git a/control-plane/api-gateway/cache/kubernetes.go b/control-plane/api-gateway/cache/kubernetes.go deleted file mode 100644 index 642a6935fb..0000000000 --- a/control-plane/api-gateway/cache/kubernetes.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cache - -import ( - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// configEntryObject is used for generic k8s events so we maintain the consul name/namespace. -type configEntryObject struct { - client.Object // embed so we fufill the object interface - - Namespace string - Name string -} - -func (c *configEntryObject) GetNamespace() string { - return c.Namespace -} - -func (c *configEntryObject) GetName() string { - return c.Name -} - -func newConfigEntryObject(namespacedName types.NamespacedName) *configEntryObject { - return &configEntryObject{ - Namespace: namespacedName.Namespace, - Name: namespacedName.Name, - } -} diff --git a/control-plane/api-gateway/cache/subscription.go b/control-plane/api-gateway/cache/subscription.go deleted file mode 100644 index 8605c95926..0000000000 --- a/control-plane/api-gateway/cache/subscription.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package cache - -import ( - "context" - - "github.com/hashicorp/consul/api" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/event" -) - -type TranslatorFn func(api.ConfigEntry) []types.NamespacedName - -// Subscription represents a watcher for events on a specific kind. -type Subscription struct { - translator TranslatorFn - ctx context.Context - cancelCtx context.CancelFunc - events chan event.GenericEvent -} - -func (s *Subscription) Cancel() { - s.cancelCtx() -} - -func (s *Subscription) Events() chan event.GenericEvent { - return s.events -} diff --git a/control-plane/api-gateway/common/constants.go b/control-plane/api-gateway/common/constants.go deleted file mode 100644 index 04701662b7..0000000000 --- a/control-plane/api-gateway/common/constants.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -const ( - GatewayClassControllerName = "consul.hashicorp.com/gateway-controller" - - AnnotationGatewayClassConfig = "consul.hashicorp.com/gateway-class-config" - - // The following annotation keys are used in the v1beta1.GatewayTLSConfig's Options on a v1beta1.Listener. - TLSCipherSuitesAnnotationKey = "api-gateway.consul.hashicorp.com/tls_cipher_suites" - TLSMaxVersionAnnotationKey = "api-gateway.consul.hashicorp.com/tls_max_version" - TLSMinVersionAnnotationKey = "api-gateway.consul.hashicorp.com/tls_min_version" -) diff --git a/control-plane/api-gateway/common/diff.go b/control-plane/api-gateway/common/diff.go deleted file mode 100644 index a50581ca31..0000000000 --- a/control-plane/api-gateway/common/diff.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "strings" - - "github.com/hashicorp/consul/api" - "golang.org/x/exp/maps" - "golang.org/x/exp/slices" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func GatewayStatusesEqual(a, b gwv1beta1.GatewayStatus) bool { - return slices.EqualFunc(a.Addresses, b.Addresses, gatewayStatusesAddressesEqual) && - slices.EqualFunc(a.Conditions, b.Conditions, conditionsEqual) && - slices.EqualFunc(a.Listeners, b.Listeners, gatewayStatusesListenersEqual) -} - -func gatewayStatusesAddressesEqual(a, b gwv1beta1.GatewayAddress) bool { - return BothNilOrEqual(a.Type, b.Type) && - a.Value == b.Value -} - -func gatewayStatusesListenersEqual(a, b gwv1beta1.ListenerStatus) bool { - return a.AttachedRoutes == b.AttachedRoutes && - a.Name == b.Name && - slices.EqualFunc(a.SupportedKinds, b.SupportedKinds, routeGroupKindsEqual) && - slices.EqualFunc(a.Conditions, b.Conditions, conditionsEqual) -} - -func routeGroupKindsEqual(a, b gwv1beta1.RouteGroupKind) bool { - return BothNilOrEqual(a.Group, b.Group) && - a.Kind == b.Kind -} - -// this intentionally ignores the last set time so we don't -// always fail a conditional check per-reconciliation. -func conditionsEqual(a, b metav1.Condition) bool { - return a.Type == b.Type && - a.Status == b.Status && - a.Reason == b.Reason && - a.Message == b.Message && - a.ObservedGeneration == b.ObservedGeneration -} - -func EntriesEqual(a, b api.ConfigEntry) bool { - switch aCast := a.(type) { - case *api.APIGatewayConfigEntry: - if bCast, ok := b.(*api.APIGatewayConfigEntry); ok { - return apiGatewaysEqual(aCast, bCast) - } - case *api.HTTPRouteConfigEntry: - if bCast, ok := b.(*api.HTTPRouteConfigEntry); ok { - return httpRoutesEqual(aCast, bCast) - } - case *api.TCPRouteConfigEntry: - if bCast, ok := b.(*api.TCPRouteConfigEntry); ok { - return tcpRoutesEqual(aCast, bCast) - } - case *api.InlineCertificateConfigEntry: - if bCast, ok := b.(*api.InlineCertificateConfigEntry); ok { - return certificatesEqual(aCast, bCast) - } - } - return false -} - -type entryComparator struct { - namespaceA string - partitionA string - namespaceB string - partitionB string -} - -func apiGatewaysEqual(a, b *api.APIGatewayConfigEntry) bool { - if a == nil || b == nil { - return false - } - - return (entryComparator{ - namespaceA: NormalizeEmptyMetadataString(a.Namespace), - partitionA: NormalizeEmptyMetadataString(a.Partition), - namespaceB: NormalizeEmptyMetadataString(b.Namespace), - partitionB: NormalizeEmptyMetadataString(b.Partition), - }).apiGatewaysEqual(*a, *b) -} - -func (e entryComparator) apiGatewaysEqual(a, b api.APIGatewayConfigEntry) bool { - return a.Kind == b.Kind && - a.Name == b.Name && - e.namespaceA == e.namespaceB && - e.partitionA == e.partitionB && - maps.Equal(a.Meta, b.Meta) && - slices.EqualFunc(a.Listeners, b.Listeners, e.apiGatewayListenersEqual) -} - -func (e entryComparator) apiGatewayListenersEqual(a, b api.APIGatewayListener) bool { - return a.Hostname == b.Hostname && - a.Name == b.Name && - a.Port == b.Port && - // normalize the protocol name - strings.EqualFold(a.Protocol, b.Protocol) && - e.apiGatewayListenerTLSConfigurationsEqual(a.TLS, b.TLS) -} - -func (e entryComparator) apiGatewayListenerTLSConfigurationsEqual(a, b api.APIGatewayTLSConfiguration) bool { - return a.MaxVersion == b.MaxVersion && - a.MinVersion == b.MinVersion && - slices.Equal(a.CipherSuites, b.CipherSuites) && - slices.EqualFunc(a.Certificates, b.Certificates, e.resourceReferencesEqual) -} - -func (e entryComparator) resourceReferencesEqual(a, b api.ResourceReference) bool { - return a.Kind == b.Kind && - a.Name == b.Name && - a.SectionName == b.SectionName && - orDefault(a.Namespace, e.namespaceA) == orDefault(b.Namespace, e.namespaceB) && - orDefault(a.Partition, e.partitionA) == orDefault(b.Partition, e.partitionB) -} - -func httpRoutesEqual(a, b *api.HTTPRouteConfigEntry) bool { - if a == nil || b == nil { - return false - } - - return (entryComparator{ - namespaceA: NormalizeEmptyMetadataString(a.Namespace), - partitionA: NormalizeEmptyMetadataString(a.Partition), - namespaceB: NormalizeEmptyMetadataString(b.Namespace), - partitionB: NormalizeEmptyMetadataString(b.Partition), - }).httpRoutesEqual(*a, *b) -} - -func (e entryComparator) httpRoutesEqual(a, b api.HTTPRouteConfigEntry) bool { - return a.Kind == b.Kind && - a.Name == b.Name && - e.namespaceA == e.namespaceB && - e.partitionA == e.partitionB && - maps.Equal(a.Meta, b.Meta) && - slices.Equal(a.Hostnames, b.Hostnames) && - slices.EqualFunc(a.Parents, b.Parents, e.resourceReferencesEqual) && - slices.EqualFunc(a.Rules, b.Rules, e.httpRouteRulesEqual) -} - -func (e entryComparator) httpRouteRulesEqual(a, b api.HTTPRouteRule) bool { - return slices.EqualFunc(a.Filters.Headers, b.Filters.Headers, e.httpHeaderFiltersEqual) && - bothNilOrEqualFunc(a.Filters.URLRewrite, b.Filters.URLRewrite, e.urlRewritesEqual) && - slices.EqualFunc(a.Matches, b.Matches, e.httpMatchesEqual) && - slices.EqualFunc(a.Services, b.Services, e.httpServicesEqual) && - bothNilOrEqualFunc(a.Filters.RetryFilter, b.Filters.RetryFilter, e.retryFiltersEqual) && - bothNilOrEqualFunc(a.Filters.TimeoutFilter, b.Filters.TimeoutFilter, e.timeoutFiltersEqual) -} - -func (e entryComparator) httpServicesEqual(a, b api.HTTPService) bool { - return a.Name == b.Name && - a.Weight == b.Weight && - orDefault(a.Namespace, e.namespaceA) == orDefault(b.Namespace, e.namespaceB) && - orDefault(a.Partition, e.partitionA) == orDefault(b.Partition, e.partitionB) && - slices.EqualFunc(a.Filters.Headers, b.Filters.Headers, e.httpHeaderFiltersEqual) && - bothNilOrEqualFunc(a.Filters.URLRewrite, b.Filters.URLRewrite, e.urlRewritesEqual) -} - -func (e entryComparator) httpMatchesEqual(a, b api.HTTPMatch) bool { - return a.Method == b.Method && - slices.EqualFunc(a.Headers, b.Headers, e.httpHeaderMatchesEqual) && - slices.EqualFunc(a.Query, b.Query, e.httpQueryMatchesEqual) && - e.httpPathMatchesEqual(a.Path, b.Path) -} - -func (e entryComparator) httpPathMatchesEqual(a, b api.HTTPPathMatch) bool { - return a.Match == b.Match && a.Value == b.Value -} - -func (e entryComparator) httpHeaderMatchesEqual(a, b api.HTTPHeaderMatch) bool { - return a.Match == b.Match && a.Name == b.Name && a.Value == b.Value -} - -func (e entryComparator) httpQueryMatchesEqual(a, b api.HTTPQueryMatch) bool { - return a.Match == b.Match && a.Name == b.Name && a.Value == b.Value -} - -func (e entryComparator) httpHeaderFiltersEqual(a, b api.HTTPHeaderFilter) bool { - return maps.Equal(a.Add, b.Add) && - maps.Equal(a.Set, b.Set) && - slices.Equal(a.Remove, b.Remove) -} - -func (e entryComparator) urlRewritesEqual(a, b api.URLRewrite) bool { - return a.Path == b.Path -} - -func (e entryComparator) retryFiltersEqual(a, b api.RetryFilter) bool { - return BothNilOrEqual(a.NumRetries, b.NumRetries) && BothNilOrEqual(a.RetryOnConnectFailure, b.RetryOnConnectFailure) && - slices.Equal(a.RetryOn, b.RetryOn) && slices.Equal(a.RetryOnStatusCodes, b.RetryOnStatusCodes) -} - -func (e entryComparator) timeoutFiltersEqual(a, b api.TimeoutFilter) bool { - return a.RequestTimeout == b.RequestTimeout && a.IdleTimeout == b.IdleTimeout -} - -func tcpRoutesEqual(a, b *api.TCPRouteConfigEntry) bool { - if a == nil || b == nil { - return false - } - - return (entryComparator{ - namespaceA: NormalizeEmptyMetadataString(a.Namespace), - partitionA: NormalizeEmptyMetadataString(a.Partition), - namespaceB: NormalizeEmptyMetadataString(b.Namespace), - partitionB: NormalizeEmptyMetadataString(b.Partition), - }).tcpRoutesEqual(*a, *b) -} - -func (e entryComparator) tcpRoutesEqual(a, b api.TCPRouteConfigEntry) bool { - return a.Kind == b.Kind && - a.Name == b.Name && - e.namespaceA == e.namespaceB && - e.partitionA == e.partitionB && - maps.Equal(a.Meta, b.Meta) && - slices.EqualFunc(a.Parents, b.Parents, e.resourceReferencesEqual) && - slices.EqualFunc(a.Services, b.Services, e.tcpRouteServicesEqual) -} - -func (e entryComparator) tcpRouteServicesEqual(a, b api.TCPService) bool { - return a.Name == b.Name && - orDefault(a.Namespace, e.namespaceA) == orDefault(b.Namespace, e.namespaceB) && - orDefault(a.Partition, e.partitionA) == orDefault(b.Partition, e.partitionB) -} - -func certificatesEqual(a, b *api.InlineCertificateConfigEntry) bool { - if a == nil || b == nil { - return false - } - - return (entryComparator{ - namespaceA: NormalizeEmptyMetadataString(a.Namespace), - partitionA: NormalizeEmptyMetadataString(a.Partition), - namespaceB: NormalizeEmptyMetadataString(b.Namespace), - partitionB: NormalizeEmptyMetadataString(b.Partition), - }).certificatesEqual(*a, *b) -} - -func (e entryComparator) certificatesEqual(a, b api.InlineCertificateConfigEntry) bool { - return a.Kind == b.Kind && - a.Name == b.Name && - e.namespaceA == e.namespaceB && - e.partitionA == e.partitionB && - maps.Equal(a.Meta, b.Meta) && - a.Certificate == b.Certificate && - a.PrivateKey == b.PrivateKey -} - -func bothNilOrEqualFunc[T any](one, two *T, fn func(T, T) bool) bool { - if one == nil && two == nil { - return true - } - if one == nil { - return false - } - if two == nil { - return false - } - return fn(*one, *two) -} - -func orDefault[T ~string](v T, fallback string) string { - if v == "" { - return fallback - } - return string(v) -} diff --git a/control-plane/api-gateway/common/finalizers.go b/control-plane/api-gateway/common/finalizers.go deleted file mode 100644 index e1fe84bdac..0000000000 --- a/control-plane/api-gateway/common/finalizers.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -const ( - // GatewayFinalizer is the finalizer we add to any gateway object. - GatewayFinalizer = "gateway-finalizer.consul.hashicorp.com" - - // NamespaceNameLabel represents that label added automatically to namespaces in newer Kubernetes clusters. - NamespaceNameLabel = "kubernetes.io/metadata.name" -) - -var ( - // constants extracted for ease of use. - KindGateway = "Gateway" - KindSecret = "Secret" - KindService = "Service" - BetaGroup = gwv1beta1.GroupVersion.Group -) - -// EnsureFinalizer ensures that our finalizer is set on an object -// returning whether or not it modified the object. -func EnsureFinalizer(object client.Object) bool { - if !object.GetDeletionTimestamp().IsZero() { - return false - } - - finalizers := object.GetFinalizers() - for _, f := range finalizers { - if f == GatewayFinalizer { - return false - } - } - - object.SetFinalizers(append(finalizers, GatewayFinalizer)) - return true -} - -// RemoveFinalizer ensures that our finalizer is absent from an object -// returning whether or not it modified the object. -func RemoveFinalizer(object client.Object) bool { - found := false - filtered := []string{} - for _, f := range object.GetFinalizers() { - if f == GatewayFinalizer { - found = true - continue - } - filtered = append(filtered, f) - } - - object.SetFinalizers(filtered) - return found -} diff --git a/control-plane/api-gateway/common/helm_config.go b/control-plane/api-gateway/common/helm_config.go deleted file mode 100644 index 7ce8e0778a..0000000000 --- a/control-plane/api-gateway/common/helm_config.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "strings" - "time" -) - -const componentAuthMethod = "k8s-component-auth-method" - -// HelmConfig is the configuration of gateways that comes in from the user's Helm values. -// This is a combination of the apiGateway stanza and other settings that impact api-gateways. -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 - ConsulDestinationNamespace string - NamespaceMirroringPrefix string - EnableNamespaces bool - EnableNamespaceMirroring bool - AuthMethod string - - // LogLevel is the logging level of the deployed Consul Dataplanes. - LogLevel string - ConsulPartition string - LogJSON bool - TLSEnabled bool - PeeringEnabled bool - ConsulTLSServerName string - ConsulCACert string - ConsulConfig ConsulConfig - - // EnableOpenShift indicates whether we're deploying into an OpenShift environment - // and should create SecurityContextConstraints. - EnableOpenShift bool - - // MapPrivilegedServicePorts is the value which Consul will add to privileged container port values (ports < 1024) - // defined on a Gateway. - MapPrivilegedServicePorts int -} - -type ConsulConfig struct { - Address string - GRPCPort int - HTTPPort int - APITimeout time.Duration -} - -func (h HelmConfig) Normalize() HelmConfig { - if h.AuthMethod != "" { - // strip off any DC naming off the back in case we're - // in a secondary DC, in which case our auth method is - // going to be a globally scoped auth method, and we want - // to target the locally scoped one, which is the auth - // method without the DC-specific suffix. - tokens := strings.Split(h.AuthMethod, componentAuthMethod) - if len(tokens) != 2 { - // skip the normalization if we can't do it. - return h - } - h.AuthMethod = tokens[0] + componentAuthMethod - } - return h -} diff --git a/control-plane/api-gateway/common/helpers.go b/control-plane/api-gateway/common/helpers.go deleted file mode 100644 index f2ac883571..0000000000 --- a/control-plane/api-gateway/common/helpers.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul/api" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func DerefAll[T any](vs []*T) []T { - e := make([]T, 0, len(vs)) - for _, v := range vs { - e = append(e, *v) - } - return e -} - -func EmptyOrEqual(v, check string) bool { - return v == "" || v == check -} - -func NilOrEqual[T ~string](v *T, check string) bool { - return v == nil || string(*v) == check -} - -func FilterIsExternalFilter(filter gwv1beta1.HTTPRouteFilter) bool { - if filter.Type != gwv1beta1.HTTPRouteFilterExtensionRef { - return false - } - - if !DerefEqual(&filter.ExtensionRef.Group, v1alpha1.ConsulHashicorpGroup) { - return false - } - - switch filter.ExtensionRef.Kind { - case v1alpha1.RouteRetryFilterKind, v1alpha1.RouteTimeoutFilterKind: - return true - } - - return false - -} - -func IndexedNamespacedNameWithDefault[T ~string, U ~string, V ~string](t T, u *U, v V) types.NamespacedName { - return types.NamespacedName{ - Namespace: DerefStringOr(u, v), - Name: string(t), - } -} - -func ResourceReferenceWithDefault[T ~string, U ~string, V ~string](kind string, name T, section string, u *U, v V, partition string) api.ResourceReference { - return api.ResourceReference{ - Kind: kind, - Name: string(name), - SectionName: section, - Namespace: DerefStringOr(u, v), - Partition: partition, - } -} - -func DerefStringOr[T ~string, U ~string](v *T, val U) string { - if v == nil { - return string(val) - } - return string(*v) -} - -func DerefLookup[T comparable, U any](v *T, lookup map[T]U) U { - var zero U - if v == nil { - return zero - } - return lookup[*v] -} - -func DerefConvertFunc[T any, U any](v *T, fn func(T) U) U { - var zero U - if v == nil { - return zero - } - return fn(*v) -} - -func DerefEqual[T ~string](v *T, check string) bool { - if v == nil { - return false - } - return string(*v) == check -} - -func DerefIntOr[T ~int | ~int32, U ~int](v *T, val U) int { - if v == nil { - return int(val) - } - return int(*v) -} - -func StringLikeSlice[T ~string](vs []T) []string { - converted := []string{} - for _, v := range vs { - converted = append(converted, string(v)) - } - return converted -} - -func ConvertMapValuesToSlice[T comparable, U any](vs map[T]U) []U { - converted := []U{} - for _, v := range vs { - converted = append(converted, v) - } - return converted -} - -func ConvertSliceFunc[T any, U any](vs []T, fn func(T) U) []U { - converted := []U{} - for _, v := range vs { - converted = append(converted, fn(v)) - } - return converted -} - -func ConvertSliceFuncIf[T any, U any](vs []T, fn func(T) (U, bool)) []U { - converted := []U{} - for _, v := range vs { - if c, ok := fn(v); ok { - converted = append(converted, c) - } - } - return converted -} - -func Flatten[T any](vs [][]T) []T { - flattened := []T{} - for _, v := range vs { - flattened = append(flattened, v...) - } - return flattened -} - -func Filter[T any](vs []T, filterFn func(T) bool) []T { - filtered := []T{} - for _, v := range vs { - if !filterFn(v) { - filtered = append(filtered, v) - } - } - return filtered -} - -func DefaultOrEqual(v, fallback, check string) bool { - if v == "" { - return fallback == check - } - return v == check -} - -// ObjectsToReconcileRequests takes a list of objects and returns a list of -// reconcile Requests. -func ObjectsToReconcileRequests[T metav1.Object](objects []T) []reconcile.Request { - requests := make([]reconcile.Request, 0, len(objects)) - - for _, object := range objects { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: object.GetNamespace(), - Name: object.GetName(), - }, - }) - } - return requests -} - -// ParentRefs takes a list of ParentReference objects and returns a list of NamespacedName objects. -func ParentRefs(group, kind, namespace string, refs []gwv1beta1.ParentReference) []types.NamespacedName { - indexed := make([]types.NamespacedName, 0, len(refs)) - for _, parent := range refs { - if NilOrEqual(parent.Group, group) && NilOrEqual(parent.Kind, kind) { - indexed = append(indexed, IndexedNamespacedNameWithDefault(parent.Name, parent.Namespace, namespace)) - } - } - return indexed -} - -// BothNilOrEqual is used to determine if two pointers to comparable -// object are either nil or both point to the same value. -func BothNilOrEqual[T comparable](one, two *T) bool { - if one == nil && two == nil { - return true - } - if one == nil { - return false - } - if two == nil { - return false - } - return *one == *two -} - -// ValueOr checks if a string-like pointer is nil, and if it is, -// returns the given value instead. -func ValueOr[T ~string](v *T, fallback string) string { - if v == nil { - return fallback - } - return string(*v) -} - -// PointerTo is a convenience method for taking a pointer -// of an object without having to declare an intermediate variable. -// It's also useful for making sure we don't accidentally take -// the pointer of a range variable directly. -func PointerTo[T any](v T) *T { - return &v -} - -// ParentsEqual checks for equality between two parent references. -func ParentsEqual(one, two gwv1beta1.ParentReference) bool { - return BothNilOrEqual(one.Group, two.Group) && - BothNilOrEqual(one.Kind, two.Kind) && - BothNilOrEqual(one.SectionName, two.SectionName) && - BothNilOrEqual(one.Port, two.Port) && - one.Name == two.Name -} - -func EntryToReference(entry api.ConfigEntry) api.ResourceReference { - return api.ResourceReference{ - Kind: entry.GetKind(), - Name: entry.GetName(), - Partition: entry.GetPartition(), - Namespace: entry.GetNamespace(), - } -} diff --git a/control-plane/api-gateway/common/helpers_test.go b/control-plane/api-gateway/common/helpers_test.go deleted file mode 100644 index 62070b434c..0000000000 --- a/control-plane/api-gateway/common/helpers_test.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "testing" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestBothNilOrEqual(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - first *string - second *string - expected bool - }{ - "both nil": { - first: nil, - second: nil, - expected: true, - }, - "second nil": { - first: PointerTo(""), - second: nil, - expected: false, - }, - "first nil": { - first: nil, - second: PointerTo(""), - expected: false, - }, - "both equal": { - first: PointerTo(""), - second: PointerTo(""), - expected: true, - }, - "both not equal": { - first: PointerTo("1"), - second: PointerTo("2"), - expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, BothNilOrEqual(tt.first, tt.second)) - }) - } -} - -func TestValueOr(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - value *string - or string - expected string - }{ - "nil value": { - value: nil, - or: "test", - expected: "test", - }, - "set value": { - value: PointerTo("value"), - or: "test", - expected: "value", - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, ValueOr(tt.value, tt.or)) - }) - } -} - -func TestNilOrEqual(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - value *string - check string - expected bool - }{ - "nil value": { - value: nil, - check: "test", - expected: true, - }, - "equal values": { - value: PointerTo("test"), - check: "test", - expected: true, - }, - "unequal values": { - value: PointerTo("value"), - check: "test", - expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, NilOrEqual(tt.value, tt.check)) - }) - } -} - -func TestEnsureFinalizer(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - object client.Object - expected bool - finalizers []string - }{ - "gateway no finalizer": { - object: &gwv1beta1.Gateway{}, - expected: true, - finalizers: []string{GatewayFinalizer}, - }, - "gateway other finalizer": { - object: &gwv1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"other"}}}, - expected: true, - finalizers: []string{"other", GatewayFinalizer}, - }, - "gateway already has finalizer": { - object: &gwv1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{GatewayFinalizer}}}, - expected: false, - finalizers: []string{GatewayFinalizer}, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, EnsureFinalizer(tt.object)) - require.Equal(t, tt.finalizers, tt.object.GetFinalizers()) - }) - } -} - -func TestRemoveFinalizer(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - object client.Object - expected bool - finalizers []string - }{ - "gateway no finalizer": { - object: &gwv1beta1.Gateway{}, - expected: false, - finalizers: []string{}, - }, - "gateway other finalizer": { - object: &gwv1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"other"}}}, - expected: false, - finalizers: []string{"other"}, - }, - "gateway multiple finalizers": { - object: &gwv1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{GatewayFinalizer, GatewayFinalizer}}}, - expected: true, - finalizers: []string{}, - }, - "gateway mixed finalizers": { - object: &gwv1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"other", GatewayFinalizer}}}, - expected: true, - finalizers: []string{"other"}, - }, - } { - t.Run(name, func(t *testing.T) { - require.Equal(t, tt.expected, RemoveFinalizer(tt.object)) - require.Equal(t, tt.finalizers, tt.object.GetFinalizers()) - }) - } -} diff --git a/control-plane/api-gateway/common/labels.go b/control-plane/api-gateway/common/labels.go deleted file mode 100644 index cba13a603e..0000000000 --- a/control-plane/api-gateway/common/labels.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "fmt" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -const ( - nameLabel = "gateway.consul.hashicorp.com/name" - namespaceLabel = "gateway.consul.hashicorp.com/namespace" - createdAtLabel = "gateway.consul.hashicorp.com/created" - ManagedLabel = "gateway.consul.hashicorp.com/managed" -) - -// LabelsForGateway formats the default labels that appear on objects managed by the controllers. -func LabelsForGateway(gateway *gwv1beta1.Gateway) map[string]string { - return map[string]string{ - nameLabel: gateway.Name, - namespaceLabel: gateway.Namespace, - createdAtLabel: fmt.Sprintf("%d", gateway.CreationTimestamp.Unix()), - ManagedLabel: "true", - } -} - -func GatewayFromPod(pod *corev1.Pod) (types.NamespacedName, bool) { - if pod.Labels[ManagedLabel] == "true" { - return types.NamespacedName{ - Name: pod.Labels[nameLabel], - Namespace: pod.Labels[namespaceLabel], - }, true - } - return types.NamespacedName{}, false -} diff --git a/control-plane/api-gateway/common/reference.go b/control-plane/api-gateway/common/reference.go deleted file mode 100644 index 78935c11e1..0000000000 --- a/control-plane/api-gateway/common/reference.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "sync" - - "github.com/hashicorp/consul/api" -) - -// ReferenceMap is contains a map of config entries stored -// by their normalized resource references (with empty string -// for namespaces and partitions stored as "default"). -type ReferenceMap struct { - data map[api.ResourceReference]api.ConfigEntry - ids map[api.ResourceReference]struct{} - mutex sync.RWMutex -} - -// NewReferenceMap constructs a reference map. -func NewReferenceMap() *ReferenceMap { - return &ReferenceMap{ - data: make(map[api.ResourceReference]api.ConfigEntry), - ids: make(map[api.ResourceReference]struct{}), - } -} - -func (r *ReferenceMap) IDs() []api.ResourceReference { - r.mutex.RLock() - defer r.mutex.RUnlock() - - var ids []api.ResourceReference - for id := range r.ids { - ids = append(ids, id) - } - return ids -} - -// Set adds an entry to the reference map. -func (r *ReferenceMap) Set(ref api.ResourceReference, v api.ConfigEntry) { - r.mutex.Lock() - defer r.mutex.Unlock() - - r.ids[ref] = struct{}{} - r.data[NormalizeMeta(ref)] = v -} - -// Get returns an entry from the reference map. -func (r *ReferenceMap) Get(ref api.ResourceReference) api.ConfigEntry { - r.mutex.RLock() - defer r.mutex.RUnlock() - - v, ok := r.data[NormalizeMeta(ref)] - if !ok { - return nil - } - return v -} - -// Entries returns a list of entries stored in the reference map. -func (r *ReferenceMap) Entries() []api.ConfigEntry { - r.mutex.RLock() - defer r.mutex.RUnlock() - - entries := make([]api.ConfigEntry, 0, len(r.data)) - for _, entry := range r.data { - entries = append(entries, entry) - } - return entries -} - -// Delete deletes an entry stored in the reference map. -func (r *ReferenceMap) Delete(ref api.ResourceReference) { - r.mutex.Lock() - defer r.mutex.Unlock() - - delete(r.ids, ref) - delete(r.data, NormalizeMeta(ref)) -} - -// Diff calculates the difference between the stored entries in two reference maps. -func (r *ReferenceMap) Diff(other *ReferenceMap) []api.ConfigEntry { - r.mutex.RLock() - defer r.mutex.RUnlock() - - other.mutex.RLock() - defer other.mutex.RUnlock() - - diffs := make([]api.ConfigEntry, 0) - - for ref, entry := range other.data { - oldRef := r.Get(ref) - // ref from the new cache doesn't exist in the old one - // this means a resource was added - if oldRef == nil { - diffs = append(diffs, entry) - continue - } - - // the entry in the old cache has an older modify index than the ref - // from the new cache - if oldRef.GetModifyIndex() < entry.GetModifyIndex() { - diffs = append(diffs, entry) - } - } - - // get all deleted entries, these are entries present in the old cache - // that are not present in the new - for ref, entry := range r.data { - if other.Get(ref) == nil { - diffs = append(diffs, entry) - } - } - - return diffs -} - -// ReferenceSet is a set of stored references. -type ReferenceSet struct { - data map[api.ResourceReference]struct{} - ids map[api.ResourceReference]struct{} - - mutex sync.RWMutex -} - -// NewReferenceSet constructs a new reference set. -func NewReferenceSet() *ReferenceSet { - return &ReferenceSet{ - data: make(map[api.ResourceReference]struct{}), - ids: make(map[api.ResourceReference]struct{}), - } -} - -// Mark adds a reference to the reference set. -func (r *ReferenceSet) Mark(ref api.ResourceReference) { - r.mutex.Lock() - defer r.mutex.Unlock() - - r.ids[ref] = struct{}{} - r.data[NormalizeMeta(ref)] = struct{}{} -} - -// Contains checks for the inclusion of a reference in the set. -func (r *ReferenceSet) Contains(ref api.ResourceReference) bool { - r.mutex.RLock() - defer r.mutex.RUnlock() - - _, ok := r.data[NormalizeMeta(ref)] - return ok -} - -// Remove drops a reference from the set. -func (r *ReferenceSet) Remove(ref api.ResourceReference) { - r.mutex.Lock() - defer r.mutex.Unlock() - - delete(r.ids, ref) - delete(r.data, NormalizeMeta(ref)) -} - -func (r *ReferenceSet) IDs() []api.ResourceReference { - r.mutex.RLock() - defer r.mutex.RUnlock() - - var ids []api.ResourceReference - for id := range r.ids { - ids = append(ids, id) - } - return ids -} - -func NormalizeMeta(ref api.ResourceReference) api.ResourceReference { - ref.Namespace = NormalizeEmptyMetadataString(ref.Namespace) - ref.Partition = NormalizeEmptyMetadataString(ref.Partition) - return ref -} - -func NormalizeEmptyMetadataString(metaString string) string { - if metaString == "" { - return "default" - } - return metaString -} diff --git a/control-plane/api-gateway/common/resources.go b/control-plane/api-gateway/common/resources.go deleted file mode 100644 index 40fe74bf8d..0000000000 --- a/control-plane/api-gateway/common/resources.go +++ /dev/null @@ -1,647 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - mapset "github.com/deckarep/golang-set" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul/api" -) - -// ConsulUpdateOperation is an operation representing an -// update in Consul. -type ConsulUpdateOperation struct { - // Entry is the ConfigEntry to write to Consul. - Entry api.ConfigEntry - // OnUpdate is an optional callback to fire after running - // the Consul update operation. If specified, then no more - // error handling occurs after the function is called, otherwise - // normal error handling logic applies. - OnUpdate func(err error) -} - -type gvkNamespacedName struct { - gvk string - nsn types.NamespacedName -} - -// KubernetesUpdates holds all update operations (including status) -// that need to be synced to Kubernetes. So long as you're -// modifying the same pointer object passed in to its Add -// function, this de-duplicates any calls to Add, in order -// for us to Add any previously unseen entires, but ignore -// them if they've already been added. -type KubernetesUpdates struct { - operations map[gvkNamespacedName]client.Object -} - -func NewKubernetesUpdates() *KubernetesUpdates { - return &KubernetesUpdates{ - operations: make(map[gvkNamespacedName]client.Object), - } -} - -func (k *KubernetesUpdates) Add(object client.Object) { - k.operations[gvkNamespacedName{ - gvk: object.GetObjectKind().GroupVersionKind().String(), - nsn: client.ObjectKeyFromObject(object), - }] = object -} - -func (k *KubernetesUpdates) Operations() []client.Object { - return ConvertMapValuesToSlice(k.operations) -} - -type ReferenceValidator interface { - GatewayCanReferenceSecret(gateway gwv1beta1.Gateway, secretRef gwv1beta1.SecretObjectReference) bool - HTTPRouteCanReferenceBackend(httproute gwv1beta1.HTTPRoute, backendRef gwv1beta1.BackendRef) bool - TCPRouteCanReferenceBackend(tcpRoute gwv1alpha2.TCPRoute, backendRef gwv1beta1.BackendRef) bool -} - -type certificate struct { - secret *corev1.Secret - gateways mapset.Set -} - -type httpRoute struct { - route gwv1beta1.HTTPRoute - gateways mapset.Set -} - -type tcpRoute struct { - route gwv1alpha2.TCPRoute - gateways mapset.Set -} - -type consulHTTPRoute struct { - route api.HTTPRouteConfigEntry - gateways mapset.Set -} - -type consulTCPRoute struct { - route api.TCPRouteConfigEntry - gateways mapset.Set -} - -type resourceSet struct { - httpRoutes mapset.Set - tcpRoutes mapset.Set - certificates mapset.Set - - consulObjects *ReferenceSet -} - -type ResourceMap struct { - translator ResourceTranslator - referenceValidator ReferenceValidator - logger logr.Logger - - services map[types.NamespacedName]api.ResourceReference - meshServices map[types.NamespacedName]api.ResourceReference - certificates mapset.Set - - // this acts a a secondary store of what has not yet - // been processed for the sake of garbage collection. - processedCertificates mapset.Set - certificateGateways map[api.ResourceReference]*certificate - tcpRouteGateways map[api.ResourceReference]*tcpRoute - httpRouteGateways map[api.ResourceReference]*httpRoute - gatewayResources map[api.ResourceReference]*resourceSet - externalFilters map[corev1.ObjectReference]client.Object - - // consul resources for a gateway - consulTCPRoutes map[api.ResourceReference]*consulTCPRoute - consulHTTPRoutes map[api.ResourceReference]*consulHTTPRoute - - // mutations - consulMutations []*ConsulUpdateOperation -} - -func NewResourceMap(translator ResourceTranslator, validator ReferenceValidator, logger logr.Logger) *ResourceMap { - return &ResourceMap{ - translator: translator, - referenceValidator: validator, - logger: logger, - processedCertificates: mapset.NewSet(), - services: make(map[types.NamespacedName]api.ResourceReference), - meshServices: make(map[types.NamespacedName]api.ResourceReference), - certificates: mapset.NewSet(), - consulTCPRoutes: make(map[api.ResourceReference]*consulTCPRoute), - consulHTTPRoutes: make(map[api.ResourceReference]*consulHTTPRoute), - certificateGateways: make(map[api.ResourceReference]*certificate), - tcpRouteGateways: make(map[api.ResourceReference]*tcpRoute), - httpRouteGateways: make(map[api.ResourceReference]*httpRoute), - gatewayResources: make(map[api.ResourceReference]*resourceSet), - } -} - -func (s *ResourceMap) AddService(id types.NamespacedName, name string) { - // this needs to be not-normalized since it gets written straight - // to Consul's configuration, including in non-enterprise builds. - s.services[id] = api.ResourceReference{ - Name: name, - Namespace: s.translator.Namespace(id.Namespace), - Partition: s.translator.ConsulPartition, - } -} - -func (s *ResourceMap) Service(id types.NamespacedName) api.ResourceReference { - return s.services[id] -} - -func (s *ResourceMap) HasService(id types.NamespacedName) bool { - _, ok := s.services[id] - return ok -} - -func (s *ResourceMap) AddMeshService(service v1alpha1.MeshService) { - // this needs to be not-normalized since it gets written straight - // to Consul's configuration, including in non-enterprise builds. - key := client.ObjectKeyFromObject(&service) - s.meshServices[key] = api.ResourceReference{ - Name: service.Spec.Name, - Namespace: s.translator.Namespace(service.Namespace), - Partition: s.translator.ConsulPartition, - } -} - -func (s *ResourceMap) MeshService(id types.NamespacedName) api.ResourceReference { - return s.meshServices[id] -} - -func (s *ResourceMap) HasMeshService(id types.NamespacedName) bool { - _, ok := s.meshServices[id] - return ok -} - -func (s *ResourceMap) Certificate(key types.NamespacedName) *corev1.Secret { - if !s.certificates.Contains(key) { - return nil - } - consulKey := NormalizeMeta(s.toConsulReference(api.InlineCertificate, key)) - if secret, ok := s.certificateGateways[consulKey]; ok { - return secret.secret - } - return nil -} - -func (s *ResourceMap) ReferenceCountCertificate(secret corev1.Secret) { - key := client.ObjectKeyFromObject(&secret) - s.certificates.Add(key) - consulKey := NormalizeMeta(s.toConsulReference(api.InlineCertificate, key)) - if _, ok := s.certificateGateways[consulKey]; !ok { - s.certificateGateways[consulKey] = &certificate{ - secret: &secret, - gateways: mapset.NewSet(), - } - } -} - -func (s *ResourceMap) ReferenceCountGateway(gateway gwv1beta1.Gateway) { - key := client.ObjectKeyFromObject(&gateway) - consulKey := NormalizeMeta(s.toConsulReference(api.APIGateway, key)) - - set := &resourceSet{ - httpRoutes: mapset.NewSet(), - tcpRoutes: mapset.NewSet(), - certificates: mapset.NewSet(), - consulObjects: NewReferenceSet(), - } - - for _, listener := range gateway.Spec.Listeners { - if listener.TLS == nil || (listener.TLS.Mode != nil && *listener.TLS.Mode != gwv1beta1.TLSModeTerminate) { - continue - } - for _, cert := range listener.TLS.CertificateRefs { - if NilOrEqual(cert.Group, "") && NilOrEqual(cert.Kind, "Secret") { - certificateKey := IndexedNamespacedNameWithDefault(cert.Name, cert.Namespace, gateway.Namespace) - - set.certificates.Add(certificateKey) - - consulCertificateKey := s.toConsulReference(api.InlineCertificate, certificateKey) - certificate, ok := s.certificateGateways[NormalizeMeta(consulCertificateKey)] - if ok { - certificate.gateways.Add(key) - set.consulObjects.Mark(consulCertificateKey) - } - } - } - } - - s.gatewayResources[consulKey] = set -} - -func (s *ResourceMap) ResourcesToGC(key types.NamespacedName) []api.ResourceReference { - consulKey := NormalizeMeta(s.toConsulReference(api.APIGateway, key)) - - resources, ok := s.gatewayResources[consulKey] - if !ok { - return nil - } - - var toGC []api.ResourceReference - - for _, id := range resources.consulObjects.IDs() { - // if any of these objects exist in the below maps - // it means we haven't "popped" it to be created - switch id.Kind { - case api.HTTPRoute: - if route, ok := s.consulHTTPRoutes[NormalizeMeta(id)]; ok && route.gateways.Cardinality() <= 1 { - // we only have a single reference, which will be this gateway, so drop - // the route altogether - toGC = append(toGC, id) - } - case api.TCPRoute: - if route, ok := s.consulTCPRoutes[NormalizeMeta(id)]; ok && route.gateways.Cardinality() <= 1 { - // we only have a single reference, which will be this gateway, so drop - // the route altogether - toGC = append(toGC, id) - } - case api.InlineCertificate: - if s.processedCertificates.Contains(id) { - continue - } - if route, ok := s.certificateGateways[NormalizeMeta(id)]; ok && route.gateways.Cardinality() <= 1 { - // we only have a single reference, which will be this gateway, so drop - // the route altogether - toGC = append(toGC, id) - } - } - } - - return toGC -} - -func (s *ResourceMap) ReferenceCountConsulHTTPRoute(route api.HTTPRouteConfigEntry) { - key := s.objectReference(&route) - - set := &consulHTTPRoute{ - route: route, - gateways: mapset.NewSet(), - } - - for gatewayKey := range s.consulGatewaysForRoute(route.Namespace, route.Parents).Iter() { - if gateway, ok := s.gatewayResources[gatewayKey.(api.ResourceReference)]; ok { - gateway.consulObjects.Mark(key) - } - - set.gateways.Add(gatewayKey) - } - - s.consulHTTPRoutes[NormalizeMeta(key)] = set -} - -func (s *ResourceMap) ReferenceCountConsulTCPRoute(route api.TCPRouteConfigEntry) { - key := s.objectReference(&route) - - set := &consulTCPRoute{ - route: route, - gateways: mapset.NewSet(), - } - - for gatewayKey := range s.consulGatewaysForRoute(route.Namespace, route.Parents).Iter() { - if gateway, ok := s.gatewayResources[gatewayKey.(api.ResourceReference)]; ok { - gateway.consulObjects.Mark(key) - } - - set.gateways.Add(gatewayKey) - } - - s.consulTCPRoutes[NormalizeMeta(key)] = set -} - -func (s *ResourceMap) ReferenceCountConsulCertificate(cert api.InlineCertificateConfigEntry) { - key := s.objectReference(&cert) - - var referenced *certificate - if existing, ok := s.certificateGateways[NormalizeMeta(key)]; ok { - referenced = existing - } else { - referenced = &certificate{ - gateways: mapset.NewSet(), - } - } - - s.certificateGateways[NormalizeMeta(key)] = referenced -} - -func (s *ResourceMap) consulGatewaysForRoute(namespace string, refs []api.ResourceReference) mapset.Set { - gateways := mapset.NewSet() - - for _, parent := range refs { - if EmptyOrEqual(parent.Kind, api.APIGateway) { - key := s.sectionlessParentReference(api.APIGateway, namespace, parent) - gateways.Add(key) - } - } - - return gateways -} - -func (s *ResourceMap) ReferenceCountHTTPRoute(route gwv1beta1.HTTPRoute) { - key := client.ObjectKeyFromObject(&route) - consulKey := NormalizeMeta(s.toConsulReference(api.HTTPRoute, key)) - - set := &httpRoute{ - route: route, - gateways: mapset.NewSet(), - } - - for gatewayKey := range s.gatewaysForRoute(route.Namespace, route.Spec.ParentRefs).Iter() { - set.gateways.Add(gatewayKey.(api.ResourceReference)) - - gateway := s.gatewayResources[gatewayKey.(api.ResourceReference)] - gateway.httpRoutes.Add(consulKey) - } - - s.httpRouteGateways[consulKey] = set -} - -func localObjectReferenceToObjectReference(filterRef gwv1beta1.LocalObjectReference, namespace string) corev1.ObjectReference { - return corev1.ObjectReference{ - Kind: string(filterRef.Kind), - Name: string(filterRef.Name), - Namespace: namespace, - } -} - -func objectToObjectReference(object client.Object) corev1.ObjectReference { - return corev1.ObjectReference{ - Kind: object.GetObjectKind().GroupVersionKind().Kind, - Name: object.GetName(), - Namespace: object.GetNamespace(), - } -} - -func (s *ResourceMap) AddExternalFilter(filter client.Object) { - if s.externalFilters == nil { - s.externalFilters = make(map[corev1.ObjectReference]client.Object) - } - - key := objectToObjectReference(filter) - s.externalFilters[key] = filter -} - -func (s *ResourceMap) GetExternalFilter(filterRef gwv1beta1.LocalObjectReference, namespace string) (client.Object, bool) { - key := localObjectReferenceToObjectReference(filterRef, namespace) - filter, ok := s.externalFilters[key] - return filter, ok -} - -func (s *ResourceMap) ExternalFilterExists(filterRef gwv1beta1.LocalObjectReference, namespace string) bool { - _, ok := s.GetExternalFilter(filterRef, namespace) - return ok -} - -func (s *ResourceMap) ReferenceCountTCPRoute(route gwv1alpha2.TCPRoute) { - key := client.ObjectKeyFromObject(&route) - consulKey := NormalizeMeta(s.toConsulReference(api.TCPRoute, key)) - - set := &tcpRoute{ - route: route, - gateways: mapset.NewSet(), - } - - for gatewayKey := range s.gatewaysForRoute(route.Namespace, route.Spec.ParentRefs).Iter() { - set.gateways.Add(gatewayKey.(api.ResourceReference)) - - gateway := s.gatewayResources[gatewayKey.(api.ResourceReference)] - gateway.tcpRoutes.Add(consulKey) - } - - s.tcpRouteGateways[consulKey] = set -} - -func (s *ResourceMap) gatewaysForRoute(namespace string, refs []gwv1beta1.ParentReference) mapset.Set { - gateways := mapset.NewSet() - - for _, parent := range refs { - if NilOrEqual(parent.Group, gwv1beta1.GroupVersion.Group) && NilOrEqual(parent.Kind, "Gateway") { - key := IndexedNamespacedNameWithDefault(parent.Name, parent.Namespace, namespace) - consulKey := NormalizeMeta(s.toConsulReference(api.APIGateway, key)) - - if _, ok := s.gatewayResources[consulKey]; ok { - gateways.Add(consulKey) - } - } - } - - return gateways -} - -func (s *ResourceMap) TranslateAndMutateHTTPRoute(key types.NamespacedName, onUpdate func(error, api.ConfigEntryStatus), mutateFn func(old *api.HTTPRouteConfigEntry, new api.HTTPRouteConfigEntry) api.HTTPRouteConfigEntry) { - consulKey := NormalizeMeta(s.toConsulReference(api.HTTPRoute, key)) - - route, ok := s.httpRouteGateways[consulKey] - if !ok { - return - } - - translated := s.translator.ToHTTPRoute(route.route, s) - - consulRoute, ok := s.consulHTTPRoutes[consulKey] - if ok { - mutated := mutateFn(&consulRoute.route, *translated) - if len(mutated.Parents) != 0 { - // if we don't have any parents set, we keep this around to allow the route - // to be GC'd. - delete(s.consulHTTPRoutes, consulKey) - s.consulMutations = append(s.consulMutations, &ConsulUpdateOperation{ - Entry: &mutated, - OnUpdate: func(err error) { - onUpdate(err, mutated.Status) - }, - }) - } - return - } - mutated := mutateFn(nil, *translated) - if len(mutated.Parents) != 0 { - // if we don't have any parents set, we keep this around to allow the route - // to be GC'd. - delete(s.consulHTTPRoutes, consulKey) - s.consulMutations = append(s.consulMutations, &ConsulUpdateOperation{ - Entry: &mutated, - OnUpdate: func(err error) { - onUpdate(err, mutated.Status) - }, - }) - } -} - -func (s *ResourceMap) MutateHTTPRoute(key types.NamespacedName, onUpdate func(error, api.ConfigEntryStatus), mutateFn func(api.HTTPRouteConfigEntry) api.HTTPRouteConfigEntry) { - consulKey := NormalizeMeta(s.toConsulReference(api.HTTPRoute, key)) - - consulRoute, ok := s.consulHTTPRoutes[consulKey] - if ok { - mutated := mutateFn(consulRoute.route) - if len(mutated.Parents) != 0 { - // if we don't have any parents set, we keep this around to allow the route - // to be GC'd. - delete(s.consulHTTPRoutes, consulKey) - s.consulMutations = append(s.consulMutations, &ConsulUpdateOperation{ - Entry: &mutated, - OnUpdate: func(err error) { - onUpdate(err, mutated.Status) - }, - }) - } - } -} - -func (s *ResourceMap) CanGCHTTPRouteOnUnbind(id api.ResourceReference) bool { - if set := s.httpRouteGateways[NormalizeMeta(id)]; set != nil { - return set.gateways.Cardinality() <= 1 - } - return true -} - -func (s *ResourceMap) TranslateAndMutateTCPRoute(key types.NamespacedName, onUpdate func(error, api.ConfigEntryStatus), mutateFn func(*api.TCPRouteConfigEntry, api.TCPRouteConfigEntry) api.TCPRouteConfigEntry) { - consulKey := NormalizeMeta(s.toConsulReference(api.TCPRoute, key)) - - route, ok := s.tcpRouteGateways[consulKey] - if !ok { - return - } - - translated := s.translator.ToTCPRoute(route.route, s) - - consulRoute, ok := s.consulTCPRoutes[consulKey] - if ok { - mutated := mutateFn(&consulRoute.route, *translated) - if len(mutated.Parents) != 0 { - // if we don't have any parents set, we keep this around to allow the route - // to be GC'd. - delete(s.consulTCPRoutes, consulKey) - s.consulMutations = append(s.consulMutations, &ConsulUpdateOperation{ - Entry: &mutated, - OnUpdate: func(err error) { - onUpdate(err, mutated.Status) - }, - }) - } - return - } - mutated := mutateFn(nil, *translated) - if len(mutated.Parents) != 0 { - // if we don't have any parents set, we keep this around to allow the route - // to be GC'd. - delete(s.consulTCPRoutes, consulKey) - s.consulMutations = append(s.consulMutations, &ConsulUpdateOperation{ - Entry: &mutated, - OnUpdate: func(err error) { - onUpdate(err, mutated.Status) - }, - }) - } -} - -func (s *ResourceMap) MutateTCPRoute(key types.NamespacedName, onUpdate func(error, api.ConfigEntryStatus), mutateFn func(api.TCPRouteConfigEntry) api.TCPRouteConfigEntry) { - consulKey := NormalizeMeta(s.toConsulReference(api.TCPRoute, key)) - - consulRoute, ok := s.consulTCPRoutes[consulKey] - if ok { - mutated := mutateFn(consulRoute.route) - if len(mutated.Parents) != 0 { - // if we don't have any parents set, we keep this around to allow the route - // to be GC'd. - delete(s.consulTCPRoutes, consulKey) - s.consulMutations = append(s.consulMutations, &ConsulUpdateOperation{ - Entry: &mutated, - OnUpdate: func(err error) { - onUpdate(err, mutated.Status) - }, - }) - } - } -} - -func (s *ResourceMap) CanGCTCPRouteOnUnbind(id api.ResourceReference) bool { - if set := s.tcpRouteGateways[NormalizeMeta(id)]; set != nil { - return set.gateways.Cardinality() <= 1 - } - return true -} - -func (s *ResourceMap) TranslateInlineCertificate(key types.NamespacedName) error { - consulKey := s.toConsulReference(api.InlineCertificate, key) - - certificate, ok := s.certificateGateways[NormalizeMeta(consulKey)] - if !ok { - return nil - } - - if certificate.secret == nil { - return nil - } - - 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: consulCertificate, - // just swallow the error and log it since we can't propagate status back on a certificate. - OnUpdate: func(error) { - if err != nil { - s.logger.Error(err, "error syncing certificate to Consul") - } - }, - }) - - return nil -} - -func (s *ResourceMap) Mutations() []*ConsulUpdateOperation { - return s.consulMutations -} - -func (s *ResourceMap) objectReference(o api.ConfigEntry) api.ResourceReference { - return api.ResourceReference{ - Kind: o.GetKind(), - Name: o.GetName(), - Namespace: o.GetNamespace(), - Partition: s.translator.ConsulPartition, - } -} - -func (s *ResourceMap) sectionlessParentReference(kind, namespace string, parent api.ResourceReference) api.ResourceReference { - return NormalizeMeta(api.ResourceReference{ - Kind: kind, - Name: parent.Name, - Namespace: orDefault(parent.Namespace, namespace), - Partition: s.translator.ConsulPartition, - }) -} - -func (s *ResourceMap) toConsulReference(kind string, key types.NamespacedName) api.ResourceReference { - return api.ResourceReference{ - Kind: kind, - Name: key.Name, - Namespace: s.translator.Namespace(key.Namespace), - Partition: s.translator.ConsulPartition, - } -} - -func (s *ResourceMap) GatewayCanReferenceSecret(gateway gwv1beta1.Gateway, ref gwv1beta1.SecretObjectReference) bool { - return s.referenceValidator.GatewayCanReferenceSecret(gateway, ref) -} - -func (s *ResourceMap) HTTPRouteCanReferenceBackend(route gwv1beta1.HTTPRoute, ref gwv1beta1.BackendRef) bool { - return s.referenceValidator.HTTPRouteCanReferenceBackend(route, ref) -} - -func (s *ResourceMap) TCPRouteCanReferenceBackend(route gwv1alpha2.TCPRoute, ref gwv1beta1.BackendRef) bool { - return s.referenceValidator.TCPRouteCanReferenceBackend(route, ref) -} diff --git a/control-plane/api-gateway/common/secrets.go b/control-plane/api-gateway/common/secrets.go deleted file mode 100644 index 1b7d8dec33..0000000000 --- a/control-plane/api-gateway/common/secrets.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "crypto/tls" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - - "github.com/miekg/dns" - corev1 "k8s.io/api/core/v1" - - "github.com/hashicorp/consul-k8s/control-plane/version" -) - -var ( - errFailedToParsePrivateKeyPem = errors.New("failed to parse private key PEM") - errKeyLengthTooShort = errors.New("RSA key length must be at least 2048-bit") - errKeyLengthTooShortFIPS = errors.New("RSA key length must be at either 2048-bit, 3072-bit, or 4096-bit in FIPS mode") -) - -func ParseCertificateData(secret corev1.Secret) (cert string, privateKey string, err error) { - decodedPrivateKey := secret.Data[corev1.TLSPrivateKeyKey] - decodedCertificate := secret.Data[corev1.TLSCertKey] - - privateKeyBlock, _ := pem.Decode(decodedPrivateKey) - if privateKeyBlock == nil { - return "", "", errFailedToParsePrivateKeyPem - } - - certificateBlock, _ := pem.Decode(decodedCertificate) - if certificateBlock == nil { - return "", "", errors.New("failed to parse certificate PEM") - } - - // make sure we have a valid x509 certificate - certificate, err := x509.ParseCertificate(certificateBlock.Bytes) - if err != nil { - return "", "", err - } - - // validate that the cert was generated with the given private key - _, err = tls.X509KeyPair(decodedCertificate, decodedPrivateKey) - if err != nil { - return "", "", err - } - - // validate that each host referenced in the CN, DNSSans, and IPSans - // are valid hostnames - if err := validateCertificateHosts(certificate); err != nil { - return "", "", err - } - - return string(decodedCertificate), string(decodedPrivateKey), nil -} - -func validateCertificateHosts(certificate *x509.Certificate) error { - hosts := []string{certificate.Subject.CommonName} - - hosts = append(hosts, certificate.DNSNames...) - - for _, ip := range certificate.IPAddresses { - hosts = append(hosts, ip.String()) - } - - for _, host := range hosts { - if _, ok := dns.IsDomainName(host); !ok { - return fmt.Errorf("host %q must be a valid DNS hostname", host) - } - } - - return nil -} - -// Envoy will silently reject any keys that are less than 2048 bytes long -// https://github.com/envoyproxy/envoy/blob/main/source/extensions/transport_sockets/tls/context_impl.cc#L238 -const MinKeyLength = 2048 - -// ValidateKeyLength ensures that the key length for a certificate is of a valid length -// for envoy dependent on if consul is running in FIPS mode or not. -func ValidateKeyLength(privateKey string) error { - privateKeyBlock, _ := pem.Decode([]byte(privateKey)) - - if privateKeyBlock == nil { - return errFailedToParsePrivateKeyPem - } - - if privateKeyBlock.Type != "RSA PRIVATE KEY" { - return nil - } - - key, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes) - if err != nil { - return err - } - - keyBitLen := key.N.BitLen() - - if version.IsFIPS() { - return fipsLenCheck(keyBitLen) - } - - return nonFipsLenCheck(keyBitLen) -} - -func nonFipsLenCheck(keyLen int) error { - // ensure private key is of the correct length - if keyLen < MinKeyLength { - return errKeyLengthTooShort - } - - return nil -} - -func fipsLenCheck(keyLen int) error { - if keyLen != 2048 && keyLen != 3072 && keyLen != 4096 { - return errKeyLengthTooShortFIPS - } - return nil -} diff --git a/control-plane/api-gateway/common/secrets_test.go b/control-plane/api-gateway/common/secrets_test.go deleted file mode 100644 index 223e8aa24e..0000000000 --- a/control-plane/api-gateway/common/secrets_test.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestValidateKeyLength(t *testing.T) { - tooShortPrivateKey := `-----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQCtmK1VjmXJ7vm4CZkkOSjc+kjGNMlyce5rXxwlDRz9LcGGc3Tg -kwUJesyBpDtxLLVHXQIPr5mWYbX/W/ezQ9sntxrATbDek8pBgoOlARebwkD2ivVW -BWfVhlryVihWlXApKiJ2n3i0m+OVtdrceC9Bv2hEMhYVOwzxtb3O0YFkbwIDAQAB -AoGAIxgnipFUEKPIRiVimUkY8ruCdNd9Fi7kNT6wEOl6v9A9PHIg4bm3Hfh+WYMb -JUEVkMzDuuoUEavFQE+WXt5L8oE1lEBmN2++FQsvllN+MRBTRg2sfw4mUWDI6S4r -h8+XNTzTIg2sUd2J3o2qNmQoOheYb+iuYDj76IFoEdwwZ0kCQQDYKKs5HAbnrLj1 -UrOp8TyHdFf0YNw5tGdbNTbffq4rlBD6SW70+Sj624i2UqdnYwRiWzdXv3zN08aI -Vfoh2cGlAkEAzZe5B6BhiX/PcIYutMtuT3K+mysFNlowrutXWoQOpR7gGAkgEt6e -oCDgx1QJRjsp6NFQxKc6l034Hzs17gqJgwJAcu9U873aUg9+HTuHOoKB28haCCAE -mU46cr3d2oKCW7uUN3EaZXmid5iJneBfENMOfrnfuHGiC9NiShXlNWCS3QJAO5Ne -w83+1ahaxUGs4SkeExmuECrcPM7P0rBRxOIFmGWlDHIAgFdQYhiE6l34vghA8b1O -CV5oRRYL84jl7M/S3wJBALDfL5YXcc8P6scLJJ1biqhLYppvGN5CUwbsJsluvHCW -XCTVIbPOaS42A0xUfpoiTcdbNSFRvdCzPR5nsGy8Y7g= ------END RSA PRIVATE KEY-----` - validPrivateKey := `-----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAzVKRcYlTHHPjPbCieOFIUT2hCouRYe4N8ZhNrSpZf/BAAn4M -d/LWn/9OrLagbxrRF6cWdWGNEI2COnBRLgNVxyPXneaHaYFqOBRi9GWhuD3sw1jn -7gf4/m/AVO8cu2JYjEX+s9RjSRzpjx+4nhit46bGNUyb9qUeQwoBidAzOSmU8nHY -y3LpuuzkjS3FEyNXHxqgpTJnV4ytx8YGkPnG92GBAlrZnr4Eclv0/Sq6OViTpeuh -z8noNkbugYWHMXGlTZ4lPnELJW2fx/HIpD2ovOO3X8XYBo5KDzs9qyKzDgIOMZLF -i/qLCLHgfosb4TMaXCeVu4fA7Y47jtGOO4mbiwIDAQABAoIBAFhicDibIDtRyaLv -K+l0NPC/4liLPwCUfM0gvmNKJS/VSICqKQzjbK+ANCpWDVb2iMaxRxItdY+IEuS8 -H736cozgaXtP1r+8lXBhmj1RmJ2ajpaC6YgGR5GjonwNWGVzjuGHaf6YcUryVrol -MhBgWE50psMf4M16Q74hCwt7o+k5Lz55xKasgc9dtSnvyCupPBwrOT+d55C1P2Wn -2oebWM4WKtCZIgvlvZrt4xQkGWy9qloxL6V1F67ZbizAyFMZUMmJv+4/whF8tmXi -aydleL64K23ZSK1pM/x0JI+7qo0GpEoA4k+2fdmh5dAOM0TrXhV5Kv01efLIaITT -s7lYjG0CgYEA4qGIM7qO3e9fHgSK/9UdxnpL/1OvfYATBMhEtR46sAxmKQGC8fTM -iTBkmLAKn3zBgDghCbygPIQjex+W+Ra7JkQIcGB6KLR8rr5GkOuF6vkqHV93RQRT -lT/1quqq3fVH6V4ymifKJCDNg0IEPcmo+M8RnXBgpFsCN4b5UyjXNScCgYEA5+4h -LITPJxGytlWzwtsy44U2PvafJYJCktW+LYqhk3xzz4qWX5ubmPz18LrEyybgcy/W -Dm4JCu+TOS2gvf2WbJKR/tKdgRN7dkU/dbgMtRL8QW5ir+5qqRITYOhiSZPIOpbP -5zg+c/ZvmK/t5h35/8l7b0bu/E1FOEF27ADpzP0CgYEArqch2gup0muI+A80N9i7 -q5vQOaL6mVM8VPEp0hLL06Sajnt1uJWZkxhSTkFMzoBMd03KWECflEOZPGep56iW -7fR8NG6Fdh0yAVDt/P0lJWKEDELoHa4p49l4sBFNQOSoWLaZdKe5ZoJJHyCfOCbT -K3wY7SYPtFnWqYhBWM8emv0CgYBdrNqNRp78orNR3c+bNjmZl6ZPTAD/f1swP1Bu -yH12Ol/0RX9y4kC4TANx1Z3Ch9ND8uA8N8lDN3x5Laqs0g29kH2TNLIU/i9xl4qI -G2xWfnKQYutNL7i4zOoyy+lW2m+W6m7Sbu8am0B7pSMrPJRK8a//Q+Em2nbIv/gu -XjgQaQKBgHKZUKkMv597vpAjgTNsKIl5RDFONBq3omnAwlK9EDLVeAxIrvrvMHBW -H/ZMFpSGp1eQgKyu1xkEqGdkYXx7BKtdTHK+Thqif2ZGWczy5rVSAIsBYDo1DGE2 -wbocWxkWNb5o2ZZtis5lTB6nr9EWo0zyaPqIh0pfjqVEES2YDEx6 ------END RSA PRIVATE KEY-----` - nonTraditionalRSAKey := `-----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCcrB9oNKLtzA3Q -02KDgtsnrxns7vJ5aCkjJCm/h0Ju7a2mel5YHSN5iLlU5oTMJVIMpWlW9E8P76/a -GLGMNfSBRVJdfW71iks/ddp4SjpDe9Bo+aY2snrR2/AP7eQepVNjFbg4YLQqvENh -05k1FuuP1/AgGVNn0kGEwzKxz35shmhRKBCvaRaHLz/fdkDIeIrVLON4FnmAmpOZ -AztZCwAZc6HZfj8Nh9Wlaw6Dg2boIgxTU160pwpX+nUxcJ9M5sUP9DBuNL0Mdrqi -U+R49uqG/5ssSk+xVik3q+WF+XySJ6H21fttWDJS2OTm/Nx/wHlBC73mthbA0emB -rkiBy9SBAgMBAAECggEAOhybz6aKcmKYE0d8yGPejwMjPh9JH+ATNh4hQBHXAdc1 -7ESCPvOb52XfvE5+nkwPeXJXNrIKq1IPq3kyTdvrc5F3Ygb3A6tGiuTXYnvBzasc -m/tRfANKjBGkovvte7J90ghJ2tt/qERJR/1Y2/jC6glB314VcjJqK+jNImfgsDa7 -1r47efKG7B5eUGvhQDTpL5ENXKxIdvCghHrLqj19QGUZ5MbXsEYrso0lxKw2Xk39 -uM8p3WTxIy0LQGyCm+FYlJ7r61tm7tUOGuNT0YiptVavIw1QPgIbRWdS2gnJu3+J -kHS0vu6AW1fJav48TA9hXcIQR70alrJA2VVqsvQouwKBgQDNs96l8BfWD6s/urIw -yzC3/VZPLFJ3BlxvkdP1UDC0S+7pgQ6qdEmJg0z5IfYzDB1PK2X/DS/70JA1LRSS -MRmjQGHCYIp9g8EqmABwfKf4YnN53KPRyR8Yq1pwaq7wKowtW+5GH95qQPINZsNO -J21AENEzq7IoB4gpM3tIaX73YwKBgQDC+yl5JvoV7e6FIpFrwL62aKrWmpidML/G -stdrg9ylCSM9SIVFINMhmFPicW1+DrkQ5HRV7DG//ZcOZNbbNmSu32PVcQI1MJgQ -rkMZ3ukUURnlvQYOEmZY4zHzTJ+jcw6kEH/+b47Bv13PpD7ZqA4/28dpU9wi9gt3 -+GiSnkKDywKBgHqjr63dPEjapK3lQFHJAu3fM7MWaMAf4cJ+/hD202LbFsDOuhC0 -Lhe3WY/7SI7cvSizZicvFJmcmi2qB+a1MWTcgKxj5I26nNMpNrHaEEcNY22XN3Be -6ZRKrSvy3wO/Sj3M3n2eiHtu5yFIUE7rQL5+iEu3JQuqmep+kBT3GMSjAoGAP77B -VlyJ0nWRT3F3vZSsRRJ/F94/GtT/PcTmbL4Vetc78CMvfuQ2YntcoWGX/Ghv1Lf7 -2MN5mF0d75TEMbLcw9dA2l0x7ZXPgVSXl3OrG/tPzi44No2JbHIKuJJKdrN9C+Jh -Fhv+vhUEZIg8DAjHb9U4opTKGZv7L+PEvHqFIHUCgYBTB2TxTgEMNZSsRwrhQRMh -tsz5rS2MoTgzk4BlSsv6xVC4GnBJ2HlNAjYEsBEg50zCCTPlZXcsNjrAxFrwWhLJ -DjN2iMsYFz4WHS94W5UYl6/35ye25KsHuS9vnNeidhFAvYgC1nIkh4mFhLoSeSCG -GODy2KwC2ssLuUHb6WoJ6A== ------END PRIVATE KEY-----` - - testCases := map[string]struct { - key string - expectedError error - }{ - "key is RSA and of the correct length": { - key: validPrivateKey, - expectedError: nil, - }, - "key is RSA and too short": { - key: tooShortPrivateKey, - expectedError: errKeyLengthTooShort, - }, - "key is non-traditional RSA key": { - key: nonTraditionalRSAKey, - expectedError: nil, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - err := ValidateKeyLength(tc.key) - require.ErrorIs(t, err, tc.expectedError) - }) - } -} diff --git a/control-plane/api-gateway/common/translation.go b/control-plane/api-gateway/common/translation.go deleted file mode 100644 index d3627b11b4..0000000000 --- a/control-plane/api-gateway/common/translation.go +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "strings" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" - "github.com/hashicorp/consul/api" -) - -// ResourceTranslator handles translating K8s resources into Consul config entries. -type ResourceTranslator struct { - EnableConsulNamespaces bool - ConsulDestNamespace string - EnableK8sMirroring bool - MirroringPrefix string - ConsulPartition string - Datacenter string -} - -func (t ResourceTranslator) NonNormalizedConfigEntryReference(kind string, id types.NamespacedName) api.ResourceReference { - return api.ResourceReference{ - Kind: kind, - Name: id.Name, - Namespace: t.Namespace(id.Namespace), - Partition: t.ConsulPartition, - } -} - -func (t ResourceTranslator) ConfigEntryReference(kind string, id types.NamespacedName) api.ResourceReference { - return NormalizeMeta(t.NonNormalizedConfigEntryReference(kind, id)) -} - -func (t ResourceTranslator) NormalizedResourceReference(kind, namespace string, ref api.ResourceReference) api.ResourceReference { - return NormalizeMeta(api.ResourceReference{ - Kind: kind, - Name: ref.Name, - SectionName: ref.SectionName, - Namespace: t.Namespace(namespace), - Partition: t.ConsulPartition, - }) -} - -func (t ResourceTranslator) Namespace(namespace string) string { - return namespaces.ConsulNamespace(namespace, t.EnableConsulNamespaces, t.ConsulDestNamespace, t.EnableK8sMirroring, t.MirroringPrefix) -} - -// ToAPIGateway translates a kuberenetes API gateway into a Consul APIGateway Config Entry. -func (t ResourceTranslator) ToAPIGateway(gateway gwv1beta1.Gateway, resources *ResourceMap, gwcc *v1alpha1.GatewayClassConfig) *api.APIGatewayConfigEntry { - namespace := t.Namespace(gateway.Namespace) - - listeners := ConvertSliceFuncIf(gateway.Spec.Listeners, func(listener gwv1beta1.Listener) (api.APIGatewayListener, bool) { - return t.toAPIGatewayListener(gateway, listener, resources, gwcc) - }) - - return &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: gateway.Name, - Namespace: namespace, - Partition: t.ConsulPartition, - Meta: t.addDatacenterToMeta(map[string]string{ - constants.MetaKeyKubeNS: gateway.Namespace, - constants.MetaKeyKubeName: gateway.Name, - }), - Listeners: listeners, - } -} - -var listenerProtocolMap = map[string]string{ - "https": "http", - "http": "http", - "tcp": "tcp", -} - -func (t ResourceTranslator) toAPIGatewayListener(gateway gwv1beta1.Gateway, listener gwv1beta1.Listener, resources *ResourceMap, gwcc *v1alpha1.GatewayClassConfig) (api.APIGatewayListener, bool) { - namespace := gateway.Namespace - - var certificates []api.ResourceReference - var cipherSuites []string - var maxVersion, minVersion string - - if listener.TLS != nil { - cipherSuitesVal := string(listener.TLS.Options[TLSCipherSuitesAnnotationKey]) - if cipherSuitesVal != "" { - cipherSuites = strings.Split(cipherSuitesVal, ",") - } - maxVersion = string(listener.TLS.Options[TLSMaxVersionAnnotationKey]) - minVersion = string(listener.TLS.Options[TLSMinVersionAnnotationKey]) - - for _, ref := range listener.TLS.CertificateRefs { - if !resources.GatewayCanReferenceSecret(gateway, ref) { - return api.APIGatewayListener{}, false - } - - if !NilOrEqual(ref.Group, "") || !NilOrEqual(ref.Kind, "Secret") { - // only translate the valid types we support - continue - } - - ref := IndexedNamespacedNameWithDefault(ref.Name, ref.Namespace, namespace) - if resources.Certificate(ref) != nil { - certificates = append(certificates, t.NonNormalizedConfigEntryReference(api.InlineCertificate, ref)) - } - } - } - - portMapping := int32(0) - if gwcc != nil { - portMapping = gwcc.Spec.MapPrivilegedContainerPorts - } - - return api.APIGatewayListener{ - Name: string(listener.Name), - Hostname: DerefStringOr(listener.Hostname, ""), - Port: ToContainerPort(listener.Port, portMapping), - Protocol: listenerProtocolMap[strings.ToLower(string(listener.Protocol))], - TLS: api.APIGatewayTLSConfiguration{ - Certificates: certificates, - CipherSuites: cipherSuites, - MaxVersion: maxVersion, - MinVersion: minVersion, - }, - }, true -} - -func ToContainerPort(portNumber gwv1beta1.PortNumber, mapPrivilegedContainerPorts int32) int { - if portNumber >= 1024 { - // We don't care about privileged port-mapping, this is a non-privileged port - return int(portNumber) - } - - return int(portNumber) + int(mapPrivilegedContainerPorts) -} - -func (t ResourceTranslator) ToHTTPRoute(route gwv1beta1.HTTPRoute, resources *ResourceMap) *api.HTTPRouteConfigEntry { - namespace := t.Namespace(route.Namespace) - - // we don't translate parent refs - - hostnames := StringLikeSlice(route.Spec.Hostnames) - rules := ConvertSliceFuncIf(route.Spec.Rules, func(rule gwv1beta1.HTTPRouteRule) (api.HTTPRouteRule, bool) { - return t.translateHTTPRouteRule(route, rule, resources) - }) - - configEntry := api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: route.Name, - Namespace: namespace, - Partition: t.ConsulPartition, - Meta: t.addDatacenterToMeta(map[string]string{ - constants.MetaKeyKubeNS: route.Namespace, - constants.MetaKeyKubeName: route.Name, - }), - Hostnames: hostnames, - Rules: rules, - } - - return &configEntry -} - -func (t ResourceTranslator) translateHTTPRouteRule(route gwv1beta1.HTTPRoute, rule gwv1beta1.HTTPRouteRule, resources *ResourceMap) (api.HTTPRouteRule, bool) { - services := ConvertSliceFuncIf(rule.BackendRefs, func(ref gwv1beta1.HTTPBackendRef) (api.HTTPService, bool) { - - return t.translateHTTPBackendRef(route, ref, resources) - }) - - if len(services) == 0 { - return api.HTTPRouteRule{}, false - } - - matches := ConvertSliceFunc(rule.Matches, t.translateHTTPMatch) - filters := t.translateHTTPFilters(rule.Filters, resources, route.Namespace) - - return api.HTTPRouteRule{ - Services: services, - Matches: matches, - Filters: filters, - }, true -} - -func (t ResourceTranslator) translateHTTPBackendRef(route gwv1beta1.HTTPRoute, ref gwv1beta1.HTTPBackendRef, resources *ResourceMap) (api.HTTPService, bool) { - id := types.NamespacedName{ - Name: string(ref.Name), - Namespace: DerefStringOr(ref.Namespace, route.Namespace), - } - - isServiceRef := NilOrEqual(ref.Group, "") && NilOrEqual(ref.Kind, "Service") - - if isServiceRef && resources.HasService(id) && resources.HTTPRouteCanReferenceBackend(route, ref.BackendRef) { - filters := t.translateHTTPFilters(ref.Filters, resources, route.Namespace) - service := resources.Service(id) - return api.HTTPService{ - Name: service.Name, - Namespace: service.Namespace, - Partition: t.ConsulPartition, - Filters: filters, - Weight: DerefIntOr(ref.Weight, 1), - }, true - } - - isMeshServiceRef := DerefEqual(ref.Group, v1alpha1.ConsulHashicorpGroup) && DerefEqual(ref.Kind, v1alpha1.MeshServiceKind) - if isMeshServiceRef && resources.HasMeshService(id) && resources.HTTPRouteCanReferenceBackend(route, ref.BackendRef) { - filters := t.translateHTTPFilters(ref.Filters, resources, route.Namespace) - service := resources.MeshService(id) - - return api.HTTPService{ - Name: service.Name, - Namespace: service.Namespace, - Partition: t.ConsulPartition, - Filters: filters, - Weight: DerefIntOr(ref.Weight, 1), - }, true - } - - return api.HTTPService{}, false -} - -var headerMatchTypeTranslation = map[gwv1beta1.HeaderMatchType]api.HTTPHeaderMatchType{ - gwv1beta1.HeaderMatchExact: api.HTTPHeaderMatchExact, - gwv1beta1.HeaderMatchRegularExpression: api.HTTPHeaderMatchRegularExpression, -} - -var headerPathMatchTypeTranslation = map[gwv1beta1.PathMatchType]api.HTTPPathMatchType{ - gwv1beta1.PathMatchExact: api.HTTPPathMatchExact, - gwv1beta1.PathMatchPathPrefix: api.HTTPPathMatchPrefix, - gwv1beta1.PathMatchRegularExpression: api.HTTPPathMatchRegularExpression, -} - -var queryMatchTypeTranslation = map[gwv1beta1.QueryParamMatchType]api.HTTPQueryMatchType{ - gwv1beta1.QueryParamMatchExact: api.HTTPQueryMatchExact, - gwv1beta1.QueryParamMatchRegularExpression: api.HTTPQueryMatchRegularExpression, -} - -func (t ResourceTranslator) translateHTTPMatch(match gwv1beta1.HTTPRouteMatch) api.HTTPMatch { - headers := ConvertSliceFunc(match.Headers, t.translateHTTPHeaderMatch) - queries := ConvertSliceFunc(match.QueryParams, t.translateHTTPQueryMatch) - - return api.HTTPMatch{ - Headers: headers, - Query: queries, - Path: DerefConvertFunc(match.Path, t.translateHTTPPathMatch), - Method: api.HTTPMatchMethod(DerefStringOr(match.Method, "")), - } -} - -func (t ResourceTranslator) translateHTTPPathMatch(match gwv1beta1.HTTPPathMatch) api.HTTPPathMatch { - return api.HTTPPathMatch{ - Match: DerefLookup(match.Type, headerPathMatchTypeTranslation), - Value: DerefStringOr(match.Value, ""), - } -} - -func (t ResourceTranslator) translateHTTPHeaderMatch(match gwv1beta1.HTTPHeaderMatch) api.HTTPHeaderMatch { - return api.HTTPHeaderMatch{ - Name: string(match.Name), - Value: match.Value, - Match: DerefLookup(match.Type, headerMatchTypeTranslation), - } -} - -func (t ResourceTranslator) translateHTTPQueryMatch(match gwv1beta1.HTTPQueryParamMatch) api.HTTPQueryMatch { - return api.HTTPQueryMatch{ - Name: string(match.Name), - Value: match.Value, - Match: DerefLookup(match.Type, queryMatchTypeTranslation), - } -} - -func (t ResourceTranslator) translateHTTPFilters(filters []gwv1beta1.HTTPRouteFilter, resourceMap *ResourceMap, namespace string) api.HTTPFilters { - var urlRewrite *api.URLRewrite - consulFilter := api.HTTPHeaderFilter{ - Add: make(map[string]string), - Set: make(map[string]string), - } - var retryFilter *api.RetryFilter - var timeoutFilter *api.TimeoutFilter - - for _, filter := range filters { - if filter.RequestHeaderModifier != nil { - consulFilter.Remove = append(consulFilter.Remove, filter.RequestHeaderModifier.Remove...) - - for _, toAdd := range filter.RequestHeaderModifier.Add { - consulFilter.Add[string(toAdd.Name)] = toAdd.Value - } - - for _, toSet := range filter.RequestHeaderModifier.Set { - consulFilter.Set[string(toSet.Name)] = toSet.Value - } - } - - // we drop any path rewrites that are not prefix matches as we don't support those - if filter.URLRewrite != nil && - filter.URLRewrite.Path != nil && - filter.URLRewrite.Path.Type == gwv1beta1.PrefixMatchHTTPPathModifier { - urlRewrite = &api.URLRewrite{Path: DerefStringOr(filter.URLRewrite.Path.ReplacePrefixMatch, "")} - } - - if filter.ExtensionRef != nil { - //get crd from resources map - crdFilter, exists := resourceMap.GetExternalFilter(*filter.ExtensionRef, namespace) - if !exists { - // this should never be the case because we only translate a route if it's actually valid, and if we're missing filters during the validation step, then we won't get here - continue - } - switch filter.ExtensionRef.Kind { - case v1alpha1.RouteRetryFilterKind: - - retryFilterCRD := crdFilter.(*v1alpha1.RouteRetryFilter) - //new filter that needs to be appended - - retryFilter = &api.RetryFilter{ - NumRetries: retryFilterCRD.Spec.NumRetries, - RetryOn: retryFilterCRD.Spec.RetryOn, - RetryOnStatusCodes: retryFilterCRD.Spec.RetryOnStatusCodes, - RetryOnConnectFailure: retryFilterCRD.Spec.RetryOnConnectFailure, - } - - case v1alpha1.RouteTimeoutFilterKind: - - timeoutFilterCRD := crdFilter.(*v1alpha1.RouteTimeoutFilter) - //new filter that needs to be appended - - timeoutFilter = &api.TimeoutFilter{ - RequestTimeout: timeoutFilterCRD.Spec.RequestTimeout, - IdleTimeout: timeoutFilterCRD.Spec.IdleTimeout, - } - - } - } - - } - return api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{consulFilter}, - URLRewrite: urlRewrite, - RetryFilter: retryFilter, - TimeoutFilter: timeoutFilter, - } -} - -func (t ResourceTranslator) ToTCPRoute(route gwv1alpha2.TCPRoute, resources *ResourceMap) *api.TCPRouteConfigEntry { - namespace := t.Namespace(route.Namespace) - - // we don't translate parent refs - - backendRefs := ConvertSliceFunc(route.Spec.Rules, func(rule gwv1alpha2.TCPRouteRule) []gwv1beta1.BackendRef { return rule.BackendRefs }) - flattenedRefs := Flatten(backendRefs) - services := ConvertSliceFuncIf(flattenedRefs, func(ref gwv1beta1.BackendRef) (api.TCPService, bool) { - return t.translateTCPRouteRule(route, ref, resources) - }) - - return &api.TCPRouteConfigEntry{ - Kind: api.TCPRoute, - Name: route.Name, - Namespace: namespace, - Partition: t.ConsulPartition, - Meta: t.addDatacenterToMeta(map[string]string{ - constants.MetaKeyKubeNS: route.Namespace, - constants.MetaKeyKubeName: route.Name, - }), - Services: services, - } -} - -func (t ResourceTranslator) translateTCPRouteRule(route gwv1alpha2.TCPRoute, ref gwv1beta1.BackendRef, resources *ResourceMap) (api.TCPService, bool) { - // we ignore weight for now - - id := types.NamespacedName{ - Name: string(ref.Name), - Namespace: DerefStringOr(ref.Namespace, route.Namespace), - } - - isServiceRef := NilOrEqual(ref.Group, "") && NilOrEqual(ref.Kind, "Service") - if isServiceRef && resources.HasService(id) && resources.TCPRouteCanReferenceBackend(route, ref) { - service := resources.Service(id) - - return api.TCPService{ - Name: service.Name, - Namespace: service.Namespace, - }, true - } - - isMeshServiceRef := DerefEqual(ref.Group, v1alpha1.ConsulHashicorpGroup) && DerefEqual(ref.Kind, v1alpha1.MeshServiceKind) - if isMeshServiceRef && resources.HasMeshService(id) && resources.TCPRouteCanReferenceBackend(route, ref) { - service := resources.MeshService(id) - - return api.TCPService{ - Name: service.Name, - Namespace: service.Namespace, - }, true - } - - return api.TCPService{}, false -} - -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: namespace, - Partition: t.ConsulPartition, - 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 { - meta := entry.GetMeta() - - return types.NamespacedName{ - Namespace: meta[constants.MetaKeyKubeNS], - Name: meta[constants.MetaKeyKubeName], - } -} - -func (t ResourceTranslator) addDatacenterToMeta(meta map[string]string) map[string]string { - if t.Datacenter == "" { - return meta - } - meta[constants.MetaKeyDatacenter] = t.Datacenter - return meta -} diff --git a/control-plane/api-gateway/common/translation_test.go b/control-plane/api-gateway/common/translation_test.go deleted file mode 100644 index d562845fc8..0000000000 --- a/control-plane/api-gateway/common/translation_test.go +++ /dev/null @@ -1,1645 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "k8s.io/utils/pointer" - "math/big" - "sigs.k8s.io/controller-runtime/pkg/client" - "strings" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - logrtest "github.com/go-logr/logr/testing" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul/api" -) - -type fakeReferenceValidator struct{} - -func (v fakeReferenceValidator) GatewayCanReferenceSecret(gateway gwv1beta1.Gateway, secretRef gwv1beta1.SecretObjectReference) bool { - return true -} - -func (v fakeReferenceValidator) HTTPRouteCanReferenceBackend(httproute gwv1beta1.HTTPRoute, backendRef gwv1beta1.BackendRef) bool { - return true -} - -func (v fakeReferenceValidator) TCPRouteCanReferenceBackend(tcpRoute gwv1alpha2.TCPRoute, backendRef gwv1beta1.BackendRef) bool { - return true -} - -func TestTranslator_Namespace(t *testing.T) { - testCases := []struct { - EnableConsulNamespaces bool - ConsulDestNamespace string - EnableK8sMirroring bool - MirroringPrefix string - Input, ExpectedOutput string - }{ - { - EnableConsulNamespaces: false, - ConsulDestNamespace: "default", - EnableK8sMirroring: false, - MirroringPrefix: "", - Input: "namespace-1", - ExpectedOutput: "", - }, - { - EnableConsulNamespaces: false, - ConsulDestNamespace: "default", - EnableK8sMirroring: true, - MirroringPrefix: "", - Input: "namespace-1", - ExpectedOutput: "", - }, - { - EnableConsulNamespaces: false, - ConsulDestNamespace: "default", - EnableK8sMirroring: true, - MirroringPrefix: "pre-", - Input: "namespace-1", - ExpectedOutput: "", - }, - { - EnableConsulNamespaces: true, - ConsulDestNamespace: "default", - EnableK8sMirroring: false, - MirroringPrefix: "", - Input: "namespace-1", - ExpectedOutput: "default", - }, - { - EnableConsulNamespaces: true, - ConsulDestNamespace: "default", - EnableK8sMirroring: true, - MirroringPrefix: "", - Input: "namespace-1", - ExpectedOutput: "namespace-1", - }, - { - EnableConsulNamespaces: true, - ConsulDestNamespace: "default", - EnableK8sMirroring: true, - MirroringPrefix: "pre-", - Input: "namespace-1", - ExpectedOutput: "pre-namespace-1", - }, - } - - for i, tc := range testCases { - t.Run(fmt.Sprintf("%s_%d", t.Name(), i), func(t *testing.T) { - translator := ResourceTranslator{ - EnableConsulNamespaces: tc.EnableConsulNamespaces, - ConsulDestNamespace: tc.ConsulDestNamespace, - EnableK8sMirroring: tc.EnableK8sMirroring, - MirroringPrefix: tc.MirroringPrefix, - } - assert.Equal(t, tc.ExpectedOutput, translator.Namespace(tc.Input)) - }) - } -} - -func TestTranslator_ToAPIGateway(t *testing.T) { - t.Parallel() - k8sObjectName := "my-k8s-gw" - k8sNamespace := "my-k8s-namespace" - - // gw status - gwLastTransmissionTime := time.Now() - - // listener one configuration - listenerOneName := "listener-one" - listenerOneHostname := "*.consul.io" - listenerOnePort := 3366 - listenerOneProtocol := "http" - - // listener one tls config - listenerOneCertName := "one-cert" - listenerOneCertK8sNamespace := "one-cert-ns" - listenerOneCertConsulNamespace := "one-cert-ns" - listenerOneCert := generateTestCertificate(t, "one-cert-ns", "one-cert") - listenerOneMaxVersion := "TLSv1_2" - listenerOneMinVersion := "TLSv1_3" - listenerOneCipherSuites := []string{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"} - - // listener one status - listenerOneLastTransmissionTime := time.Now() - - // listener two configuration - listenerTwoName := "listener-two" - listenerTwoHostname := "*.consul.io" - listenerTwoPort := 5432 - listenerTwoProtocol := "http" - - // listener one tls config - listenerTwoCertName := "two-cert" - listenerTwoCertK8sNamespace := "two-cert-ns" - listenerTwoCertConsulNamespace := "two-cert-ns" - listenerTwoCert := generateTestCertificate(t, "two-cert-ns", "two-cert") - - // listener two status - listenerTwoLastTransmissionTime := time.Now() - - testCases := map[string]struct { - annotations map[string]string - expectedGWName string - listenerOneK8sCertRefs []gwv1beta1.SecretObjectReference - listenerOneTLSOptions map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue - }{ - "gw name": { - annotations: make(map[string]string), - expectedGWName: k8sObjectName, - listenerOneK8sCertRefs: []gwv1beta1.SecretObjectReference{ - { - Name: gwv1beta1.ObjectName(listenerOneCertName), - Namespace: PointerTo(gwv1beta1.Namespace(listenerOneCertK8sNamespace)), - }, - }, - listenerOneTLSOptions: map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue{ - TLSMaxVersionAnnotationKey: gwv1beta1.AnnotationValue(listenerOneMaxVersion), - TLSMinVersionAnnotationKey: gwv1beta1.AnnotationValue(listenerOneMinVersion), - TLSCipherSuitesAnnotationKey: gwv1beta1.AnnotationValue(strings.Join(listenerOneCipherSuites, ",")), - }, - }, - "when k8s has certs that are not referenced in consul": { - annotations: make(map[string]string), - expectedGWName: k8sObjectName, - listenerOneK8sCertRefs: []gwv1beta1.SecretObjectReference{ - { - Name: gwv1beta1.ObjectName(listenerOneCertName), - Namespace: PointerTo(gwv1beta1.Namespace(listenerOneCertK8sNamespace)), - }, - { - Name: gwv1beta1.ObjectName("cert that won't exist in the translated type"), - Namespace: PointerTo(gwv1beta1.Namespace(listenerOneCertK8sNamespace)), - }, - }, - listenerOneTLSOptions: map[gwv1beta1.AnnotationKey]gwv1beta1.AnnotationValue{ - TLSMaxVersionAnnotationKey: gwv1beta1.AnnotationValue(listenerOneMaxVersion), - TLSMinVersionAnnotationKey: gwv1beta1.AnnotationValue(listenerOneMinVersion), - TLSCipherSuitesAnnotationKey: gwv1beta1.AnnotationValue(strings.Join(listenerOneCipherSuites, ",")), - }, - }, - } - - for name, tc := range testCases { - tc := tc - t.Run(name, func(t *testing.T) { - t.Parallel() - - input := gwv1beta1.Gateway{ - TypeMeta: metav1.TypeMeta{ - Kind: "Gateway", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: k8sObjectName, - Namespace: k8sNamespace, - Annotations: tc.annotations, - }, - Spec: gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{ - { - Name: gwv1beta1.SectionName(listenerOneName), - Hostname: PointerTo(gwv1beta1.Hostname(listenerOneHostname)), - Port: gwv1beta1.PortNumber(listenerOnePort), - Protocol: gwv1beta1.ProtocolType(listenerOneProtocol), - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: tc.listenerOneK8sCertRefs, - Options: tc.listenerOneTLSOptions, - }, - }, - { - Name: gwv1beta1.SectionName(listenerTwoName), - Hostname: PointerTo(gwv1beta1.Hostname(listenerTwoHostname)), - Port: gwv1beta1.PortNumber(listenerTwoPort), - Protocol: gwv1beta1.ProtocolType(listenerTwoProtocol), - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - { - Name: gwv1beta1.ObjectName(listenerTwoCertName), - Namespace: PointerTo(gwv1beta1.Namespace(listenerTwoCertK8sNamespace)), - }, - }, - }, - }, - }, - }, - Status: gwv1beta1.GatewayStatus{ - Conditions: []metav1.Condition{ - { - Type: string(gwv1beta1.GatewayConditionAccepted), - Status: metav1.ConditionTrue, - LastTransitionTime: metav1.Time{Time: gwLastTransmissionTime}, - Reason: string(gwv1beta1.GatewayReasonAccepted), - Message: "I'm accepted", - }, - }, - Listeners: []gwv1beta1.ListenerStatus{ - { - Name: gwv1beta1.SectionName(listenerOneName), - AttachedRoutes: 5, - Conditions: []metav1.Condition{ - { - Type: string(gwv1beta1.GatewayConditionReady), - Status: metav1.ConditionTrue, - LastTransitionTime: metav1.Time{Time: listenerOneLastTransmissionTime}, - Reason: string(gwv1beta1.GatewayConditionReady), - Message: "I'm ready", - }, - }, - }, - - { - Name: gwv1beta1.SectionName(listenerTwoName), - AttachedRoutes: 3, - Conditions: []metav1.Condition{ - { - Type: string(gwv1beta1.GatewayConditionReady), - Status: metav1.ConditionTrue, - LastTransitionTime: metav1.Time{Time: listenerTwoLastTransmissionTime}, - Reason: string(gwv1beta1.GatewayConditionReady), - Message: "I'm also ready", - }, - }, - }, - }, - }, - } - - expectedConfigEntry := &api.APIGatewayConfigEntry{ - Kind: api.APIGateway, - Name: tc.expectedGWName, - Meta: map[string]string{ - constants.MetaKeyKubeNS: k8sNamespace, - constants.MetaKeyKubeName: k8sObjectName, - }, - Listeners: []api.APIGatewayListener{ - { - Name: listenerOneName, - Hostname: listenerOneHostname, - Port: listenerOnePort, - Protocol: listenerOneProtocol, - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{ - { - Kind: api.InlineCertificate, - Name: listenerOneCertName, - Namespace: listenerOneCertConsulNamespace, - }, - }, - CipherSuites: listenerOneCipherSuites, - MaxVersion: listenerOneMaxVersion, - MinVersion: listenerOneMinVersion, - }, - }, - { - Name: listenerTwoName, - Hostname: listenerTwoHostname, - Port: listenerTwoPort, - Protocol: listenerTwoProtocol, - TLS: api.APIGatewayTLSConfiguration{ - Certificates: []api.ResourceReference{ - { - Kind: api.InlineCertificate, - Name: listenerTwoCertName, - Namespace: listenerTwoCertConsulNamespace, - }, - }, - CipherSuites: nil, - MaxVersion: "", - MinVersion: "", - }, - }, - }, - Status: api.ConfigEntryStatus{}, - Namespace: k8sNamespace, - } - translator := ResourceTranslator{ - EnableConsulNamespaces: true, - ConsulDestNamespace: "", - EnableK8sMirroring: true, - MirroringPrefix: "", - } - - resources := NewResourceMap(translator, fakeReferenceValidator{}, logrtest.NewTestLogger(t)) - resources.ReferenceCountCertificate(listenerOneCert) - resources.ReferenceCountCertificate(listenerTwoCert) - - actualConfigEntry := translator.ToAPIGateway(input, resources, &v1alpha1.GatewayClassConfig{}) - - if diff := cmp.Diff(expectedConfigEntry, actualConfigEntry); diff != "" { - t.Errorf("Translator.GatewayToAPIGateway() mismatch (-want +got):\n%s", diff) - } - }) - } -} - -func TestTranslator_ToHTTPRoute(t *testing.T) { - t.Parallel() - type args struct { - k8sHTTPRoute gwv1beta1.HTTPRoute - services []types.NamespacedName - meshServices []v1alpha1.MeshService - externalFilters []client.Object - } - - tests := map[string]struct { - args args - want api.HTTPRouteConfigEntry - }{ - "base test": { - args: args{ - k8sHTTPRoute: gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "k8s-http-route", - Namespace: "k8s-ns", - Annotations: map[string]string{}, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Namespace: PointerTo(gwv1beta1.Namespace("k8s-gw-ns")), - Name: gwv1beta1.ObjectName("api-gw"), - Kind: PointerTo(gwv1beta1.Kind("Gateway")), - SectionName: PointerTo(gwv1beta1.SectionName("listener-1")), - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{ - "host-name.example.com", - "consul.io", - }, - Rules: []gwv1beta1.HTTPRouteRule{ - { - Matches: []gwv1beta1.HTTPRouteMatch{ - { - Path: &gwv1beta1.HTTPPathMatch{ - Type: PointerTo(gwv1beta1.PathMatchPathPrefix), - Value: PointerTo("/v1"), - }, - Headers: []gwv1beta1.HTTPHeaderMatch{ - { - Type: PointerTo(gwv1beta1.HeaderMatchExact), - Name: "my header match", - Value: "the value", - }, - }, - QueryParams: []gwv1beta1.HTTPQueryParamMatch{ - { - Type: PointerTo(gwv1beta1.QueryParamMatchExact), - Name: "search", - Value: "term", - }, - }, - Method: PointerTo(gwv1beta1.HTTPMethodGet), - }, - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "Magic", - Value: "v2", - }, - { - Name: "Another One", - Value: "dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "add it on", - Value: "the value", - }, - }, - Remove: []string{"time to go"}, - }, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: PointerTo("v1"), - }, - }, - }, - }, - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "service one", - Namespace: PointerTo(gwv1beta1.Namespace("other")), - }, - Weight: PointerTo(int32(45)), - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "svc - Magic", - Value: "svc - v2", - }, - { - Name: "svc - Another One", - Value: "svc - dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "svc - add it on", - Value: "svc - the value", - }, - }, - Remove: []string{"svc - time to go"}, - }, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: PointerTo("path"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - services: []types.NamespacedName{ - {Name: "service one", Namespace: "other"}, - }, - }, - want: api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "k8s-http-route", - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "other", - }, - }, - }, - }, - Hostnames: []string{ - "host-name.example.com", - "consul.io", - }, - Meta: map[string]string{ - constants.MetaKeyKubeNS: "k8s-ns", - constants.MetaKeyKubeName: "k8s-http-route", - }, - Namespace: "k8s-ns", - }, - }, - "dropping path rewrites that are not prefix match": { - args: args{ - k8sHTTPRoute: gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "k8s-http-route", - Namespace: "k8s-ns", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Namespace: PointerTo(gwv1beta1.Namespace("k8s-gw-ns")), - Name: gwv1beta1.ObjectName("api-gw"), - SectionName: PointerTo(gwv1beta1.SectionName("listener-1")), - Kind: PointerTo(gwv1beta1.Kind("Gateway")), - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{ - "host-name.example.com", - "consul.io", - }, - Rules: []gwv1beta1.HTTPRouteRule{ - { - Matches: []gwv1beta1.HTTPRouteMatch{ - { - Path: &gwv1beta1.HTTPPathMatch{ - Type: PointerTo(gwv1beta1.PathMatchPathPrefix), - Value: PointerTo("/v1"), - }, - Headers: []gwv1beta1.HTTPHeaderMatch{ - { - Type: PointerTo(gwv1beta1.HeaderMatchExact), - Name: "my header match", - Value: "the value", - }, - }, - QueryParams: []gwv1beta1.HTTPQueryParamMatch{ - { - Type: PointerTo(gwv1beta1.QueryParamMatchExact), - Name: "search", - Value: "term", - }, - }, - Method: PointerTo(gwv1beta1.HTTPMethodGet), - }, - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "Magic", - Value: "v2", - }, - { - Name: "Another One", - Value: "dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "add it on", - Value: "the value", - }, - }, - Remove: []string{"time to go"}, - }, - // THIS IS THE CHANGE - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.FullPathHTTPPathModifier, - ReplaceFullPath: PointerTo("v1"), - }, - }, - }, - }, - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "service one", - Namespace: PointerTo(gwv1beta1.Namespace("some ns")), - }, - Weight: PointerTo(int32(45)), - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "svc - Magic", - Value: "svc - v2", - }, - { - Name: "svc - Another One", - Value: "svc - dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "svc - add it on", - Value: "svc - the value", - }, - }, - Remove: []string{"svc - time to go"}, - }, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: PointerTo("path"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - services: []types.NamespacedName{ - {Name: "service one", Namespace: "some ns"}, - }, - }, - want: api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "k8s-http-route", - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{ - "host-name.example.com", - "consul.io", - }, - Meta: map[string]string{ - constants.MetaKeyKubeNS: "k8s-ns", - constants.MetaKeyKubeName: "k8s-http-route", - }, - Namespace: "k8s-ns", - }, - }, - "parent ref that is not registered with consul is dropped": { - args: args{ - k8sHTTPRoute: gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "k8s-http-route", - Namespace: "k8s-ns", - Annotations: map[string]string{}, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Namespace: PointerTo(gwv1beta1.Namespace("k8s-gw-ns")), - Name: gwv1beta1.ObjectName("api-gw"), - Kind: PointerTo(gwv1beta1.Kind("Gateway")), - SectionName: PointerTo(gwv1beta1.SectionName("listener-1")), - }, - - { - Namespace: PointerTo(gwv1beta1.Namespace("k8s-gw-ns")), - Name: gwv1beta1.ObjectName("consul don't know about me"), - Kind: PointerTo(gwv1beta1.Kind("Gateway")), - SectionName: PointerTo(gwv1beta1.SectionName("listener-1")), - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{ - "host-name.example.com", - "consul.io", - }, - Rules: []gwv1beta1.HTTPRouteRule{ - { - Matches: []gwv1beta1.HTTPRouteMatch{ - { - Path: &gwv1beta1.HTTPPathMatch{ - Type: PointerTo(gwv1beta1.PathMatchPathPrefix), - Value: PointerTo("/v1"), - }, - Headers: []gwv1beta1.HTTPHeaderMatch{ - { - Type: PointerTo(gwv1beta1.HeaderMatchExact), - Name: "my header match", - Value: "the value", - }, - }, - QueryParams: []gwv1beta1.HTTPQueryParamMatch{ - { - Type: PointerTo(gwv1beta1.QueryParamMatchExact), - Name: "search", - Value: "term", - }, - }, - Method: PointerTo(gwv1beta1.HTTPMethodGet), - }, - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "Magic", - Value: "v2", - }, - { - Name: "Another One", - Value: "dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "add it on", - Value: "the value", - }, - }, - Remove: []string{"time to go"}, - }, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: PointerTo("v1"), - }, - }, - }, - }, - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "service one", - Namespace: PointerTo(gwv1beta1.Namespace("some ns")), - }, - Weight: PointerTo(int32(45)), - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "svc - Magic", - Value: "svc - v2", - }, - { - Name: "svc - Another One", - Value: "svc - dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "svc - add it on", - Value: "svc - the value", - }, - }, - Remove: []string{"svc - time to go"}, - }, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: PointerTo("path"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - services: []types.NamespacedName{ - {Name: "service one", Namespace: "some ns"}, - }, - }, - want: api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "k8s-http-route", - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{ - "host-name.example.com", - "consul.io", - }, - Meta: map[string]string{ - constants.MetaKeyKubeNS: "k8s-ns", - constants.MetaKeyKubeName: "k8s-http-route", - }, - Namespace: "k8s-ns", - }, - }, - "when section name on apigw is not supplied": { - args: args{ - k8sHTTPRoute: gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "k8s-http-route", - Namespace: "k8s-ns", - Annotations: map[string]string{}, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Namespace: PointerTo(gwv1beta1.Namespace("k8s-gw-ns")), - Name: gwv1beta1.ObjectName("api-gw"), - Kind: PointerTo(gwv1beta1.Kind("Gateway")), - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{ - "host-name.example.com", - "consul.io", - }, - Rules: []gwv1beta1.HTTPRouteRule{ - { - Matches: []gwv1beta1.HTTPRouteMatch{ - { - Path: &gwv1beta1.HTTPPathMatch{ - Type: PointerTo(gwv1beta1.PathMatchPathPrefix), - Value: PointerTo("/v1"), - }, - Headers: []gwv1beta1.HTTPHeaderMatch{ - { - Type: PointerTo(gwv1beta1.HeaderMatchExact), - Name: "my header match", - Value: "the value", - }, - }, - QueryParams: []gwv1beta1.HTTPQueryParamMatch{ - { - Type: PointerTo(gwv1beta1.QueryParamMatchExact), - Name: "search", - Value: "term", - }, - }, - Method: PointerTo(gwv1beta1.HTTPMethodGet), - }, - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "Magic", - Value: "v2", - }, - { - Name: "Another One", - Value: "dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "add it on", - Value: "the value", - }, - }, - Remove: []string{"time to go"}, - }, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: PointerTo("v1"), - }, - }, - }, - }, - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - // this ref should get dropped - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "service two", - Namespace: PointerTo(gwv1beta1.Namespace("some ns")), - }, - }, - }, - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "some-service-part-three", - Namespace: PointerTo(gwv1beta1.Namespace("svc-ns")), - Group: PointerTo(gwv1beta1.Group(v1alpha1.ConsulHashicorpGroup)), - Kind: PointerTo(gwv1beta1.Kind(v1alpha1.MeshServiceKind)), - }, - }, - }, - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "service one", - Namespace: PointerTo(gwv1beta1.Namespace("some ns")), - }, - Weight: PointerTo(int32(45)), - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "svc - Magic", - Value: "svc - v2", - }, - { - Name: "svc - Another One", - Value: "svc - dj khaled", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "svc - add it on", - Value: "svc - the value", - }, - }, - Remove: []string{"svc - time to go"}, - }, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: PointerTo("path"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - services: []types.NamespacedName{ - {Name: "service one", Namespace: "some ns"}, - }, - meshServices: []v1alpha1.MeshService{ - {ObjectMeta: metav1.ObjectMeta{Name: "some-service-part-three", Namespace: "svc-ns"}, Spec: v1alpha1.MeshServiceSpec{Name: "some-override"}}, - }, - }, - want: api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "k8s-http-route", - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "add it on": "the value", - }, - Remove: []string{"time to go"}, - Set: map[string]string{ - "Magic": "v2", - "Another One": "dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{Path: "v1"}, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - {Name: "some-override", Namespace: "svc-ns", Weight: 1, Filters: api.HTTPFilters{Headers: []api.HTTPHeaderFilter{{Add: make(map[string]string), Set: make(map[string]string)}}}}, - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{ - "svc - add it on": "svc - the value", - }, - Remove: []string{"svc - time to go"}, - Set: map[string]string{ - "svc - Magic": "svc - v2", - "svc - Another One": "svc - dj khaled", - }, - }, - }, - URLRewrite: &api.URLRewrite{ - Path: "path", - }, - }, - Namespace: "some ns", - }, - }, - }, - }, - Hostnames: []string{ - "host-name.example.com", - "consul.io", - }, - Meta: map[string]string{ - constants.MetaKeyKubeNS: "k8s-ns", - constants.MetaKeyKubeName: "k8s-http-route", - }, - Namespace: "k8s-ns", - }, - }, - "test with external filters": { - args: args{ - k8sHTTPRoute: gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "k8s-http-route", - Namespace: "k8s-ns", - Annotations: map[string]string{}, - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Namespace: PointerTo(gwv1beta1.Namespace("k8s-gw-ns")), - Name: gwv1beta1.ObjectName("api-gw"), - Kind: PointerTo(gwv1beta1.Kind("Gateway")), - SectionName: PointerTo(gwv1beta1.SectionName("listener-1")), - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{ - "host-name.example.com", - "consul.io", - }, - Rules: []gwv1beta1.HTTPRouteRule{ - { - Matches: []gwv1beta1.HTTPRouteMatch{ - { - Path: &gwv1beta1.HTTPPathMatch{ - Type: PointerTo(gwv1beta1.PathMatchPathPrefix), - Value: PointerTo("/v1"), - }, - Headers: []gwv1beta1.HTTPHeaderMatch{ - { - Type: PointerTo(gwv1beta1.HeaderMatchExact), - Name: "my header match", - Value: "the value", - }, - }, - QueryParams: []gwv1beta1.HTTPQueryParamMatch{ - { - Type: PointerTo(gwv1beta1.QueryParamMatchExact), - Name: "search", - Value: "term", - }, - }, - Method: PointerTo(gwv1beta1.HTTPMethodGet), - }, - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - ExtensionRef: &gwv1beta1.LocalObjectReference{ - Name: "test", - Kind: v1alpha1.RouteRetryFilterKind, - Group: "consul.hashicorp.com/v1alpha1", - }, - }, - }, - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "service one", - Namespace: PointerTo(gwv1beta1.Namespace("other")), - }, - Weight: PointerTo(int32(45)), - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - ExtensionRef: &gwv1beta1.LocalObjectReference{ - Name: "test", - Kind: v1alpha1.RouteRetryFilterKind, - Group: "consul.hashicorp.com/v1alpha1", - }, - }, - }, - }, - }, - }, - }, - }, - }, - services: []types.NamespacedName{ - {Name: "service one", Namespace: "other"}, - }, - externalFilters: []client.Object{ - &v1alpha1.RouteRetryFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: v1alpha1.RouteRetryFilterKind, - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "k8s-ns", - }, - Spec: v1alpha1.RouteRetryFilterSpec{ - NumRetries: pointer.Uint32(3), - RetryOn: []string{"cancelled"}, - RetryOnStatusCodes: []uint32{500, 502}, - RetryOnConnectFailure: pointer.Bool(false), - }, - }, - - &v1alpha1.RouteRetryFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: v1alpha1.RouteRetryFilterKind, - APIVersion: "consul.hashicorp.com/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "other-namespace-even-though-same-name", - }, - Spec: v1alpha1.RouteRetryFilterSpec{ - NumRetries: pointer.Uint32(3), - RetryOn: []string{"don't"}, - RetryOnStatusCodes: []uint32{404}, - RetryOnConnectFailure: pointer.Bool(true), - }, - }, - }, - }, - want: api.HTTPRouteConfigEntry{ - Kind: api.HTTPRoute, - Name: "k8s-http-route", - Rules: []api.HTTPRouteRule{ - { - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{{Add: map[string]string{}, Set: map[string]string{}}}, - URLRewrite: nil, - RetryFilter: &api.RetryFilter{ - NumRetries: pointer.Uint32(3), - RetryOn: []string{"cancelled"}, - RetryOnStatusCodes: []uint32{500, 502}, - RetryOnConnectFailure: pointer.Bool(false), - }, - }, - Matches: []api.HTTPMatch{ - { - Headers: []api.HTTPHeaderMatch{ - { - Match: api.HTTPHeaderMatchExact, - Name: "my header match", - Value: "the value", - }, - }, - Method: api.HTTPMatchMethodGet, - Path: api.HTTPPathMatch{ - Match: api.HTTPPathMatchPrefix, - Value: "/v1", - }, - Query: []api.HTTPQueryMatch{ - { - Match: api.HTTPQueryMatchExact, - Name: "search", - Value: "term", - }, - }, - }, - }, - Services: []api.HTTPService{ - { - Name: "service one", - Weight: 45, - Filters: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{{Add: map[string]string{}, Set: map[string]string{}}}, - RetryFilter: &api.RetryFilter{ - NumRetries: pointer.Uint32(3), - RetryOn: []string{"cancelled"}, - RetryOnStatusCodes: []uint32{500, 502}, - RetryOnConnectFailure: pointer.Bool(false), - }, - }, - Namespace: "other", - }, - }, - }, - }, - Hostnames: []string{ - "host-name.example.com", - "consul.io", - }, - Meta: map[string]string{ - constants.MetaKeyKubeNS: "k8s-ns", - constants.MetaKeyKubeName: "k8s-http-route", - }, - Namespace: "k8s-ns", - }, - }, - } - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - tr := ResourceTranslator{ - EnableConsulNamespaces: true, - EnableK8sMirroring: true, - } - - resources := NewResourceMap(tr, fakeReferenceValidator{}, logrtest.NewTestLogger(t)) - for _, service := range tc.args.services { - resources.AddService(service, service.Name) - } - for _, service := range tc.args.meshServices { - resources.AddMeshService(service) - } - - for _, filterToAdd := range tc.args.externalFilters { - resources.AddExternalFilter(filterToAdd) - } - - got := tr.ToHTTPRoute(tc.args.k8sHTTPRoute, resources) - if diff := cmp.Diff(&tc.want, got); diff != "" { - t.Errorf("Translator.ToHTTPRoute() mismatch (-want +got):\n%s", diff) - } - }) - } -} - -func TestTranslator_ToTCPRoute(t *testing.T) { - t.Parallel() - type args struct { - k8sRoute gwv1alpha2.TCPRoute - services []types.NamespacedName - meshServices []v1alpha1.MeshService - } - tests := map[string]struct { - args args - want api.TCPRouteConfigEntry - }{ - "base test": { - args: args{ - k8sRoute: gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-route", - Namespace: "k8s-ns", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - Rules: []gwv1alpha2.TCPRouteRule{ - { - BackendRefs: []gwv1beta1.BackendRef{ - { - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "some-service", - Namespace: PointerTo(gwv1beta1.Namespace("svc-ns")), - }, - Weight: new(int32), - }, - }, - }, - { - BackendRefs: []gwv1beta1.BackendRef{ - { - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "some-service-part-two", - Namespace: PointerTo(gwv1beta1.Namespace("svc-ns")), - }, - Weight: new(int32), - }, - { - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Group: PointerTo(gwv1beta1.Group(v1alpha1.ConsulHashicorpGroup)), - Kind: PointerTo(gwv1beta1.Kind(v1alpha1.MeshServiceKind)), - Name: "some-service-part-three", - Namespace: PointerTo(gwv1beta1.Namespace("svc-ns")), - }, - Weight: new(int32), - }, - }, - }, - }, - }, - }, - services: []types.NamespacedName{ - {Name: "some-service", Namespace: "svc-ns"}, - {Name: "some-service-part-two", Namespace: "svc-ns"}, - }, - meshServices: []v1alpha1.MeshService{ - {ObjectMeta: metav1.ObjectMeta{Name: "some-service-part-three", Namespace: "svc-ns"}, Spec: v1alpha1.MeshServiceSpec{Name: "some-override"}}, - }, - }, - want: api.TCPRouteConfigEntry{ - Kind: api.TCPRoute, - Name: "tcp-route", - Namespace: "k8s-ns", - Services: []api.TCPService{ - { - Name: "some-service", - Partition: "", - Namespace: "svc-ns", - }, - { - Name: "some-service-part-two", - Partition: "", - Namespace: "svc-ns", - }, - { - Name: "some-override", - Partition: "", - Namespace: "svc-ns", - }, - }, - Meta: map[string]string{ - constants.MetaKeyKubeNS: "k8s-ns", - constants.MetaKeyKubeName: "tcp-route", - }, - }, - }, - } - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - tr := ResourceTranslator{ - EnableConsulNamespaces: true, - EnableK8sMirroring: true, - } - - resources := NewResourceMap(tr, fakeReferenceValidator{}, logrtest.NewTestLogger(t)) - for _, service := range tt.args.services { - resources.AddService(service, service.Name) - } - for _, service := range tt.args.meshServices { - resources.AddMeshService(service) - } - - got := tr.ToTCPRoute(tt.args.k8sRoute, resources) - if diff := cmp.Diff(&tt.want, got); diff != "" { - t.Errorf("Translator.TCPRouteToTCPRoute() mismatch (-want +got):\n%s", diff) - } - }) - } -} - -func generateTestCertificate(t *testing.T, namespace, name string) corev1.Secret { - privateKey, err := rsa.GenerateKey(rand.Reader, 1024) - require.NoError(t, err) - - usage := x509.KeyUsageCertSign - expiration := time.Now().AddDate(10, 0, 0) - - cert := &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: "consul.test", - }, - IsCA: true, - 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 - caPrivateKey := 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 corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - }, - Data: map[string][]byte{ - corev1.TLSCertKey: certBytes, - corev1.TLSPrivateKeyKey: privateKeyBytes, - }, - } -} - -func TestResourceTranslator_translateHTTPFilters(t1 *testing.T) { - type fields struct { - EnableConsulNamespaces bool - ConsulDestNamespace string - EnableK8sMirroring bool - MirroringPrefix string - ConsulPartition string - Datacenter string - } - type args struct { - filters []gwv1beta1.HTTPRouteFilter - } - tests := []struct { - name string - fields fields - args args - want api.HTTPFilters - }{ - { - name: "no httproutemodifier set", - fields: fields{}, - args: args{ - filters: []gwv1beta1.HTTPRouteFilter{ - { - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{}, - }, - }, - }, - want: api.HTTPFilters{ - Headers: []api.HTTPHeaderFilter{ - { - Add: map[string]string{}, - Set: map[string]string{}, - }, - }, - URLRewrite: nil, - }, - }, - } - for _, tt := range tests { - t1.Run(tt.name, func(t1 *testing.T) { - t := ResourceTranslator{ - EnableConsulNamespaces: tt.fields.EnableConsulNamespaces, - ConsulDestNamespace: tt.fields.ConsulDestNamespace, - EnableK8sMirroring: tt.fields.EnableK8sMirroring, - MirroringPrefix: tt.fields.MirroringPrefix, - ConsulPartition: tt.fields.ConsulPartition, - Datacenter: tt.fields.Datacenter, - } - assert.Equalf(t1, tt.want, t.translateHTTPFilters(tt.args.filters, nil, ""), "translateHTTPFilters(%v)", tt.args.filters) - }) - } -} diff --git a/control-plane/api-gateway/controllers/finalizer.go b/control-plane/api-gateway/controllers/finalizer.go deleted file mode 100644 index c12f5f29e7..0000000000 --- a/control-plane/api-gateway/controllers/finalizer.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// EnsureFinalizer ensures that the given object has the given finalizer. -func EnsureFinalizer(ctx context.Context, client client.Client, object client.Object, finalizer string) (didUpdate bool, err error) { - finalizers := object.GetFinalizers() - for _, f := range finalizers { - if f == finalizer { - return false, nil - } - } - object.SetFinalizers(append(finalizers, finalizer)) - if err := client.Update(ctx, object); err != nil { - return false, err - } - - return true, nil -} - -// RemoveFinalizer removes the given finalizer from the given object. -func RemoveFinalizer(ctx context.Context, client client.Client, object client.Object, finalizer string) (didUpdate bool, err error) { - finalizers := object.GetFinalizers() - - for i, f := range finalizers { - if f == finalizer { - finalizers = append(finalizers[:i], finalizers[i+1:]...) - object.SetFinalizers(finalizers) - if err := client.Update(ctx, object); err != nil { - return false, err - } - return true, nil - } - } - - return false, nil -} diff --git a/control-plane/api-gateway/controllers/finalizer_test.go b/control-plane/api-gateway/controllers/finalizer_test.go deleted file mode 100644 index dc265ef6ca..0000000000 --- a/control-plane/api-gateway/controllers/finalizer_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestEnsureFinalizer(t *testing.T) { - t.Parallel() - - finalizer := "test-finalizer" - - cases := map[string]struct { - initialFinalizers []string - finalizerToAdd string - expectedDidUpdate bool - }{ - "should update": {[]string{}, finalizer, true}, - "should not update": {[]string{finalizer}, finalizer, false}, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - // It doesn't matter what the object is, as long as it implements client.Object. - // A Pod was as good as any other object here. - testObj := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-obj", - Finalizers: tc.initialFinalizers, - }, - } - - client := fake.NewClientBuilder().WithObjects(testObj).Build() - - didUpdate, err := EnsureFinalizer(context.Background(), client, testObj, tc.finalizerToAdd) - - require.NoError(t, err) - require.Equal(t, tc.expectedDidUpdate, didUpdate) - }) - } -} - -func TestRemoveFinalizer(t *testing.T) { - t.Parallel() - - finalizer := "test-finalizer" - - cases := map[string]struct { - initialFinalizers []string - finalizerToRemove string - expectedDidUpdate bool - }{ - "should update": {[]string{finalizer}, finalizer, true}, - "should not update": {[]string{}, finalizer, false}, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - // It doesn't matter what the object is, as long as it implements client.Object. - // A Pod was as good as any other object here. - testObj := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-obj", - Finalizers: tc.initialFinalizers, - }, - } - - client := fake.NewClientBuilder().WithObjects(testObj).Build() - - didUpdate, err := RemoveFinalizer(context.Background(), client, testObj, tc.finalizerToRemove) - - require.NoError(t, err) - require.Equal(t, tc.expectedDidUpdate, didUpdate) - }) - } -} diff --git a/control-plane/api-gateway/controllers/gateway_controller.go b/control-plane/api-gateway/controllers/gateway_controller.go deleted file mode 100644 index f7ef3af83b..0000000000 --- a/control-plane/api-gateway/controllers/gateway_controller.go +++ /dev/null @@ -1,1166 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "fmt" - "reflect" - "strconv" - "strings" - - mapset "github.com/deckarep/golang-set" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - - "github.com/go-logr/logr" - appsv1 "k8s.io/api/apps/v1" - 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/fields" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/builder" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/binding" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/cache" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/gatekeeper" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul/api" -) - -// GatewayControllerConfig holds the values necessary for configuring the GatewayController. -type GatewayControllerConfig struct { - HelmConfig common.HelmConfig - ConsulClientConfig *consul.Config - ConsulServerConnMgr consul.ServerConnectionManager - NamespacesEnabled bool - CrossNamespaceACLPolicy string - Partition string - Datacenter string - AllowK8sNamespacesSet mapset.Set - DenyK8sNamespacesSet mapset.Set -} - -// GatewayController reconciles a Gateway object. -// The Gateway is responsible for defining the behavior of API gateways. -type GatewayController struct { - HelmConfig common.HelmConfig - Log logr.Logger - Translator common.ResourceTranslator - - cache *cache.Cache - gatewayCache *cache.GatewayCache - allowK8sNamespacesSet mapset.Set - denyK8sNamespacesSet mapset.Set - client.Client -} - -// Reconcile handles the reconciliation loop for Gateway objects. -func (r *GatewayController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - consulKey := r.Translator.ConfigEntryReference(api.APIGateway, req.NamespacedName) - nonNormalizedConsulKey := r.Translator.NonNormalizedConfigEntryReference(api.APIGateway, req.NamespacedName) - - var gateway gwv1beta1.Gateway - - log := r.Log.V(1).WithValues("gateway", req.NamespacedName) - log.Info("Reconciling Gateway") - - // get the gateway - if err := r.Client.Get(ctx, req.NamespacedName, &gateway); err != nil { - if !k8serrors.IsNotFound(err) { - log.Error(err, "unable to get Gateway") - } - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - // get the gateway class - gatewayClass, err := r.getGatewayClassForGateway(ctx, gateway) - if err != nil { - log.Error(err, "unable to get GatewayClass") - return ctrl.Result{}, err - } - - // get the gateway class config - gatewayClassConfig, err := r.getConfigForGatewayClass(ctx, gatewayClass) - if err != nil { - log.Error(err, "error fetching the gateway class config") - return ctrl.Result{}, err - } - - // get all namespaces - namespaces, err := r.getNamespaces(ctx) - if err != nil { - log.Error(err, "unable to list Namespaces") - return ctrl.Result{}, err - } - - // get all reference grants - grants, err := r.getReferenceGrants(ctx) - if err != nil { - log.Error(err, "unable to list ReferenceGrants") - return ctrl.Result{}, err - } - - // get related gateway service - service, err := r.getDeployedGatewayService(ctx, req.NamespacedName) - if err != nil { - log.Error(err, "unable to fetch service for Gateway") - } - - // get related gateway pods - pods, err := r.getDeployedGatewayPods(ctx, gateway) - if err != nil { - log.Error(err, "unable to list Pods for Gateway") - return ctrl.Result{}, err - } - - // construct our resource map - referenceValidator := binding.NewReferenceValidator(grants) - resources := common.NewResourceMap(r.Translator, referenceValidator, log) - - if err := r.fetchCertificatesForGateway(ctx, resources, gateway); err != nil { - log.Error(err, "unable to fetch certificates for gateway") - return ctrl.Result{}, err - } - - // fetch our inline certificates from cache, this needs to happen - // here since the certificates need to be reference counted before - // the gateways. - r.fetchConsulInlineCertificates(resources) - - // add our current gateway even if it's not controlled by us so we - // can garbage collect any resources for it. - resources.ReferenceCountGateway(gateway) - - if err := r.fetchControlledGateways(ctx, resources); err != nil { - log.Error(err, "unable to fetch controlled gateways") - return ctrl.Result{}, err - } - - // get all http routes referencing this gateway - httpRoutes, err := r.getRelatedHTTPRoutes(ctx, req.NamespacedName, resources) - if err != nil { - log.Error(err, "unable to list HTTPRoutes") - return ctrl.Result{}, err - } - - // get all tcp routes referencing this gateway - tcpRoutes, err := r.getRelatedTCPRoutes(ctx, req.NamespacedName, resources) - if err != nil { - log.Error(err, "unable to list TCPRoutes") - return ctrl.Result{}, err - } - - if err := r.fetchServicesForRoutes(ctx, resources, tcpRoutes, httpRoutes); err != nil { - log.Error(err, "unable to fetch services for routes") - return ctrl.Result{}, err - } - - // fetch the rest of the consul objects from cache - consulServices := r.getConsulServices(consulKey) - consulGateway := r.getConsulGateway(consulKey) - r.fetchConsulHTTPRoutes(consulKey, resources) - r.fetchConsulTCPRoutes(consulKey, resources) - - binder := binding.NewBinder(binding.BinderConfig{ - Logger: log, - Translator: r.Translator, - ControllerName: common.GatewayClassControllerName, - Namespaces: namespaces, - GatewayClassConfig: gatewayClassConfig, - GatewayClass: gatewayClass, - Gateway: gateway, - Pods: pods, - Service: service, - HTTPRoutes: httpRoutes, - TCPRoutes: tcpRoutes, - Resources: resources, - ConsulGateway: consulGateway, - ConsulGatewayServices: consulServices, - }) - - updates := binder.Snapshot() - - if updates.UpsertGatewayDeployment { - if err := r.cache.EnsureRoleBinding(r.HelmConfig.AuthMethod, gateway.Name, gateway.Namespace); err != nil { - log.Error(err, "error creating role binding") - return ctrl.Result{}, err - } - - err := r.updateGatekeeperResources(ctx, log, &gateway, updates.GatewayClassConfig) - if err != nil { - if k8serrors.IsConflict(err) { - log.Info("error updating object when updating gateway resources, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "unable to update gateway resources") - return ctrl.Result{}, err - } - r.gatewayCache.EnsureSubscribed(nonNormalizedConsulKey, req.NamespacedName) - } else { - err := r.deleteGatekeeperResources(ctx, log, &gateway) - if err != nil { - if k8serrors.IsConflict(err) { - log.Info("error updating object when deleting gateway resources, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "unable to delete gateway resources") - return ctrl.Result{}, err - } - r.gatewayCache.RemoveSubscription(nonNormalizedConsulKey) - // make sure we have deregistered all services even if they haven't - // hit cache yet - if err := r.deregisterAllServices(ctx, nonNormalizedConsulKey); err != nil { - log.Error(err, "error deregistering services") - return ctrl.Result{}, err - } - } - - for _, deletion := range updates.Consul.Deletions { - log.Info("deleting from Consul", "kind", deletion.Kind, "namespace", deletion.Namespace, "name", deletion.Name) - if err := r.cache.Delete(ctx, deletion); err != nil { - log.Error(err, "error deleting config entry") - return ctrl.Result{}, err - } - } - - for _, update := range updates.Consul.Updates { - entry := update.Entry - log.Info("updating in Consul", "kind", entry.GetKind(), "namespace", entry.GetNamespace(), "name", entry.GetName()) - err := r.cache.Write(ctx, entry) - if update.OnUpdate != nil { - // swallow any potential error with our handler if one is provided - update.OnUpdate(err) - continue - } - - if err != nil { - log.Error(err, "error updating config entry") - return ctrl.Result{}, err - } - } - - if updates.UpsertGatewayDeployment { - // We only do some registration/deregistraion if we still have a valid gateway - // otherwise, we've already deregistered everything related to the gateway, so - // no need to do any of the following. - for _, registration := range updates.Consul.Registrations { - log.Info("registering service in Consul", "service", registration.Service.Service, "id", registration.Service.ID) - if err := r.cache.Register(ctx, registration); err != nil { - log.Error(err, "error registering service") - return ctrl.Result{}, err - } - } - - for _, deregistration := range updates.Consul.Deregistrations { - log.Info("deregistering service in Consul", "id", deregistration.ServiceID) - if err := r.cache.Deregister(ctx, deregistration); err != nil { - log.Error(err, "error deregistering service") - return ctrl.Result{}, err - } - } - } - - for _, update := range updates.Kubernetes.Updates.Operations() { - log.Info("update in Kubernetes", "kind", update.GetObjectKind().GroupVersionKind().Kind, "namespace", update.GetNamespace(), "name", update.GetName()) - if err := r.updateAndResetStatus(ctx, update); err != nil { - if k8serrors.IsConflict(err) { - log.Info("error updating object for gateway, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "error updating object") - return ctrl.Result{}, err - } - } - - for _, update := range updates.Kubernetes.StatusUpdates.Operations() { - log.Info("update status in Kubernetes", "kind", update.GetObjectKind().GroupVersionKind().Kind, "namespace", update.GetNamespace(), "name", update.GetName()) - if err := r.Client.Status().Update(ctx, update); err != nil { - if k8serrors.IsConflict(err) { - log.Info("error updating status for gateway, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "error updating status") - return ctrl.Result{}, err - } - } - - return ctrl.Result{}, nil -} - -func (r *GatewayController) deregisterAllServices(ctx context.Context, consulKey api.ResourceReference) error { - services, err := r.gatewayCache.FetchServicesFor(ctx, consulKey) - if err != nil { - return err - } - for _, service := range services { - if err := r.cache.Deregister(ctx, api.CatalogDeregistration{ - Node: service.Node, - ServiceID: service.ServiceID, - Namespace: service.Namespace, - }); err != nil { - return err - } - } - return nil -} - -func (r *GatewayController) updateAndResetStatus(ctx context.Context, o client.Object) error { - // we create a copy so that we can re-update its status if need be - status := reflect.ValueOf(o.DeepCopyObject()).Elem().FieldByName("Status") - if err := r.Client.Update(ctx, o); err != nil { - return err - } - - // reset the status in case it needs to be updated below - reflect.ValueOf(o).Elem().FieldByName("Status").Set(status) - return nil -} - -func configEntriesTo[T api.ConfigEntry](entries []api.ConfigEntry) []T { - es := []T{} - for _, e := range entries { - es = append(es, e.(T)) - } - return es -} - -func (r *GatewayController) deleteGatekeeperResources(ctx context.Context, log logr.Logger, gw *gwv1beta1.Gateway) error { - gk := gatekeeper.New(log, r.Client) - err := gk.Delete(ctx, types.NamespacedName{ - Namespace: gw.Namespace, - Name: gw.Name, - }) - if err != nil { - return err - } - - return nil -} - -func (r *GatewayController) updateGatekeeperResources(ctx context.Context, log logr.Logger, gw *gwv1beta1.Gateway, gwcc *v1alpha1.GatewayClassConfig) error { - gk := gatekeeper.New(log, r.Client) - err := gk.Upsert(ctx, *gw, *gwcc, r.HelmConfig) - if err != nil { - return err - } - - return nil -} - -// SetupWithGatewayControllerManager registers the controller with the given manager. -func SetupGatewayControllerWithManager(ctx context.Context, mgr ctrl.Manager, config GatewayControllerConfig) (*cache.Cache, error) { - cacheConfig := cache.Config{ - ConsulClientConfig: config.ConsulClientConfig, - ConsulServerConnMgr: config.ConsulServerConnMgr, - NamespacesEnabled: config.NamespacesEnabled, - Datacenter: config.Datacenter, - CrossNamespaceACLPolicy: config.CrossNamespaceACLPolicy, - Logger: mgr.GetLogger(), - } - c := cache.New(cacheConfig) - gwc := cache.NewGatewayCache(ctx, cacheConfig) - - predicate, _ := predicate.LabelSelectorPredicate( - *metav1.SetAsLabelSelector(map[string]string{ - common.ManagedLabel: "true", - }), - ) - - r := &GatewayController{ - Client: mgr.GetClient(), - Log: mgr.GetLogger(), - HelmConfig: config.HelmConfig.Normalize(), - Translator: common.ResourceTranslator{ - EnableConsulNamespaces: config.HelmConfig.EnableNamespaces, - ConsulDestNamespace: config.HelmConfig.ConsulDestinationNamespace, - EnableK8sMirroring: config.HelmConfig.EnableNamespaceMirroring, - MirroringPrefix: config.HelmConfig.NamespaceMirroringPrefix, - ConsulPartition: config.HelmConfig.ConsulPartition, - Datacenter: config.Datacenter, - }, - denyK8sNamespacesSet: config.DenyK8sNamespacesSet, - allowK8sNamespacesSet: config.AllowK8sNamespacesSet, - cache: c, - gatewayCache: gwc, - } - - return c, ctrl.NewControllerManagedBy(mgr). - For(&gwv1beta1.Gateway{}). - Owns(&appsv1.Deployment{}). - Owns(&corev1.Service{}). - Owns(&corev1.Pod{}). - Watches( - source.NewKindWithCache(&gwv1beta1.ReferenceGrant{}, mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformReferenceGrant(ctx)), - ). - Watches( - source.NewKindWithCache(&gwv1beta1.GatewayClass{}, mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformGatewayClass(ctx)), - ). - Watches( - source.NewKindWithCache(&gwv1beta1.HTTPRoute{}, mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformHTTPRoute(ctx)), - ). - Watches( - source.NewKindWithCache(&gwv1alpha2.TCPRoute{}, mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformTCPRoute(ctx)), - ). - Watches( - source.NewKindWithCache(&corev1.Secret{}, mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformSecret(ctx)), - ). - Watches( - source.NewKindWithCache(&v1alpha1.MeshService{}, mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformMeshService(ctx)), - ). - Watches( - source.NewKindWithCache(&corev1.Endpoints{}, mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformEndpoints(ctx)), - ). - Watches( - &source.Kind{Type: &corev1.Pod{}}, - handler.EnqueueRequestsFromMapFunc(r.transformPods(ctx)), - builder.WithPredicates(predicate), - ). - Watches( - // Subscribe to changes from Consul for APIGateways - &source.Channel{Source: c.Subscribe(ctx, api.APIGateway, r.transformConsulGateway).Events()}, - &handler.EnqueueRequestForObject{}, - ). - Watches( - // Subscribe to changes from Consul for HTTPRoutes - &source.Channel{Source: c.Subscribe(ctx, api.HTTPRoute, r.transformConsulHTTPRoute(ctx)).Events()}, - &handler.EnqueueRequestForObject{}, - ). - Watches( - // Subscribe to changes from Consul for TCPRoutes - &source.Channel{Source: c.Subscribe(ctx, api.TCPRoute, r.transformConsulTCPRoute(ctx)).Events()}, - &handler.EnqueueRequestForObject{}, - ). - Watches( - // Subscribe to changes from Consul for InlineCertificates - &source.Channel{Source: c.Subscribe(ctx, api.InlineCertificate, r.transformConsulInlineCertificate(ctx)).Events()}, - &handler.EnqueueRequestForObject{}, - ). - Watches( - source.NewKindWithCache((&v1alpha1.RouteRetryFilter{}), mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformRouteRetryFilter(ctx)), - ). - Watches( - source.NewKindWithCache((&v1alpha1.RouteTimeoutFilter{}), mgr.GetCache()), - handler.EnqueueRequestsFromMapFunc(r.transformRouteTimeoutFilter(ctx)), - ).Complete(r) -} - -// transformGatewayClass will check the list of GatewayClass objects for a matching -// class, then return a list of reconcile Requests for it. -func (r *GatewayController) transformGatewayClass(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - gatewayClass := o.(*gwv1beta1.GatewayClass) - gatewayList := &gwv1beta1.GatewayList{} - if err := r.Client.List(ctx, gatewayList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(Gateway_GatewayClassIndex, gatewayClass.Name), - }); err != nil { - return nil - } - return common.ObjectsToReconcileRequests(pointersOf(gatewayList.Items)) - } -} - -// transformHTTPRoute will check the HTTPRoute object for a matching -// class, then return a list of reconcile Requests for Gateways referring to it. -func (r *GatewayController) transformHTTPRoute(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - route := o.(*gwv1beta1.HTTPRoute) - - refs := refsToRequests(common.ParentRefs(common.BetaGroup, common.KindGateway, route.Namespace, route.Spec.ParentRefs)) - statusRefs := refsToRequests(common.ParentRefs(common.BetaGroup, common.KindGateway, route.Namespace, common.ConvertSliceFunc(route.Status.Parents, func(parentStatus gwv1beta1.RouteParentStatus) gwv1beta1.ParentReference { - return parentStatus.ParentRef - }))) - return append(refs, statusRefs...) - } -} - -// transformTCPRoute will check the TCPRoute object for a matching -// class, then return a list of reconcile Requests for Gateways referring to it. -func (r *GatewayController) transformTCPRoute(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - route := o.(*gwv1alpha2.TCPRoute) - - refs := refsToRequests(common.ParentRefs(common.BetaGroup, common.KindGateway, route.Namespace, route.Spec.ParentRefs)) - statusRefs := refsToRequests(common.ParentRefs(common.BetaGroup, common.KindGateway, route.Namespace, common.ConvertSliceFunc(route.Status.Parents, func(parentStatus gwv1beta1.RouteParentStatus) gwv1beta1.ParentReference { - return parentStatus.ParentRef - }))) - return append(refs, statusRefs...) - } -} - -// transformSecret will check the Secret object for a matching -// class, then return a list of reconcile Requests for Gateways referring to it. -func (r *GatewayController) transformSecret(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - secret := o.(*corev1.Secret) - gatewayList := &gwv1beta1.GatewayList{} - if err := r.Client.List(ctx, gatewayList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(Secret_GatewayIndex, client.ObjectKeyFromObject(secret).String()), - }); err != nil { - return nil - } - return common.ObjectsToReconcileRequests(pointersOf(gatewayList.Items)) - } -} - -// transformReferenceGrant will check the ReferenceGrant object for a matching -// class, then return a list of reconcile Requests for Gateways referring to it. -func (r *GatewayController) transformReferenceGrant(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - // just re-reconcile all gateways for now ideally this will filter down to gateways - // affected, but technically the blast radius is gateways in the namespace + referencing - // the namespace + the routes that bind to them. - gatewayList := &gwv1beta1.GatewayList{} - if err := r.Client.List(ctx, gatewayList); err != nil { - return nil - } - - return common.ObjectsToReconcileRequests(pointersOf(gatewayList.Items)) - } -} - -// transformMeshService will return a list of gateways that are referenced -// by a TCPRoute or HTTPRoute that references the mesh service. -func (r *GatewayController) transformMeshService(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - service := o.(*v1alpha1.MeshService) - key := client.ObjectKeyFromObject(service).String() - - return r.gatewaysForRoutesReferencing(ctx, TCPRoute_MeshServiceIndex, HTTPRoute_MeshServiceIndex, key) - } -} - -// transformConsulGateway will return a list of gateways that this corresponds to. -func (r *GatewayController) transformConsulGateway(entry api.ConfigEntry) []types.NamespacedName { - return []types.NamespacedName{common.EntryToNamespacedName(entry)} -} - -// transformConsulHTTPRoute will return a list of gateways that need to be reconciled. -func (r *GatewayController) transformConsulHTTPRoute(ctx context.Context) func(entry api.ConfigEntry) []types.NamespacedName { - return func(entry api.ConfigEntry) []types.NamespacedName { - parents := mapset.NewSet() - for _, parent := range entry.(*api.HTTPRouteConfigEntry).Parents { - parents.Add(api.ResourceReference{ - Kind: parent.Kind, - Name: parent.Name, - Namespace: parent.Namespace, - Partition: parent.Partition, - }) - } - - var gateways []types.NamespacedName - for parent := range parents.Iter() { - if gateway := r.cache.Get(parent.(api.ResourceReference)); gateway != nil { - gateways = append(gateways, common.EntryToNamespacedName(gateway)) - } - } - return gateways - } -} - -// transformRouteRetryFilter will return a list of routes that need to be reconciled. -func (r *GatewayController) transformRouteRetryFilter(ctx context.Context) func(object client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - return r.gatewaysForRoutesReferencing(ctx, "", HTTPRoute_RouteRetryFilterIndex, client.ObjectKeyFromObject(o).String()) - } -} - -// transformTimeoutRetryFilter will return a list of routes that need to be reconciled. -func (r *GatewayController) transformRouteTimeoutFilter(ctx context.Context) func(object client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - return r.gatewaysForRoutesReferencing(ctx, "", HTTPRoute_RouteTimeoutFilterIndex, client.ObjectKeyFromObject(o).String()) - } -} - -func (r *GatewayController) transformConsulTCPRoute(ctx context.Context) func(entry api.ConfigEntry) []types.NamespacedName { - return func(entry api.ConfigEntry) []types.NamespacedName { - parents := mapset.NewSet() - for _, parent := range entry.(*api.TCPRouteConfigEntry).Parents { - parents.Add(api.ResourceReference{ - Kind: parent.Kind, - Name: parent.Name, - Namespace: parent.Namespace, - Partition: parent.Partition, - }) - } - - var gateways []types.NamespacedName - for parent := range parents.Iter() { - if gateway := r.cache.Get(parent.(api.ResourceReference)); gateway != nil { - gateways = append(gateways, common.EntryToNamespacedName(gateway)) - } - } - return gateways - } -} - -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(), - Name: entry.GetName(), - Namespace: entry.GetNamespace(), - Partition: entry.GetPartition(), - } - - var gateways []types.NamespacedName - for _, entry := range r.cache.List(api.APIGateway) { - gateway := entry.(*api.APIGatewayConfigEntry) - if gatewayReferencesCertificate(certificateKey, gateway) { - gateways = append(gateways, common.EntryToNamespacedName(gateway)) - } - } - - return gateways - } -} - -func gatewayReferencesCertificate(certificateKey api.ResourceReference, gateway *api.APIGatewayConfigEntry) bool { - for _, listener := range gateway.Listeners { - for _, cert := range listener.TLS.Certificates { - if cert == certificateKey { - return true - } - } - } - return false -} - -func (r *GatewayController) transformPods(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - pod := o.(*corev1.Pod) - - if gateway, managed := common.GatewayFromPod(pod); managed { - return []reconcile.Request{ - {NamespacedName: gateway}, - } - } - - return nil - } -} - -// transformEndpoints will return a list of gateways that are referenced -// by a TCPRoute or HTTPRoute that references the service. -func (r *GatewayController) transformEndpoints(ctx context.Context) func(o client.Object) []reconcile.Request { - return func(o client.Object) []reconcile.Request { - key := client.ObjectKeyFromObject(o) - endpoints := o.(*corev1.Endpoints) - - if shouldIgnore(key.Namespace, r.denyK8sNamespacesSet, r.allowK8sNamespacesSet) || isLabeledIgnore(endpoints.Labels) { - return nil - } - - return r.gatewaysForRoutesReferencing(ctx, TCPRoute_ServiceIndex, HTTPRoute_ServiceIndex, key.String()) - } -} - -// gatewaysForRoutesReferencing returns a mapping of all gateways that are referenced by routes that -// have a backend associated with the given key and index. -func (r *GatewayController) gatewaysForRoutesReferencing(ctx context.Context, tcpIndex, httpIndex, key string) []reconcile.Request { - requestSet := make(map[types.NamespacedName]struct{}) - - if tcpIndex != "" { - tcpRouteList := &gwv1alpha2.TCPRouteList{} - if err := r.Client.List(ctx, tcpRouteList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(tcpIndex, key), - }); err != nil { - r.Log.Error(err, "unable to list TCPRoutes") - } - for _, route := range tcpRouteList.Items { - for _, ref := range common.ParentRefs(common.BetaGroup, common.KindGateway, route.Namespace, route.Spec.ParentRefs) { - requestSet[ref] = struct{}{} - } - } - } - - httpRouteList := &gwv1beta1.HTTPRouteList{} - if err := r.Client.List(ctx, httpRouteList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(httpIndex, key), - }); err != nil { - r.Log.Error(err, "unable to list HTTPRoutes") - } - for _, route := range httpRouteList.Items { - for _, ref := range common.ParentRefs(common.BetaGroup, common.KindGateway, route.Namespace, route.Spec.ParentRefs) { - requestSet[ref] = struct{}{} - } - } - - requests := []reconcile.Request{} - for request := range requestSet { - requests = append(requests, reconcile.Request{NamespacedName: request}) - } - return requests -} - -// pointersOf returns a list of pointers to the list of objects passed in. -func pointersOf[T any](objects []T) []*T { - pointers := make([]*T, 0, len(objects)) - for _, object := range objects { - pointers = append(pointers, pointerTo(object)) - } - return pointers -} - -// pointerTo returns a pointer to the object type passed in. -func pointerTo[T any](v T) *T { - return &v -} - -// refsToRequests takes a list of NamespacedName objects and returns a list of -// reconcile Requests. -func refsToRequests(objects []types.NamespacedName) []reconcile.Request { - requests := make([]reconcile.Request, 0, len(objects)) - for _, object := range objects { - requests = append(requests, reconcile.Request{ - NamespacedName: object, - }) - } - return requests -} - -// kubernetes helpers - -func (c *GatewayController) getNamespaces(ctx context.Context) (map[string]corev1.Namespace, error) { - var list corev1.NamespaceList - - if err := c.Client.List(ctx, &list); err != nil { - return nil, err - } - namespaces := map[string]corev1.Namespace{} - for _, namespace := range list.Items { - namespaces[namespace.Name] = namespace - } - - return namespaces, nil -} - -func (c *GatewayController) getReferenceGrants(ctx context.Context) ([]gwv1beta1.ReferenceGrant, error) { - var list gwv1beta1.ReferenceGrantList - - if err := c.Client.List(ctx, &list); err != nil { - return nil, err - } - - return list.Items, nil -} - -func (c *GatewayController) getDeployedGatewayService(ctx context.Context, gateway types.NamespacedName) (*corev1.Service, error) { - service := &corev1.Service{} - - // we use the implicit association of a service name/namespace with a corresponding gateway - if err := c.Client.Get(ctx, gateway, service); err != nil { - return nil, client.IgnoreNotFound(err) - } - - return service, nil -} - -func (c *GatewayController) getDeployedGatewayPods(ctx context.Context, gateway gwv1beta1.Gateway) ([]corev1.Pod, error) { - labels := common.LabelsForGateway(&gateway) - - var list corev1.PodList - - if err := c.Client.List(ctx, &list, client.MatchingLabels(labels)); err != nil { - return nil, err - } - - return list.Items, nil -} - -func (c *GatewayController) getRelatedHTTPRoutes(ctx context.Context, gateway types.NamespacedName, resources *common.ResourceMap) ([]gwv1beta1.HTTPRoute, error) { - var list gwv1beta1.HTTPRouteList - - if err := c.Client.List(ctx, &list, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(HTTPRoute_GatewayIndex, gateway.String()), - }); err != nil { - return nil, err - } - - for _, route := range list.Items { - resources.ReferenceCountHTTPRoute(route) - - _, err := c.getExternalFiltersForHTTPRoute(ctx, route, resources) - if err != nil { - c.Log.Error(err, "unable to list HTTPRoute ExternalFilters") - return nil, err - } - } - - return list.Items, nil -} - -func (c *GatewayController) getExternalFiltersForHTTPRoute(ctx context.Context, route gwv1beta1.HTTPRoute, resources *common.ResourceMap) ([]interface{}, error) { - var externalFilters []interface{} - for _, rule := range route.Spec.Rules { - ruleFilters, err := c.filterFiltersForExternalRefs(ctx, route, rule.Filters, resources) - if err != nil { - return nil, err - } - externalFilters = append(externalFilters, ruleFilters...) - - for _, backendRef := range rule.BackendRefs { - backendRefFilter, err := c.filterFiltersForExternalRefs(ctx, route, backendRef.Filters, resources) - if err != nil { - return nil, err - } - - externalFilters = append(externalFilters, backendRefFilter...) - } - } - - return externalFilters, nil -} - -func (c *GatewayController) filterFiltersForExternalRefs(ctx context.Context, route gwv1beta1.HTTPRoute, filters []gwv1beta1.HTTPRouteFilter, resources *common.ResourceMap) ([]interface{}, error) { - var externalFilters []interface{} - - for _, filter := range filters { - var externalFilter client.Object - - //check to see if we need to grab this filter - if filter.ExtensionRef == nil { - continue - } - switch kind := filter.ExtensionRef.Kind; kind { - case v1alpha1.RouteRetryFilterKind: - externalFilter = &v1alpha1.RouteRetryFilter{} - case v1alpha1.RouteTimeoutFilterKind: - externalFilter = &v1alpha1.RouteTimeoutFilter{} - default: - continue - } - - //get object from API - err := c.Client.Get(ctx, client.ObjectKey{ - Name: string(filter.ExtensionRef.Name), - Namespace: route.Namespace, - }, externalFilter) - - if err != nil { - if k8serrors.IsNotFound(err) { - c.Log.Info(fmt.Sprintf("externalref %s:%s not found: %v", filter.ExtensionRef.Kind, filter.ExtensionRef.Name, err)) - //ignore, the validation call should mark this route as error - continue - } else { - return nil, err - } - } - - //add external ref (or error) to resource map for this route - resources.AddExternalFilter(externalFilter) - externalFilters = append(externalFilters, externalFilter) - } - return externalFilters, nil -} - -func (c *GatewayController) getRelatedTCPRoutes(ctx context.Context, gateway types.NamespacedName, resources *common.ResourceMap) ([]gwv1alpha2.TCPRoute, error) { - var list gwv1alpha2.TCPRouteList - - if err := c.Client.List(ctx, &list, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(TCPRoute_GatewayIndex, gateway.String()), - }); err != nil { - return nil, err - } - - for _, route := range list.Items { - resources.ReferenceCountTCPRoute(route) - } - - return list.Items, nil -} - -func (c *GatewayController) getConfigForGatewayClass(ctx context.Context, gatewayClassConfig *gwv1beta1.GatewayClass) (*v1alpha1.GatewayClassConfig, error) { - if gatewayClassConfig == nil { - // if we don't have a gateway class we can't fetch the corresponding config - return nil, nil - } - - config := &v1alpha1.GatewayClassConfig{} - if ref := gatewayClassConfig.Spec.ParametersRef; ref != nil { - if string(ref.Group) != v1alpha1.GroupVersion.Group || - ref.Kind != v1alpha1.GatewayClassConfigKind || - gatewayClassConfig.Spec.ControllerName != common.GatewayClassControllerName { - // we don't have supported params, so return nil - return nil, nil - } - - if err := c.Client.Get(ctx, types.NamespacedName{Name: ref.Name}, config); err != nil { - return nil, client.IgnoreNotFound(err) - } - } - return config, nil -} - -func (c *GatewayController) getGatewayClassForGateway(ctx context.Context, gateway gwv1beta1.Gateway) (*gwv1beta1.GatewayClass, error) { - var gatewayClass gwv1beta1.GatewayClass - if err := c.Client.Get(ctx, types.NamespacedName{Name: string(gateway.Spec.GatewayClassName)}, &gatewayClass); err != nil { - return nil, client.IgnoreNotFound(err) - } - return &gatewayClass, nil -} - -// resource map construction routines - -func (c *GatewayController) fetchControlledGateways(ctx context.Context, resources *common.ResourceMap) error { - set := mapset.NewSet() - - list := gwv1beta1.GatewayClassList{} - if err := c.Client.List(ctx, &list, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(GatewayClass_ControllerNameIndex, common.GatewayClassControllerName), - }); err != nil { - return err - } - for _, gatewayClass := range list.Items { - set.Add(gatewayClass.Name) - } - - gateways := &gwv1beta1.GatewayList{} - if err := c.Client.List(ctx, gateways); err != nil { - return err - } - - for _, gateway := range gateways.Items { - if set.Contains(string(gateway.Spec.GatewayClassName)) { - resources.ReferenceCountGateway(gateway) - } - } - return nil -} - -func (c *GatewayController) fetchCertificatesForGateway(ctx context.Context, resources *common.ResourceMap, gateway gwv1beta1.Gateway) error { - certificates := mapset.NewSet() - - for _, listener := range gateway.Spec.Listeners { - if listener.TLS != nil { - for _, cert := range listener.TLS.CertificateRefs { - if common.NilOrEqual(cert.Group, "") && common.NilOrEqual(cert.Kind, common.KindSecret) { - certificates.Add(common.IndexedNamespacedNameWithDefault(cert.Name, cert.Namespace, gateway.Namespace)) - } - } - } - } - - for key := range certificates.Iter() { - if err := c.fetchSecret(ctx, resources, key.(types.NamespacedName)); err != nil { - return err - } - } - - return nil -} - -func (c *GatewayController) fetchSecret(ctx context.Context, resources *common.ResourceMap, key types.NamespacedName) error { - var secret corev1.Secret - if err := c.Client.Get(ctx, key, &secret); err != nil { - return client.IgnoreNotFound(err) - } - - resources.ReferenceCountCertificate(secret) - - return nil -} - -func (c *GatewayController) fetchServicesForRoutes(ctx context.Context, resources *common.ResourceMap, tcpRoutes []gwv1alpha2.TCPRoute, httpRoutes []gwv1beta1.HTTPRoute) error { - serviceBackends := mapset.NewSet() - meshServiceBackends := mapset.NewSet() - - for _, route := range httpRoutes { - for _, rule := range route.Spec.Rules { - for _, backend := range rule.BackendRefs { - if common.DerefEqual(backend.Group, v1alpha1.ConsulHashicorpGroup) && - common.DerefEqual(backend.Kind, v1alpha1.MeshServiceKind) { - meshServiceBackends.Add(common.IndexedNamespacedNameWithDefault(backend.Name, backend.Namespace, route.Namespace)) - } else if common.NilOrEqual(backend.Group, "") && common.NilOrEqual(backend.Kind, "Service") { - serviceBackends.Add(common.IndexedNamespacedNameWithDefault(backend.Name, backend.Namespace, route.Namespace)) - } - } - } - } - - for _, route := range tcpRoutes { - for _, rule := range route.Spec.Rules { - for _, backend := range rule.BackendRefs { - if common.DerefEqual(backend.Group, v1alpha1.ConsulHashicorpGroup) && - common.DerefEqual(backend.Kind, v1alpha1.MeshServiceKind) { - meshServiceBackends.Add(common.IndexedNamespacedNameWithDefault(backend.Name, backend.Namespace, route.Namespace)) - } else if common.NilOrEqual(backend.Group, "") && common.NilOrEqual(backend.Kind, "Service") { - serviceBackends.Add(common.IndexedNamespacedNameWithDefault(backend.Name, backend.Namespace, route.Namespace)) - } - } - } - } - - for key := range meshServiceBackends.Iter() { - if err := c.fetchMeshService(ctx, resources, key.(types.NamespacedName)); err != nil { - return err - } - } - - for key := range serviceBackends.Iter() { - if err := c.fetchServicesForEndpoints(ctx, resources, key.(types.NamespacedName)); err != nil { - return err - } - } - return nil -} - -func (c *GatewayController) fetchMeshService(ctx context.Context, resources *common.ResourceMap, key types.NamespacedName) error { - var service v1alpha1.MeshService - if err := c.Client.Get(ctx, key, &service); err != nil { - return client.IgnoreNotFound(err) - } - - resources.AddMeshService(service) - - return nil -} - -func (c *GatewayController) fetchServicesForEndpoints(ctx context.Context, resources *common.ResourceMap, key types.NamespacedName) error { - - if shouldIgnore(key.Namespace, c.denyK8sNamespacesSet, c.allowK8sNamespacesSet) { - return nil - } - - var endpoints corev1.Endpoints - if err := c.Client.Get(ctx, key, &endpoints); err != nil { - return client.IgnoreNotFound(err) - } - - if isLabeledIgnore(endpoints.Labels) { - return nil - } - - for _, subset := range endpoints.Subsets { - for _, address := range subset.Addresses { - if address.TargetRef != nil && address.TargetRef.Kind == "Pod" { - objectKey := types.NamespacedName{Name: address.TargetRef.Name, Namespace: address.TargetRef.Namespace} - - var pod corev1.Pod - if err := c.Client.Get(ctx, objectKey, &pod); err != nil { - if k8serrors.IsNotFound(err) { - continue - } - return err - } - - resources.AddService(key, serviceName(pod, endpoints)) - - } - } - } - - return nil -} - -// cache routines - -func (c *GatewayController) getConsulServices(ref api.ResourceReference) []api.CatalogService { - return c.gatewayCache.ServicesFor(ref) -} - -func (c *GatewayController) getConsulGateway(ref api.ResourceReference) *api.APIGatewayConfigEntry { - if entry := c.cache.Get(ref); entry != nil { - return entry.(*api.APIGatewayConfigEntry) - } - return nil -} - -func (c *GatewayController) fetchConsulHTTPRoutes(ref api.ResourceReference, resources *common.ResourceMap) { - for _, route := range configEntriesTo[*api.HTTPRouteConfigEntry](c.cache.List(api.HTTPRoute)) { - if routeReferencesGateway(route.Namespace, ref, route.Parents) { - resources.ReferenceCountConsulHTTPRoute(*route) - } - } -} - -func (c *GatewayController) fetchConsulTCPRoutes(ref api.ResourceReference, resources *common.ResourceMap) { - for _, route := range configEntriesTo[*api.TCPRouteConfigEntry](c.cache.List(api.TCPRoute)) { - if routeReferencesGateway(route.Namespace, ref, route.Parents) { - resources.ReferenceCountConsulTCPRoute(*route) - } - } -} - -func (c *GatewayController) fetchConsulInlineCertificates(resources *common.ResourceMap) { - for _, cert := range configEntriesTo[*api.InlineCertificateConfigEntry](c.cache.List(api.InlineCertificate)) { - resources.ReferenceCountConsulCertificate(*cert) - } -} - -func routeReferencesGateway(namespace string, ref api.ResourceReference, refs []api.ResourceReference) bool { - // we don't need to check partition here since they're all in the same partition - if namespace == "" { - namespace = "default" - } - - for _, parent := range refs { - if common.EmptyOrEqual(parent.Kind, api.APIGateway) { - if common.DefaultOrEqual(parent.Namespace, namespace, ref.Namespace) && - parent.Name == ref.Name { - return true - } - } - } - - return false -} - -func serviceName(pod corev1.Pod, serviceEndpoints corev1.Endpoints) string { - svcName := serviceEndpoints.Name - // If the annotation has a comma, it is a multi port Pod. In that case we always use the name of the endpoint. - if serviceNameFromAnnotation, ok := pod.Annotations[constants.AnnotationService]; ok && serviceNameFromAnnotation != "" && !strings.Contains(serviceNameFromAnnotation, ",") { - svcName = serviceNameFromAnnotation - } - return svcName -} - -func isLabeledIgnore(labels map[string]string) bool { - value, labelExists := labels[constants.LabelServiceIgnore] - shouldIgnore, err := strconv.ParseBool(value) - - return shouldIgnore && labelExists && err == nil -} - -// shouldIgnore ignores namespaces where we don't connect-inject. -func shouldIgnore(namespace string, denySet, allowSet mapset.Set) bool { - // Ignores system namespaces. - if namespace == metav1.NamespaceSystem || namespace == metav1.NamespacePublic || namespace == "local-path-storage" { - return true - } - - // Ignores deny list. - if denySet.Contains(namespace) { - return true - } - - // Ignores if not in allow list or allow list is not *. - if !allowSet.Contains("*") && !allowSet.Contains(namespace) { - return true - } - - return false -} diff --git a/control-plane/api-gateway/controllers/gateway_controller_integration_test.go b/control-plane/api-gateway/controllers/gateway_controller_integration_test.go deleted file mode 100644 index 2605991238..0000000000 --- a/control-plane/api-gateway/controllers/gateway_controller_integration_test.go +++ /dev/null @@ -1,1325 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "math/big" - "sync" - "testing" - "time" - - mapset "github.com/deckarep/golang-set" - logrtest "github.com/go-logr/logr/testr" - "github.com/stretchr/testify/require" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/cache" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/helper/test" - "github.com/hashicorp/consul/api" -) - -func TestControllerDoesNotInfinitelyReconcile(t *testing.T) { - //TODO @apigatewayteam test is consistently failing on main after merge, fix in a follow up PR - t.Skip() - s := runtime.NewScheme() - require.NoError(t, clientgoscheme.AddToScheme(s)) - require.NoError(t, gwv1alpha2.Install(s)) - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - testCases := map[string]struct { - namespace string - certFn func(*testing.T, context.Context, client.WithWatch, string) *corev1.Secret - gwFn func(*testing.T, context.Context, client.WithWatch, string) *gwv1beta1.Gateway - httpRouteFn func(*testing.T, context.Context, client.WithWatch, *gwv1beta1.Gateway) *gwv1beta1.HTTPRoute - tcpRouteFn func(*testing.T, context.Context, client.WithWatch, *gwv1beta1.Gateway) *v1alpha2.TCPRoute - }{ - "all fields set": { - namespace: "consul", - certFn: createCert, - gwFn: createAllFieldsSetAPIGW, - httpRouteFn: createAllFieldsSetHTTPRoute, - tcpRouteFn: createAllFieldsSetTCPRoute, - }, - "minimal fields set": { - namespace: "", - certFn: createCert, - gwFn: minimalFieldsSetAPIGW, - httpRouteFn: minimalFieldsSetHTTPRoute, - tcpRouteFn: minimalFieldsSetTCPRoute, - }, - "funky casing to test normalization doesnt cause infinite reconciliation": { - namespace: "", - certFn: createCert, - gwFn: createFunkyCasingFieldsAPIGW, - httpRouteFn: createFunkyCasingFieldsHTTPRoute, - tcpRouteFn: createFunkyCasingFieldsTCPRoute, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - k8sClient := registerFieldIndexersForTest(fake.NewClientBuilder().WithScheme(s)).Build() - consulTestServerClient := test.TestServerWithMockConnMgrWatcher(t, nil) - ctx, cancel := context.WithCancel(context.Background()) - - t.Cleanup(func() { - cancel() - }) - logger := logrtest.New(t) - - cacheCfg := cache.Config{ - ConsulClientConfig: consulTestServerClient.Cfg, - ConsulServerConnMgr: consulTestServerClient.Watcher, - Logger: logger, - } - resourceCache := cache.New(cacheCfg) - - gwCache := cache.NewGatewayCache(ctx, cacheCfg) - - gwCtrl := GatewayController{ - HelmConfig: common.HelmConfig{}, - Log: logger, - Translator: common.ResourceTranslator{}, - cache: resourceCache, - gatewayCache: gwCache, - Client: k8sClient, - allowK8sNamespacesSet: mapset.NewSet(), - denyK8sNamespacesSet: mapset.NewSet(), - } - - go func() { - resourceCache.Run(ctx) - }() - - resourceCache.WaitSynced(ctx) - - 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)) - 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) - - // reconcile so we add the finalizer - _, err := gwCtrl.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: k8sGWObj.Namespace, - Name: k8sGWObj.Name, - }, - }) - require.NoError(t, err) - - // reconcile again so that we get the creation with the finalizer - _, err = gwCtrl.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: k8sGWObj.Namespace, - Name: k8sGWObj.Name, - }, - }) - require.NoError(t, err) - - httpRouteObj := tc.httpRouteFn(t, ctx, k8sClient, k8sGWObj) - tcpRouteObj := tc.tcpRouteFn(t, ctx, k8sClient, k8sGWObj) - - // reconcile again so that we get the route bound to the gateway - _, err = gwCtrl.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: k8sGWObj.Namespace, - Name: k8sGWObj.Name, - }, - }) - require.NoError(t, err) - - // reconcile again so that we get the route bound to the gateway - _, err = gwCtrl.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: k8sGWObj.Namespace, - Name: k8sGWObj.Name, - }, - }) - require.NoError(t, err) - - wg := &sync.WaitGroup{} - // we never get the event from the cert because when it's created there are no gateways that reference it - wg.Add(3) - go func(w *sync.WaitGroup) { - gwDone := false - httpRouteDone := false - tcpRouteDone := false - for { - // get the creation events from the upsert and then continually read from channel so we dont block other subs - select { - case <-ctx.Done(): - return - case <-gwSub.Events(): - if !gwDone { - gwDone = true - wg.Done() - } - case <-httpRouteSub.Events(): - if !httpRouteDone { - httpRouteDone = true - wg.Done() - } - case <-tcpRouteSub.Events(): - if !tcpRouteDone { - tcpRouteDone = true - wg.Done() - } - case <-inlineCertSub.Events(): - } - } - }(wg) - - wg.Wait() - - gwNamespaceName := types.NamespacedName{ - Name: k8sGWObj.Name, - Namespace: k8sGWObj.Namespace, - } - - httpRouteNamespaceName := types.NamespacedName{ - Name: httpRouteObj.Name, - Namespace: httpRouteObj.Namespace, - } - - tcpRouteNamespaceName := types.NamespacedName{ - Name: tcpRouteObj.Name, - Namespace: tcpRouteObj.Namespace, - } - - certNamespaceName := types.NamespacedName{ - Name: cert.Name, - Namespace: cert.Namespace, - } - - 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.InlineCertificate, certNamespaceName) - - curGWModifyIndex := resourceCache.Get(gwRef).GetModifyIndex() - curHTTPRouteModifyIndex := resourceCache.Get(httpRouteRef).GetModifyIndex() - curTCPRouteModifyIndex := resourceCache.Get(tcpRouteRef).GetModifyIndex() - curCertModifyIndex := resourceCache.Get(certRef).GetModifyIndex() - - err = k8sClient.Get(ctx, gwNamespaceName, k8sGWObj) - require.NoError(t, err) - curGWResourceVersion := k8sGWObj.ResourceVersion - - err = k8sClient.Get(ctx, httpRouteNamespaceName, httpRouteObj) - require.NoError(t, err) - curHTTPRouteResourceVersion := httpRouteObj.ResourceVersion - - err = k8sClient.Get(ctx, tcpRouteNamespaceName, tcpRouteObj) - require.NoError(t, err) - curTCPRouteResourceVersion := tcpRouteObj.ResourceVersion - - err = k8sClient.Get(ctx, certNamespaceName, cert) - require.NoError(t, err) - curCertResourceVersion := cert.ResourceVersion - - go func() { - // reconcile multiple times with no changes to be sure - for i := 0; i < 5; i++ { - _, err = gwCtrl.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: k8sGWObj.Namespace, - }, - }) - require.NoError(t, err) - } - }() - - require.Never(t, func() bool { - err = k8sClient.Get(ctx, gwNamespaceName, k8sGWObj) - require.NoError(t, err) - newGWResourceVersion := k8sGWObj.ResourceVersion - - err = k8sClient.Get(ctx, httpRouteNamespaceName, httpRouteObj) - require.NoError(t, err) - newHTTPRouteResourceVersion := httpRouteObj.ResourceVersion - - err = k8sClient.Get(ctx, tcpRouteNamespaceName, tcpRouteObj) - require.NoError(t, err) - newTCPRouteResourceVersion := tcpRouteObj.ResourceVersion - - err = k8sClient.Get(ctx, certNamespaceName, cert) - require.NoError(t, err) - newCertResourceVersion := cert.ResourceVersion - - return curGWModifyIndex == resourceCache.Get(gwRef).GetModifyIndex() && - curGWResourceVersion == newGWResourceVersion && - curHTTPRouteModifyIndex == resourceCache.Get(httpRouteRef).GetModifyIndex() && - curHTTPRouteResourceVersion == newHTTPRouteResourceVersion && - curTCPRouteModifyIndex == resourceCache.Get(tcpRouteRef).GetModifyIndex() && - curTCPRouteResourceVersion == newTCPRouteResourceVersion && - curCertModifyIndex == resourceCache.Get(certRef).GetModifyIndex() && - curCertResourceVersion == newCertResourceVersion - }, time.Duration(2*time.Second), time.Duration(500*time.Millisecond), fmt.Sprintf("curGWModifyIndex: %d, newIndx: %d", curGWModifyIndex, resourceCache.Get(gwRef).GetModifyIndex()), - ) - }) - } -} - -func createAllFieldsSetAPIGW(t *testing.T, ctx context.Context, k8sClient client.WithWatch, namespace string) *gwv1beta1.Gateway { - // listener one configuration - listenerOneName := "listener-one" - listenerOneHostname := "*.consul.io" - listenerOnePort := 3366 - listenerOneProtocol := "https" - - // listener two configuration - listenerTwoName := "listener-two" - listenerTwoHostname := "*.consul.io" - listenerTwoPort := 5432 - listenerTwoProtocol := "http" - - // listener three configuration - listenerThreeName := "listener-three" - listenerThreePort := 8081 - listenerThreeProtocol := "tcp" - - // listener four configuration - listenerFourName := "listener-four" - listenerFourHostname := "*.consul.io" - listenerFourPort := 5433 - listenerFourProtocol := "http" - - // Write gw to k8s - gwClassCfg := &v1alpha1.GatewayClassConfig{ - TypeMeta: metav1.TypeMeta{ - Kind: "GatewayClassConfig", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gateway-class-config", - }, - Spec: v1alpha1.GatewayClassConfigSpec{}, - } - gwClass := &gwv1beta1.GatewayClass{ - TypeMeta: metav1.TypeMeta{ - Kind: "GatewayClass", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gatewayclass", - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: "consul.hashicorp.com/gateway-controller", - ParametersRef: &gwv1beta1.ParametersReference{ - Group: "consul.hashicorp.com", - Kind: "GatewayClassConfig", - Name: "gateway-class-config", - }, - Description: new(string), - }, - } - gw := &gwv1beta1.Gateway{ - TypeMeta: metav1.TypeMeta{ - Kind: "Gateway", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gw", - Namespace: namespace, - Annotations: make(map[string]string), - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: gwv1beta1.ObjectName(gwClass.Name), - Listeners: []gwv1beta1.Listener{ - { - Name: gwv1beta1.SectionName(listenerOneName), - Hostname: common.PointerTo(gwv1beta1.Hostname(listenerOneHostname)), - Port: gwv1beta1.PortNumber(listenerOnePort), - Protocol: gwv1beta1.ProtocolType(listenerOneProtocol), - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - { - Kind: common.PointerTo(gwv1beta1.Kind("Secret")), - Name: gwv1beta1.ObjectName("one-cert"), - Namespace: common.PointerTo(gwv1beta1.Namespace(namespace)), - }, - }, - }, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("All")), - }, - }, - }, - { - Name: gwv1beta1.SectionName(listenerTwoName), - Hostname: common.PointerTo(gwv1beta1.Hostname(listenerTwoHostname)), - Port: gwv1beta1.PortNumber(listenerTwoPort), - Protocol: gwv1beta1.ProtocolType(listenerTwoProtocol), - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("Same")), - }, - }, - }, - { - Name: gwv1beta1.SectionName(listenerThreeName), - Port: gwv1beta1.PortNumber(listenerThreePort), - Protocol: gwv1beta1.ProtocolType(listenerThreeProtocol), - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("All")), - }, - }, - }, - { - Name: gwv1beta1.SectionName(listenerFourName), - Hostname: common.PointerTo(gwv1beta1.Hostname(listenerFourHostname)), - Port: gwv1beta1.PortNumber(listenerFourPort), - Protocol: gwv1beta1.ProtocolType(listenerFourProtocol), - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("Selector")), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - common.NamespaceNameLabel: "consul", - }, - MatchExpressions: []metav1.LabelSelectorRequirement{}, - }, - }, - }, - }, - }, - }, - } - - err := k8sClient.Create(ctx, gwClassCfg) - require.NoError(t, err) - - err = k8sClient.Create(ctx, gwClass) - require.NoError(t, err) - - err = k8sClient.Create(ctx, gw) - require.NoError(t, err) - - return gw -} - -func createAllFieldsSetHTTPRoute(t *testing.T, ctx context.Context, k8sClient client.WithWatch, gw *gwv1beta1.Gateway) *gwv1beta1.HTTPRoute { - svcDefault := &v1alpha1.ServiceDefaults{ - TypeMeta: metav1.TypeMeta{ - Kind: "ServiceDefaults", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - }, - Spec: v1alpha1.ServiceDefaultsSpec{ - Protocol: "http", - }, - } - - svc := &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - Labels: map[string]string{"app": "Service"}, - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "high", - Protocol: "TCP", - Port: 8080, - }, - }, - Selector: map[string]string{"app": "Service"}, - }, - } - - serviceAccount := &corev1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - }, - } - - deployment := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - Labels: map[string]string{"app": "Service"}, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: common.PointerTo(int32(1)), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "Service"}, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{}, - Spec: corev1.PodSpec{}, - }, - }, - } - - err := k8sClient.Create(ctx, svcDefault) - require.NoError(t, err) - - err = k8sClient.Create(ctx, svc) - require.NoError(t, err) - - err = k8sClient.Create(ctx, serviceAccount) - require.NoError(t, err) - - err = k8sClient.Create(ctx, deployment) - require.NoError(t, err) - - route := &gwv1beta1.HTTPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "HTTPRoute", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "http-route", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Kind: (*gwv1beta1.Kind)(&gw.Kind), - Namespace: (*gwv1beta1.Namespace)(&gw.Namespace), - Name: gwv1beta1.ObjectName(gw.Name), - SectionName: &gw.Spec.Listeners[0].Name, - Port: &gw.Spec.Listeners[0].Port, - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{"route.consul.io"}, - Rules: []gwv1beta1.HTTPRouteRule{ - { - Matches: []gwv1beta1.HTTPRouteMatch{ - { - Path: &gwv1beta1.HTTPPathMatch{ - Type: common.PointerTo(gwv1beta1.PathMatchType("PathPrefix")), - Value: common.PointerTo("/v1"), - }, - Headers: []gwv1beta1.HTTPHeaderMatch{ - { - Type: common.PointerTo(gwv1beta1.HeaderMatchExact), - Name: "version", - Value: "version", - }, - }, - QueryParams: []gwv1beta1.HTTPQueryParamMatch{ - { - Type: common.PointerTo(gwv1beta1.QueryParamMatchExact), - Name: "search", - Value: "q", - }, - }, - Method: common.PointerTo(gwv1beta1.HTTPMethod("GET")), - }, - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - Type: gwv1beta1.HTTPRouteFilterRequestHeaderModifier, - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "foo", - Value: "bax", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "arc", - Value: "reactor", - }, - }, - Remove: []string{"remove"}, - }, - }, - { - Type: gwv1beta1.HTTPRouteFilterURLRewrite, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Hostname: common.PointerTo(gwv1beta1.PreciseHostname("host.com")), - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.FullPathHTTPPathModifier, - ReplaceFullPath: common.PointerTo("/foobar"), - }, - }, - }, - - { - Type: gwv1beta1.HTTPRouteFilterURLRewrite, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Hostname: common.PointerTo(gwv1beta1.PreciseHostname("host.com")), - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: common.PointerTo("/foo"), - }, - }, - }, - }, - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "Service", - Port: common.PointerTo(gwv1beta1.PortNumber(8080)), - }, - Weight: common.PointerTo(int32(50)), - }, - }, - }, - }, - }, - }, - } - - err = k8sClient.Create(ctx, route) - require.NoError(t, err) - - return route -} - -func createAllFieldsSetTCPRoute(t *testing.T, ctx context.Context, k8sClient client.WithWatch, gw *gwv1beta1.Gateway) *v1alpha2.TCPRoute { - route := &v1alpha2.TCPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "TCPRoute", - APIVersion: "gateway.networking.k8s.io/v1alpha2", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-route", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Kind: (*gwv1beta1.Kind)(&gw.Kind), - Namespace: (*gwv1beta1.Namespace)(&gw.Namespace), - Name: gwv1beta1.ObjectName(gw.Name), - SectionName: &gw.Spec.Listeners[2].Name, - Port: &gw.Spec.Listeners[2].Port, - }, - }, - }, - Rules: []gwv1alpha2.TCPRouteRule{ - { - BackendRefs: []gwv1beta1.BackendRef{ - { - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "Service", - Port: common.PointerTo(gwv1beta1.PortNumber(25000)), - }, - Weight: common.PointerTo(int32(50)), - }, - }, - }, - }, - }, - } - - err := k8sClient.Create(ctx, route) - require.NoError(t, err) - - return route -} - -func createCert(t *testing.T, ctx context.Context, k8sClient client.WithWatch, certNS string) *corev1.Secret { - // listener one tls config - certName := "one-cert" - - privateKey, err := rsa.GenerateKey(rand.Reader, 2048) - require.NoError(t, err) - - usage := x509.KeyUsageCertSign - expiration := time.Now().AddDate(10, 0, 0) - - cert := &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: "consul.test", - }, - IsCA: true, - 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 - caPrivateKey := 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), - }) - - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: certNS, - Name: certName, - }, - Data: map[string][]byte{ - corev1.TLSCertKey: certBytes, - corev1.TLSPrivateKeyKey: privateKeyBytes, - }, - } - - err = k8sClient.Create(ctx, secret) - require.NoError(t, err) - - return secret -} - -func minimalFieldsSetAPIGW(t *testing.T, ctx context.Context, k8sClient client.WithWatch, namespace string) *gwv1beta1.Gateway { - // listener one configuration - listenerOneName := "listener-one" - listenerOneHostname := "*.consul.io" - listenerOnePort := 3366 - listenerOneProtocol := "https" - - // listener three configuration - listenerThreeName := "listener-three" - listenerThreePort := 8081 - listenerThreeProtocol := "tcp" - - // Write gw to k8s - gwClassCfg := &v1alpha1.GatewayClassConfig{ - TypeMeta: metav1.TypeMeta{ - Kind: "GatewayClassConfig", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gateway-class-config", - }, - Spec: v1alpha1.GatewayClassConfigSpec{}, - } - gwClass := &gwv1beta1.GatewayClass{ - TypeMeta: metav1.TypeMeta{ - Kind: "GatewayClass", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gatewayclass", - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: "consul.hashicorp.com/gateway-controller", - ParametersRef: &gwv1beta1.ParametersReference{ - Group: "consul.hashicorp.com", - Kind: "GatewayClassConfig", - Name: "gateway-class-config", - }, - Description: new(string), - }, - } - gw := &gwv1beta1.Gateway{ - TypeMeta: metav1.TypeMeta{ - Kind: "Gateway", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gw", - Annotations: make(map[string]string), - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: gwv1beta1.ObjectName(gwClass.Name), - Listeners: []gwv1beta1.Listener{ - { - Name: gwv1beta1.SectionName(listenerOneName), - Hostname: common.PointerTo(gwv1beta1.Hostname(listenerOneHostname)), - Port: gwv1beta1.PortNumber(listenerOnePort), - Protocol: gwv1beta1.ProtocolType(listenerOneProtocol), - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - { - Kind: common.PointerTo(gwv1beta1.Kind("Secret")), - Name: gwv1beta1.ObjectName("one-cert"), - Namespace: common.PointerTo(gwv1beta1.Namespace(namespace)), - }, - }, - }, - }, - { - Name: gwv1beta1.SectionName(listenerThreeName), - Port: gwv1beta1.PortNumber(listenerThreePort), - Protocol: gwv1beta1.ProtocolType(listenerThreeProtocol), - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("All")), - }, - }, - }, - }, - }, - } - - err := k8sClient.Create(ctx, gwClassCfg) - require.NoError(t, err) - - err = k8sClient.Create(ctx, gwClass) - require.NoError(t, err) - - err = k8sClient.Create(ctx, gw) - require.NoError(t, err) - - return gw -} - -func minimalFieldsSetHTTPRoute(t *testing.T, ctx context.Context, k8sClient client.WithWatch, gw *gwv1beta1.Gateway) *gwv1beta1.HTTPRoute { - svcDefault := &v1alpha1.ServiceDefaults{ - TypeMeta: metav1.TypeMeta{ - Kind: "ServiceDefaults", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - }, - Spec: v1alpha1.ServiceDefaultsSpec{ - Protocol: "http", - }, - } - - svc := &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - Labels: map[string]string{"app": "Service"}, - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "high", - Protocol: "TCP", - Port: 8080, - }, - }, - Selector: map[string]string{"app": "Service"}, - }, - } - - serviceAccount := &corev1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - }, - } - - deployment := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - Labels: map[string]string{"app": "Service"}, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: common.PointerTo(int32(1)), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "Service"}, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{}, - Spec: corev1.PodSpec{}, - }, - }, - } - - err := k8sClient.Create(ctx, svcDefault) - require.NoError(t, err) - - err = k8sClient.Create(ctx, svc) - require.NoError(t, err) - - err = k8sClient.Create(ctx, serviceAccount) - require.NoError(t, err) - - err = k8sClient.Create(ctx, deployment) - require.NoError(t, err) - - route := &gwv1beta1.HTTPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "HTTPRoute", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "http-route", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Kind: (*gwv1beta1.Kind)(&gw.Kind), - Namespace: (*gwv1beta1.Namespace)(&gw.Namespace), - Name: gwv1beta1.ObjectName(gw.Name), - SectionName: &gw.Spec.Listeners[0].Name, - Port: &gw.Spec.Listeners[0].Port, - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{"route.consul.io"}, - Rules: []gwv1beta1.HTTPRouteRule{ - { - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "Service", - Port: common.PointerTo(gwv1beta1.PortNumber(8080)), - }, - }, - }, - }, - }, - }, - }, - } - - err = k8sClient.Create(ctx, route) - require.NoError(t, err) - - return route -} - -func minimalFieldsSetTCPRoute(t *testing.T, ctx context.Context, k8sClient client.WithWatch, gw *gwv1beta1.Gateway) *v1alpha2.TCPRoute { - route := &v1alpha2.TCPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "TCPRoute", - APIVersion: "gateway.networking.k8s.io/v1alpha2", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-route", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Kind: (*gwv1beta1.Kind)(&gw.Kind), - Namespace: (*gwv1beta1.Namespace)(&gw.Namespace), - Name: gwv1beta1.ObjectName(gw.Name), - SectionName: &gw.Spec.Listeners[1].Name, - Port: &gw.Spec.Listeners[1].Port, - }, - }, - }, - Rules: []gwv1alpha2.TCPRouteRule{ - { - BackendRefs: []gwv1beta1.BackendRef{ - { - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "Service", - Port: common.PointerTo(gwv1beta1.PortNumber(25000)), - }, - }, - }, - }, - }, - }, - } - - err := k8sClient.Create(ctx, route) - require.NoError(t, err) - - return route -} - -func createFunkyCasingFieldsAPIGW(t *testing.T, ctx context.Context, k8sClient client.WithWatch, namespace string) *gwv1beta1.Gateway { - // listener one configuration - listenerOneName := "listener-one" - listenerOneHostname := "*.consul.io" - listenerOnePort := 3366 - listenerOneProtocol := "hTtPs" - - // listener two configuration - listenerTwoName := "listener-two" - listenerTwoHostname := "*.consul.io" - listenerTwoPort := 5432 - listenerTwoProtocol := "HTTP" - - // listener three configuration - listenerThreeName := "listener-three" - listenerThreePort := 8081 - listenerThreeProtocol := "tCp" - - // listener four configuration - listenerFourName := "listener-four" - listenerFourHostname := "*.consul.io" - listenerFourPort := 5433 - listenerFourProtocol := "hTTp" - - // Write gw to k8s - gwClassCfg := &v1alpha1.GatewayClassConfig{ - TypeMeta: metav1.TypeMeta{ - Kind: "GatewayClassConfig", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gateway-class-config", - }, - Spec: v1alpha1.GatewayClassConfigSpec{}, - } - gwClass := &gwv1beta1.GatewayClass{ - TypeMeta: metav1.TypeMeta{ - Kind: "GatewayClass", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gatewayclass", - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: "consul.hashicorp.com/gateway-controller", - ParametersRef: &gwv1beta1.ParametersReference{ - Group: "consul.hashicorp.com", - Kind: "GatewayClassConfig", - Name: "gateway-class-config", - }, - Description: new(string), - }, - } - gw := &gwv1beta1.Gateway{ - TypeMeta: metav1.TypeMeta{ - Kind: "Gateway", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "gw", - Namespace: namespace, - Annotations: make(map[string]string), - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: gwv1beta1.ObjectName(gwClass.Name), - Listeners: []gwv1beta1.Listener{ - { - Name: gwv1beta1.SectionName(listenerOneName), - Hostname: common.PointerTo(gwv1beta1.Hostname(listenerOneHostname)), - Port: gwv1beta1.PortNumber(listenerOnePort), - Protocol: gwv1beta1.ProtocolType(listenerOneProtocol), - TLS: &gwv1beta1.GatewayTLSConfig{ - CertificateRefs: []gwv1beta1.SecretObjectReference{ - { - Kind: common.PointerTo(gwv1beta1.Kind("Secret")), - Name: gwv1beta1.ObjectName("one-cert"), - Namespace: common.PointerTo(gwv1beta1.Namespace(namespace)), - }, - }, - }, - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("All")), - }, - }, - }, - { - Name: gwv1beta1.SectionName(listenerTwoName), - Hostname: common.PointerTo(gwv1beta1.Hostname(listenerTwoHostname)), - Port: gwv1beta1.PortNumber(listenerTwoPort), - Protocol: gwv1beta1.ProtocolType(listenerTwoProtocol), - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("Same")), - }, - }, - }, - { - Name: gwv1beta1.SectionName(listenerThreeName), - Port: gwv1beta1.PortNumber(listenerThreePort), - Protocol: gwv1beta1.ProtocolType(listenerThreeProtocol), - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("All")), - }, - }, - }, - { - Name: gwv1beta1.SectionName(listenerFourName), - Hostname: common.PointerTo(gwv1beta1.Hostname(listenerFourHostname)), - Port: gwv1beta1.PortNumber(listenerFourPort), - Protocol: gwv1beta1.ProtocolType(listenerFourProtocol), - AllowedRoutes: &gwv1beta1.AllowedRoutes{ - Namespaces: &gwv1beta1.RouteNamespaces{ - From: common.PointerTo(gwv1beta1.FromNamespaces("Selector")), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - common.NamespaceNameLabel: "consul", - }, - MatchExpressions: []metav1.LabelSelectorRequirement{}, - }, - }, - }, - }, - }, - }, - } - - err := k8sClient.Create(ctx, gwClassCfg) - require.NoError(t, err) - - err = k8sClient.Create(ctx, gwClass) - require.NoError(t, err) - - err = k8sClient.Create(ctx, gw) - require.NoError(t, err) - - return gw -} - -func createFunkyCasingFieldsHTTPRoute(t *testing.T, ctx context.Context, k8sClient client.WithWatch, gw *gwv1beta1.Gateway) *gwv1beta1.HTTPRoute { - svcDefault := &v1alpha1.ServiceDefaults{ - TypeMeta: metav1.TypeMeta{ - Kind: "ServiceDefaults", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - }, - Spec: v1alpha1.ServiceDefaultsSpec{ - Protocol: "hTtp", - }, - } - - svc := &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - Labels: map[string]string{"app": "Service"}, - }, - Spec: corev1.ServiceSpec{ - Ports: []corev1.ServicePort{ - { - Name: "high", - Protocol: "TCP", - Port: 8080, - }, - }, - Selector: map[string]string{"app": "Service"}, - }, - } - - serviceAccount := &corev1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - }, - } - - deployment := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "Service", - Labels: map[string]string{"app": "Service"}, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: common.PointerTo(int32(1)), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "Service"}, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{}, - Spec: corev1.PodSpec{}, - }, - }, - } - - err := k8sClient.Create(ctx, svcDefault) - require.NoError(t, err) - - err = k8sClient.Create(ctx, svc) - require.NoError(t, err) - - err = k8sClient.Create(ctx, serviceAccount) - require.NoError(t, err) - - err = k8sClient.Create(ctx, deployment) - require.NoError(t, err) - - route := &gwv1beta1.HTTPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "HTTPRoute", - APIVersion: "gateway.networking.k8s.io/v1beta1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "http-route", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Namespace: (*gwv1beta1.Namespace)(&gw.Namespace), - Name: gwv1beta1.ObjectName(gw.Name), - SectionName: &gw.Spec.Listeners[0].Name, - Port: &gw.Spec.Listeners[0].Port, - }, - }, - }, - Hostnames: []gwv1beta1.Hostname{"route.consul.io"}, - Rules: []gwv1beta1.HTTPRouteRule{ - { - Matches: []gwv1beta1.HTTPRouteMatch{ - { - Path: &gwv1beta1.HTTPPathMatch{ - Type: common.PointerTo(gwv1beta1.PathMatchPathPrefix), - }, - Headers: []gwv1beta1.HTTPHeaderMatch{ - { - Type: common.PointerTo(gwv1beta1.HeaderMatchExact), - Name: "version", - Value: "version", - }, - }, - QueryParams: []gwv1beta1.HTTPQueryParamMatch{ - { - Type: common.PointerTo(gwv1beta1.QueryParamMatchExact), - Name: "search", - Value: "q", - }, - }, - Method: common.PointerTo(gwv1beta1.HTTPMethod("geT")), - }, - }, - Filters: []gwv1beta1.HTTPRouteFilter{ - { - Type: gwv1beta1.HTTPRouteFilterRequestHeaderModifier, - RequestHeaderModifier: &gwv1beta1.HTTPHeaderFilter{ - Set: []gwv1beta1.HTTPHeader{ - { - Name: "foo", - Value: "bax", - }, - }, - Add: []gwv1beta1.HTTPHeader{ - { - Name: "arc", - Value: "reactor", - }, - }, - Remove: []string{"remove"}, - }, - }, - { - Type: gwv1beta1.HTTPRouteFilterURLRewrite, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Hostname: common.PointerTo(gwv1beta1.PreciseHostname("host.com")), - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.FullPathHTTPPathModifier, - ReplaceFullPath: common.PointerTo("/foobar"), - }, - }, - }, - - { - Type: gwv1beta1.HTTPRouteFilterURLRewrite, - URLRewrite: &gwv1beta1.HTTPURLRewriteFilter{ - Hostname: common.PointerTo(gwv1beta1.PreciseHostname("host.com")), - Path: &gwv1beta1.HTTPPathModifier{ - Type: gwv1beta1.PrefixMatchHTTPPathModifier, - ReplacePrefixMatch: common.PointerTo("/foo"), - }, - }, - }, - }, - BackendRefs: []gwv1beta1.HTTPBackendRef{ - { - BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "Service", - Port: common.PointerTo(gwv1beta1.PortNumber(8080)), - }, - Weight: common.PointerTo(int32(-50)), - }, - }, - }, - }, - }, - }, - } - - err = k8sClient.Create(ctx, route) - require.NoError(t, err) - - return route -} - -func createFunkyCasingFieldsTCPRoute(t *testing.T, ctx context.Context, k8sClient client.WithWatch, gw *gwv1beta1.Gateway) *v1alpha2.TCPRoute { - route := &v1alpha2.TCPRoute{ - TypeMeta: metav1.TypeMeta{ - Kind: "TCPRoute", - APIVersion: "gateway.networking.k8s.io/v1alpha2", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-route", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - { - Namespace: (*gwv1beta1.Namespace)(&gw.Namespace), - Name: gwv1beta1.ObjectName(gw.Name), - SectionName: &gw.Spec.Listeners[2].Name, - Port: &gw.Spec.Listeners[2].Port, - }, - }, - }, - Rules: []gwv1alpha2.TCPRouteRule{ - { - BackendRefs: []gwv1beta1.BackendRef{ - { - BackendObjectReference: gwv1beta1.BackendObjectReference{ - Name: "Service", - Port: common.PointerTo(gwv1beta1.PortNumber(25000)), - }, - Weight: common.PointerTo(int32(-50)), - }, - }, - }, - }, - }, - } - - err := k8sClient.Create(ctx, route) - require.NoError(t, err) - - return route -} diff --git a/control-plane/api-gateway/controllers/gateway_controller_test.go b/control-plane/api-gateway/controllers/gateway_controller_test.go deleted file mode 100644 index 7b21d01ff8..0000000000 --- a/control-plane/api-gateway/controllers/gateway_controller_test.go +++ /dev/null @@ -1,642 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "testing" - - mapset "github.com/deckarep/golang-set" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestTransformEndpoints(t *testing.T) { - t.Parallel() - - httpRoute := &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http", - Namespace: "test", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - Rules: []gwv1beta1.HTTPRouteRule{ - {BackendRefs: []gwv1beta1.HTTPBackendRef{ - {BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "http-test-namespace"}, - }}, - {BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "http-other-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}, - }}, - {BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "http-system-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("system"))}, - }}, - {BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "http-public-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("public"))}, - }}, - {BackendRef: gwv1beta1.BackendRef{ - BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "http-local-path-storage-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("local-path-storage"))}, - }}}, - }, - }, - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "http-gateway"}, - {Name: "general-gateway"}, - }, - }, - }, - } - - tcpRoute := &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp", - Namespace: "test", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - Rules: []gwv1alpha2.TCPRouteRule{ - {BackendRefs: []gwv1beta1.BackendRef{ - {BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "tcp-test-namespace"}}, - {BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "tcp-other-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}}, - {BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "tcp-system-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("system"))}}, - {BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "tcp-public-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("public"))}}, - {BackendObjectReference: gwv1beta1.BackendObjectReference{Name: "tcp-local-path-storage-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("local-path-storage"))}}, - }}, - }, - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "tcp-gateway"}, - {Name: "general-gateway"}, - }, - }, - }, - } - - for name, tt := range map[string]struct { - endpoints *corev1.Endpoints - expected []reconcile.Request - allowedNamespaces []string - denyNamespaces []string - }{ - "ignore system namespace": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-system-namespace", - Namespace: metav1.NamespaceSystem, - }, - }, - allowedNamespaces: []string{"*"}, - }, - "ignore public namespace": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-public-namespace", - Namespace: metav1.NamespacePublic, - }, - }, - allowedNamespaces: []string{"*"}, - }, - "ignore local-path-storage namespace": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-local-path-storage-namespace", - Namespace: "local-path-storage", - }, - }, - allowedNamespaces: []string{"*"}, - }, - "explicit deny namespace": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-test-namespace", - Namespace: "test", - }, - }, - allowedNamespaces: []string{"*"}, - denyNamespaces: []string{"test"}, - }, - "ignore labels": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-test-namespace", - Namespace: "test", - Labels: map[string]string{ - constants.LabelServiceIgnore: "true", - }, - }, - }, - allowedNamespaces: []string{"test"}, - }, - "http same namespace wildcard allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-test-namespace", - Namespace: "test", - }, - }, - allowedNamespaces: []string{"*"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "http-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - "http same namespace explicit allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-test-namespace", - Namespace: "test", - }, - }, - allowedNamespaces: []string{"test"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "http-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - "http other namespace wildcard allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-other-namespace", - Namespace: "other", - }, - }, - allowedNamespaces: []string{"*"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "http-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - "http other namespace explicit allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "http-other-namespace", - Namespace: "other", - }, - }, - allowedNamespaces: []string{"other"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "http-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - "tcp same namespace wildcard allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-test-namespace", - Namespace: "test", - }, - }, - allowedNamespaces: []string{"*"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "tcp-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - "tcp same namespace explicit allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-test-namespace", - Namespace: "test", - }, - }, - allowedNamespaces: []string{"test"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "tcp-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - "tcp other namespace wildcard allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-other-namespace", - Namespace: "other", - }, - }, - allowedNamespaces: []string{"*"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "tcp-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - "tcp other namespace explicit allow": { - endpoints: &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "tcp-other-namespace", - Namespace: "other", - }, - }, - allowedNamespaces: []string{"other"}, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "tcp-gateway", Namespace: "test"}}, - {NamespacedName: types.NamespacedName{Name: "general-gateway", Namespace: "test"}}, - }, - }, - } { - t.Run(name, func(t *testing.T) { - s := runtime.NewScheme() - require.NoError(t, clientgoscheme.AddToScheme(s)) - require.NoError(t, gwv1alpha2.Install(s)) - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - denySet := mapset.NewSet() - for _, v := range tt.denyNamespaces { - denySet.Add(v) - } - allowSet := mapset.NewSet() - for _, v := range tt.allowedNamespaces { - allowSet.Add(v) - } - - fakeClient := registerFieldIndexersForTest(fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(httpRoute, tcpRoute)).Build() - - controller := GatewayController{ - Client: fakeClient, - denyK8sNamespacesSet: denySet, - allowK8sNamespacesSet: allowSet, - } - - fn := controller.transformEndpoints(context.Background()) - require.ElementsMatch(t, tt.expected, fn(tt.endpoints)) - }) - } -} - -func TestTransformHTTPRoute(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - route *gwv1beta1.HTTPRoute - expected []reconcile.Request - }{ - "route with parent empty namespace": { - route: &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "default"}}, - }, - }, - "route with parent with namespace": { - route: &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "other"}}, - }, - }, - "route with non gateway parent with namespace": { - route: &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway", Group: common.PointerTo(gwv1beta1.Group("group"))}, - }, - }, - }, - }, - expected: []reconcile.Request{}, - }, - "route with parent in status and no namespace": { - route: &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Status: gwv1beta1.HTTPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway"}}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "default"}}, - }, - }, - "route with parent in status and namespace": { - route: &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Status: gwv1beta1.HTTPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "other"}}, - }, - }, - "route with non gateway parent in status": { - route: &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Status: gwv1beta1.HTTPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway", Group: common.PointerTo(gwv1beta1.Group("group"))}}, - }, - }, - }, - }, - expected: []reconcile.Request{}, - }, - "route parent in spec and in status": { - route: &gwv1beta1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1beta1.HTTPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway-one"}, - }, - }, - }, - Status: gwv1beta1.HTTPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway-two"}}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway-one", Namespace: "default"}}, - {NamespacedName: types.NamespacedName{Name: "gateway-two", Namespace: "default"}}, - }, - }, - } { - t.Run(name, func(t *testing.T) { - controller := GatewayController{} - - fn := controller.transformHTTPRoute(context.Background()) - require.ElementsMatch(t, tt.expected, fn(tt.route)) - }) - } -} - -func TestTransformTCPRoute(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - route *gwv1alpha2.TCPRoute - expected []reconcile.Request - }{ - "route with parent empty namespace": { - route: &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway"}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "default"}}, - }, - }, - "route with parent with namespace": { - route: &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "other"}}, - }, - }, - "route with non gateway parent with namespace": { - route: &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway", Group: common.PointerTo(gwv1beta1.Group("group"))}, - }, - }, - }, - }, - expected: []reconcile.Request{}, - }, - "route with parent in status and no namespace": { - route: &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Status: gwv1alpha2.TCPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway"}}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "default"}}, - }, - }, - "route with parent in status and namespace": { - route: &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Status: gwv1alpha2.TCPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "other"}}, - }, - }, - "route with non gateway parent in status": { - route: &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Status: gwv1alpha2.TCPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway", Group: common.PointerTo(gwv1beta1.Group("group"))}}, - }, - }, - }, - }, - expected: []reconcile.Request{}, - }, - "route parent in spec and in status": { - route: &gwv1alpha2.TCPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - }, - Spec: gwv1alpha2.TCPRouteSpec{ - CommonRouteSpec: gwv1beta1.CommonRouteSpec{ - ParentRefs: []gwv1beta1.ParentReference{ - {Name: "gateway-one"}, - }, - }, - }, - Status: gwv1alpha2.TCPRouteStatus{ - RouteStatus: gwv1beta1.RouteStatus{ - Parents: []gwv1beta1.RouteParentStatus{ - {ParentRef: gwv1beta1.ParentReference{Name: "gateway-two"}}, - }, - }, - }, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway-one", Namespace: "default"}}, - {NamespacedName: types.NamespacedName{Name: "gateway-two", Namespace: "default"}}, - }, - }, - } { - t.Run(name, func(t *testing.T) { - controller := GatewayController{} - - fn := controller.transformTCPRoute(context.Background()) - require.ElementsMatch(t, tt.expected, fn(tt.route)) - }) - } -} - -func TestTransformSecret(t *testing.T) { - t.Parallel() - - gateway := &gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "gateway", - Namespace: "test", - }, - Spec: gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{ - {Name: "terminate", TLS: &gwv1beta1.GatewayTLSConfig{ - Mode: common.PointerTo(gwv1beta1.TLSModeTerminate), - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "secret-no-namespace"}, - {Name: "secret-namespace", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}, - }, - }}, - {Name: "passthrough", TLS: &gwv1beta1.GatewayTLSConfig{ - Mode: common.PointerTo(gwv1beta1.TLSModePassthrough), - CertificateRefs: []gwv1beta1.SecretObjectReference{ - {Name: "passthrough", Namespace: common.PointerTo(gwv1beta1.Namespace("other"))}, - }, - }}, - }, - }, - } - - for name, tt := range map[string]struct { - secret *corev1.Secret - expected []reconcile.Request - }{ - "explicit namespace from parent": { - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "secret-namespace", Namespace: "other"}, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "test"}}, - }, - }, - "implicit namespace from parent": { - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "secret-no-namespace", Namespace: "test"}, - }, - expected: []reconcile.Request{ - {NamespacedName: types.NamespacedName{Name: "gateway", Namespace: "test"}}, - }, - }, - "mismatched namespace": { - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "secret-no-namespace", Namespace: "other"}, - }, - }, - "mismatched names": { - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "something", Namespace: "test"}, - }, - }, - "passthrough ignored": { - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "passthrough", Namespace: "other"}, - }, - }, - } { - t.Run(name, func(t *testing.T) { - tt := tt - - t.Parallel() - - s := runtime.NewScheme() - require.NoError(t, clientgoscheme.AddToScheme(s)) - require.NoError(t, gwv1alpha2.Install(s)) - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - fakeClient := registerFieldIndexersForTest(fake.NewClientBuilder().WithScheme(s)).WithRuntimeObjects(gateway).Build() - - controller := GatewayController{ - Client: fakeClient, - } - - fn := controller.transformSecret(context.Background()) - require.ElementsMatch(t, tt.expected, fn(tt.secret)) - }) - } -} diff --git a/control-plane/api-gateway/controllers/gatewayclass_controller.go b/control-plane/api-gateway/controllers/gatewayclass_controller.go deleted file mode 100644 index 3bde2d6ab1..0000000000 --- a/control-plane/api-gateway/controllers/gatewayclass_controller.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "fmt" - "github.com/go-logr/logr" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "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" - "sigs.k8s.io/controller-runtime/pkg/source" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -const ( - gatewayClassFinalizer = "gateway-exists-finalizer.consul.hashicorp.com" - - // GatewayClass status fields. - accepted = "Accepted" - invalidParameters = "InvalidParameters" -) - -// GatewayClassController reconciles a GatewayClass object. -// The GatewayClass is responsible for defining the behavior of API gateways -// which reference the given class. -type GatewayClassController struct { - ControllerName string - Log logr.Logger - - client.Client -} - -// Reconcile handles the reconciliation loop for GatewayClass objects. -func (r *GatewayClassController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := r.Log.WithValues("gatewayClass", req.NamespacedName.Name) - log.V(1).Info("Reconciling GatewayClass") - - gc := &gwv1beta1.GatewayClass{} - - err := r.Client.Get(ctx, req.NamespacedName, gc) - if err != nil { - if k8serrors.IsNotFound(err) { - return ctrl.Result{}, nil - } - log.Error(err, "unable to get GatewayClass") - return ctrl.Result{}, err - } - - if string(gc.Spec.ControllerName) != r.ControllerName { - // This GatewayClass is not for this controller. - _, err := RemoveFinalizer(ctx, r.Client, gc, gatewayClassFinalizer) - if err != nil { - log.Error(err, "unable to remove finalizer") - } - - return ctrl.Result{}, err - } - - if !gc.ObjectMeta.DeletionTimestamp.IsZero() { - // We have a deletion request. Ensure we are not in use. - used, err := r.isGatewayClassInUse(ctx, gc) - if err != nil { - log.Error(err, "unable to check if GatewayClass is in use") - return ctrl.Result{}, err - } - if used { - log.Info("GatewayClass is in use, cannot delete") - return ctrl.Result{}, nil - } - // Remove our finalizer. - if _, err := RemoveFinalizer(ctx, r.Client, gc, gatewayClassFinalizer); err != nil { - if k8serrors.IsConflict(err) { - log.V(1).Info("error removing finalizer for gatewayClass, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "unable to remove finalizer") - return ctrl.Result{}, err - } - return ctrl.Result{}, nil - } - - // We are creating or updating the GatewayClass. - didUpdate, err := EnsureFinalizer(ctx, r.Client, gc, gatewayClassFinalizer) - if err != nil { - if k8serrors.IsConflict(err) { - log.V(1).Info("error adding finalizer for gatewayClass, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "unable to add finalizer") - return ctrl.Result{}, err - } - if didUpdate { - // We updated the GatewayClass, requeue to avoid another update. - return ctrl.Result{}, nil - } - - didUpdate, err = r.validateParametersRef(ctx, gc, log) - if didUpdate { - if err := r.Client.Status().Update(ctx, gc); err != nil { - if k8serrors.IsConflict(err) { - log.V(1).Info("error updating status for gatewayClass, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "unable to update status for GatewayClass") - return ctrl.Result{}, err - } - return ctrl.Result{}, nil - } - if err != nil { - log.Error(err, "unable to validate ParametersRef") - } - - return ctrl.Result{}, err -} - -// SetupWithManager registers the controller with the given manager. -func (r *GatewayClassController) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&gwv1beta1.GatewayClass{}). - // Watch for changes to GatewayClassConfig objects. - Watches(source.NewKindWithCache(&v1alpha1.GatewayClassConfig{}, mgr.GetCache()), r.gatewayClassConfigFieldIndexEventHandler(ctx)). - // Watch for changes to Gateway objects that reference this GatewayClass. - Watches(source.NewKindWithCache(&gwv1beta1.Gateway{}, mgr.GetCache()), r.gatewayFieldIndexEventHandler(ctx)). - Complete(r) -} - -// isGatewayClassInUse returns true if the given GatewayClass is referenced by any Gateway objects. -func (r *GatewayClassController) isGatewayClassInUse(ctx context.Context, gc *gwv1beta1.GatewayClass) (bool, error) { - list := &gwv1beta1.GatewayList{} - if err := r.Client.List(ctx, list, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(Gateway_GatewayClassIndex, gc.Name), - }); err != nil { - return false, err - } - - return len(list.Items) != 0, nil -} - -// validateParametersRef validates the ParametersRef field of the given GatewayClass -// if it is set, ensuring that the referenced object is a GatewayClassConfig that exists. -func (r *GatewayClassController) validateParametersRef(ctx context.Context, gc *gwv1beta1.GatewayClass, log logr.Logger) (didUpdate bool, err error) { - parametersRef := gc.Spec.ParametersRef - if parametersRef != nil { - if parametersRef.Kind != v1alpha1.GatewayClassConfigKind { - didUpdate = r.setCondition(gc, metav1.Condition{ - Type: accepted, - Status: metav1.ConditionFalse, - Reason: invalidParameters, - Message: fmt.Sprintf("Incorrect type for parametersRef. Expected GatewayClassConfig, got %q.", parametersRef.Kind), - }) - return didUpdate, nil - } - - err = r.Client.Get(ctx, types.NamespacedName{Name: parametersRef.Name}, &v1alpha1.GatewayClassConfig{}) - if k8serrors.IsNotFound(err) { - didUpdate := r.setCondition(gc, metav1.Condition{ - Type: accepted, - Status: metav1.ConditionFalse, - Reason: invalidParameters, - Message: fmt.Sprintf("GatewayClassConfig not found %q.", parametersRef.Name), - }) - return didUpdate, nil - } - if err != nil { - log.Error(err, "unable to fetch GatewayClassConfig") - return false, err - } - } - - didUpdate = r.setCondition(gc, metav1.Condition{ - Type: accepted, - Status: metav1.ConditionTrue, - Reason: accepted, - Message: "GatewayClass Accepted", - }) - - return didUpdate, err -} - -// setCondition sets the given condition on the given GatewayClass. -func (r *GatewayClassController) setCondition(gc *gwv1beta1.GatewayClass, condition metav1.Condition) (didUpdate bool) { - condition.LastTransitionTime = metav1.Now() - condition.ObservedGeneration = gc.GetGeneration() - - // Set the condition if it already exists. - for i, c := range gc.Status.Conditions { - if c.Type == condition.Type { - // The condition already exists and is up to date. - if equalConditions(condition, c) { - return false - } - - gc.Status.Conditions[i] = condition - - return true - } - } - - // Append the condition if it does not exist. - gc.Status.Conditions = append(gc.Status.Conditions, condition) - - return true -} - -// gatewayClassConfigFieldIndexEventHandler returns an EventHandler that will enqueue -// reconcile.Requests for GatewayClass objects that reference the GatewayClassConfig -// object that triggered the event. -func (r *GatewayClassController) gatewayClassConfigFieldIndexEventHandler(ctx context.Context) handler.EventHandler { - return handler.EnqueueRequestsFromMapFunc(func(o client.Object) []reconcile.Request { - requests := []reconcile.Request{} - - // Get all GatewayClass objects from the field index of the GatewayClassConfig which triggered the event. - var gcList gwv1beta1.GatewayClassList - err := r.Client.List(ctx, &gcList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(GatewayClass_GatewayClassConfigIndex, o.GetName()), - }) - if err != nil { - r.Log.Error(err, "unable to list gateway classes") - } - - // Create a reconcile request for each GatewayClass. - for _, gc := range gcList.Items { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: gc.Name, - }, - }) - } - - return requests - }) -} - -// gatewayFieldIndexEventHandler returns an EventHandler that will enqueue -// reconcile.Requests for GatewayClass objects from Gateways which reference the GatewayClass -// when those Gateways are updated. -func (r *GatewayClassController) gatewayFieldIndexEventHandler(ctx context.Context) handler.EventHandler { - return handler.EnqueueRequestsFromMapFunc(func(o client.Object) []reconcile.Request { - // Get the Gateway object that triggered the event. - g := o.(*gwv1beta1.Gateway) - - // Return a slice with the single reconcile.Request for the GatewayClass - // that the Gateway references. - return []reconcile.Request{ - { - NamespacedName: types.NamespacedName{ - Name: string(g.Spec.GatewayClassName), - }, - }, - } - }) -} - -func equalConditions(a, b metav1.Condition) bool { - return a.Type == b.Type && - a.Status == b.Status && - a.Reason == b.Reason && - a.Message == b.Message && - a.ObservedGeneration == b.ObservedGeneration -} diff --git a/control-plane/api-gateway/controllers/gatewayclass_controller_test.go b/control-plane/api-gateway/controllers/gatewayclass_controller_test.go deleted file mode 100644 index 0eeaf4c1de..0000000000 --- a/control-plane/api-gateway/controllers/gatewayclass_controller_test.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "fmt" - "testing" - - logrtest "github.com/go-logr/logr/testr" - "github.com/stretchr/testify/require" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - "sigs.k8s.io/gateway-api/apis/v1beta1" - 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" -) - -func TestGatewayClassReconciler(t *testing.T) { - t.Parallel() - - namespace := "" // GatewayClass is cluster-scoped. - name := "test-gatewayclass" - - req := ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: namespace, - Name: name, - }, - } - - deletionTimestamp := metav1.Now() - - cases := map[string]struct { - gatewayClass *gwv1beta1.GatewayClass - k8sObjects []runtime.Object - expectedResult ctrl.Result - expectedError error - expectedFinalizers []string - expectedIsDeleted bool - expectedConditions []metav1.Condition - }{ - "successful reconcile with no change": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{gatewayClassFinalizer}, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: common.GatewayClassControllerName, - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedFinalizers: []string{gatewayClassFinalizer}, - expectedIsDeleted: false, - expectedConditions: []metav1.Condition{ - { - Type: accepted, - Status: metav1.ConditionTrue, - Reason: accepted, - Message: "GatewayClass Accepted", - }, - }, - }, - "successful reconcile that adds finalizer": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{}, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: common.GatewayClassControllerName, - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedFinalizers: []string{gatewayClassFinalizer}, - expectedConditions: []metav1.Condition{}, - }, - "attempt to reconcile a GatewayClass with a different controller name": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{}, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: "foo", - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedConditions: []metav1.Condition{}, - }, - "attempt to reconcile a GatewayClass with a different controller name removing our finalizer": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{gatewayClassFinalizer}, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: "foo", - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedConditions: []metav1.Condition{}, - }, - "attempt to reconcile a GatewayClass with an incorrect parametersRef type": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{gatewayClassFinalizer}, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: common.GatewayClassControllerName, - ParametersRef: &gwv1beta1.ParametersReference{ - Kind: "some-nonsense", - }, - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedFinalizers: []string{gatewayClassFinalizer}, - expectedConditions: []metav1.Condition{ - { - Type: accepted, - Status: metav1.ConditionFalse, - Reason: invalidParameters, - Message: fmt.Sprintf("Incorrect type for parametersRef. Expected GatewayClassConfig, got %q.", "some-nonsense"), - }, - }, - }, - "attempt to reconcile a GatewayClass with a GatewayClassConfig that does not exist": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{gatewayClassFinalizer}, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: common.GatewayClassControllerName, - ParametersRef: &gwv1beta1.ParametersReference{ - Kind: v1alpha1.GatewayClassConfigKind, - Name: "does-not-exist", - }, - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedFinalizers: []string{gatewayClassFinalizer}, - expectedConditions: []metav1.Condition{ - { - Type: accepted, - Status: metav1.ConditionFalse, - Reason: invalidParameters, - Message: fmt.Sprintf("GatewayClassConfig not found %q.", "does-not-exist"), - }, - }, - }, - "attempt to reconcile a non-existent object": { - k8sObjects: []runtime.Object{}, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedConditions: []metav1.Condition{}, - }, - "attempt to remove a GatewayClass that is not in use": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{ - gatewayClassFinalizer, - }, - DeletionTimestamp: &deletionTimestamp, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: common.GatewayClassControllerName, - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedFinalizers: []string{}, - expectedIsDeleted: true, - }, - "attempt to remove a GatewayClass that is in use": { - gatewayClass: &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - Finalizers: []string{ - gatewayClassFinalizer, - }, - DeletionTimestamp: &deletionTimestamp, - }, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: common.GatewayClassControllerName, - }, - }, - k8sObjects: []runtime.Object{ - &gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "default", - Name: "test-gateway", - }, - Spec: gwv1beta1.GatewaySpec{ - GatewayClassName: v1beta1.ObjectName(name), - }, - }, - }, - expectedResult: ctrl.Result{}, - expectedError: nil, - expectedFinalizers: []string{gatewayClassFinalizer}, - }, - // */ - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - s := runtime.NewScheme() - require.NoError(t, clientgoscheme.AddToScheme(s)) - require.NoError(t, gwv1alpha2.Install(s)) - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - objs := tc.k8sObjects - if tc.gatewayClass != nil { - objs = append(objs, tc.gatewayClass) - } - - fakeClient := registerFieldIndexersForTest(fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...)).Build() - - r := &GatewayClassController{ - Client: fakeClient, - ControllerName: common.GatewayClassControllerName, - Log: logrtest.New(t), - } - result, err := r.Reconcile(context.Background(), req) - - require.Equal(t, tc.expectedResult, result) - require.Equal(t, tc.expectedError, err) - - // Check the GatewayClass after reconciliation. - gc := &gwv1beta1.GatewayClass{} - err = r.Client.Get(context.Background(), req.NamespacedName, gc) - - if tc.gatewayClass == nil || tc.expectedIsDeleted { - // There shouldn't be a GatewayClass to check. - require.True(t, apierrors.IsNotFound(err)) - return - } - - require.NoError(t, client.IgnoreNotFound(err)) - require.Equal(t, tc.expectedFinalizers, gc.ObjectMeta.Finalizers) - require.Equal(t, len(tc.expectedConditions), len(gc.Status.Conditions), "expected %+v, got %+v", tc.expectedConditions, gc.Status.Conditions) - for i, expectedCondition := range tc.expectedConditions { - require.True(t, equalConditions(expectedCondition, gc.Status.Conditions[i]), "expected %+v, got %+v", expectedCondition, gc.Status.Conditions[i]) - } - }) - } -} diff --git a/control-plane/api-gateway/controllers/gatewayclassconfig_controller.go b/control-plane/api-gateway/controllers/gatewayclassconfig_controller.go deleted file mode 100644 index 878d6549f9..0000000000 --- a/control-plane/api-gateway/controllers/gatewayclassconfig_controller.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "time" - - "github.com/go-logr/logr" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - "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" - "sigs.k8s.io/controller-runtime/pkg/source" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" -) - -const ( - gatewayClassConfigFinalizer = "gateway-class-exists-finalizer.consul.hashicorp.com" -) - -// The GatewayClassConfigController manages the state of GatewayClassConfigs. -type GatewayClassConfigController struct { - client.Client - - Log logr.Logger -} - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.8.3/pkg/reconcile -func (r *GatewayClassConfigController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := r.Log.WithValues("gatewayClassConfig", req.NamespacedName.Name) - log.V(1).Info("Reconciling GatewayClassConfig ") - - gcc := &v1alpha1.GatewayClassConfig{} - if err := r.Client.Get(ctx, req.NamespacedName, gcc); err != nil { - if k8serrors.IsNotFound(err) { - return ctrl.Result{}, nil - } - log.Error(err, "failed to get gateway class config") - return ctrl.Result{}, err - } - - if !gcc.ObjectMeta.DeletionTimestamp.IsZero() { - // We have a deletion, ensure we're not in use. - used, err := gatewayClassConfigInUse(ctx, r.Client, gcc) - if err != nil { - log.Error(err, "failed to check if the gateway class config is still in use") - return ctrl.Result{}, err - } - if used { - log.Info("gateway class config still in use") - // Requeue as to not block the reconciliation loop. - return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - } - // gcc is no longer in use. - if _, err := RemoveFinalizer(ctx, r.Client, gcc, gatewayClassConfigFinalizer); err != nil { - if k8serrors.IsConflict(err) { - log.V(1).Info("error removing gateway class config finalizer, will try to re-reconcile") - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "error removing gateway class config finalizer") - return ctrl.Result{}, err - } - return ctrl.Result{}, nil - } - - if _, err := EnsureFinalizer(ctx, r.Client, gcc, gatewayClassConfigFinalizer); err != nil { - if k8serrors.IsConflict(err) { - log.V(1).Info("error adding gateway class config finalizer, will try to re-reconcile") - - return ctrl.Result{Requeue: true}, nil - } - log.Error(err, "error adding gateway class config finalizer") - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -// gatewayClassUsesConfig determines whether a given GatewayClass references a -// given GatewayClassConfig. Since these resources are scoped to the cluster, -// namespace is not considered. -func gatewayClassUsesConfig(gc gwv1beta1.GatewayClass, gcc *v1alpha1.GatewayClassConfig) bool { - parameterRef := gc.Spec.ParametersRef - return parameterRef != nil && - string(parameterRef.Group) == v1alpha1.ConsulHashicorpGroup && - parameterRef.Kind == v1alpha1.GatewayClassConfigKind && - parameterRef.Name == gcc.Name -} - -// GatewayClassConfigInUse determines whether any GatewayClass in the cluster -// references the provided GatewayClassConfig. -func gatewayClassConfigInUse(ctx context.Context, k8sClient client.Client, gcc *v1alpha1.GatewayClassConfig) (bool, error) { - list := &gwv1beta1.GatewayClassList{} - if err := k8sClient.List(ctx, list); err != nil { - return false, err - } - - for _, gc := range list.Items { - if gatewayClassUsesConfig(gc, gcc) { - return true, nil - } - } - - return false, nil -} - -func (r *GatewayClassConfigController) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.GatewayClassConfig{}). - // Watch for changes to GatewayClass objects associated with this config for purposes of finalizer removal. - Watches(source.NewKindWithCache(&gwv1beta1.GatewayClass{}, mgr.GetCache()), r.transformGatewayClassToGatewayClassConfig(ctx)). - Complete(r) -} - -func (r *GatewayClassConfigController) transformGatewayClassToGatewayClassConfig(ctx context.Context) handler.EventHandler { - return handler.EnqueueRequestsFromMapFunc(func(o client.Object) []reconcile.Request { - gc := o.(*gwv1beta1.GatewayClass) - - pr := gc.Spec.ParametersRef - if pr != nil && pr.Kind == v1alpha1.GatewayClassConfigKind { - return []reconcile.Request{{ - NamespacedName: types.NamespacedName{ - Name: pr.Name, - }, - }} - } - - return nil - }) -} diff --git a/control-plane/api-gateway/controllers/gatewayclassconfig_controller_test.go b/control-plane/api-gateway/controllers/gatewayclassconfig_controller_test.go deleted file mode 100644 index 40023d498f..0000000000 --- a/control-plane/api-gateway/controllers/gatewayclassconfig_controller_test.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - "testing" - "time" - - logrtest "github.com/go-logr/logr/testr" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/stretchr/testify/require" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestGatewayClassConfigReconcile(t *testing.T) { - t.Parallel() - deletionTimestamp := meta.Now() - cases := []struct { - name string - k8sObjects func() []runtime.Object - expErr string - requeue bool - requeueAfter time.Duration - }{ - { - name: "Successfully reconcile without any changes", - k8sObjects: func() []runtime.Object { - gatewayClassConfig := v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-api-gateway", - }, - } - return []runtime.Object{&gatewayClassConfig} - }, - }, - { - name: "GatewayClassConfig Does Not Exist", - k8sObjects: func() []runtime.Object { - return []runtime.Object{} - }, - }, - { - name: "Remove not-in-use GatewayClassConfig", - k8sObjects: func() []runtime.Object { - gatewayClassConfig := v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-api-gateway", - DeletionTimestamp: &deletionTimestamp, - }, - } - return []runtime.Object{&gatewayClassConfig} - }, - }, - { - name: "Try to remove in-use GatewayClassConfig", - k8sObjects: func() []runtime.Object { - gatewayClassConfig := v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-api-gateway", - DeletionTimestamp: &deletionTimestamp, - }, - } - gatewayClass := gwv1beta1.GatewayClass{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-api-gateway-class", - }, - Spec: gwv1beta1.GatewayClassSpec{ - ParametersRef: &gwv1beta1.ParametersReference{ - Group: gwv1beta1.Group(v1alpha1.ConsulHashicorpGroup), - Kind: v1alpha1.GatewayClassConfigKind, - Name: gatewayClassConfig.ObjectMeta.Name, - Namespace: nil, - }, - }, - Status: gwv1beta1.GatewayClassStatus{}, - } - return []runtime.Object{&gatewayClassConfig, &gatewayClass} - }, - requeueAfter: time.Second * 10, - }, - } - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - s := runtime.NewScheme() - require.NoError(t, clientgoscheme.AddToScheme(s)) - require.NoError(t, gwv1alpha2.Install(s)) - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(tt.k8sObjects()...).Build() - - // Create the gateway class config controller. - gcc := &GatewayClassConfigController{ - Client: fakeClient, - Log: logrtest.New(t), - } - - resp, err := gcc.Reconcile(context.Background(), ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: "", - Name: "consul-api-gateway", - }, - }) - if tt.expErr != "" { - require.EqualError(t, err, tt.expErr) - } else { - require.NoError(t, err) - } - require.Equal(t, tt.requeue, resp.Requeue) - }) - } -} diff --git a/control-plane/api-gateway/controllers/index.go b/control-plane/api-gateway/controllers/index.go deleted file mode 100644 index 131ec383e7..0000000000 --- a/control-plane/api-gateway/controllers/index.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - 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" -) - -const ( - // Naming convention: TARGET_REFERENCE. - GatewayClass_GatewayClassConfigIndex = "__gatewayclass_referencing_gatewayclassconfig" - GatewayClass_ControllerNameIndex = "__gatewayclass_controller_name" - Gateway_GatewayClassIndex = "__gateway_referencing_gatewayclass" - HTTPRoute_GatewayIndex = "__httproute_referencing_gateway" - HTTPRoute_ServiceIndex = "__httproute_referencing_service" - HTTPRoute_MeshServiceIndex = "__httproute_referencing_mesh_service" - TCPRoute_GatewayIndex = "__tcproute_referencing_gateway" - TCPRoute_ServiceIndex = "__tcproute_referencing_service" - TCPRoute_MeshServiceIndex = "__tcproute_referencing_mesh_service" - MeshService_PeerIndex = "__meshservice_referencing_peer" - Secret_GatewayIndex = "__secret_referencing_gateway" - HTTPRoute_RouteRetryFilterIndex = "__httproute_referencing_retryfilter" - HTTPRoute_RouteTimeoutFilterIndex = "__httproute_referencing_timeoutfilter" -) - -// RegisterFieldIndexes registers all of the field indexes for the API gateway 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 RegisterFieldIndexes(ctx context.Context, mgr ctrl.Manager) error { - for _, index := range indexes { - if err := mgr.GetFieldIndexer().IndexField(ctx, index.target, index.name, index.indexerFunc); err != nil { - return err - } - } - return nil -} - -type index struct { - name string - target client.Object - indexerFunc client.IndexerFunc -} - -var indexes = []index{ - { - name: GatewayClass_GatewayClassConfigIndex, - target: &gwv1beta1.GatewayClass{}, - indexerFunc: gatewayClassConfigForGatewayClass, - }, - { - name: GatewayClass_ControllerNameIndex, - target: &gwv1beta1.GatewayClass{}, - indexerFunc: gatewayClassControllerName, - }, - { - name: Gateway_GatewayClassIndex, - target: &gwv1beta1.Gateway{}, - indexerFunc: gatewayClassForGateway, - }, - { - name: Secret_GatewayIndex, - target: &gwv1beta1.Gateway{}, - indexerFunc: gatewayForSecret, - }, - { - name: HTTPRoute_GatewayIndex, - target: &gwv1beta1.HTTPRoute{}, - indexerFunc: gatewaysForHTTPRoute, - }, - { - name: HTTPRoute_ServiceIndex, - target: &gwv1beta1.HTTPRoute{}, - indexerFunc: servicesForHTTPRoute, - }, - { - name: HTTPRoute_MeshServiceIndex, - target: &gwv1beta1.HTTPRoute{}, - indexerFunc: meshServicesForHTTPRoute, - }, - { - name: TCPRoute_GatewayIndex, - target: &gwv1alpha2.TCPRoute{}, - indexerFunc: gatewaysForTCPRoute, - }, - { - name: TCPRoute_ServiceIndex, - target: &gwv1alpha2.TCPRoute{}, - indexerFunc: servicesForTCPRoute, - }, - { - name: TCPRoute_MeshServiceIndex, - target: &gwv1alpha2.TCPRoute{}, - indexerFunc: meshServicesForTCPRoute, - }, - { - name: MeshService_PeerIndex, - target: &v1alpha1.MeshService{}, - indexerFunc: peersForMeshService, - }, - { - name: HTTPRoute_RouteRetryFilterIndex, - target: &gwv1beta1.HTTPRoute{}, - indexerFunc: filtersForHTTPRoute, - }, - { - name: HTTPRoute_RouteTimeoutFilterIndex, - target: &gwv1beta1.HTTPRoute{}, - indexerFunc: filtersForHTTPRoute, - }, -} - -// gatewayClassConfigForGatewayClass creates an index of every GatewayClassConfig referenced by a GatewayClass. -func gatewayClassConfigForGatewayClass(o client.Object) []string { - gc := o.(*gwv1beta1.GatewayClass) - - pr := gc.Spec.ParametersRef - if pr != nil && pr.Kind == v1alpha1.GatewayClassConfigKind { - return []string{pr.Name} - } - - return []string{} -} - -func gatewayClassControllerName(o client.Object) []string { - gc := o.(*gwv1beta1.GatewayClass) - - if gc.Spec.ControllerName != "" { - return []string{string(gc.Spec.ControllerName)} - } - - return []string{} -} - -// gatewayClassForGateway creates an index of every GatewayClass referenced by a Gateway. -func gatewayClassForGateway(o client.Object) []string { - g := o.(*gwv1beta1.Gateway) - return []string{string(g.Spec.GatewayClassName)} -} - -func peersForMeshService(o client.Object) []string { - m := o.(*v1alpha1.MeshService) - if m.Spec.Peer != nil { - return []string{string(*m.Spec.Peer)} - } - return nil -} - -func gatewayForSecret(o client.Object) []string { - gateway := o.(*gwv1beta1.Gateway) - var secretReferences []string - for _, listener := range gateway.Spec.Listeners { - if listener.TLS == nil || *listener.TLS.Mode != gwv1beta1.TLSModeTerminate { - continue - } - for _, cert := range listener.TLS.CertificateRefs { - if common.NilOrEqual(cert.Group, "") && common.NilOrEqual(cert.Kind, "Secret") { - // If an explicit Secret namespace is not provided, use the Gateway namespace to lookup the provided Secret Name. - secretReferences = append(secretReferences, common.IndexedNamespacedNameWithDefault(cert.Name, cert.Namespace, gateway.Namespace).String()) - } - } - } - return secretReferences -} - -func gatewaysForHTTPRoute(o client.Object) []string { - route := o.(*gwv1beta1.HTTPRoute) - statusRefs := common.ConvertSliceFunc(route.Status.Parents, func(parentStatus gwv1beta1.RouteParentStatus) gwv1beta1.ParentReference { - return parentStatus.ParentRef - }) - return gatewaysForRoute(route.Namespace, route.Spec.ParentRefs, statusRefs) -} - -func gatewaysForTCPRoute(o client.Object) []string { - route := o.(*gwv1alpha2.TCPRoute) - statusRefs := common.ConvertSliceFunc(route.Status.Parents, func(parentStatus gwv1beta1.RouteParentStatus) gwv1beta1.ParentReference { - return parentStatus.ParentRef - }) - return gatewaysForRoute(route.Namespace, route.Spec.ParentRefs, statusRefs) -} - -func servicesForHTTPRoute(o client.Object) []string { - route := o.(*gwv1beta1.HTTPRoute) - refs := []string{} - for _, rule := range route.Spec.Rules { - BACKEND_LOOP: - for _, ref := range rule.BackendRefs { - if common.NilOrEqual(ref.Group, "") && common.NilOrEqual(ref.Kind, "Service") { - backendRef := common.IndexedNamespacedNameWithDefault(ref.Name, ref.Namespace, route.Namespace).String() - for _, member := range refs { - if member == backendRef { - continue BACKEND_LOOP - } - } - refs = append(refs, backendRef) - } - } - } - return refs -} - -func meshServicesForHTTPRoute(o client.Object) []string { - route := o.(*gwv1beta1.HTTPRoute) - refs := []string{} - for _, rule := range route.Spec.Rules { - BACKEND_LOOP: - for _, ref := range rule.BackendRefs { - if common.DerefEqual(ref.Group, v1alpha1.ConsulHashicorpGroup) && common.DerefEqual(ref.Kind, v1alpha1.MeshServiceKind) { - backendRef := common.IndexedNamespacedNameWithDefault(ref.Name, ref.Namespace, route.Namespace).String() - for _, member := range refs { - if member == backendRef { - continue BACKEND_LOOP - } - } - refs = append(refs, backendRef) - } - } - } - return refs -} - -func servicesForTCPRoute(o client.Object) []string { - route := o.(*gwv1alpha2.TCPRoute) - refs := []string{} - for _, rule := range route.Spec.Rules { - BACKEND_LOOP: - for _, ref := range rule.BackendRefs { - if common.NilOrEqual(ref.Group, "") && common.NilOrEqual(ref.Kind, common.KindService) { - backendRef := common.IndexedNamespacedNameWithDefault(ref.Name, ref.Namespace, route.Namespace).String() - for _, member := range refs { - if member == backendRef { - continue BACKEND_LOOP - } - } - refs = append(refs, backendRef) - } - } - } - return refs -} - -func meshServicesForTCPRoute(o client.Object) []string { - route := o.(*gwv1alpha2.TCPRoute) - refs := []string{} - for _, rule := range route.Spec.Rules { - BACKEND_LOOP: - for _, ref := range rule.BackendRefs { - if common.DerefEqual(ref.Group, v1alpha1.ConsulHashicorpGroup) && common.DerefEqual(ref.Kind, v1alpha1.MeshServiceKind) { - backendRef := common.IndexedNamespacedNameWithDefault(ref.Name, ref.Namespace, route.Namespace).String() - for _, member := range refs { - if member == backendRef { - continue BACKEND_LOOP - } - } - refs = append(refs, backendRef) - } - } - } - return refs -} - -func gatewaysForRoute(namespace string, refs []gwv1beta1.ParentReference, statusRefs []gwv1beta1.ParentReference) []string { - var references []string - for _, parent := range refs { - if common.NilOrEqual(parent.Group, common.BetaGroup) && common.NilOrEqual(parent.Kind, common.KindGateway) { - // If an explicit Gateway namespace is not provided, use the Route namespace to lookup the provided Gateway Namespace. - references = append(references, common.IndexedNamespacedNameWithDefault(parent.Name, parent.Namespace, namespace).String()) - } - } - for _, parent := range statusRefs { - if common.NilOrEqual(parent.Group, common.BetaGroup) && common.NilOrEqual(parent.Kind, common.KindGateway) { - // If an explicit Gateway namespace is not provided, use the Route namespace to lookup the provided Gateway Namespace. - references = append(references, common.IndexedNamespacedNameWithDefault(parent.Name, parent.Namespace, namespace).String()) - } - } - return references -} - -func filtersForHTTPRoute(o client.Object) []string { - route := o.(*gwv1beta1.HTTPRoute) - filters := []string{} - var nilString *string - - for _, rule := range route.Spec.Rules { - FILTERS_LOOP: - for _, filter := range rule.Filters { - if common.FilterIsExternalFilter(filter) { - //TODO this seems like its type agnostic, so this might just work without having to make - //multiple index functions per custom filter type? - - //index external filters - filter := common.IndexedNamespacedNameWithDefault(string(filter.ExtensionRef.Name), nilString, route.Namespace).String() - for _, member := range filters { - if member == filter { - continue FILTERS_LOOP - } - } - filters = append(filters, filter) - } - } - - //same thing but over the backend refs - BACKEND_LOOP: - for _, ref := range rule.BackendRefs { - for _, filter := range ref.Filters { - if common.FilterIsExternalFilter(filter) { - filter := common.IndexedNamespacedNameWithDefault(string(filter.ExtensionRef.Name), nilString, route.Namespace).String() - for _, member := range filters { - if member == filter { - continue BACKEND_LOOP - } - } - filters = append(filters, filter) - } - } - } - } - return filters -} diff --git a/control-plane/api-gateway/controllers/index_test.go b/control-plane/api-gateway/controllers/index_test.go deleted file mode 100644 index 5655a3c3da..0000000000 --- a/control-plane/api-gateway/controllers/index_test.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import "sigs.k8s.io/controller-runtime/pkg/client/fake" - -func registerFieldIndexersForTest(clientBuilder *fake.ClientBuilder) *fake.ClientBuilder { - for _, index := range indexes { - clientBuilder = clientBuilder.WithIndex(index.target, index.name, index.indexerFunc) - } - return clientBuilder -} diff --git a/control-plane/api-gateway/gatekeeper/dataplane.go b/control-plane/api-gateway/gatekeeper/dataplane.go deleted file mode 100644 index adaf0699b5..0000000000 --- a/control-plane/api-gateway/gatekeeper/dataplane.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "fmt" - "strconv" - - corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" - "k8s.io/apimachinery/pkg/util/intstr" -) - -const ( - allCapabilities = "all" - netBindCapability = "NET_BIND_SERVICE" - consulDataplaneDNSBindHost = "127.0.0.1" - consulDataplaneDNSBindPort = 8600 - defaultPrometheusScrapePath = "/metrics" - defaultEnvoyProxyConcurrency = 1 - volumeName = "consul-connect-inject-data" -) - -func consulDataplaneContainer(config common.HelmConfig, gcc v1alpha1.GatewayClassConfig, name, namespace string) (corev1.Container, error) { - // Extract the service account token's volume mount. - var ( - err error - bearerTokenFile string - ) - - if config.AuthMethod != "" { - bearerTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" - } - - args, err := getDataplaneArgs(namespace, config, bearerTokenFile, name) - if err != nil { - return corev1.Container{}, err - } - - probe := &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Port: intstr.FromInt(constants.ProxyDefaultHealthPort), - Path: "/ready", - }, - }, - InitialDelaySeconds: 1, - } - - container := corev1.Container{ - 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 - // because we set file system to be read-only. - Env: []corev1.EnvVar{ - { - Name: "TMPDIR", - Value: "/consul/connect-inject", - }, - { - Name: "NODE_NAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", - }, - }, - }, - { - Name: "DP_SERVICE_NODE_NAME", - Value: "$(NODE_NAME)-virtual", - }, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: volumeName, - MountPath: "/consul/connect-inject", - }, - }, - Args: args, - ReadinessProbe: probe, - } - - // Configure the Readiness Address for the proxy's health check to be the Pod IP. - container.Env = append(container.Env, corev1.EnvVar{ - Name: "DP_ENVOY_READY_BIND_ADDRESS", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{FieldPath: "status.podIP"}, - }, - }) - // Configure the port on which the readiness probe will query the proxy for its health. - container.Ports = append(container.Ports, corev1.ContainerPort{ - Name: "proxy-health", - ContainerPort: int32(constants.ProxyDefaultHealthPort), - }) - // Configure the resource requests and limits for the proxy if they are set. - if gcc.Spec.DeploymentSpec.Resources != nil { - container.Resources = *gcc.Spec.DeploymentSpec.Resources - } - - // If not running in an OpenShift environment, - // skip setting the security context and let OpenShift set it for us. - if !config.EnableOpenShift { - container.SecurityContext = &corev1.SecurityContext{ - ReadOnlyRootFilesystem: pointer.Bool(true), - // We have to run as root if we want to bind to any - // sort of privileged ports. The drop "all" is intended - // to drop any Linux capabilities you'd get as root - // other than NET_BIND_SERVICE. - RunAsUser: pointer.Int64(0), - Capabilities: &corev1.Capabilities{ - Add: []corev1.Capability{netBindCapability}, - Drop: []corev1.Capability{allCapabilities}, - }, - } - } - - return container, nil -} - -func getDataplaneArgs(namespace string, config common.HelmConfig, bearerTokenFile string, name string) ([]string, error) { - proxyIDFileName := "/consul/connect-inject/proxyid" - envoyConcurrency := defaultEnvoyProxyConcurrency - - args := []string{ - "-addresses", config.ConsulConfig.Address, - "-grpc-port=" + strconv.Itoa(config.ConsulConfig.GRPCPort), - "-proxy-service-id-path=" + proxyIDFileName, - "-log-level=" + config.LogLevel, - "-log-json=" + strconv.FormatBool(config.LogJSON), - "-envoy-concurrency=" + strconv.Itoa(envoyConcurrency), - } - - consulNamespace := namespaces.ConsulNamespace(namespace, config.EnableNamespaces, config.ConsulDestinationNamespace, config.EnableNamespaceMirroring, config.NamespaceMirroringPrefix) - - if config.AuthMethod != "" { - args = append(args, - "-credential-type=login", - "-login-auth-method="+config.AuthMethod, - "-login-bearer-token-path="+bearerTokenFile, - "-login-meta="+fmt.Sprintf("gateway=%s/%s", namespace, name), - ) - if config.ConsulPartition != "" { - args = append(args, "-login-partition="+config.ConsulPartition) - } - } - if config.EnableNamespaces { - args = append(args, "-service-namespace="+consulNamespace) - } - if config.ConsulPartition != "" { - args = append(args, "-service-partition="+config.ConsulPartition) - } - if config.TLSEnabled { - if config.ConsulTLSServerName != "" { - args = append(args, "-tls-server-name="+config.ConsulTLSServerName) - } - if config.ConsulCACert != "" { - args = append(args, "-ca-certs="+constants.ConsulCAFile) - } - } else { - args = append(args, "-tls-disabled") - } - - // Configure the readiness port on the dataplane sidecar if proxy health checks are enabled. - args = append(args, fmt.Sprintf("%s=%d", "-envoy-ready-bind-port", constants.ProxyDefaultHealthPort)) - - args = append(args, fmt.Sprintf("-envoy-admin-bind-port=%d", 19000)) - - // Set a default scrape path that can be overwritten by the annotation. - prometheusScrapePath := defaultPrometheusScrapePath - args = append(args, "-telemetry-prom-scrape-path="+prometheusScrapePath) - - return args, nil -} diff --git a/control-plane/api-gateway/gatekeeper/deployment.go b/control-plane/api-gateway/gatekeeper/deployment.go deleted file mode 100644 index f3e9545e57..0000000000 --- a/control-plane/api-gateway/gatekeeper/deployment.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "context" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "k8s.io/apimachinery/pkg/types" - - appsv1 "k8s.io/api/apps/v1" - 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" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -const ( - defaultInstances int32 = 1 -) - -func (g *Gatekeeper) upsertDeployment(ctx context.Context, gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) error { - // Get Deployment if it exists. - existingDeployment := &appsv1.Deployment{} - exists := false - - err := g.Client.Get(ctx, g.namespacedName(gateway), existingDeployment) - if err != nil && !k8serrors.IsNotFound(err) { - return err - } else if k8serrors.IsNotFound(err) { - exists = false - } else { - exists = true - } - - var currentReplicas *int32 - if exists { - currentReplicas = existingDeployment.Spec.Replicas - } - - deployment, err := g.deployment(gateway, gcc, config, currentReplicas) - if err != nil { - return err - } - - if exists { - g.Log.V(1).Info("Existing Gateway Deployment found.") - - // If the user has set the number of replicas, let's respect that. - deployment.Spec.Replicas = existingDeployment.Spec.Replicas - } - - mutated := deployment.DeepCopy() - mutator := newDeploymentMutator(deployment, mutated, gcc, gateway, g.Client.Scheme()) - - result, err := controllerutil.CreateOrUpdate(ctx, g.Client, mutated, mutator) - if err != nil { - return err - } - - switch result { - case controllerutil.OperationResultCreated: - g.Log.V(1).Info("Created Deployment") - case controllerutil.OperationResultUpdated: - g.Log.V(1).Info("Updated Deployment") - case controllerutil.OperationResultNone: - g.Log.V(1).Info("No change to deployment") - } - - return nil -} - -func (g *Gatekeeper) deleteDeployment(ctx context.Context, gwName types.NamespacedName) error { - err := g.Client.Delete(ctx, &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: gwName.Name, Namespace: gwName.Namespace}}) - if k8serrors.IsNotFound(err) { - return nil - } - - return err -} - -func (g *Gatekeeper) deployment(gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig, currentReplicas *int32) (*appsv1.Deployment, error) { - initContainer, err := initContainer(config, gateway.Name, gateway.Namespace) - if err != nil { - return nil, err - } - - container, err := consulDataplaneContainer(config, gcc, gateway.Name, gateway.Namespace) - if err != nil { - return nil, err - } - - return &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: gateway.Name, - Namespace: gateway.Namespace, - Labels: common.LabelsForGateway(&gateway), - }, - Spec: appsv1.DeploymentSpec{ - Replicas: deploymentReplicas(gcc, currentReplicas), - Selector: &metav1.LabelSelector{ - MatchLabels: common.LabelsForGateway(&gateway), - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: common.LabelsForGateway(&gateway), - Annotations: map[string]string{ - "consul.hashicorp.com/connect-inject": "false", - }, - }, - Spec: corev1.PodSpec{ - Volumes: []corev1.Volume{ - { - Name: volumeName, - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{Medium: corev1.StorageMediumMemory}, - }, - }, - }, - InitContainers: []corev1.Container{ - initContainer, - }, - Containers: []corev1.Container{ - container, - }, - Affinity: &corev1.Affinity{ - PodAntiAffinity: &corev1.PodAntiAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ - { - Weight: 1, - PodAffinityTerm: corev1.PodAffinityTerm{ - LabelSelector: &metav1.LabelSelector{ - MatchLabels: common.LabelsForGateway(&gateway), - }, - TopologyKey: "kubernetes.io/hostname", - }, - }, - }, - }, - }, - NodeSelector: gcc.Spec.NodeSelector, - Tolerations: gcc.Spec.Tolerations, - ServiceAccountName: g.serviceAccountName(gateway, config), - }, - }, - }, - }, nil -} - -func mergeDeployments(gcc v1alpha1.GatewayClassConfig, a, b *appsv1.Deployment) *appsv1.Deployment { - if !compareDeployments(a, b) { - b.Spec.Template = a.Spec.Template - b.Spec.Replicas = deploymentReplicas(gcc, a.Spec.Replicas) - } - - return b -} - -func compareDeployments(a, b *appsv1.Deployment) bool { - // since K8s adds a bunch of defaults when we create a deployment, check that - // they don't differ by the things that we may actually change, namely container - // ports - if len(b.Spec.Template.Spec.Containers) != len(a.Spec.Template.Spec.Containers) { - return false - } - for i, container := range a.Spec.Template.Spec.Containers { - otherPorts := b.Spec.Template.Spec.Containers[i].Ports - if len(container.Ports) != len(otherPorts) { - return false - } - for j, port := range container.Ports { - otherPort := otherPorts[j] - if port.ContainerPort != otherPort.ContainerPort { - return false - } - if port.Protocol != otherPort.Protocol { - return false - } - } - } - - if b.Spec.Replicas == nil && a.Spec.Replicas == nil { - return true - } else if b.Spec.Replicas == nil { - return false - } else if a.Spec.Replicas == nil { - return false - } - - return *b.Spec.Replicas == *a.Spec.Replicas -} - -func newDeploymentMutator(deployment, mutated *appsv1.Deployment, gcc v1alpha1.GatewayClassConfig, gateway gwv1beta1.Gateway, scheme *runtime.Scheme) resourceMutator { - return func() error { - mutated = mergeDeployments(gcc, deployment, mutated) - return ctrl.SetControllerReference(&gateway, mutated, scheme) - } -} - -func deploymentReplicas(gcc v1alpha1.GatewayClassConfig, currentReplicas *int32) *int32 { - instanceValue := defaultInstances - - // If currentReplicas is not nil use current value when building deployment... - if currentReplicas != nil { - instanceValue = *currentReplicas - } else if gcc.Spec.DeploymentSpec.DefaultInstances != nil { - // otherwise use the default value on the GatewayClassConfig if set. - instanceValue = *gcc.Spec.DeploymentSpec.DefaultInstances - } - - if gcc.Spec.DeploymentSpec.MaxInstances != nil { - // Check if the deployment replicas are greater than the maximum and lower to the maximum if so. - maxValue := *gcc.Spec.DeploymentSpec.MaxInstances - if instanceValue > maxValue { - instanceValue = maxValue - } - } - - if gcc.Spec.DeploymentSpec.MinInstances != nil { - // Check if the deployment replicas are less than the minimum and raise to the minimum if so. - minValue := *gcc.Spec.DeploymentSpec.MinInstances - if instanceValue < minValue { - instanceValue = minValue - } - - } - return &instanceValue -} diff --git a/control-plane/api-gateway/gatekeeper/gatekeeper.go b/control-plane/api-gateway/gatekeeper/gatekeeper.go deleted file mode 100644 index 6cb7170fc8..0000000000 --- a/control-plane/api-gateway/gatekeeper/gatekeeper.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "context" - "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" -) - -// Gatekeeper is used to manage the lifecycle of Gateway deployments and services. -type Gatekeeper struct { - Log logr.Logger - Client client.Client -} - -// New creates a new Gatekeeper from the Config. -func New(log logr.Logger, client client.Client) *Gatekeeper { - return &Gatekeeper{ - Log: log, - Client: client, - } -} - -// Upsert creates or updates the resources for handling routing of network traffic. -// This is done in order based on dependencies between resources. -func (g *Gatekeeper) Upsert(ctx context.Context, gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) error { - g.Log.V(1).Info(fmt.Sprintf("Upsert Gateway Deployment %s/%s", gateway.Namespace, gateway.Name)) - - if err := g.upsertRole(ctx, gateway, gcc, config); err != nil { - return err - } - - if err := g.upsertServiceAccount(ctx, gateway, config); err != nil { - return err - } - - if err := g.upsertRoleBinding(ctx, gateway, gcc, config); err != nil { - return err - } - - if err := g.upsertService(ctx, gateway, gcc, config); err != nil { - return err - } - - if err := g.upsertDeployment(ctx, gateway, gcc, config); err != nil { - return err - } - - return nil -} - -// 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, 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.deleteService(ctx, gatewayName); err != nil { - return err - } - - if err := g.deleteRoleBinding(ctx, gatewayName); err != nil { - return err - } - - if err := g.deleteServiceAccount(ctx, gatewayName); err != nil { - return err - } - - if err := g.deleteRole(ctx, gatewayName); err != nil { - return err - } - - return nil -} - -// resourceMutator is passed to create or update functions to mutate Kubernetes resources. -type resourceMutator = func() error - -func (g *Gatekeeper) namespacedName(gateway gwv1beta1.Gateway) types.NamespacedName { - return types.NamespacedName{ - Namespace: gateway.Namespace, - Name: gateway.Name, - } -} - -func (g *Gatekeeper) serviceAccountName(gateway gwv1beta1.Gateway, config common.HelmConfig) string { - if config.AuthMethod == "" && !config.EnableOpenShift { - return "" - } - return gateway.Name -} diff --git a/control-plane/api-gateway/gatekeeper/gatekeeper_test.go b/control-plane/api-gateway/gatekeeper/gatekeeper_test.go deleted file mode 100644 index 562b139274..0000000000 --- a/control-plane/api-gateway/gatekeeper/gatekeeper_test.go +++ /dev/null @@ -1,1299 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "context" - "fmt" - "testing" - - logrtest "github.com/go-logr/logr/testr" - common "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/stretchr/testify/require" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - rbac "k8s.io/api/rbac/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" - "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -var ( - createdAtLabelKey = "gateway.consul.hashicorp.com/created" - createdAtLabelValue = "101010" - name = "test" - namespace = "default" - labels = map[string]string{ - "gateway.consul.hashicorp.com/name": name, - "gateway.consul.hashicorp.com/namespace": namespace, - createdAtLabelKey: createdAtLabelValue, - "gateway.consul.hashicorp.com/managed": "true", - } - listeners = []gwv1beta1.Listener{ - { - Name: "Listener 1", - Port: 8080, - Protocol: "TCP", - Hostname: common.PointerTo(gwv1beta1.Hostname("example.com")), - }, - { - Name: "Listener 2", - Port: 8081, - Protocol: "TCP", - }, - { - Name: "Listener 3", - Port: 8080, - Protocol: "TCP", - Hostname: common.PointerTo(gwv1beta1.Hostname("example.net")), - }, - } -) - -type testCase struct { - gateway gwv1beta1.Gateway - gatewayClassConfig v1alpha1.GatewayClassConfig - helmConfig common.HelmConfig - - initialResources resources - finalResources resources -} - -type resources struct { - deployments []*appsv1.Deployment - roles []*rbac.Role - roleBindings []*rbac.RoleBinding - services []*corev1.Service - serviceAccounts []*corev1.ServiceAccount -} - -func TestUpsert(t *testing.T) { - t.Parallel() - - cases := map[string]testCase{ - "create a new gateway deployment with only Deployment": { - 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{}, - initialResources: resources{}, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "create a new gateway with service and map privileged ports correctly": { - gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{ - { - Name: "Listener 1", - Port: 80, - Protocol: "TCP", - }, - { - Name: "Listener 2", - Port: 8080, - Protocol: "TCP", - }, - }, - }, - }, - 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")), - MapPrivilegedContainerPorts: 2000, - }, - }, - helmConfig: common.HelmConfig{}, - initialResources: resources{}, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{ - configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ - { - Name: "Listener 1", - Protocol: "TCP", - Port: 80, - TargetPort: intstr.FromInt(2080), - }, - { - Name: "Listener 2", - Protocol: "TCP", - Port: 8080, - TargetPort: intstr.FromInt(8080), - }, - }, "1"), - }, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "create a new gateway deployment with managed Service": { - 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{}, - initialResources: resources{}, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{ - configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ - { - Name: "Listener 1", - Protocol: "TCP", - Port: 8080, - TargetPort: intstr.FromInt(8080), - }, - { - Name: "Listener 2", - Protocol: "TCP", - Port: 8081, - TargetPort: intstr.FromInt(8081), - }, - }, "1"), - }, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "create a new gateway deployment with managed Service and ACLs": { - 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", - }, - initialResources: resources{}, - finalResources: 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"), - }, - services: []*corev1.Service{ - configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ - { - Name: "Listener 1", - Protocol: "TCP", - Port: 8080, - TargetPort: intstr.FromInt(8080), - }, - { - Name: "Listener 2", - Protocol: "TCP", - Port: 8081, - TargetPort: intstr.FromInt(8081), - }, - }, "1"), - }, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - }, - "create a new gateway where the GatewayClassConfig has a default number of instances greater than the max on the GatewayClassConfig": { - 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(8)), - MaxInstances: common.PointerTo(int32(5)), - MinInstances: common.PointerTo(int32(2)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - ServiceType: (*corev1.ServiceType)(common.PointerTo("NodePort")), - }, - }, - helmConfig: common.HelmConfig{}, - initialResources: resources{}, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 5, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "create a new gateway where the GatewayClassConfig has a default number of instances lesser than the min on the GatewayClassConfig": { - 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(1)), - MaxInstances: common.PointerTo(int32(5)), - MinInstances: common.PointerTo(int32(2)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - ServiceType: (*corev1.ServiceType)(common.PointerTo("NodePort")), - }, - }, - helmConfig: common.HelmConfig{}, - initialResources: resources{}, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 2, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "update a gateway, adding a listener to a service": { - 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", - }, - 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"), - }, - services: []*corev1.Service{ - configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ - { - Name: "Listener 1", - Protocol: "TCP", - Port: 8080, - }, - }, "1"), - }, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "2"), - }, - roles: []*rbac.Role{ - configureRole(name, namespace, labels, "1", false), - }, - roleBindings: []*rbac.RoleBinding{ - configureRoleBinding(name, namespace, labels, "1"), - }, - services: []*corev1.Service{ - configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ - { - Name: "Listener 1", - Protocol: "TCP", - Port: 8080, - TargetPort: intstr.FromInt(8080), - }, - { - Name: "Listener 2", - Protocol: "TCP", - Port: 8081, - TargetPort: intstr.FromInt(8081), - }, - }, "2"), - }, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - }, - "update a gateway, removing a listener from a service": { - gateway: gwv1beta1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: gwv1beta1.GatewaySpec{ - Listeners: []gwv1beta1.Listener{ - listeners[0], - }, - }, - }, - 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", - }, - 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"), - }, - 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"), - }, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "2"), - }, - roles: []*rbac.Role{ - configureRole(name, namespace, labels, "1", false), - }, - roleBindings: []*rbac.RoleBinding{ - configureRoleBinding(name, namespace, labels, "1"), - }, - services: []*corev1.Service{ - configureService(name, namespace, labels, nil, (corev1.ServiceType)("NodePort"), []corev1.ServicePort{ - { - Name: "Listener 1", - Protocol: "TCP", - Port: 8080, - TargetPort: intstr.FromInt(8080), - }, - }, "2"), - }, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - }, - "updating a gateway deployment respects the number of replicas a user has set": { - 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(5)), - MaxInstances: common.PointerTo(int32(7)), - MinInstances: common.PointerTo(int32(1)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - ServiceType: (*corev1.ServiceType)(common.PointerTo("NodePort")), - }, - }, - helmConfig: common.HelmConfig{}, - initialResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 5, nil, nil, "", "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 5, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "update a gateway deployment by scaling it when no min or max number of instances is defined on the GatewayClassConfig": { - 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: nil, - MinInstances: nil, - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - ServiceType: (*corev1.ServiceType)(common.PointerTo("NodePort")), - }, - }, - helmConfig: common.HelmConfig{}, - initialResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 8, nil, nil, "", "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 8, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "update a gateway deployment by scaling it lower than the min number of instances on the GatewayClassConfig": { - 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(5)), - MinInstances: common.PointerTo(int32(2)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - ServiceType: (*corev1.ServiceType)(common.PointerTo("NodePort")), - }, - }, - helmConfig: common.HelmConfig{}, - initialResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 1, nil, nil, "", "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 2, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "update a gateway deployment by scaling it higher than the max number of instances on the GatewayClassConfig": { - 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(5)), - MinInstances: common.PointerTo(int32(2)), - }, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{}, - ServiceType: (*corev1.ServiceType)(common.PointerTo("NodePort")), - }, - }, - helmConfig: common.HelmConfig{}, - initialResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 10, nil, nil, "", "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 5, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "create a new gateway with openshift enabled": { - 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{}, - OpenshiftSCCName: "test-api-gateway", - }, - }, - helmConfig: common.HelmConfig{ - EnableOpenShift: true, - }, - initialResources: resources{}, - finalResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{ - configureRole(name, namespace, labels, "1", true), - }, - roleBindings: []*rbac.RoleBinding{ - configureRoleBinding(name, namespace, labels, "1"), - }, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - s := runtime.NewScheme() - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - require.NoError(t, rbac.AddToScheme(s)) - require.NoError(t, corev1.AddToScheme(s)) - require.NoError(t, appsv1.AddToScheme(s)) - - log := logrtest.New(t) - - objs := append(joinResources(tc.initialResources), &tc.gateway, &tc.gatewayClassConfig) - client := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).Build() - - gatekeeper := New(log, client) - - err := gatekeeper.Upsert(context.Background(), tc.gateway, tc.gatewayClassConfig, tc.helmConfig) - require.NoError(t, err) - require.NoError(t, validateResourcesExist(t, client, tc.finalResources)) - }) - } -} - -func TestDelete(t *testing.T) { - t.Parallel() - - cases := map[string]testCase{ - "delete a gateway deployment with only Deployment": { - 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{}, - initialResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{}, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "delete a gateway deployment with a managed Service": { - 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{}, - initialResources: resources{ - deployments: []*appsv1.Deployment{ - configureDeployment(name, namespace, labels, 3, nil, nil, "", "1"), - }, - roles: []*rbac.Role{}, - 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"), - }, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{}, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - "delete a gateway deployment with managed Service and ACLs": { - 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", - }, - 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"), - }, - 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"), - }, - serviceAccounts: []*corev1.ServiceAccount{ - configureServiceAccount(name, namespace, labels, "1"), - }, - }, - finalResources: resources{ - deployments: []*appsv1.Deployment{}, - roles: []*rbac.Role{}, - services: []*corev1.Service{}, - serviceAccounts: []*corev1.ServiceAccount{}, - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - s := runtime.NewScheme() - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - require.NoError(t, rbac.AddToScheme(s)) - require.NoError(t, corev1.AddToScheme(s)) - require.NoError(t, appsv1.AddToScheme(s)) - - log := logrtest.New(t) - - objs := append(joinResources(tc.initialResources), &tc.gateway, &tc.gatewayClassConfig) - client := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).Build() - - gatekeeper := New(log, client) - - 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.finalResources)) - require.NoError(t, validateResourcesAreDeleted(t, client, tc.initialResources)) - }) - } -} - -func joinResources(resources resources) (objs []client.Object) { - for _, deployment := range resources.deployments { - objs = append(objs, deployment) - } - - for _, role := range resources.roles { - objs = append(objs, role) - } - - for _, roleBinding := range resources.roleBindings { - objs = append(objs, roleBinding) - } - - for _, service := range resources.services { - objs = append(objs, service) - } - - for _, serviceAccount := range resources.serviceAccounts { - objs = append(objs, serviceAccount) - } - - return objs -} - -func validateResourcesExist(t *testing.T, client client.Client, resources resources) error { - t.Helper() - - for _, expected := range resources.deployments { - actual := &appsv1.Deployment{} - 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 - actual.Spec.Selector.MatchLabels[createdAtLabelKey] = createdAtLabelValue - actual.Spec.Template.ObjectMeta.Labels[createdAtLabelKey] = createdAtLabelValue - - require.Equal(t, expected.Name, actual.Name) - require.Equal(t, expected.Namespace, actual.Namespace) - require.Equal(t, expected.APIVersion, actual.APIVersion) - require.Equal(t, expected.Labels, actual.Labels) - if expected.Spec.Replicas != nil { - require.NotNil(t, actual.Spec.Replicas) - require.EqualValues(t, *expected.Spec.Replicas, *actual.Spec.Replicas) - } - } - - for _, expected := range resources.roles { - actual := &rbac.Role{} - 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.roleBindings { - actual := &rbac.RoleBinding{} - 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.services { - actual := &corev1.Service{} - 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 - actual.Spec.Selector[createdAtLabelKey] = createdAtLabelValue - - require.Equal(t, expected, actual) - } - - for _, expected := range resources.serviceAccounts { - actual := &corev1.ServiceAccount{} - 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) - } - - return nil -} - -func validateResourcesAreDeleted(t *testing.T, k8sClient client.Client, resources resources) error { - t.Helper() - - for _, expected := range resources.deployments { - actual := &appsv1.Deployment{} - err := k8sClient.Get(context.Background(), types.NamespacedName{ - Name: expected.Name, - Namespace: expected.Namespace, - }, actual) - if !k8serrors.IsNotFound(err) { - return fmt.Errorf("expected deployment %s to be deleted", expected.Name) - } - require.Error(t, err) - } - - for _, expected := range resources.roles { - actual := &rbac.Role{} - err := k8sClient.Get(context.Background(), types.NamespacedName{ - Name: expected.Name, - Namespace: expected.Namespace, - }, actual) - if !k8serrors.IsNotFound(err) { - return fmt.Errorf("expected role %s to be deleted", expected.Name) - } - require.Error(t, err) - } - - for _, expected := range resources.roleBindings { - actual := &rbac.RoleBinding{} - err := k8sClient.Get(context.Background(), types.NamespacedName{ - Name: expected.Name, - Namespace: expected.Namespace, - }, actual) - if !k8serrors.IsNotFound(err) { - return fmt.Errorf("expected rolebinding %s to be deleted", expected.Name) - } - require.Error(t, err) - } - - for _, expected := range resources.services { - actual := &corev1.Service{} - err := k8sClient.Get(context.Background(), types.NamespacedName{ - Name: expected.Name, - Namespace: expected.Namespace, - }, actual) - if !k8serrors.IsNotFound(err) { - return fmt.Errorf("expected service %s to be deleted", expected.Name) - } - require.Error(t, err) - } - - for _, expected := range resources.serviceAccounts { - actual := &corev1.ServiceAccount{} - err := k8sClient.Get(context.Background(), types.NamespacedName{ - Name: expected.Name, - Namespace: expected.Namespace, - }, actual) - if !k8serrors.IsNotFound(err) { - return fmt.Errorf("expected service account %s to be deleted", expected.Name) - } - require.Error(t, err) - } - - return nil -} - -func configureDeployment(name, namespace string, labels map[string]string, replicas int32, nodeSelector map[string]string, tolerations []corev1.Toleration, serviceAccoutName, resourceVersion string) *appsv1.Deployment { - return &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - 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), - }, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: labels, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - Annotations: map[string]string{ - "consul.hashicorp.com/connect-inject": "false", - }, - }, - Spec: corev1.PodSpec{ - Affinity: &corev1.Affinity{ - PodAntiAffinity: &corev1.PodAntiAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ - { - Weight: 1, - PodAffinityTerm: corev1.PodAffinityTerm{ - LabelSelector: &metav1.LabelSelector{ - MatchLabels: labels, - }, - TopologyKey: "kubernetes.io/hostname", - }, - }, - }, - }, - }, - NodeSelector: nodeSelector, - Tolerations: tolerations, - ServiceAccountName: serviceAccoutName, - }, - }, - }, - } -} - -func configureRole(name, namespace string, labels map[string]string, resourceVersion string, openshiftEnabled bool) *rbac.Role { - rules := []rbac.PolicyRule{} - - if openshiftEnabled { - rules = []rbac.PolicyRule{ - { - APIGroups: []string{"security.openshift.io"}, - Resources: []string{"securitycontextconstraints"}, - ResourceNames: []string{name + "-api-gateway"}, - Verbs: []string{"use"}, - }, - } - } - return &rbac.Role{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "Role", - }, - 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), - }, - }, - }, - Rules: rules, - } -} - -func configureRoleBinding(name, namespace string, labels map[string]string, resourceVersion string) *rbac.RoleBinding { - return &rbac.RoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "RoleBinding", - }, - 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), - }, - }, - }, - RoleRef: rbac.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "Role", - Name: name, - }, - Subjects: []rbac.Subject{ - { - Kind: "ServiceAccount", - Name: name, - Namespace: namespace, - }, - }, - } -} - -func configureService(name, namespace string, labels, annotations map[string]string, serviceType corev1.ServiceType, ports []corev1.ServicePort, resourceVersion string) *corev1.Service { - return &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - Labels: labels, - Annotations: annotations, - ResourceVersion: resourceVersion, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "gateway.networking.k8s.io/v1beta1", - Kind: "Gateway", - Name: name, - Controller: common.PointerTo(true), - BlockOwnerDeletion: common.PointerTo(true), - }, - }, - }, - Spec: corev1.ServiceSpec{ - Selector: labels, - Type: serviceType, - Ports: ports, - }, - } -} - -func configureServiceAccount(name, namespace string, labels map[string]string, resourceVersion string) *corev1.ServiceAccount { - return &corev1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - 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), - }, - }, - }, - } -} diff --git a/control-plane/api-gateway/gatekeeper/init.go b/control-plane/api-gateway/gatekeeper/init.go deleted file mode 100644 index f3d4ad1f95..0000000000 --- a/control-plane/api-gateway/gatekeeper/init.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "bytes" - "strconv" - "strings" - "text/template" - - corev1 "k8s.io/api/core/v1" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" - "k8s.io/utils/pointer" -) - -const ( - injectInitContainerName = "consul-connect-inject-init" - initContainersUserAndGroupID = 5996 -) - -type initContainerCommandData struct { - ServiceName string - ServiceAccountName string - AuthMethod string - - // Log settings for the connect-init command. - LogLevel string - LogJSON bool -} - -// containerInit 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 initContainer(config common.HelmConfig, name, namespace string) (corev1.Container, error) { - data := initContainerCommandData{ - AuthMethod: config.AuthMethod, - LogLevel: config.LogLevel, - LogJSON: config.LogJSON, - ServiceName: name, - ServiceAccountName: name, - } - - // Create expected volume mounts - volMounts := []corev1.VolumeMount{ - { - Name: volumeName, - MountPath: "/consul/connect-inject", - }, - } - - var bearerTokenFile string - if config.AuthMethod != "" { - bearerTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" - } - - // Render the command - var buf bytes.Buffer - tpl := template.Must(template.New("root").Parse(strings.TrimSpace(initContainerCommandTpl))) - - if err := tpl.Execute(&buf, &data); err != nil { - return corev1.Container{}, err - } - - consulNamespace := namespaces.ConsulNamespace(namespace, config.EnableNamespaces, config.ConsulDestinationNamespace, config.EnableNamespaceMirroring, config.NamespaceMirroringPrefix) - - initContainerName := injectInitContainerName - container := corev1.Container{ - Name: initContainerName, - Image: config.ImageConsulK8S, - - Env: []corev1.EnvVar{ - { - Name: "POD_NAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.name"}, - }, - }, - { - Name: "POD_NAMESPACE", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.namespace"}, - }, - }, - { - Name: "NODE_NAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", - }, - }, - }, - { - Name: "CONSUL_ADDRESSES", - Value: config.ConsulConfig.Address, - }, - { - Name: "CONSUL_GRPC_PORT", - Value: strconv.Itoa(config.ConsulConfig.GRPCPort), - }, - { - Name: "CONSUL_HTTP_PORT", - Value: strconv.Itoa(config.ConsulConfig.HTTPPort), - }, - { - Name: "CONSUL_API_TIMEOUT", - Value: config.ConsulConfig.APITimeout.String(), - }, - { - Name: "CONSUL_NODE_NAME", - Value: "$(NODE_NAME)-virtual", - }, - }, - VolumeMounts: volMounts, - Command: []string{"/bin/sh", "-ec", buf.String()}, - } - - if config.TLSEnabled { - container.Env = append(container.Env, - corev1.EnvVar{ - Name: "CONSUL_USE_TLS", - Value: "true", - }, - corev1.EnvVar{ - Name: "CONSUL_CACERT_PEM", - Value: config.ConsulCACert, - }, - corev1.EnvVar{ - Name: "CONSUL_TLS_SERVER_NAME", - Value: config.ConsulTLSServerName, - }) - } - - if config.AuthMethod != "" { - container.Env = append(container.Env, - corev1.EnvVar{ - Name: "CONSUL_LOGIN_AUTH_METHOD", - Value: config.AuthMethod, - }, - corev1.EnvVar{ - Name: "CONSUL_LOGIN_BEARER_TOKEN_FILE", - Value: bearerTokenFile, - }, - corev1.EnvVar{ - Name: "CONSUL_LOGIN_META", - Value: "pod=$(POD_NAMESPACE)/$(POD_NAME)", - }) - - if config.ConsulPartition != "" { - container.Env = append(container.Env, corev1.EnvVar{ - Name: "CONSUL_LOGIN_PARTITION", - Value: config.ConsulPartition, - }) - } - } - container.Env = append(container.Env, - corev1.EnvVar{ - Name: "CONSUL_NAMESPACE", - Value: consulNamespace, - }) - - if config.ConsulPartition != "" { - container.Env = append(container.Env, - corev1.EnvVar{ - Name: "CONSUL_PARTITION", - Value: config.ConsulPartition, - }) - } - - // Openshift Assigns the security context for us, do not enable if it is enabled. - if !config.EnableOpenShift { - container.SecurityContext = &corev1.SecurityContext{ - RunAsUser: pointer.Int64(initContainersUserAndGroupID), - RunAsGroup: pointer.Int64(initContainersUserAndGroupID), - RunAsNonRoot: pointer.Bool(true), - Privileged: pointer.Bool(false), - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{"ALL"}, - }, - } - } - - return container, nil -} - -// initContainerCommandTpl is the template for the command executed by -// the init container. -const initContainerCommandTpl = ` -consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ - -gateway-kind="api-gateway" \ - -log-json={{ .LogJSON }} \ - {{- if .AuthMethod }} - -service-account-name="{{ .ServiceAccountName }}" \ - {{- end }} - -service-name="{{ .ServiceName }}" -` diff --git a/control-plane/api-gateway/gatekeeper/role.go b/control-plane/api-gateway/gatekeeper/role.go deleted file mode 100644 index 705e9bffff..0000000000 --- a/control-plane/api-gateway/gatekeeper/role.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "context" - "errors" - - "k8s.io/apimachinery/pkg/types" - 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" - rbac "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrl "sigs.k8s.io/controller-runtime" -) - -func (g *Gatekeeper) upsertRole(ctx context.Context, gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) error { - if config.AuthMethod == "" && !config.EnableOpenShift { - return g.deleteRole(ctx, types.NamespacedName{Namespace: gateway.Namespace, Name: gateway.Name}) - } - - role := &rbac.Role{} - - // If the Role already exists, ensure that we own the Role - err := g.Client.Get(ctx, g.namespacedName(gateway), role) - if err != nil && !k8serrors.IsNotFound(err) { - return err - } else if !k8serrors.IsNotFound(err) { - // Ensure we own the Role. - for _, ref := range role.GetOwnerReferences() { - if ref.UID == gateway.GetUID() && ref.Name == gateway.GetName() { - // We found ourselves! - return nil - } - } - return errors.New("role not owned by controller") - } - - role = g.role(gateway, gcc, config) - if err := ctrl.SetControllerReference(&gateway, role, g.Client.Scheme()); err != nil { - return err - } - if err := g.Client.Create(ctx, role); err != nil { - return err - } - - return nil -} - -func (g *Gatekeeper) deleteRole(ctx context.Context, gwName types.NamespacedName) error { - if err := g.Client.Delete(ctx, &rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: gwName.Name, Namespace: gwName.Namespace}}); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - return nil -} - -func (g *Gatekeeper) role(gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) *rbac.Role { - role := &rbac.Role{ - ObjectMeta: metav1.ObjectMeta{ - Name: gateway.Name, - Namespace: gateway.Namespace, - Labels: common.LabelsForGateway(&gateway), - }, - Rules: []rbac.PolicyRule{}, - } - - if gcc.Spec.PodSecurityPolicy != "" { - role.Rules = append(role.Rules, rbac.PolicyRule{ - APIGroups: []string{"policy"}, - Resources: []string{"podsecuritypolicies"}, - ResourceNames: []string{gcc.Spec.PodSecurityPolicy}, - Verbs: []string{"use"}, - }) - } - - if config.EnableOpenShift { - role.Rules = append(role.Rules, rbac.PolicyRule{ - APIGroups: []string{"security.openshift.io"}, - Resources: []string{"securitycontextconstraints"}, - ResourceNames: []string{gcc.Spec.OpenshiftSCCName}, - Verbs: []string{"use"}, - }) - } - - return role -} diff --git a/control-plane/api-gateway/gatekeeper/rolebinding.go b/control-plane/api-gateway/gatekeeper/rolebinding.go deleted file mode 100644 index 1a60e752c8..0000000000 --- a/control-plane/api-gateway/gatekeeper/rolebinding.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "context" - "errors" - - "k8s.io/apimachinery/pkg/types" - 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" - rbac "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrl "sigs.k8s.io/controller-runtime" -) - -func (g *Gatekeeper) upsertRoleBinding(ctx context.Context, gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) error { - if config.AuthMethod == "" && !config.EnableOpenShift { - return g.deleteRole(ctx, types.NamespacedName{Namespace: gateway.Namespace, Name: gateway.Name}) - } - - roleBinding := &rbac.RoleBinding{} - - // If the RoleBinding already exists, ensure that we own the RoleBinding - err := g.Client.Get(ctx, g.namespacedName(gateway), roleBinding) - if err != nil && !k8serrors.IsNotFound(err) { - return err - } else if !k8serrors.IsNotFound(err) { - // Ensure we own the Role. - for _, ref := range roleBinding.GetOwnerReferences() { - if ref.UID == gateway.GetUID() && ref.Name == gateway.GetName() { - // We found ourselves! - return nil - } - } - return errors.New("role not owned by controller") - } - - // Create or update the RoleBinding - roleBinding = g.roleBinding(gateway, gcc, config) - if err := ctrl.SetControllerReference(&gateway, roleBinding, g.Client.Scheme()); err != nil { - return err - } - if err := g.Client.Create(ctx, roleBinding); err != nil { - return err - } - - return nil -} - -func (g *Gatekeeper) deleteRoleBinding(ctx context.Context, gwName types.NamespacedName) error { - if err := g.Client.Delete(ctx, &rbac.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: gwName.Name, Namespace: gwName.Namespace}}); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - return nil -} - -func (g *Gatekeeper) roleBinding(gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) *rbac.RoleBinding { - // Create resources for reference. This avoids bugs if naming patterns change. - serviceAccount := g.serviceAccount(gateway) - role := g.role(gateway, gcc, config) - - return &rbac.RoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: gateway.Name, - Namespace: gateway.Namespace, - Labels: common.LabelsForGateway(&gateway), - }, - RoleRef: rbac.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "Role", - Name: role.Name, - }, - Subjects: []rbac.Subject{ - { - Kind: "ServiceAccount", - Name: serviceAccount.Name, - Namespace: serviceAccount.Namespace, - }, - }, - } -} diff --git a/control-plane/api-gateway/gatekeeper/service.go b/control-plane/api-gateway/gatekeeper/service.go deleted file mode 100644 index a30a3df89f..0000000000 --- a/control-plane/api-gateway/gatekeeper/service.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "context" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "k8s.io/apimachinery/pkg/types" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -var ( - defaultServiceAnnotations = []string{ - "external-dns.alpha.kubernetes.io/hostname", - } -) - -func (g *Gatekeeper) upsertService(ctx context.Context, gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig, config common.HelmConfig) error { - if gcc.Spec.ServiceType == nil { - return g.deleteService(ctx, types.NamespacedName{Namespace: gateway.Namespace, Name: gateway.Name}) - } - - service := g.service(gateway, gcc) - - mutated := service.DeepCopy() - mutator := newServiceMutator(service, mutated, gateway, g.Client.Scheme()) - - result, err := controllerutil.CreateOrUpdate(ctx, g.Client, mutated, mutator) - if err != nil { - return err - } - - switch result { - case controllerutil.OperationResultCreated: - g.Log.V(1).Info("Created Service") - case controllerutil.OperationResultUpdated: - g.Log.V(1).Info("Updated Service") - case controllerutil.OperationResultNone: - g.Log.V(1).Info("No change to service") - } - - return nil -} - -func (g *Gatekeeper) deleteService(ctx context.Context, gwName types.NamespacedName) error { - if err := g.Client.Delete(ctx, &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: gwName.Name, Namespace: gwName.Namespace}}); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - return nil -} - -func (g *Gatekeeper) service(gateway gwv1beta1.Gateway, gcc v1alpha1.GatewayClassConfig) *corev1.Service { - seenPorts := map[gwv1beta1.PortNumber]struct{}{} - ports := []corev1.ServicePort{} - for _, listener := range gateway.Spec.Listeners { - if _, seen := seenPorts[listener.Port]; seen { - // We've already added this listener's port to the Service - continue - } - - ports = append(ports, corev1.ServicePort{ - Name: string(listener.Name), - // only TCP-based services are supported for now - Protocol: corev1.ProtocolTCP, - Port: int32(listener.Port), - TargetPort: intstr.FromInt(common.ToContainerPort(listener.Port, gcc.Spec.MapPrivilegedContainerPorts)), - }) - - seenPorts[listener.Port] = struct{}{} - } - - // Copy annotations from the Gateway, filtered by those allowed by the GatewayClassConfig. - allowedAnnotations := gcc.Spec.CopyAnnotations.Service - if allowedAnnotations == nil { - allowedAnnotations = defaultServiceAnnotations - } - annotations := make(map[string]string) - for _, allowedAnnotation := range allowedAnnotations { - if value, found := gateway.Annotations[allowedAnnotation]; found { - annotations[allowedAnnotation] = value - } - } - - return &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: gateway.Name, - Namespace: gateway.Namespace, - Labels: common.LabelsForGateway(&gateway), - Annotations: annotations, - }, - Spec: corev1.ServiceSpec{ - Selector: common.LabelsForGateway(&gateway), - Type: *gcc.Spec.ServiceType, - Ports: ports, - }, - } -} - -// mergeService is used to keep annotations and ports from the `from` Service -// to the `to` service. This prevents an infinite reconciliation loop when -// Kubernetes adds this configuration back in. -func mergeService(from, to *corev1.Service) *corev1.Service { - if areServicesEqual(from, to) { - return to - } - - to.Annotations = from.Annotations - to.Spec.Ports = from.Spec.Ports - - return to -} - -func areServicesEqual(a, b *corev1.Service) bool { - if !equality.Semantic.DeepEqual(a.Annotations, b.Annotations) { - return false - } - if len(b.Spec.Ports) != len(a.Spec.Ports) { - return false - } - - for i, port := range a.Spec.Ports { - otherPort := b.Spec.Ports[i] - if port.Port != otherPort.Port { - return false - } - if port.Protocol != otherPort.Protocol { - return false - } - } - return true -} - -func newServiceMutator(service, mutated *corev1.Service, gateway gwv1beta1.Gateway, scheme *runtime.Scheme) resourceMutator { - return func() error { - mutated = mergeService(service, mutated) - return ctrl.SetControllerReference(&gateway, mutated, scheme) - } -} diff --git a/control-plane/api-gateway/gatekeeper/serviceaccount.go b/control-plane/api-gateway/gatekeeper/serviceaccount.go deleted file mode 100644 index d1c5c9883a..0000000000 --- a/control-plane/api-gateway/gatekeeper/serviceaccount.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatekeeper - -import ( - "context" - "errors" - - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "k8s.io/apimachinery/pkg/types" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrl "sigs.k8s.io/controller-runtime" -) - -func (g *Gatekeeper) upsertServiceAccount(ctx context.Context, gateway gwv1beta1.Gateway, config common.HelmConfig) error { - if config.AuthMethod == "" && !config.EnableOpenShift { - return g.deleteServiceAccount(ctx, types.NamespacedName{Namespace: gateway.Namespace, Name: gateway.Name}) - } - - serviceAccount := &corev1.ServiceAccount{} - exists := false - - // Get ServiceAccount if it exists. - err := g.Client.Get(ctx, g.namespacedName(gateway), serviceAccount) - if err != nil && !k8serrors.IsNotFound(err) { - return err - } else if k8serrors.IsNotFound(err) { - exists = false - } else { - exists = true - } - - if exists { - // Ensure we own the ServiceAccount. - for _, ref := range serviceAccount.GetOwnerReferences() { - if ref.UID == gateway.GetUID() && ref.Name == gateway.GetName() { - // We found ourselves! - return nil - } - } - return errors.New("ServiceAccount not owned by controller") - } - - // Create the ServiceAccount. - serviceAccount = g.serviceAccount(gateway) - if err := ctrl.SetControllerReference(&gateway, serviceAccount, g.Client.Scheme()); err != nil { - return err - } - if err := g.Client.Create(ctx, serviceAccount); err != nil { - return err - } - - return nil -} - -func (g *Gatekeeper) deleteServiceAccount(ctx context.Context, gwName types.NamespacedName) error { - if err := g.Client.Delete(ctx, &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: gwName.Name, Namespace: gwName.Namespace}}); err != nil { - if k8serrors.IsNotFound(err) { - return nil - } - return err - } - - return nil -} - -func (g *Gatekeeper) serviceAccount(gateway gwv1beta1.Gateway) *corev1.ServiceAccount { - return &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: gateway.Name, - Namespace: gateway.Namespace, - Labels: common.LabelsForGateway(&gateway), - }, - } -} diff --git a/control-plane/api/common/common.go b/control-plane/api/common/common.go index a4063d6147..7c761b6477 100644 --- a/control-plane/api/common/common.go +++ b/control-plane/api/common/common.go @@ -1,22 +1,16 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package common holds code that isn't tied to a particular CRD version or type. package common const ( - ServiceDefaults string = "servicedefaults" - ProxyDefaults string = "proxydefaults" - ServiceResolver string = "serviceresolver" - ServiceRouter string = "servicerouter" - ServiceSplitter string = "servicesplitter" - ServiceIntentions string = "serviceintentions" - ExportedServices string = "exportedservices" - IngressGateway string = "ingressgateway" - TerminatingGateway string = "terminatinggateway" - SamenessGroup string = "samenessgroup" - JWTProvider string = "jwtprovider" - ControlPlaneRequestLimit string = "controlplanerequestlimit" + ServiceDefaults string = "servicedefaults" + ProxyDefaults string = "proxydefaults" + ServiceResolver string = "serviceresolver" + ServiceRouter string = "servicerouter" + ServiceSplitter string = "servicesplitter" + ServiceIntentions string = "serviceintentions" + ExportedServices string = "exportedservices" + IngressGateway string = "ingressgateway" + TerminatingGateway string = "terminatinggateway" Global string = "global" Mesh string = "mesh" diff --git a/control-plane/api/common/configentry.go b/control-plane/api/common/configentry.go index 3559d8a6bc..2d83ce05b0 100644 --- a/control-plane/api/common/configentry.go +++ b/control-plane/api/common/configentry.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/control-plane/api/common/configentry_webhook.go b/control-plane/api/common/configentry_webhook.go index 4b8a482d6c..4028a5e3cb 100644 --- a/control-plane/api/common/configentry_webhook.go +++ b/control-plane/api/common/configentry_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/control-plane/api/common/configentry_webhook_test.go b/control-plane/api/common/configentry_webhook_test.go index 2760ff15ff..3a2dc9098b 100644 --- a/control-plane/api/common/configentry_webhook_test.go +++ b/control-plane/api/common/configentry_webhook_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/control-plane/api/v1alpha1/api_gateway_types.go b/control-plane/api/v1alpha1/api_gateway_types.go deleted file mode 100644 index 90f6376d98..0000000000 --- a/control-plane/api/v1alpha1/api_gateway_types.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - GatewayClassConfigKind = "GatewayClassConfig" - MeshServiceKind = "MeshService" -) - -func init() { - SchemeBuilder.Register(&GatewayClassConfig{}, &GatewayClassConfigList{}) - SchemeBuilder.Register(&MeshService{}, &MeshServiceList{}) -} - -// +genclient -// +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster - -// GatewayClassConfig defines the values that may be set on a GatewayClass for Consul API Gateway. -type GatewayClassConfig struct { - // Standard Kubernetes resource metadata. - metav1.TypeMeta `json:",inline"` - - // Standard object's metadata. - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Spec defines the desired state of GatewayClassConfig. - Spec GatewayClassConfigSpec `json:"spec,omitempty"` -} - -// +k8s:deepcopy-gen=true - -// GatewayClassConfigSpec specifies the desired state of the Config CRD. -type GatewayClassConfigSpec struct { - - // +kubebuilder:validation:Enum=ClusterIP;NodePort;LoadBalancer - ServiceType *corev1.ServiceType `json:"serviceType,omitempty"` - - // NodeSelector is a selector which must be true for the pod to fit on a node. - // Selector which must match a node's labels for the pod to be scheduled on that node. - // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - NodeSelector map[string]string `json:"nodeSelector,omitempty"` - - // Tolerations allow the scheduler to schedule nodes with matching taints. - // More Info: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ - Tolerations []corev1.Toleration `json:"tolerations,omitempty"` - - // Deployment defines the deployment configuration for the gateway. - DeploymentSpec DeploymentSpec `json:"deployment,omitempty"` - - // Annotation Information to copy to services or deployments - CopyAnnotations CopyAnnotationsSpec `json:"copyAnnotations,omitempty"` - - // The name of an existing Kubernetes PodSecurityPolicy to bind to the managed ServiceAccount if ACLs are managed. - PodSecurityPolicy string `json:"podSecurityPolicy,omitempty"` - - // The name of the OpenShift SecurityContextConstraints resource for this gateway class to use. - OpenshiftSCCName string `json:"openshiftSCCName,omitempty"` - - // The value to add to privileged ports ( ports < 1024) for gateway containers - MapPrivilegedContainerPorts int32 `json:"mapPrivilegedContainerPorts,omitempty"` -} - -// +k8s:deepcopy-gen=true - -type DeploymentSpec struct { - // +kubebuilder:default:=1 - // +kubebuilder:validation:Maximum=8 - // +kubebuilder:validation:Minimum=1 - // Number of gateway instances that should be deployed by default - DefaultInstances *int32 `json:"defaultInstances,omitempty"` - // +kubebuilder:default:=8 - // +kubebuilder:validation:Maximum=8 - // +kubebuilder:validation:Minimum=1 - // Max allowed number of gateway instances - MaxInstances *int32 `json:"maxInstances,omitempty"` - // +kubebuilder:default:=1 - // +kubebuilder:validation:Maximum=8 - // +kubebuilder:validation:Minimum=1 - // Minimum allowed number of gateway instances - MinInstances *int32 `json:"minInstances,omitempty"` - - // Resources defines the resource requirements for the gateway. - Resources *corev1.ResourceRequirements `json:"resources,omitempty"` -} - -//+kubebuilder:object:generate=true - -// CopyAnnotationsSpec defines the annotations that should be copied to the gateway service. -type CopyAnnotationsSpec struct { - // List of annotations to copy to the gateway service. - Service []string `json:"service,omitempty"` -} - -// +kubebuilder:object:root=true - -// GatewayClassConfigList is a list of Config resources. -type GatewayClassConfigList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata"` - - // Items is the list of Configs. - Items []GatewayClassConfig `json:"items"` -} - -// +genclient -// +kubebuilder:object:root=true - -// MeshService holds a reference to an externally managed Consul Service Mesh service. -type MeshService struct { - metav1.TypeMeta `json:",inline"` - // Standard object's metadata. - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Spec defines the desired state of MeshService. - Spec MeshServiceSpec `json:"spec,omitempty"` -} - -// +k8s:deepcopy-gen=true - -// MeshServiceSpec specifies the 'spec' of the MeshService CRD. -type MeshServiceSpec struct { - // Name holds the service name for a Consul service. - Name string `json:"name,omitempty"` - // Peer optionally specifies the name of the peer exporting the Consul service. - // If not specified, the Consul service is assumed to be in the local datacenter. - Peer *string `json:"peer,omitempty"` -} - -// +kubebuilder:object:root=true - -// MeshServiceList is a list of MeshService resources. -type MeshServiceList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata"` - - Items []MeshService `json:"items"` -} diff --git a/control-plane/api/v1alpha1/api_gateway_types_test.go b/control-plane/api/v1alpha1/api_gateway_types_test.go deleted file mode 100644 index 6e0690b9b2..0000000000 --- a/control-plane/api/v1alpha1/api_gateway_types_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "testing" - - "github.com/stretchr/testify/require" - core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestGatewayClassConfigDeepCopy(t *testing.T) { - var nilConfig *GatewayClassConfig - require.Nil(t, nilConfig.DeepCopy()) - require.Nil(t, nilConfig.DeepCopyObject()) - lbType := core.ServiceTypeLoadBalancer - spec := GatewayClassConfigSpec{ - ServiceType: &lbType, - NodeSelector: map[string]string{ - "test": "test", - }, - OpenshiftSCCName: "restricted-v2", - } - config := &GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Spec: spec, - } - copy := config.DeepCopy() - copyObject := config.DeepCopyObject() - require.Equal(t, copy, copyObject) - - var nilSpec *GatewayClassConfigSpec - require.Nil(t, nilSpec.DeepCopy()) - specCopy := (&spec).DeepCopy() - require.Equal(t, spec.NodeSelector, specCopy.NodeSelector) - - var nilConfigList *GatewayClassConfigList - require.Nil(t, nilConfigList.DeepCopyObject()) - configList := &GatewayClassConfigList{ - Items: []GatewayClassConfig{*config}, - } - copyConfigList := configList.DeepCopy() - copyConfigListObject := configList.DeepCopyObject() - require.Equal(t, copyConfigList, copyConfigListObject) -} diff --git a/control-plane/api/v1alpha1/controlplanerequestlimit_types.go b/control-plane/api/v1alpha1/controlplanerequestlimit_types.go deleted file mode 100644 index ac2c05ded0..0000000000 --- a/control-plane/api/v1alpha1/controlplanerequestlimit_types.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - consul "github.com/hashicorp/consul/api" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/validation/field" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" -) - -const ( - ControlPlaneRequestLimitKubeKind = "controlplanerequestlimit" -) - -func init() { - SchemeBuilder.Register(&ControlPlaneRequestLimit{}, &ControlPlaneRequestLimitList{}) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// ControlPlaneRequestLimit is the Schema for the controlplanerequestlimits API. -// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" -type ControlPlaneRequestLimit struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ControlPlaneRequestLimitSpec `json:"spec,omitempty"` - Status `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// ControlPlaneRequestLimitList contains a list of ControlPlaneRequestLimit. -type ControlPlaneRequestLimitList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []ControlPlaneRequestLimit `json:"items"` -} - -type ReadWriteRatesConfig struct { - ReadRate float64 `json:"readRate,omitempty"` - WriteRate float64 `json:"writeRate,omitempty"` -} - -func (c *ReadWriteRatesConfig) toConsul() *consul.ReadWriteRatesConfig { - if c == nil { - return nil - } - return &consul.ReadWriteRatesConfig{ - ReadRate: c.ReadRate, - WriteRate: c.WriteRate, - } -} - -func (c *ReadWriteRatesConfig) validate(path *field.Path) field.ErrorList { - if c == nil { - return nil - } - - var errs field.ErrorList - - if c.ReadRate < 0 { - errs = append(errs, field.Invalid(path.Child("readRate"), c.ReadRate, "readRate must be >= 0")) - } - - if c.WriteRate <= 0 { - errs = append(errs, field.Invalid(path.Child("writeRate"), c.WriteRate, "writeRate must be > 0")) - } - return errs -} - -// ControlPlaneRequestLimitSpec defines the desired state of ControlPlaneRequestLimit. -type ControlPlaneRequestLimitSpec struct { - Mode string `json:"mode,omitempty"` - ReadWriteRatesConfig `json:",inline"` - ACL *ReadWriteRatesConfig `json:"acl,omitempty"` - Catalog *ReadWriteRatesConfig `json:"catalog,omitempty"` - ConfigEntry *ReadWriteRatesConfig `json:"configEntry,omitempty"` - ConnectCA *ReadWriteRatesConfig `json:"connectCA,omitempty"` - Coordinate *ReadWriteRatesConfig `json:"coordinate,omitempty"` - DiscoveryChain *ReadWriteRatesConfig `json:"discoveryChain,omitempty"` - Health *ReadWriteRatesConfig `json:"health,omitempty"` - Intention *ReadWriteRatesConfig `json:"intention,omitempty"` - KV *ReadWriteRatesConfig `json:"kv,omitempty"` - Tenancy *ReadWriteRatesConfig `json:"tenancy,omitempty"` - PreparedQuery *ReadWriteRatesConfig `json:"perparedQuery,omitempty"` - Session *ReadWriteRatesConfig `json:"session,omitempty"` - Txn *ReadWriteRatesConfig `json:"txn,omitempty"` -} - -// GetObjectMeta returns object meta. -func (c *ControlPlaneRequestLimit) GetObjectMeta() metav1.ObjectMeta { - return c.ObjectMeta -} - -// AddFinalizer adds a finalizer to the list of finalizers. -func (c *ControlPlaneRequestLimit) AddFinalizer(name string) { - c.ObjectMeta.Finalizers = append(c.ObjectMeta.Finalizers, name) -} - -// RemoveFinalizer removes this finalizer from the list. -func (c *ControlPlaneRequestLimit) RemoveFinalizer(name string) { - for i, n := range c.ObjectMeta.Finalizers { - if n == name { - c.ObjectMeta.Finalizers = append(c.ObjectMeta.Finalizers[:i], c.ObjectMeta.Finalizers[i+1:]...) - return - } - } -} - -// Finalizers returns the list of finalizers for this object. -func (c *ControlPlaneRequestLimit) Finalizers() []string { - return c.ObjectMeta.Finalizers -} - -// ConsulKind returns the Consul config entry kind, i.e. service-defaults, not -// servicedefaults. -func (c *ControlPlaneRequestLimit) ConsulKind() string { - return consul.RateLimitIPConfig -} - -// ConsulGlobalResource returns if the resource exists in the default -// Consul namespace only. -func (c *ControlPlaneRequestLimit) ConsulGlobalResource() bool { - return true -} - -// ConsulMirroringNS returns the Consul namespace that the config entry should -// be created in if namespaces and mirroring are enabled. -func (c *ControlPlaneRequestLimit) ConsulMirroringNS() string { - return common.DefaultConsulNamespace -} - -// KubeKind returns the Kube config entry kind, i.e. servicedefaults, not -// service-defaults. -func (c *ControlPlaneRequestLimit) KubeKind() string { - return ControlPlaneRequestLimitKubeKind -} - -// ConsulName returns the name of the config entry as saved in Consul. -// This may be different than KubernetesName() in the case of a ServiceIntentions -// config entry. -func (c *ControlPlaneRequestLimit) ConsulName() string { - return c.ObjectMeta.Name -} - -// KubernetesName returns the name of the Kubernetes resource. -func (c *ControlPlaneRequestLimit) KubernetesName() string { - return c.ObjectMeta.Name -} - -// SetSyncedCondition updates the synced condition. -func (c *ControlPlaneRequestLimit) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { - c.Status.Conditions = Conditions{ - { - Type: ConditionSynced, - Status: status, - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: message, - }, - } -} - -// SetLastSyncedTime updates the last synced time. -func (c *ControlPlaneRequestLimit) SetLastSyncedTime(time *metav1.Time) { - c.Status.LastSyncedTime = time -} - -// SyncedCondition gets the synced condition. -func (c *ControlPlaneRequestLimit) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { - cond := c.Status.GetCondition(ConditionSynced) - if cond == nil { - return corev1.ConditionUnknown, "", "" - } - return cond.Status, cond.Reason, cond.Message -} - -// SyncedConditionStatus returns the status of the synced condition. -func (c *ControlPlaneRequestLimit) SyncedConditionStatus() corev1.ConditionStatus { - condition := c.Status.GetCondition(ConditionSynced) - if condition == nil { - return corev1.ConditionUnknown - } - return condition.Status -} - -// ToConsul converts the resource to the corresponding Consul API definition. -// Its return type is the generic ConfigEntry but a specific config entry -// type should be constructed e.g. ServiceConfigEntry. -func (c *ControlPlaneRequestLimit) ToConsul(datacenter string) consul.ConfigEntry { - return &consul.RateLimitIPConfigEntry{ - Kind: c.ConsulKind(), - Name: c.ConsulName(), - Mode: c.Spec.Mode, - ReadRate: c.Spec.ReadRate, - WriteRate: c.Spec.WriteRate, - Meta: meta(datacenter), - ACL: c.Spec.ACL.toConsul(), - Catalog: c.Spec.Catalog.toConsul(), - ConfigEntry: c.Spec.ConfigEntry.toConsul(), - ConnectCA: c.Spec.ConnectCA.toConsul(), - Coordinate: c.Spec.Coordinate.toConsul(), - DiscoveryChain: c.Spec.DiscoveryChain.toConsul(), - Health: c.Spec.Health.toConsul(), - Intention: c.Spec.Intention.toConsul(), - KV: c.Spec.KV.toConsul(), - Tenancy: c.Spec.Tenancy.toConsul(), - PreparedQuery: c.Spec.PreparedQuery.toConsul(), - Session: c.Spec.Session.toConsul(), - Txn: c.Spec.Txn.toConsul(), - } -} - -// MatchesConsul returns true if the resource has the same fields as the Consul -// config entry. -func (c *ControlPlaneRequestLimit) MatchesConsul(candidate consul.ConfigEntry) bool { - configEntry, ok := candidate.(*consul.RateLimitIPConfigEntry) - if !ok { - return false - } - // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(c.ToConsul(""), configEntry, cmpopts.IgnoreFields(consul.RateLimitIPConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) -} - -// Validate returns an error if the resource is invalid. -func (c *ControlPlaneRequestLimit) Validate(consulMeta common.ConsulMeta) error { - var errs field.ErrorList - path := field.NewPath("spec") - - if c.Spec.Mode != "permissive" && c.Spec.Mode != "enforcing" && c.Spec.Mode != "disabled" { - errs = append(errs, field.Invalid(path.Child("mode"), c.Spec.Mode, "mode must be one of: permissive, enforcing, disabled")) - } - - errs = append(errs, c.Spec.ReadWriteRatesConfig.validate(path)...) - errs = append(errs, c.Spec.ACL.validate(path.Child("acl"))...) - errs = append(errs, c.Spec.Catalog.validate(path.Child("catalog"))...) - errs = append(errs, c.Spec.ConfigEntry.validate(path.Child("configEntry"))...) - errs = append(errs, c.Spec.ConnectCA.validate(path.Child("connectCA"))...) - errs = append(errs, c.Spec.Coordinate.validate(path.Child("coordinate"))...) - errs = append(errs, c.Spec.DiscoveryChain.validate(path.Child("discoveryChain"))...) - errs = append(errs, c.Spec.Health.validate(path.Child("health"))...) - errs = append(errs, c.Spec.Intention.validate(path.Child("intention"))...) - errs = append(errs, c.Spec.KV.validate(path.Child("kv"))...) - errs = append(errs, c.Spec.Tenancy.validate(path.Child("tenancy"))...) - errs = append(errs, c.Spec.PreparedQuery.validate(path.Child("preparedQuery"))...) - errs = append(errs, c.Spec.Session.validate(path.Child("session"))...) - errs = append(errs, c.Spec.Txn.validate(path.Child("txn"))...) - - if len(errs) > 0 { - return apierrors.NewInvalid( - schema.GroupKind{Group: ConsulHashicorpGroup, Kind: ControlPlaneRequestLimitKubeKind}, - c.KubernetesName(), errs) - } - - return nil -} - -// DefaultNamespaceFields has no behaviour here as control-plane-request-limit have no namespace specific fields. -func (s *ControlPlaneRequestLimit) DefaultNamespaceFields(_ common.ConsulMeta) { -} diff --git a/control-plane/api/v1alpha1/controlplanerequestlimit_types_test.go b/control-plane/api/v1alpha1/controlplanerequestlimit_types_test.go deleted file mode 100644 index 12633250ab..0000000000 --- a/control-plane/api/v1alpha1/controlplanerequestlimit_types_test.go +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "testing" - "time" - - consul "github.com/hashicorp/consul/api" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" -) - -func TestControlPlaneRequestLimit_ToConsul(t *testing.T) { - cases := map[string]struct { - input *ControlPlaneRequestLimit - expected *consul.RateLimitIPConfigEntry - }{ - "empty fields": { - &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "disabled", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 0, - WriteRate: 0, - }, - }, - }, - &consul.RateLimitIPConfigEntry{ - Name: "foo", - Kind: consul.RateLimitIPConfig, - Mode: "disabled", - Meta: map[string]string{ - common.DatacenterKey: "datacenter", - common.SourceKey: common.SourceValue, - }, - ReadRate: 0, - WriteRate: 0, - }, - }, - "every field set": { - &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ACL: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Catalog: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConfigEntry: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConnectCA: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Coordinate: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - DiscoveryChain: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Health: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Intention: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - KV: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Tenancy: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - PreparedQuery: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Session: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Txn: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - }, - }, - &consul.RateLimitIPConfigEntry{ - Kind: consul.RateLimitIPConfig, - Name: "foo", - Mode: "permissive", - ReadRate: 100.0, - WriteRate: 100.0, - Meta: map[string]string{ - common.DatacenterKey: "datacenter", - common.SourceKey: common.SourceValue, - }, - ACL: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Catalog: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConfigEntry: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConnectCA: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Coordinate: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - DiscoveryChain: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Health: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Intention: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - KV: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Tenancy: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - PreparedQuery: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Session: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Txn: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - }, - }, - } - - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - output := testCase.input.ToConsul("datacenter") - require.Equal(t, testCase.expected, output) - }) - } -} - -func TestControlPlaneRequestLimit_MatchesConsul(t *testing.T) { - cases := map[string]struct { - internal *ControlPlaneRequestLimit - consul consul.ConfigEntry - matches bool - }{ - "empty fields matches": { - &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-test-service", - }, - Spec: ControlPlaneRequestLimitSpec{}, - }, - &consul.RateLimitIPConfigEntry{ - Kind: consul.RateLimitIPConfig, - Name: "my-test-service", - Namespace: "namespace", - CreateIndex: 1, - ModifyIndex: 2, - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - }, - true, - }, - "all fields populated matches": { - &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-test-service", - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ACL: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Catalog: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConfigEntry: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConnectCA: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Coordinate: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - DiscoveryChain: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Health: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Intention: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - KV: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Tenancy: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - PreparedQuery: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Session: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Txn: &ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - }, - }, - &consul.RateLimitIPConfigEntry{ - Kind: consul.RateLimitIPConfig, - Name: "my-test-service", - Mode: "permissive", - ReadRate: 100.0, - WriteRate: 100.0, - Meta: map[string]string{ - common.DatacenterKey: "datacenter", - common.SourceKey: common.SourceValue, - }, - ACL: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Catalog: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConfigEntry: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConnectCA: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Coordinate: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - DiscoveryChain: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Health: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Intention: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - KV: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Tenancy: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - PreparedQuery: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Session: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Txn: &consul.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - }, - true, - }, - "mismatched types does not match": { - &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-test-service", - }, - Spec: ControlPlaneRequestLimitSpec{}, - }, - &consul.ProxyConfigEntry{ - Kind: consul.RateLimitIPConfig, - Name: "my-test-service", - Namespace: "namespace", - CreateIndex: 1, - ModifyIndex: 2, - }, - false, - }, - } - - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - require.Equal(t, testCase.matches, testCase.internal.MatchesConsul(testCase.consul)) - }) - } -} - -func TestControlPlaneRequestLimit_Validate(t *testing.T) { - invalidReadWriteRatesConfig := &ReadWriteRatesConfig{ - ReadRate: -1, - WriteRate: 0, - } - - validReadWriteRatesConfig := &ReadWriteRatesConfig{ - ReadRate: 100, - WriteRate: 100, - } - - cases := map[string]struct { - input *ControlPlaneRequestLimit - expectedErrMsgs []string - }{ - "invalid": { - input: &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.ControlPlaneRequestLimit, - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "invalid", - ACL: invalidReadWriteRatesConfig, - Catalog: invalidReadWriteRatesConfig, - ConfigEntry: invalidReadWriteRatesConfig, - ConnectCA: invalidReadWriteRatesConfig, - Coordinate: invalidReadWriteRatesConfig, - DiscoveryChain: invalidReadWriteRatesConfig, - Health: invalidReadWriteRatesConfig, - Intention: invalidReadWriteRatesConfig, - KV: invalidReadWriteRatesConfig, - Tenancy: invalidReadWriteRatesConfig, - PreparedQuery: invalidReadWriteRatesConfig, - Session: invalidReadWriteRatesConfig, - Txn: invalidReadWriteRatesConfig, - }, - }, - expectedErrMsgs: []string{ - `spec.mode: Invalid value: "invalid": mode must be one of: permissive, enforcing, disabled`, - `spec.acl.readRate: Invalid value: -1: readRate must be >= 0, spec.acl.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.catalog.readRate: Invalid value: -1: readRate must be >= 0, spec.catalog.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.configEntry.readRate: Invalid value: -1: readRate must be >= 0, spec.configEntry.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.connectCA.readRate: Invalid value: -1: readRate must be >= 0, spec.connectCA.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.coordinate.readRate: Invalid value: -1: readRate must be >= 0, spec.coordinate.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.discoveryChain.readRate: Invalid value: -1: readRate must be >= 0, spec.discoveryChain.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.health.readRate: Invalid value: -1: readRate must be >= 0, spec.health.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.intention.readRate: Invalid value: -1: readRate must be >= 0, spec.intention.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.kv.readRate: Invalid value: -1: readRate must be >= 0, spec.kv.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.tenancy.readRate: Invalid value: -1: readRate must be >= 0, spec.tenancy.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.preparedQuery.readRate: Invalid value: -1: readRate must be >= 0, spec.preparedQuery.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.session.readRate: Invalid value: -1: readRate must be >= 0, spec.session.writeRate: Invalid value: 0: writeRate must be > 0`, - `spec.txn.readRate: Invalid value: -1: readRate must be >= 0, spec.txn.writeRate: Invalid value: 0: writeRate must be > 0`, - }, - }, - "valid": { - input: &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.ControlPlaneRequestLimit, - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: *validReadWriteRatesConfig, - ACL: validReadWriteRatesConfig, - Catalog: validReadWriteRatesConfig, - ConfigEntry: validReadWriteRatesConfig, - ConnectCA: validReadWriteRatesConfig, - Coordinate: validReadWriteRatesConfig, - DiscoveryChain: validReadWriteRatesConfig, - Health: validReadWriteRatesConfig, - Intention: validReadWriteRatesConfig, - KV: validReadWriteRatesConfig, - Tenancy: validReadWriteRatesConfig, - PreparedQuery: validReadWriteRatesConfig, - Session: validReadWriteRatesConfig, - Txn: validReadWriteRatesConfig, - }, - }, - expectedErrMsgs: []string{}, - }, - } - - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(common.ConsulMeta{}) - if len(testCase.expectedErrMsgs) != 0 { - require.Error(t, err) - for _, s := range testCase.expectedErrMsgs { - require.Contains(t, err.Error(), s) - } - } else { - require.NoError(t, err) - } - }) - } -} - -func TestControlPlaneRequestLimit_AddFinalizer(t *testing.T) { - controlPlaneRequestLimit := &ControlPlaneRequestLimit{} - controlPlaneRequestLimit.AddFinalizer("finalizer") - require.Equal(t, []string{"finalizer"}, controlPlaneRequestLimit.ObjectMeta.Finalizers) -} - -func TestControlPlaneRequestLimit_RemoveFinalizer(t *testing.T) { - controlPlaneRequestLimit := &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Finalizers: []string{"f1", "f2"}, - }, - } - controlPlaneRequestLimit.RemoveFinalizer("f1") - require.Equal(t, []string{"f2"}, controlPlaneRequestLimit.ObjectMeta.Finalizers) -} - -func TestControlPlaneRequestLimit_SetSyncedCondition(t *testing.T) { - controlPlaneRequestLimit := &ControlPlaneRequestLimit{} - controlPlaneRequestLimit.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") - - require.Equal(t, corev1.ConditionTrue, controlPlaneRequestLimit.Status.Conditions[0].Status) - require.Equal(t, "reason", controlPlaneRequestLimit.Status.Conditions[0].Reason) - require.Equal(t, "message", controlPlaneRequestLimit.Status.Conditions[0].Message) - now := metav1.Now() - require.True(t, controlPlaneRequestLimit.Status.Conditions[0].LastTransitionTime.Before(&now)) -} - -func TestControlPlaneRequestLimit_SetLastSyncedTime(t *testing.T) { - controlPlaneRequestLimit := &ControlPlaneRequestLimit{} - syncedTime := metav1.NewTime(time.Now()) - controlPlaneRequestLimit.SetLastSyncedTime(&syncedTime) - - require.Equal(t, &syncedTime, controlPlaneRequestLimit.Status.LastSyncedTime) -} - -func TestControlPlaneRequestLimit_GetSyncedConditionStatus(t *testing.T) { - cases := []corev1.ConditionStatus{ - corev1.ConditionUnknown, - corev1.ConditionFalse, - corev1.ConditionTrue, - } - for _, status := range cases { - t.Run(string(status), func(t *testing.T) { - controlPlaneRequestLimit := &ControlPlaneRequestLimit{ - Status: Status{ - Conditions: []Condition{{ - Type: ConditionSynced, - Status: status, - }}, - }, - } - - require.Equal(t, status, controlPlaneRequestLimit.SyncedConditionStatus()) - }) - } -} - -func TestControlPlaneRequestLimit_GetConditionWhenStatusNil(t *testing.T) { - require.Nil(t, (&ControlPlaneRequestLimit{}).GetCondition(ConditionSynced)) -} - -func TestControlPlaneRequestLimit_SyncedConditionStatusWhenStatusNil(t *testing.T) { - require.Equal(t, corev1.ConditionUnknown, (&ControlPlaneRequestLimit{}).SyncedConditionStatus()) -} - -func TestControlPlaneRequestLimit_SyncedConditionWhenStatusNil(t *testing.T) { - status, reason, message := (&ControlPlaneRequestLimit{}).SyncedCondition() - require.Equal(t, corev1.ConditionUnknown, status) - require.Equal(t, "", reason) - require.Equal(t, "", message) -} - -func TestControlPlaneRequestLimit_ConsulKind(t *testing.T) { - require.Equal(t, consul.RateLimitIPConfig, (&ControlPlaneRequestLimit{}).ConsulKind()) -} - -func TestControlPlaneRequestLimit_KubeKind(t *testing.T) { - require.Equal(t, "controlplanerequestlimit", (&ControlPlaneRequestLimit{}).KubeKind()) -} - -func TestControlPlaneRequestLimit_ConsulName(t *testing.T) { - require.Equal(t, "foo", (&ControlPlaneRequestLimit{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) -} - -func TestControlPlaneRequestLimit_KubernetesName(t *testing.T) { - require.Equal(t, "foo", (&ControlPlaneRequestLimit{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) -} - -func TestControlPlaneRequestLimit_ConsulNamespace(t *testing.T) { - require.Equal(t, "default", (&ControlPlaneRequestLimit{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}}).ConsulMirroringNS()) -} - -func TestControlPlaneRequestLimit_ConsulGlobalResource(t *testing.T) { - require.True(t, (&ControlPlaneRequestLimit{}).ConsulGlobalResource()) -} - -func TestControlPlaneRequestLimit_ObjectMeta(t *testing.T) { - meta := metav1.ObjectMeta{ - Name: "name", - Namespace: "namespace", - } - controlPlaneRequestLimit := &ControlPlaneRequestLimit{ - ObjectMeta: meta, - } - require.Equal(t, meta, controlPlaneRequestLimit.GetObjectMeta()) -} diff --git a/control-plane/api/v1alpha1/controlplanerequestlimit_webhook.go b/control-plane/api/v1alpha1/controlplanerequestlimit_webhook.go deleted file mode 100644 index d99d9143f7..0000000000 --- a/control-plane/api/v1alpha1/controlplanerequestlimit_webhook.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "context" - "fmt" - "net/http" - - "github.com/go-logr/logr" - admissionv1 "k8s.io/api/admission/v1" - "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 ControlPlaneRequestLimitWebhook struct { - client.Client - Logger logr.Logger - decoder *admission.Decoder - ConsulMeta common.ConsulMeta -} - -// NOTE: The path value in the below line is the path to the webhook. -// If it is updated, run code-gen, update subcommand/controller/command.go -// and the consul-helm value for the path to the webhook. -// -// NOTE: The below line cannot be combined with any other comment. If it is -// it will break the code generation. -// -// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-controlplanerequestlimits,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=controlplanerequestlimits,versions=v1alpha1,name=mutate-controlplanerequestlimits.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 - -func (v *ControlPlaneRequestLimitWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { - var limit ControlPlaneRequestLimit - var limitList ControlPlaneRequestLimitList - err := v.decoder.Decode(req, &limit) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - if req.Operation == admissionv1.Create { - v.Logger.Info("validate create", "name", limit.KubernetesName()) - - if limit.KubernetesName() != common.ControlPlaneRequestLimit { - return admission.Errored(http.StatusBadRequest, - fmt.Errorf(`%s resource name must be "%s"`, - limit.KubeKind(), common.ControlPlaneRequestLimit)) - } - - if err := v.Client.List(ctx, &limitList); err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - - if len(limitList.Items) > 0 { - return admission.Errored(http.StatusBadRequest, - fmt.Errorf("%s resource already defined - only one control plane request limit entry is supported", - limit.KubeKind())) - } - } - - return common.ValidateConfigEntry(ctx, req, v.Logger, v, &limit, v.ConsulMeta) -} - -func (v *ControlPlaneRequestLimitWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { - var limitList ControlPlaneRequestLimitList - if err := v.Client.List(ctx, &limitList); err != nil { - return nil, err - } - var entries []common.ConfigEntryResource - for _, item := range limitList.Items { - entries = append(entries, common.ConfigEntryResource(&item)) - } - return entries, nil -} - -func (v *ControlPlaneRequestLimitWebhook) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/control-plane/api/v1alpha1/controlplanerequestlimit_webhook_test.go b/control-plane/api/v1alpha1/controlplanerequestlimit_webhook_test.go deleted file mode 100644 index c1ab7cc6af..0000000000 --- a/control-plane/api/v1alpha1/controlplanerequestlimit_webhook_test.go +++ /dev/null @@ -1,145 +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" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" -) - -func TestValidateControlPlaneRequestLimit(t *testing.T) { - otherNS := "other" - - cases := map[string]struct { - existingResources []runtime.Object - newResource *ControlPlaneRequestLimit - expAllow bool - expErrMessage string - }{ - "no duplicates, valid": { - existingResources: nil, - newResource: &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.ControlPlaneRequestLimit, - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 100, - WriteRate: 100, - }, - }, - }, - expAllow: true, - }, - "invalid resource name": { - existingResources: nil, - newResource: &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "invalid", - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 100, - WriteRate: 100, - }, - }, - }, - expAllow: false, - expErrMessage: `controlplanerequestlimit resource name must be "controlplanerequestlimit"`, - }, - "resource already exists": { - existingResources: []runtime.Object{ - &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.ControlPlaneRequestLimit, - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 100, - WriteRate: 100, - }, - }, - }, - }, - newResource: &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.ControlPlaneRequestLimit, - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 100, - WriteRate: 100, - }, - }, - }, - expAllow: false, - expErrMessage: `controlplanerequestlimit resource already defined - only one control plane request limit entry is supported`, - }, - "invalid spec": { - existingResources: nil, - newResource: &ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.ControlPlaneRequestLimit, - }, - Spec: ControlPlaneRequestLimitSpec{ - Mode: "invalid", - ReadWriteRatesConfig: ReadWriteRatesConfig{ - ReadRate: 100, - WriteRate: 100, - }, - }, - }, - expAllow: false, - expErrMessage: `controlplanerequestlimit.consul.hashicorp.com "controlplanerequestlimit" is invalid: spec.mode: Invalid value: "invalid": mode must be one of: permissive, enforcing, disabled`, - }, - } - 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, &ControlPlaneRequestLimit{}, &ControlPlaneRequestLimitList{}) - client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.existingResources...).Build() - decoder, err := admission.NewDecoder(s) - require.NoError(t, err) - - validator := &ControlPlaneRequestLimitWebhook{ - Client: client, - Logger: logrtest.New(t), - decoder: decoder, - } - response := validator.Handle(ctx, admission.Request{ - AdmissionRequest: admissionv1.AdmissionRequest{ - Name: c.newResource.KubernetesName(), - Namespace: otherNS, - Operation: admissionv1.Create, - Object: runtime.RawExtension{ - Raw: marshalledRequestObject, - }, - }, - }) - - require.Equal(t, c.expAllow, response.Allowed) - if c.expErrMessage != "" { - require.Equal(t, c.expErrMessage, response.AdmissionResponse.Result.Message) - } - }) - } -} diff --git a/control-plane/api/v1alpha1/exportedservices_types.go b/control-plane/api/v1alpha1/exportedservices_types.go index 06d6ce30cf..e05f17a177 100644 --- a/control-plane/api/v1alpha1/exportedservices_types.go +++ b/control-plane/api/v1alpha1/exportedservices_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -19,7 +16,6 @@ import ( ) const ExportedServicesKubeKind = "exportedservices" -const WildcardSpecifier = "*" func init() { SchemeBuilder.Register(&ExportedServices{}, &ExportedServicesList{}) @@ -72,10 +68,8 @@ type ExportedService struct { type ServiceConsumer struct { // Partition is the admin partition to export the service to. Partition string `json:"partition,omitempty"` - // Peer is the name of the peer to export the service to. + // [Experimental] Peer is the name of the peer to export the service to. Peer string `json:"peer,omitempty"` - // SamenessGroup is the name of the sameness group to export the service to. - SamenessGroup string `json:"samenessGroup,omitempty"` } func (in *ExportedServices) GetObjectMeta() metav1.ObjectMeta { @@ -172,9 +166,8 @@ func (in *ExportedService) toConsul() capi.ExportedService { var consumers []capi.ServiceConsumer for _, consumer := range in.Consumers { consumers = append(consumers, capi.ServiceConsumer{ - Partition: consumer.Partition, - Peer: consumer.Peer, - SamenessGroup: consumer.SamenessGroup, + Partition: consumer.Partition, + Peer: consumer.Peer, }) } return capi.ExportedService{ @@ -234,34 +227,14 @@ func (in *ExportedService) validate(path *field.Path, consulMeta common.ConsulMe } func (in *ServiceConsumer) validate(path *field.Path, consulMeta common.ConsulMeta) *field.Error { - count := 0 - - if in.Partition != "" { - count++ - } - if in.Peer != "" { - count++ - } - if in.SamenessGroup != "" { - count++ + if in.Partition != "" && in.Peer != "" { + return field.Invalid(path, *in, "both partition and peer cannot be specified.") } - if count > 1 { - return field.Invalid(path, *in, "service consumer must define at most one of Peer, Partition, or SamenessGroup") - } - if count == 0 { - return field.Invalid(path, *in, "service consumer must define at least one of Peer, Partition, or SamenessGroup") + if in.Partition == "" && in.Peer == "" { + return field.Invalid(path, *in, "either partition or peer must be specified.") } if !consulMeta.PartitionsEnabled && in.Partition != "" { - return field.Invalid(path.Child("partition"), in.Partition, "Consul Admin Partitions need to be enabled to specify partition.") - } - if in.Partition == WildcardSpecifier { - return field.Invalid(path.Child("partition"), "", "exporting to all partitions (wildcard) is not supported") - } - if in.Peer == WildcardSpecifier { - return field.Invalid(path.Child("peer"), "", "exporting to all peers (wildcard) is not supported") - } - if in.SamenessGroup == WildcardSpecifier { - return field.Invalid(path.Child("samenessgroup"), "", "exporting to all sameness groups (wildcard) is not supported") + return field.Invalid(path.Child("partitions"), in.Partition, "Consul Admin Partitions need to be enabled to specify partition.") } return nil } diff --git a/control-plane/api/v1alpha1/exportedservices_types_test.go b/control-plane/api/v1alpha1/exportedservices_types_test.go index d759a6f270..8826166a76 100644 --- a/control-plane/api/v1alpha1/exportedservices_types_test.go +++ b/control-plane/api/v1alpha1/exportedservices_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -59,9 +56,6 @@ func TestExportedServices_MatchesConsul(t *testing.T) { { Peer: "second-peer", }, - { - SamenessGroup: "sg1", - }, }, }, { @@ -77,9 +71,6 @@ func TestExportedServices_MatchesConsul(t *testing.T) { { Peer: "third-peer", }, - { - SamenessGroup: "sg2", - }, }, }, }, @@ -101,9 +92,6 @@ func TestExportedServices_MatchesConsul(t *testing.T) { { Peer: "second-peer", }, - { - SamenessGroup: "sg1", - }, }, }, { @@ -119,9 +107,6 @@ func TestExportedServices_MatchesConsul(t *testing.T) { { Peer: "third-peer", }, - { - SamenessGroup: "sg2", - }, }, }, }, @@ -195,9 +180,6 @@ func TestExportedServices_ToConsul(t *testing.T) { { Peer: "second-peer", }, - { - SamenessGroup: "sg2", - }, }, }, { @@ -213,9 +195,6 @@ func TestExportedServices_ToConsul(t *testing.T) { { Peer: "third-peer", }, - { - SamenessGroup: "sg3", - }, }, }, }, @@ -237,9 +216,6 @@ func TestExportedServices_ToConsul(t *testing.T) { { Peer: "second-peer", }, - { - SamenessGroup: "sg2", - }, }, }, { @@ -255,9 +231,6 @@ func TestExportedServices_ToConsul(t *testing.T) { { Peer: "third-peer", }, - { - SamenessGroup: "sg3", - }, }, }, }, @@ -302,9 +275,6 @@ func TestExportedServices_Validate(t *testing.T) { { Peer: "second-peer", }, - { - SamenessGroup: "sg2", - }, }, }, }, @@ -358,10 +328,10 @@ func TestExportedServices_Validate(t *testing.T) { namespaceEnabled: true, partitionsEnabled: true, expectedErrMsgs: []string{ - `service consumer must define at most one of Peer, Partition, or SamenessGroup`, + `spec.services[0].consumers[0]: Invalid value: v1alpha1.ServiceConsumer{Partition:"second", Peer:"second-peer"}: both partition and peer cannot be specified.`, }, }, - "none of peer, partition, or sameness group defined": { + "neither partition nor peer name specified": { input: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: common.DefaultConsulPartition, @@ -381,7 +351,7 @@ func TestExportedServices_Validate(t *testing.T) { namespaceEnabled: true, partitionsEnabled: true, expectedErrMsgs: []string{ - `service consumer must define at least one of Peer, Partition, or SamenessGroup`, + `spec.services[0].consumers[0]: Invalid value: v1alpha1.ServiceConsumer{Partition:"", Peer:""}: either partition or peer must be specified.`, }, }, "partition provided when partitions are disabled": { @@ -406,7 +376,7 @@ func TestExportedServices_Validate(t *testing.T) { namespaceEnabled: true, partitionsEnabled: false, expectedErrMsgs: []string{ - `spec.services[0].consumers[0].partition: Invalid value: "test-partition": Consul Admin Partitions need to be enabled to specify partition.`, + `spec.services[0].consumers[0].partitions: Invalid value: "test-partition": Consul Admin Partitions need to be enabled to specify partition.`, }, }, "namespace provided when namespaces are disabled": { @@ -434,81 +404,6 @@ func TestExportedServices_Validate(t *testing.T) { `spec.services[0]: Invalid value: "frontend": Consul Namespaces must be enabled to specify service namespace.`, }, }, - "exporting to all partitions is not supported": { - input: &ExportedServices{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.DefaultConsulPartition, - }, - Spec: ExportedServicesSpec{ - Services: []ExportedService{ - { - Name: "service-frontend", - Namespace: "frontend", - Consumers: []ServiceConsumer{ - { - Partition: "*", - }, - }, - }, - }, - }, - }, - namespaceEnabled: true, - partitionsEnabled: true, - expectedErrMsgs: []string{ - `exporting to all partitions (wildcard) is not supported`, - }, - }, - "exporting to all peers (wildcard) is not supported": { - input: &ExportedServices{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.DefaultConsulPartition, - }, - Spec: ExportedServicesSpec{ - Services: []ExportedService{ - { - Name: "service-frontend", - Namespace: "frontend", - Consumers: []ServiceConsumer{ - { - Peer: "*", - }, - }, - }, - }, - }, - }, - namespaceEnabled: true, - partitionsEnabled: true, - expectedErrMsgs: []string{ - `exporting to all peers (wildcard) is not supported`, - }, - }, - "exporting to all sameness groups (wildcard) is not supported": { - input: &ExportedServices{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.DefaultConsulPartition, - }, - Spec: ExportedServicesSpec{ - Services: []ExportedService{ - { - Name: "service-frontend", - Namespace: "frontend", - Consumers: []ServiceConsumer{ - { - SamenessGroup: "*", - }, - }, - }, - }, - }, - }, - namespaceEnabled: true, - partitionsEnabled: true, - expectedErrMsgs: []string{ - `exporting to all sameness groups (wildcard) is not supported`, - }, - }, "multiple errors": { input: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ @@ -525,10 +420,6 @@ func TestExportedServices_Validate(t *testing.T) { Peer: "second-peer", }, {}, - { - SamenessGroup: "sg2", - Partition: "partition2", - }, }, }, }, @@ -537,9 +428,8 @@ func TestExportedServices_Validate(t *testing.T) { namespaceEnabled: true, partitionsEnabled: true, expectedErrMsgs: []string{ - `spec.services[0].consumers[0]: Invalid value: v1alpha1.ServiceConsumer{Partition:"second", Peer:"second-peer", SamenessGroup:""}: service consumer must define at most one of Peer, Partition, or SamenessGroup`, - `spec.services[0].consumers[1]: Invalid value: v1alpha1.ServiceConsumer{Partition:"", Peer:"", SamenessGroup:""}: service consumer must define at least one of Peer, Partition, or SamenessGroup`, - `spec.services[0].consumers[2]: Invalid value: v1alpha1.ServiceConsumer{Partition:"partition2", Peer:"", SamenessGroup:"sg2"}: service consumer must define at most one of Peer, Partition, or SamenessGroup`, + `spec.services[0].consumers[0]: Invalid value: v1alpha1.ServiceConsumer{Partition:"second", Peer:"second-peer"}: both partition and peer cannot be specified.`, + `spec.services[0].consumers[1]: Invalid value: v1alpha1.ServiceConsumer{Partition:"", Peer:""}: either partition or peer must be specified.`, }, }, } diff --git a/control-plane/api/v1alpha1/exportedservices_webhook.go b/control-plane/api/v1alpha1/exportedservices_webhook.go index 6c870427ac..5a3d2cb2f1 100644 --- a/control-plane/api/v1alpha1/exportedservices_webhook.go +++ b/control-plane/api/v1alpha1/exportedservices_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/exportedservices_webhook_test.go b/control-plane/api/v1alpha1/exportedservices_webhook_test.go index 7cca7ff915..3a66fbdd9c 100644 --- a/control-plane/api/v1alpha1/exportedservices_webhook_test.go +++ b/control-plane/api/v1alpha1/exportedservices_webhook_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -123,7 +120,7 @@ func TestValidateExportedServices(t *testing.T) { Partition: "", }, expAllow: false, - expErrMessage: "exportedservices.consul.hashicorp.com \"default\" is invalid: spec.services[0].consumers[0].partition: Invalid value: \"other\": Consul Admin Partitions need to be enabled to specify partition.", + expErrMessage: "exportedservices.consul.hashicorp.com \"default\" is invalid: spec.services[0].consumers[0].partitions: Invalid value: \"other\": Consul Admin Partitions need to be enabled to specify partition.", }, "no services": { existingResources: []runtime.Object{}, diff --git a/control-plane/api/v1alpha1/groupversion_info.go b/control-plane/api/v1alpha1/groupversion_info.go index 3657e9b048..cdbe085af4 100644 --- a/control-plane/api/v1alpha1/groupversion_info.go +++ b/control-plane/api/v1alpha1/groupversion_info.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package v1alpha1 contains API Schema definitions for the consul.hashicorp.com v1alpha1 API group // +kubebuilder:object:generate=true // +groupName=consul.hashicorp.com diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index c781ab8cc8..fde3cdd4e5 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/ingressgateway_types_test.go b/control-plane/api/v1alpha1/ingressgateway_types_test.go index 73b53f5fff..37a23ff678 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types_test.go +++ b/control-plane/api/v1alpha1/ingressgateway_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/ingressgateway_webhook.go b/control-plane/api/v1alpha1/ingressgateway_webhook.go index 04e31a0a3e..7f8ba37558 100644 --- a/control-plane/api/v1alpha1/ingressgateway_webhook.go +++ b/control-plane/api/v1alpha1/ingressgateway_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/jwtprovider_types.go b/control-plane/api/v1alpha1/jwtprovider_types.go deleted file mode 100644 index fee0ef9a78..0000000000 --- a/control-plane/api/v1alpha1/jwtprovider_types.go +++ /dev/null @@ -1,663 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "encoding/base64" - "encoding/json" - "net/url" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/consul-k8s/control-plane/api/common" - "github.com/hashicorp/consul/api" - capi "github.com/hashicorp/consul/api" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -const ( - JWTProviderKubeKind string = "jwtprovider" -) - -func init() { - SchemeBuilder.Register(&JWTProvider{}, &JWTProviderList{}) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// JWTProvider is the Schema for the jwtproviders API. -type JWTProvider struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - Spec JWTProviderSpec `json:"spec,omitempty"` - Status `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// JWTProviderList contains a list of JWTProvider. -type JWTProviderList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []JWTProvider `json:"items"` -} - -// JWTProviderSpec defines the desired state of JWTProvider -// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" -// +kubebuilder:printcolumn:name="Last Synced",type="date",JSONPath=".status.lastSyncedTime",description="The last successful synced time of the resource with Consul" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" -type JWTProviderSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - - // JSONWebKeySet defines a JSON Web Key Set, its location on disk, or the - // means with which to fetch a key set from a remote server. - JSONWebKeySet *JSONWebKeySet `json:"jsonWebKeySet,omitempty"` - - // Issuer is the entity that must have issued the JWT. - // This value must match the "iss" claim of the token. - Issuer string `json:"issuer,omitempty"` - - // Audiences is the set of audiences the JWT is allowed to access. - // If specified, all JWTs verified with this provider must address - // at least one of these to be considered valid. - Audiences []string `json:"audiences,omitempty"` - - // Locations where the JWT will be present in requests. - // Envoy will check all of these locations to extract a JWT. - // If no locations are specified Envoy will default to: - // 1. Authorization header with Bearer schema: - // "Authorization: Bearer " - // 2. accessToken query parameter. - Locations []*JWTLocation `json:"locations,omitempty"` - - // Forwarding defines rules for forwarding verified JWTs to the backend. - Forwarding *JWTForwardingConfig `json:"forwarding,omitempty"` - - // ClockSkewSeconds specifies the maximum allowable time difference - // from clock skew when validating the "exp" (Expiration) and "nbf" - // (Not Before) claims. - // - // Default value is 30 seconds. - ClockSkewSeconds int `json:"clockSkewSeconds,omitempty"` - - // CacheConfig defines configuration for caching the validation - // result for previously seen JWTs. Caching results can speed up - // verification when individual tokens are expected to be handled - // multiple times. - CacheConfig *JWTCacheConfig `json:"cacheConfig,omitempty"` -} - -type JWTLocations []*JWTLocation - -func (j JWTLocations) toConsul() []*capi.JWTLocation { - if j == nil { - return nil - } - result := make([]*capi.JWTLocation, 0, len(j)) - for _, loc := range j { - result = append(result, loc.toConsul()) - } - return result -} - -func (j JWTLocations) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - for i, loc := range j { - errs = append(errs, loc.validate(path.Index(i))...) - } - return errs -} - -// JWTLocation is a location where the JWT could be present in requests. -// -// Only one of Header, QueryParam, or Cookie can be specified. -type JWTLocation struct { - // Header defines how to extract a JWT from an HTTP request header. - Header *JWTLocationHeader `json:"header,omitempty"` - - // QueryParam defines how to extract a JWT from an HTTP request - // query parameter. - QueryParam *JWTLocationQueryParam `json:"queryParam,omitempty"` - - // Cookie defines how to extract a JWT from an HTTP request cookie. - Cookie *JWTLocationCookie `json:"cookie,omitempty"` -} - -func (j *JWTLocation) toConsul() *capi.JWTLocation { - if j == nil { - return nil - } - return &capi.JWTLocation{ - Header: j.Header.toConsul(), - QueryParam: j.QueryParam.toConsul(), - Cookie: j.Cookie.toConsul(), - } -} - -func (j *JWTLocation) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if j == nil { - return append(errs, field.Invalid(path, j, "location must not be nil")) - } - - if 1 != countTrue( - j.Header != nil, - j.QueryParam != nil, - j.Cookie != nil, - ) { - asJSON, _ := json.Marshal(j) - return append(errs, field.Invalid(path, string(asJSON), "exactly one of 'header', 'queryParam', or 'cookie' is required")) - } - - errs = append(errs, j.Header.validate(path.Child("header"))...) - errs = append(errs, j.QueryParam.validate(path.Child("queryParam"))...) - errs = append(errs, j.Cookie.validate(path.Child("cookie"))...) - return errs -} - -// JWTLocationHeader defines how to extract a JWT from an HTTP -// request header. -type JWTLocationHeader struct { - // Name is the name of the header containing the token. - Name string `json:"name,omitempty"` - - // ValuePrefix is an optional prefix that precedes the token in the - // header value. - // For example, "Bearer " is a standard value prefix for a header named - // "Authorization", but the prefix is not part of the token itself: - // "Authorization: Bearer " - ValuePrefix string `json:"valuePrefix,omitempty"` - - // Forward defines whether the header with the JWT should be - // forwarded after the token has been verified. If false, the - // header will not be forwarded to the backend. - // - // Default value is false. - Forward bool `json:"forward,omitempty"` -} - -func (j *JWTLocationHeader) toConsul() *capi.JWTLocationHeader { - if j == nil { - return nil - } - return &capi.JWTLocationHeader{ - Name: j.Name, - ValuePrefix: j.ValuePrefix, - Forward: j.Forward, - } -} - -func (j *JWTLocationHeader) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if j == nil { - return errs - } - - if j.Name == "" { - errs = append(errs, field.Invalid(path.Child("name"), j.Name, "JWT location header name is required")) - } - return errs -} - -// JWTLocationQueryParam defines how to extract a JWT from an HTTP request query parameter. -type JWTLocationQueryParam struct { - // Name is the name of the query param containing the token. - Name string `json:"name,omitempty"` -} - -func (j *JWTLocationQueryParam) toConsul() *capi.JWTLocationQueryParam { - if j == nil { - return nil - } - return &capi.JWTLocationQueryParam{ - Name: j.Name, - } -} - -func (j *JWTLocationQueryParam) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if j == nil { - return nil - } - if j.Name == "" { - errs = append(errs, field.Invalid(path.Child("name"), j.Name, "JWT location query parameter name is required")) - } - return errs -} - -// JWTLocationCookie defines how to extract a JWT from an HTTP request cookie. -type JWTLocationCookie struct { - // Name is the name of the cookie containing the token. - Name string `json:"name,omitempty"` -} - -func (j *JWTLocationCookie) toConsul() *capi.JWTLocationCookie { - if j == nil { - return nil - } - return &capi.JWTLocationCookie{ - Name: j.Name, - } -} - -func (j *JWTLocationCookie) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if j == nil { - return nil - } - if j.Name == "" { - errs = append(errs, field.Invalid(path.Child("name"), j.Name, "JWT location cookie name is required")) - } - return errs -} - -type JWTForwardingConfig struct { - // HeaderName is a header name to use when forwarding a verified - // JWT to the backend. The verified JWT could have been extracted - // from any location (query param, header, or cookie). - // - // The header value will be base64-URL-encoded, and will not be - // padded unless PadForwardPayloadHeader is true. - HeaderName string `json:"headerName,omitempty"` - - // PadForwardPayloadHeader determines whether padding should be added - // to the base64 encoded token forwarded with ForwardPayloadHeader. - // - // Default value is false. - PadForwardPayloadHeader bool `json:"padForwardPayloadHeader,omitempty"` -} - -func (j *JWTForwardingConfig) toConsul() *capi.JWTForwardingConfig { - if j == nil { - return nil - } - return &capi.JWTForwardingConfig{ - HeaderName: j.HeaderName, - PadForwardPayloadHeader: j.PadForwardPayloadHeader, - } -} - -func (j *JWTForwardingConfig) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if j == nil { - return nil - } - - if j.HeaderName == "" { - errs = append(errs, field.Invalid(path.Child("HeaderName"), j.HeaderName, "JWT forwarding header name is required")) - } - return errs -} - -// JSONWebKeySet defines a key set, its location on disk, or the -// means with which to fetch a key set from a remote server. -// -// Exactly one of Local or Remote must be specified. -type JSONWebKeySet struct { - // Local specifies a local source for the key set. - Local *LocalJWKS `json:"local,omitempty"` - - // Remote specifies how to fetch a key set from a remote server. - Remote *RemoteJWKS `json:"remote,omitempty"` -} - -func (j *JSONWebKeySet) toConsul() *capi.JSONWebKeySet { - if j == nil { - return nil - } - - return &capi.JSONWebKeySet{ - Local: j.Local.toConsul(), - Remote: j.Remote.toConsul(), - } -} - -func (j *JSONWebKeySet) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if j == nil { - return append(errs, field.Invalid(path, j, "jsonWebKeySet is required")) - } - - if countTrue(j.Local != nil, j.Remote != nil) != 1 { - asJSON, _ := json.Marshal(j) - return append(errs, field.Invalid(path, string(asJSON), "exactly one of 'local' or 'remote' is required")) - } - errs = append(errs, j.Local.validate(path.Child("local"))...) - errs = append(errs, j.Remote.validate(path.Child("remote"))...) - return errs -} - -// LocalJWKS specifies a location for a local JWKS. -// -// Only one of String and Filename can be specified. -type LocalJWKS struct { - // JWKS contains a base64 encoded JWKS. - JWKS string `json:"jwks,omitempty"` - - // Filename configures a location on disk where the JWKS can be - // found. If specified, the file must be present on the disk of ALL - // proxies with intentions referencing this provider. - Filename string `json:"filename,omitempty"` -} - -func (l *LocalJWKS) toConsul() *capi.LocalJWKS { - if l == nil { - return nil - } - return &capi.LocalJWKS{ - JWKS: l.JWKS, - Filename: l.Filename, - } -} - -func (l *LocalJWKS) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if l == nil { - return errs - } - - if countTrue(l.JWKS != "", l.Filename != "") != 1 { - asJSON, _ := json.Marshal(l) - return append(errs, field.Invalid(path, string(asJSON), "Exactly one of 'jwks' or 'filename' is required")) - } - if l.JWKS != "" { - if _, err := base64.StdEncoding.DecodeString(l.JWKS); err != nil { - return append(errs, field.Invalid(path.Child("jwks"), l.JWKS, "JWKS must be a valid base64-encoded string")) - } - } - return errs -} - -// RemoteJWKS specifies how to fetch a JWKS from a remote server. -type RemoteJWKS struct { - // URI is the URI of the server to query for the JWKS. - URI string `json:"uri,omitempty"` - - // RequestTimeoutMs is the number of milliseconds to - // time out when making a request for the JWKS. - RequestTimeoutMs int `json:"requestTimeoutMs,omitempty"` - - // CacheDuration is the duration after which cached keys - // should be expired. - // - // Default value is 5 minutes. - CacheDuration time.Duration `json:"cacheDuration,omitempty"` - - // FetchAsynchronously indicates that the JWKS should be fetched - // when a client request arrives. Client requests will be paused - // until the JWKS is fetched. - // If false, the proxy listener will wait for the JWKS to be - // fetched before being activated. - // - // Default value is false. - FetchAsynchronously bool `json:"fetchAsynchronously,omitempty"` - - // RetryPolicy defines a retry policy for fetching JWKS. - // - // There is no retry by default. - RetryPolicy *JWKSRetryPolicy `json:"retryPolicy,omitempty"` -} - -func (r *RemoteJWKS) toConsul() *capi.RemoteJWKS { - if r == nil { - return nil - } - return &capi.RemoteJWKS{ - URI: r.URI, - RequestTimeoutMs: r.RequestTimeoutMs, - CacheDuration: r.CacheDuration, - FetchAsynchronously: r.FetchAsynchronously, - RetryPolicy: r.RetryPolicy.toConsul(), - } -} - -func (r *RemoteJWKS) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if r == nil { - return errs - } - - if r.URI == "" { - errs = append(errs, field.Invalid(path.Child("uri"), r.URI, "remote JWKS URI is required")) - } else if _, err := url.ParseRequestURI(r.URI); err != nil { - errs = append(errs, field.Invalid(path.Child("uri"), r.URI, "remote JWKS URI is invalid")) - } - - errs = append(errs, r.RetryPolicy.validate(path.Child("retryPolicy"))...) - return errs -} - -type JWKSRetryPolicy struct { - // NumRetries is the number of times to retry fetching the JWKS. - // The retry strategy uses jittered exponential backoff with - // a base interval of 1s and max of 10s. - // - // Default value is 0. - NumRetries int `json:"numRetries,omitempty"` - - // Backoff policy - // - // Defaults to Envoy's backoff policy - RetryPolicyBackOff *RetryPolicyBackOff `json:"retryPolicyBackOff,omitempty"` -} - -func (j *JWKSRetryPolicy) toConsul() *capi.JWKSRetryPolicy { - if j == nil { - return nil - } - return &capi.JWKSRetryPolicy{ - NumRetries: j.NumRetries, - RetryPolicyBackOff: j.RetryPolicyBackOff.toConsul(), - } -} - -func (j *JWKSRetryPolicy) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if j == nil { - return errs - } - - return append(errs, j.RetryPolicyBackOff.validate(path.Child("retryPolicyBackOff"))...) -} - -type RetryPolicyBackOff struct { - // BaseInterval to be used for the next back off computation - // - // The default value from envoy is 1s - BaseInterval time.Duration `json:"baseInterval,omitempty"` - - // MaxInternal to be used to specify the maximum interval between retries. - // Optional but should be greater or equal to BaseInterval. - // - // Defaults to 10 times BaseInterval - MaxInterval time.Duration `json:"maxInterval,omitempty"` -} - -func (r *RetryPolicyBackOff) toConsul() *capi.RetryPolicyBackOff { - if r == nil { - return nil - } - return &capi.RetryPolicyBackOff{ - BaseInterval: r.BaseInterval, - MaxInterval: r.MaxInterval, - } -} - -func (r *RetryPolicyBackOff) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if r == nil { - return errs - } - - if (r.MaxInterval != 0) && (r.BaseInterval > r.MaxInterval) { - asJSON, _ := json.Marshal(r) - errs = append(errs, field.Invalid(path, string(asJSON), "maxInterval should be greater or equal to baseInterval")) - } - return errs -} - -type JWTCacheConfig struct { - // Size specifies the maximum number of JWT verification - // results to cache. - // - // Defaults to 0, meaning that JWT caching is disabled. - Size int `json:"size,omitempty"` -} - -func (j *JWTCacheConfig) toConsul() *capi.JWTCacheConfig { - if j == nil { - return nil - } - return &capi.JWTCacheConfig{ - Size: j.Size, - } -} - -func (j *JWTProvider) GetObjectMeta() metav1.ObjectMeta { - return j.ObjectMeta -} - -func (j *JWTProvider) AddFinalizer(name string) { - j.ObjectMeta.Finalizers = append(j.Finalizers(), name) -} - -func (j *JWTProvider) RemoveFinalizer(name string) { - var newFinalizers []string - for _, oldF := range j.Finalizers() { - if oldF != name { - newFinalizers = append(newFinalizers, oldF) - } - } - j.ObjectMeta.Finalizers = newFinalizers -} - -func (j *JWTProvider) Finalizers() []string { - return j.ObjectMeta.Finalizers -} - -func (j *JWTProvider) ConsulKind() string { - return capi.JWTProvider -} - -func (j *JWTProvider) ConsulGlobalResource() bool { - return true -} - -func (j *JWTProvider) ConsulMirroringNS() string { - return common.DefaultConsulNamespace -} - -func (j *JWTProvider) KubeKind() string { - return JWTProviderKubeKind -} - -func (j *JWTProvider) ConsulName() string { - return j.ObjectMeta.Name -} - -func (j *JWTProvider) KubernetesName() string { - return j.ObjectMeta.Name -} - -func (j *JWTProvider) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { - j.Status.Conditions = Conditions{ - { - Type: ConditionSynced, - Status: status, - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: message, - }, - } -} - -func (j *JWTProvider) SetLastSyncedTime(time *metav1.Time) { - j.Status.LastSyncedTime = time -} - -// SyncedCondition gets the synced condition. -func (j *JWTProvider) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { - cond := j.Status.GetCondition(ConditionSynced) - if cond == nil { - return corev1.ConditionUnknown, "", "" - } - return cond.Status, cond.Reason, cond.Message -} - -// SyncedConditionStatus returns the status of the synced condition. -func (j *JWTProvider) SyncedConditionStatus() corev1.ConditionStatus { - cond := j.Status.GetCondition(ConditionSynced) - if cond == nil { - return corev1.ConditionUnknown - } - return cond.Status -} - -// ToConsul converts the resource to the corresponding Consul API definition. -// Its return type is the generic ConfigEntry but a specific config entry -// type should be constructed e.g. ServiceConfigEntry. -func (j *JWTProvider) ToConsul(datacenter string) api.ConfigEntry { - return &capi.JWTProviderConfigEntry{ - Kind: j.ConsulKind(), - Name: j.ConsulName(), - JSONWebKeySet: j.Spec.JSONWebKeySet.toConsul(), - Issuer: j.Spec.Issuer, - Audiences: j.Spec.Audiences, - Locations: JWTLocations(j.Spec.Locations).toConsul(), - Forwarding: j.Spec.Forwarding.toConsul(), - ClockSkewSeconds: j.Spec.ClockSkewSeconds, - CacheConfig: j.Spec.CacheConfig.toConsul(), - Meta: meta(datacenter), - } -} - -// MatchesConsul returns true if the resource has the same fields as the Consul -// config entry. -func (j *JWTProvider) MatchesConsul(candidate api.ConfigEntry) bool { - configEntry, ok := candidate.(*capi.JWTProviderConfigEntry) - if !ok { - return false - } - // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(j.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.JWTProviderConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) -} - -// Validate returns an error if the resource is invalid. -func (j *JWTProvider) Validate(consulMeta common.ConsulMeta) error { - var errs field.ErrorList - path := field.NewPath("spec") - - errs = append(errs, j.Spec.JSONWebKeySet.validate(path.Child("jsonWebKeySet"))...) - errs = append(errs, JWTLocations(j.Spec.Locations).validate(path.Child("locations"))...) - errs = append(errs, j.Spec.Forwarding.validate(path.Child("forwarding"))...) - if len(errs) > 0 { - return apierrors.NewInvalid( - schema.GroupKind{Group: ConsulHashicorpGroup, Kind: JWTProviderKubeKind}, - j.KubernetesName(), errs) - } - return nil -} - -// DefaultNamespaceFields sets Consul namespace fields on the config entry -// spec to their default values if namespaces are enabled. -func (j *JWTProvider) DefaultNamespaceFields(_ common.ConsulMeta) {} - -func countTrue(vals ...bool) int { - var result int - for _, v := range vals { - if v { - result++ - } - } - return result -} - -var _ common.ConfigEntryResource = (*JWTProvider)(nil) diff --git a/control-plane/api/v1alpha1/jwtprovider_types_test.go b/control-plane/api/v1alpha1/jwtprovider_types_test.go deleted file mode 100644 index 15a3e7a5d6..0000000000 --- a/control-plane/api/v1alpha1/jwtprovider_types_test.go +++ /dev/null @@ -1,730 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "testing" - "time" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" - capi "github.com/hashicorp/consul/api" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Test MatchesConsul for cases that should return true. -func TestJWTProvider_MatchesConsul(t *testing.T) { - cases := map[string]struct { - Ours JWTProvider - Theirs capi.ConfigEntry - Matches bool - }{ - "empty fields matches": { - Ours: JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-okta", - }, - Spec: JWTProviderSpec{}, - }, - Theirs: &capi.JWTProviderConfigEntry{ - Kind: capi.JWTProvider, - Name: "test-okta", - Namespace: "default", - CreateIndex: 1, - ModifyIndex: 2, - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - }, - Matches: true, - }, - "all fields set matches": { - Ours: JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-okta2", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Local: &LocalJWKS{ - JWKS: "jwks-string", - Filename: "jwks-file", - }, - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - RequestTimeoutMs: 567, - CacheDuration: 890, - FetchAsynchronously: true, - RetryPolicy: &JWKSRetryPolicy{ - NumRetries: 1, - RetryPolicyBackOff: &RetryPolicyBackOff{ - BaseInterval: 23, - MaxInterval: 456, - }, - }, - }, - }, - Issuer: "test-issuer", - Audiences: []string{"aud1", "aud2"}, - Locations: []*JWTLocation{ - { - Header: &JWTLocationHeader{ - Name: "jwt-header", - ValuePrefix: "my-bearer", - Forward: true, - }, - }, - { - QueryParam: &JWTLocationQueryParam{ - Name: "jwt-query-param", - }, - }, - { - Cookie: &JWTLocationCookie{ - Name: "jwt-cookie", - }, - }, - }, - Forwarding: &JWTForwardingConfig{ - HeaderName: "jwt-forward-header", - PadForwardPayloadHeader: true, - }, - ClockSkewSeconds: 357, - CacheConfig: &JWTCacheConfig{ - Size: 468, - }, - }, - }, - Theirs: &capi.JWTProviderConfigEntry{ - Kind: capi.JWTProvider, - Name: "test-okta2", - Namespace: "default", - JSONWebKeySet: &capi.JSONWebKeySet{ - Local: &capi.LocalJWKS{ - JWKS: "jwks-string", - Filename: "jwks-file", - }, - Remote: &capi.RemoteJWKS{ - URI: "https://jwks.example.com", - RequestTimeoutMs: 567, - CacheDuration: 890, - FetchAsynchronously: true, - RetryPolicy: &capi.JWKSRetryPolicy{ - NumRetries: 1, - RetryPolicyBackOff: &capi.RetryPolicyBackOff{ - BaseInterval: 23, - MaxInterval: 456, - }, - }, - }, - }, - Issuer: "test-issuer", - Audiences: []string{"aud1", "aud2"}, - Locations: []*capi.JWTLocation{ - { - Header: &capi.JWTLocationHeader{ - Name: "jwt-header", - ValuePrefix: "my-bearer", - Forward: true, - }, - }, - { - QueryParam: &capi.JWTLocationQueryParam{ - Name: "jwt-query-param", - }, - }, - { - Cookie: &capi.JWTLocationCookie{ - Name: "jwt-cookie", - }, - }, - }, - Forwarding: &capi.JWTForwardingConfig{ - HeaderName: "jwt-forward-header", - PadForwardPayloadHeader: true, - }, - ClockSkewSeconds: 357, - CacheConfig: &capi.JWTCacheConfig{ - Size: 468, - }, - }, - Matches: true, - }, - "mismatched types does not match": { - Ours: JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-okta3", - }, - Spec: JWTProviderSpec{}, - }, - Theirs: &capi.JWTProviderConfigEntry{}, - Matches: false, - }, - } - for name, c := range cases { - c := c - t.Run(name, func(t *testing.T) { - require.Equal(t, c.Matches, c.Ours.MatchesConsul(c.Theirs)) - }) - } -} - -func TestJWTProvider_ToConsul(t *testing.T) { - cases := map[string]struct { - Ours JWTProvider - Exp *capi.JWTProviderConfigEntry - }{ - "empty fields": { - Ours: JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-okta1", - }, - Spec: JWTProviderSpec{}, - }, - Exp: &capi.JWTProviderConfigEntry{ - Kind: capi.JWTProvider, - Name: "test-okta1", - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - }, - }, - "every field set": { - Ours: JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-okta2", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Local: &LocalJWKS{ - JWKS: "jwks-string", - Filename: "jwks-file", - }, - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - RequestTimeoutMs: 567, - CacheDuration: 890, - FetchAsynchronously: true, - RetryPolicy: &JWKSRetryPolicy{ - NumRetries: 1, - RetryPolicyBackOff: &RetryPolicyBackOff{ - BaseInterval: 23, - MaxInterval: 456, - }, - }, - }, - }, - Issuer: "test-issuer", - Audiences: []string{"aud1", "aud2"}, - Locations: []*JWTLocation{ - { - Header: &JWTLocationHeader{ - Name: "jwt-header", - ValuePrefix: "my-bearer", - Forward: true, - }, - }, - { - QueryParam: &JWTLocationQueryParam{ - Name: "jwt-query-param", - }, - }, - { - Cookie: &JWTLocationCookie{ - Name: "jwt-cookie", - }, - }, - }, - Forwarding: &JWTForwardingConfig{ - HeaderName: "jwt-forward-header", - PadForwardPayloadHeader: true, - }, - ClockSkewSeconds: 357, - CacheConfig: &JWTCacheConfig{ - Size: 468, - }, - }, - }, - Exp: &capi.JWTProviderConfigEntry{ - Kind: capi.JWTProvider, - Name: "test-okta2", - JSONWebKeySet: &capi.JSONWebKeySet{ - Local: &capi.LocalJWKS{ - JWKS: "jwks-string", - Filename: "jwks-file", - }, - Remote: &capi.RemoteJWKS{ - URI: "https://jwks.example.com", - RequestTimeoutMs: 567, - CacheDuration: 890, - FetchAsynchronously: true, - RetryPolicy: &capi.JWKSRetryPolicy{ - NumRetries: 1, - RetryPolicyBackOff: &capi.RetryPolicyBackOff{ - BaseInterval: 23, - MaxInterval: 456, - }, - }, - }, - }, - Issuer: "test-issuer", - Audiences: []string{"aud1", "aud2"}, - Locations: []*capi.JWTLocation{ - { - Header: &capi.JWTLocationHeader{ - Name: "jwt-header", - ValuePrefix: "my-bearer", - Forward: true, - }, - }, - { - QueryParam: &capi.JWTLocationQueryParam{ - Name: "jwt-query-param", - }, - }, - { - Cookie: &capi.JWTLocationCookie{ - Name: "jwt-cookie", - }, - }, - }, - Forwarding: &capi.JWTForwardingConfig{ - HeaderName: "jwt-forward-header", - PadForwardPayloadHeader: true, - }, - ClockSkewSeconds: 357, - CacheConfig: &capi.JWTCacheConfig{ - Size: 468, - }, - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - }, - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - act := c.Ours.ToConsul("datacenter") - mesh, ok := act.(*capi.JWTProviderConfigEntry) - require.True(t, ok, "could not cast") - require.Equal(t, c.Exp, mesh) - }) - } -} - -func TestJWTProvider_Validate(t *testing.T) { - cases := map[string]struct { - input *JWTProvider - expectedErrMsgs []string - consulMeta common.ConsulMeta - }{ - "valid - local jwks": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-okta1", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Local: &LocalJWKS{ - Filename: "jwks.txt", - }, - }, - }, - Status: Status{}, - }, - expectedErrMsgs: nil, - }, - - "valid - remote jwks": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwt-provider", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - FetchAsynchronously: true, - }, - }, - Locations: []*JWTLocation{ - { - Header: &JWTLocationHeader{ - Name: "Authorization", - }, - }, - }, - Forwarding: &JWTForwardingConfig{ - HeaderName: "jwt-forward-header", - }, - }, - }, - expectedErrMsgs: nil, - }, - - "valid - remote jwks with all fields": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwt-provider", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - RequestTimeoutMs: 5000, - CacheDuration: 10 * time.Second, - FetchAsynchronously: true, - RetryPolicy: &JWKSRetryPolicy{ - NumRetries: 3, - RetryPolicyBackOff: &RetryPolicyBackOff{ - BaseInterval: 5 * time.Second, - MaxInterval: 20 * time.Second, - }, - }, - }, - }, - Issuer: "test-issuer", - Audiences: []string{"aud1", "aud2"}, - Locations: []*JWTLocation{ - { - Header: &JWTLocationHeader{ - Name: "Authorization", - ValuePrefix: "Bearer", - Forward: true, - }, - }, - { - QueryParam: &JWTLocationQueryParam{ - Name: "access-token", - }, - }, - { - Cookie: &JWTLocationCookie{ - Name: "session-id", - }, - }, - }, - Forwarding: &JWTForwardingConfig{ - HeaderName: "jwt-forward-header", - PadForwardPayloadHeader: true, - }, - ClockSkewSeconds: 20, - CacheConfig: &JWTCacheConfig{ - Size: 30, - }, - }, - }, - expectedErrMsgs: nil, - }, - - "invalid - nil jwks": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-no-jwks", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: nil, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-no-jwks" is invalid: spec.jsonWebKeySet: Invalid value: "null": jsonWebKeySet is required`, - }, - }, - - "invalid - empty jwks": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-no-jwks", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{}, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-no-jwks" is invalid: spec.jsonWebKeySet: Invalid value: "{}": exactly one of 'local' or 'remote' is required`, - }, - }, - - "invalid - local jwks with non-base64 string": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwks-base64", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Local: &LocalJWKS{ - JWKS: "not base64 encoded", - }, - }, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-jwks-base64" is invalid: spec.jsonWebKeySet.local.jwks: Invalid value: "not base64 encoded": JWKS must be a valid base64-encoded string`, - }, - }, - - "invalid - both local and remote jwks set": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwks-local-and-remote", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Local: &LocalJWKS{Filename: "jwks.txt"}, - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - }, - }, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-jwks-local-and-remote" is invalid: spec.jsonWebKeySet: Invalid value: "{\"local\":{\"filename\":\"jwks.txt\"},\"remote\":{\"uri\":\"https://jwks.example.com\"}}": exactly one of 'local' or 'remote' is required`, - }, - }, - - "invalid - remote jwks missing uri": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwks-missing-uri", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Remote: &RemoteJWKS{ - FetchAsynchronously: true, - }, - }, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-jwks-missing-uri" is invalid: spec.jsonWebKeySet.remote.uri: Invalid value: "": remote JWKS URI is required`, - }, - }, - - "invalid - remote jwks invalid uri": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwks-invalid-uri", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Remote: &RemoteJWKS{ - URI: "invalid-uri", - }, - }, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-jwks-invalid-uri" is invalid: spec.jsonWebKeySet.remote.uri: Invalid value: "invalid-uri": remote JWKS URI is invalid`, - }, - }, - - "invalid - JWT location with all fields": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwks-all-locations", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - }, - }, - Locations: []*JWTLocation{ - { - Header: &JWTLocationHeader{ - Name: "jwt-header", - }, - QueryParam: &JWTLocationQueryParam{ - Name: "jwt-query-param", - }, - Cookie: &JWTLocationCookie{ - Name: "jwt-cookie", - }, - }, - }, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-jwks-all-locations" is invalid: spec.locations[0]: Invalid value: "{\"header\":{\"name\":\"jwt-header\"},\"queryParam\":{\"name\":\"jwt-query-param\"},\"cookie\":{\"name\":\"jwt-cookie\"}}": exactly one of 'header', 'queryParam', or 'cookie' is required`, - }, - }, - - "invalid - JWT location with two fields": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwks-two-locations", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - }, - }, - Locations: []*JWTLocation{ - { - Header: &JWTLocationHeader{ - Name: "jwt-header", - }, - Cookie: &JWTLocationCookie{ - Name: "jwt-cookie", - }, - }, - }, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-jwks-two-locations" is invalid: spec.locations[0]: Invalid value: "{\"header\":{\"name\":\"jwt-header\"},\"cookie\":{\"name\":\"jwt-cookie\"}}": exactly one of 'header', 'queryParam', or 'cookie' is required`, - }, - }, - - "invalid - remote jwks retry policy maxInterval < baseInterval": { - input: &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwks-retry-intervals", - }, - Spec: JWTProviderSpec{ - JSONWebKeySet: &JSONWebKeySet{ - Remote: &RemoteJWKS{ - URI: "https://jwks.example.com", - RetryPolicy: &JWKSRetryPolicy{ - NumRetries: 0, - RetryPolicyBackOff: &RetryPolicyBackOff{ - BaseInterval: 100 * time.Second, - MaxInterval: 10 * time.Second, - }, - }, - }, - }, - }, - }, - expectedErrMsgs: []string{ - `jwtprovider.consul.hashicorp.com "test-jwks-retry-intervals" is invalid: spec.jsonWebKeySet.remote.retryPolicy.retryPolicyBackOff: Invalid value: "{\"baseInterval\":100000000000,\"maxInterval\":10000000000}": maxInterval should be greater or equal to baseInterval`, - }, - }, - } - - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(testCase.consulMeta) - if len(testCase.expectedErrMsgs) != 0 { - require.Error(t, err) - for _, s := range testCase.expectedErrMsgs { - require.Contains(t, err.Error(), s) - } - } else { - require.NoError(t, err) - } - }) - } - -} - -func TestJWTProvider_AddFinalizer(t *testing.T) { - jwt := &JWTProvider{} - jwt.AddFinalizer("finalizer") - require.Equal(t, []string{"finalizer"}, jwt.ObjectMeta.Finalizers) -} - -func TestJWTProvider_RemoveFinalizer(t *testing.T) { - jwt := &JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Finalizers: []string{"f1", "f2"}, - }, - } - jwt.RemoveFinalizer("f1") - require.Equal(t, []string{"f2"}, jwt.ObjectMeta.Finalizers) -} - -func TestJWTProvider_SetSyncedCondition(t *testing.T) { - jwt := &JWTProvider{} - jwt.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") - - require.Equal(t, corev1.ConditionTrue, jwt.Status.Conditions[0].Status) - require.Equal(t, "reason", jwt.Status.Conditions[0].Reason) - require.Equal(t, "message", jwt.Status.Conditions[0].Message) - now := metav1.Now() - require.True(t, jwt.Status.Conditions[0].LastTransitionTime.Before(&now)) -} - -func TestJWTProvider_SetLastSyncedTime(t *testing.T) { - jwt := &JWTProvider{} - syncedTime := metav1.NewTime(time.Now()) - jwt.SetLastSyncedTime(&syncedTime) - require.Equal(t, &syncedTime, jwt.Status.LastSyncedTime) -} - -func TestJWTProvider_GetSyncedConditionStatus(t *testing.T) { - cases := []corev1.ConditionStatus{ - corev1.ConditionUnknown, - corev1.ConditionFalse, - corev1.ConditionTrue, - } - for _, status := range cases { - t.Run(string(status), func(t *testing.T) { - jwt := &JWTProvider{ - Status: Status{ - Conditions: []Condition{{ - Type: ConditionSynced, - Status: status, - }}, - }, - } - - require.Equal(t, status, jwt.SyncedConditionStatus()) - }) - } -} - -func TestJWTProvider_GetConditionWhenStatusNil(t *testing.T) { - require.Nil(t, (&JWTProvider{}).GetCondition(ConditionSynced)) -} - -func TestJWTProvider_SyncedConditionStatusWhenStatusNil(t *testing.T) { - require.Equal(t, corev1.ConditionUnknown, (&JWTProvider{}).SyncedConditionStatus()) -} - -func TestJWTProvider_SyncedConditionWhenStatusNil(t *testing.T) { - status, reason, message := (&JWTProvider{}).SyncedCondition() - require.Equal(t, corev1.ConditionUnknown, status) - require.Equal(t, "", reason) - require.Equal(t, "", message) -} - -func TestJWTProvider_ConsulKind(t *testing.T) { - require.Equal(t, capi.JWTProvider, (&JWTProvider{}).ConsulKind()) -} - -func TestJWTProvider_KubeKind(t *testing.T) { - require.Equal(t, "jwtprovider", (&JWTProvider{}).KubeKind()) -} - -func TestJWTProvider_ConsulName(t *testing.T) { - require.Equal(t, "foo", (&JWTProvider{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) -} - -func TestJWTProvider_KubernetesName(t *testing.T) { - require.Equal(t, "foo", (&JWTProvider{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) -} - -func TestJWTProvider_ConsulNamespace(t *testing.T) { - require.Equal(t, common.DefaultConsulNamespace, (&JWTProvider{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}}).ConsulMirroringNS()) -} - -func TestJWTProvider_ConsulGlobalResource(t *testing.T) { - require.True(t, (&JWTProvider{}).ConsulGlobalResource()) -} - -func TestJWTProvider_ObjectMeta(t *testing.T) { - meta := metav1.ObjectMeta{ - Name: "name", - Namespace: "namespace", - } - jwt := &JWTProvider{ - ObjectMeta: meta, - } - require.Equal(t, meta, jwt.GetObjectMeta()) -} diff --git a/control-plane/api/v1alpha1/jwtprovider_webhook.go b/control-plane/api/v1alpha1/jwtprovider_webhook.go deleted file mode 100644 index c434c83c01..0000000000 --- a/control-plane/api/v1alpha1/jwtprovider_webhook.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "context" - "net/http" - - "github.com/go-logr/logr" - "github.com/hashicorp/consul-k8s/control-plane/api/common" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// +kubebuilder:object:generate=false - -type JWTProviderWebhook struct { - Logger logr.Logger - - // ConsulMeta contains metadata specific to the Consul installation. - ConsulMeta common.ConsulMeta - - decoder *admission.Decoder - client.Client -} - -// NOTE: The path value in the below line is the path to the webhook. -// If it is updated, run code-gen, update subcommand/controller/command.go -// and the consul-helm value for the path to the webhook. -// -// NOTE: The below line cannot be combined with any other comment. If it is it will break the code generation. -// -// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-jwtprovider,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=jwtproviders,versions=v1alpha1,name=mutate-jwtprovider.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 - -func (v *JWTProviderWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { - var resource JWTProvider - err := v.decoder.Decode(req, &resource) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - return common.ValidateConfigEntry(ctx, req, v.Logger, v, &resource, v.ConsulMeta) -} - -func (v *JWTProviderWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { - var resourceList JWTProviderList - if err := v.Client.List(ctx, &resourceList); err != nil { - return nil, err - } - var entries []common.ConfigEntryResource - for _, item := range resourceList.Items { - entries = append(entries, common.ConfigEntryResource(&item)) - } - return entries, nil -} - -func (v *JWTProviderWebhook) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/control-plane/api/v1alpha1/mesh_types.go b/control-plane/api/v1alpha1/mesh_types.go index 162132a47a..502e567829 100644 --- a/control-plane/api/v1alpha1/mesh_types.go +++ b/control-plane/api/v1alpha1/mesh_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -51,9 +48,6 @@ type MeshList struct { type MeshSpec struct { // TransparentProxy controls the configuration specific to proxies in "transparent" mode. Added in v1.10.0. TransparentProxy TransparentProxyMeshConfig `json:"transparentProxy,omitempty"` - // AllowEnablingPermissiveMutualTLS must be true in order to allow setting - // MutualTLSMode=permissive in either service-defaults or proxy-defaults. - AllowEnablingPermissiveMutualTLS bool `json:"allowEnablingPermissiveMutualTLS,omitempty"` // TLS defines the TLS configuration for the service mesh. TLS *MeshTLSConfig `json:"tls,omitempty"` // HTTP defines the HTTP configuration for the service mesh. @@ -195,12 +189,11 @@ func (in *Mesh) SetLastSyncedTime(time *metav1.Time) { func (in *Mesh) ToConsul(datacenter string) capi.ConfigEntry { return &capi.MeshConfigEntry{ - TransparentProxy: in.Spec.TransparentProxy.toConsul(), - AllowEnablingPermissiveMutualTLS: in.Spec.AllowEnablingPermissiveMutualTLS, - TLS: in.Spec.TLS.toConsul(), - HTTP: in.Spec.HTTP.toConsul(), - Peering: in.Spec.Peering.toConsul(), - Meta: meta(datacenter), + TransparentProxy: in.Spec.TransparentProxy.toConsul(), + TLS: in.Spec.TLS.toConsul(), + HTTP: in.Spec.HTTP.toConsul(), + Peering: in.Spec.Peering.toConsul(), + Meta: meta(datacenter), } } diff --git a/control-plane/api/v1alpha1/mesh_types_test.go b/control-plane/api/v1alpha1/mesh_types_test.go index f2ea714f60..392c38d354 100644 --- a/control-plane/api/v1alpha1/mesh_types_test.go +++ b/control-plane/api/v1alpha1/mesh_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -48,7 +45,6 @@ func TestMesh_MatchesConsul(t *testing.T) { TransparentProxy: TransparentProxyMeshConfig{ MeshDestinationsOnly: true, }, - AllowEnablingPermissiveMutualTLS: true, TLS: &MeshTLSConfig{ Incoming: &MeshDirectionalTLSConfig{ TLSMinVersion: "TLSv1_0", @@ -73,7 +69,6 @@ func TestMesh_MatchesConsul(t *testing.T) { TransparentProxy: capi.TransparentProxyMeshConfig{ MeshDestinationsOnly: true, }, - AllowEnablingPermissiveMutualTLS: true, TLS: &capi.MeshTLSConfig{ Incoming: &capi.MeshDirectionalTLSConfig{ TLSMinVersion: "TLSv1_0", @@ -150,7 +145,6 @@ func TestMesh_ToConsul(t *testing.T) { TransparentProxy: TransparentProxyMeshConfig{ MeshDestinationsOnly: true, }, - AllowEnablingPermissiveMutualTLS: true, TLS: &MeshTLSConfig{ Incoming: &MeshDirectionalTLSConfig{ TLSMinVersion: "TLSv1_0", @@ -175,7 +169,6 @@ func TestMesh_ToConsul(t *testing.T) { TransparentProxy: capi.TransparentProxyMeshConfig{ MeshDestinationsOnly: true, }, - AllowEnablingPermissiveMutualTLS: true, TLS: &capi.MeshTLSConfig{ Incoming: &capi.MeshDirectionalTLSConfig{ TLSMinVersion: "TLSv1_0", diff --git a/control-plane/api/v1alpha1/mesh_webhook.go b/control-plane/api/v1alpha1/mesh_webhook.go index 1c0ea3088e..5c714c4e5f 100644 --- a/control-plane/api/v1alpha1/mesh_webhook.go +++ b/control-plane/api/v1alpha1/mesh_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/mesh_webhook_test.go b/control-plane/api/v1alpha1/mesh_webhook_test.go index 2266a6b77e..83cedb0ba4 100644 --- a/control-plane/api/v1alpha1/mesh_webhook_test.go +++ b/control-plane/api/v1alpha1/mesh_webhook_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringacceptor_types.go b/control-plane/api/v1alpha1/peeringacceptor_types.go index e1ca013475..032870cb80 100644 --- a/control-plane/api/v1alpha1/peeringacceptor_types.go +++ b/control-plane/api/v1alpha1/peeringacceptor_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringacceptor_types_test.go b/control-plane/api/v1alpha1/peeringacceptor_types_test.go index d7c05e7e2c..33d437f46a 100644 --- a/control-plane/api/v1alpha1/peeringacceptor_types_test.go +++ b/control-plane/api/v1alpha1/peeringacceptor_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringacceptor_webhook.go b/control-plane/api/v1alpha1/peeringacceptor_webhook.go index 2bb48b3580..60367c1384 100644 --- a/control-plane/api/v1alpha1/peeringacceptor_webhook.go +++ b/control-plane/api/v1alpha1/peeringacceptor_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringacceptor_webhook_test.go b/control-plane/api/v1alpha1/peeringacceptor_webhook_test.go index 251ab87c8e..02ddbca588 100644 --- a/control-plane/api/v1alpha1/peeringacceptor_webhook_test.go +++ b/control-plane/api/v1alpha1/peeringacceptor_webhook_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringdialer_types.go b/control-plane/api/v1alpha1/peeringdialer_types.go index 89c16bf3ad..4ddde3fe2f 100644 --- a/control-plane/api/v1alpha1/peeringdialer_types.go +++ b/control-plane/api/v1alpha1/peeringdialer_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringdialer_types_test.go b/control-plane/api/v1alpha1/peeringdialer_types_test.go index 69c3569acd..7e358facb8 100644 --- a/control-plane/api/v1alpha1/peeringdialer_types_test.go +++ b/control-plane/api/v1alpha1/peeringdialer_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringdialer_webhook.go b/control-plane/api/v1alpha1/peeringdialer_webhook.go index 76c2011e4c..fc0b1c38f6 100644 --- a/control-plane/api/v1alpha1/peeringdialer_webhook.go +++ b/control-plane/api/v1alpha1/peeringdialer_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/peeringdialer_webhook_test.go b/control-plane/api/v1alpha1/peeringdialer_webhook_test.go index 42372451d1..df69923a92 100644 --- a/control-plane/api/v1alpha1/peeringdialer_webhook_test.go +++ b/control-plane/api/v1alpha1/peeringdialer_webhook_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/proxydefaults_types.go b/control-plane/api/v1alpha1/proxydefaults_types.go index 7b1529b941..215ec708ff 100644 --- a/control-plane/api/v1alpha1/proxydefaults_types.go +++ b/control-plane/api/v1alpha1/proxydefaults_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -67,17 +64,6 @@ type ProxyDefaultsSpec struct { // Note: This cannot be set using the CRD and should be set using annotations on the // services that are part of the mesh. TransparentProxy *TransparentProxy `json:"transparentProxy,omitempty"` - // MutualTLSMode controls whether mutual TLS is required for all incoming - // connections when transparent proxy is enabled. This can be set to - // "permissive" or "strict". "strict" is the default which requires mutual - // TLS for incoming connections. In the insecure "permissive" mode, - // connections to the sidecar proxy public listener port require mutual - // TLS, but connections to the service port do not require mutual TLS and - // are proxied to the application unmodified. Note: Intentions are not - // enforced for non-mTLS connections. To keep your services secure, we - // recommend using "strict" mode whenever possible and enabling - // "permissive" mode only when necessary. - MutualTLSMode MutualTLSMode `json:"mutualTLSMode,omitempty"` // Config is an arbitrary map of configuration values used by Connect proxies. // Any values that your proxy allows can be configured globally here. // Supports JSON config values. See https://www.consul.io/docs/connect/proxies/envoy#configuration-formatting @@ -89,15 +75,6 @@ type ProxyDefaultsSpec struct { MeshGateway MeshGateway `json:"meshGateway,omitempty"` // Expose controls the default expose path configuration for Envoy. Expose Expose `json:"expose,omitempty"` - // AccessLogs controls all envoy instances' access logging configuration. - AccessLogs *AccessLogs `json:"accessLogs,omitempty"` - // EnvoyExtensions are a list of extensions to modify Envoy proxy configuration. - EnvoyExtensions EnvoyExtensions `json:"envoyExtensions,omitempty"` - // FailoverPolicy specifies the exact mechanism used for failover. - FailoverPolicy *FailoverPolicy `json:"failoverPolicy,omitempty"` - // PrioritizeByLocality controls whether the locality of services within the - // local partition will be used to prioritize connectivity. - PrioritizeByLocality *PrioritizeByLocality `json:"prioritizeByLocality,omitempty"` } func (in *ProxyDefaults) GetObjectMeta() metav1.ObjectMeta { @@ -182,18 +159,13 @@ func (in *ProxyDefaults) SetLastSyncedTime(time *metav1.Time) { func (in *ProxyDefaults) ToConsul(datacenter string) capi.ConfigEntry { consulConfig := in.convertConfig() return &capi.ProxyConfigEntry{ - Kind: in.ConsulKind(), - Name: in.ConsulName(), - MeshGateway: in.Spec.MeshGateway.toConsul(), - Expose: in.Spec.Expose.toConsul(), - Config: consulConfig, - TransparentProxy: in.Spec.TransparentProxy.toConsul(), - MutualTLSMode: in.Spec.MutualTLSMode.toConsul(), - AccessLogs: in.Spec.AccessLogs.toConsul(), - EnvoyExtensions: in.Spec.EnvoyExtensions.toConsul(), - FailoverPolicy: in.Spec.FailoverPolicy.toConsul(), - PrioritizeByLocality: in.Spec.PrioritizeByLocality.toConsul(), - Meta: meta(datacenter), + Kind: in.ConsulKind(), + Name: in.ConsulName(), + MeshGateway: in.Spec.MeshGateway.toConsul(), + Expose: in.Spec.Expose.toConsul(), + Config: consulConfig, + TransparentProxy: in.Spec.TransparentProxy.toConsul(), + Meta: meta(datacenter), } } @@ -217,23 +189,13 @@ func (in *ProxyDefaults) Validate(_ common.ConsulMeta) error { if err := in.Spec.TransparentProxy.validate(path.Child("transparentProxy")); err != nil { allErrs = append(allErrs, err) } - if err := in.Spec.MutualTLSMode.validate(); err != nil { - allErrs = append(allErrs, field.Invalid(path.Child("mutualTLSMode"), in.Spec.MutualTLSMode, err.Error())) - } if err := in.Spec.Mode.validate(path.Child("mode")); err != nil { allErrs = append(allErrs, err) } if err := in.validateConfig(path.Child("config")); err != nil { allErrs = append(allErrs, err) } - if err := in.Spec.AccessLogs.validate(path.Child("accessLogs")); err != nil { - allErrs = append(allErrs, err) - } allErrs = append(allErrs, in.Spec.Expose.validate(path.Child("expose"))...) - allErrs = append(allErrs, in.Spec.EnvoyExtensions.validate(path.Child("envoyExtensions"))...) - allErrs = append(allErrs, in.Spec.FailoverPolicy.validate(path.Child("failoverPolicy"))...) - allErrs = append(allErrs, in.Spec.PrioritizeByLocality.validate(path.Child("prioritizeByLocality"))...) - if len(allErrs) > 0 { return apierrors.NewInvalid( schema.GroupKind{Group: ConsulHashicorpGroup, Kind: ProxyDefaultsKubeKind}, @@ -271,93 +233,7 @@ func (in *ProxyDefaults) validateConfig(path *field.Path) *field.Error { } var outConfig map[string]interface{} if err := json.Unmarshal(in.Spec.Config, &outConfig); err != nil { - return field.Invalid(path, string(in.Spec.Config), fmt.Sprintf(`must be valid map value: %s`, err)) + return field.Invalid(path, in.Spec.Config, fmt.Sprintf(`must be valid map value: %s`, err)) } return nil } - -// LogSinkType represents the destination for Envoy access logs. -// One of "file", "stderr", or "stdout". -type LogSinkType string - -const ( - DefaultLogSinkType LogSinkType = "" - FileLogSinkType LogSinkType = "file" - StdErrLogSinkType LogSinkType = "stderr" - StdOutLogSinkType LogSinkType = "stdout" -) - -// AccessLogs describes the access logging configuration for all Envoy proxies in the mesh. -type AccessLogs struct { - // Enabled turns on all access logging - Enabled bool `json:"enabled,omitempty"` - - // DisableListenerLogs turns off just listener logs for connections rejected by Envoy because they don't - // have a matching listener filter. - DisableListenerLogs bool `json:"disableListenerLogs,omitempty"` - - // Type selects the output for logs - // one of "file", "stderr". "stdout" - Type LogSinkType `json:"type,omitempty"` - - // Path is the output file to write logs for file-type logging - Path string `json:"path,omitempty"` - - // JSONFormat is a JSON-formatted string of an Envoy access log format dictionary. - // See for more info on formatting: https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#format-dictionaries - // Defining JSONFormat and TextFormat is invalid. - JSONFormat string `json:"jsonFormat,omitempty"` - - // TextFormat is a representation of Envoy access logs format. - // See for more info on formatting: https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#format-strings - // Defining JSONFormat and TextFormat is invalid. - TextFormat string `json:"textFormat,omitempty"` -} - -func (in *AccessLogs) validate(path *field.Path) *field.Error { - if in == nil { - return nil - } - - switch in.Type { - case DefaultLogSinkType, StdErrLogSinkType, StdOutLogSinkType: - // OK - case FileLogSinkType: - if in.Path == "" { - return field.Invalid(path.Child("path"), in.Path, "path must be specified when using file type access logs") - } - default: - return field.Invalid(path.Child("type"), in.Type, "invalid access log type (must be one of \"stdout\", \"stderr\", \"file\"") - } - - if in.JSONFormat != "" && in.TextFormat != "" { - return field.Invalid(path.Child("textFormat"), in.TextFormat, "cannot specify both access log jsonFormat and textFormat") - } - - if in.Type != FileLogSinkType && in.Path != "" { - return field.Invalid(path.Child("path"), in.Path, "path is only valid for file type access logs") - } - - if in.JSONFormat != "" { - msg := json.RawMessage{} - if err := json.Unmarshal([]byte(in.JSONFormat), &msg); err != nil { - return field.Invalid(path.Child("jsonFormat"), in.JSONFormat, "invalid access log json") - } - } - - return nil -} - -func (in *AccessLogs) toConsul() *capi.AccessLogsConfig { - if in == nil { - return nil - } - return &capi.AccessLogsConfig{ - Enabled: in.Enabled, - DisableListenerLogs: in.DisableListenerLogs, - JSONFormat: in.JSONFormat, - Path: in.Path, - TextFormat: in.TextFormat, - Type: capi.LogSinkType(in.Type), - } -} diff --git a/control-plane/api/v1alpha1/proxydefaults_types_test.go b/control-plane/api/v1alpha1/proxydefaults_types_test.go index 6a965fce3a..2950a3a36e 100644 --- a/control-plane/api/v1alpha1/proxydefaults_types_test.go +++ b/control-plane/api/v1alpha1/proxydefaults_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -74,33 +71,6 @@ func TestProxyDefaults_MatchesConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: MutualTLSModePermissive, - AccessLogs: &AccessLogs{ - Enabled: true, - DisableListenerLogs: true, - Type: FileLogSinkType, - Path: "/var/log/envoy.logs", - TextFormat: "ITS WORKING %START_TIME%", - }, - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: json.RawMessage(`{"ClusterName": "zipkin_cluster", "Port": "9411", "CollectorEndpoint":"/api/v2/spans"}`), - Required: true, - }, - }, - FailoverPolicy: &FailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-1"}, - }, - PrioritizeByLocality: &PrioritizeByLocality{ - Mode: "failover", - }, }, }, Theirs: &capi.ProxyConfigEntry{ @@ -133,40 +103,6 @@ func TestProxyDefaults_MatchesConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: capi.MutualTLSModePermissive, - AccessLogs: &capi.AccessLogsConfig{ - Enabled: true, - DisableListenerLogs: true, - Type: capi.FileLogSinkType, - Path: "/var/log/envoy.logs", - TextFormat: "ITS WORKING %START_TIME%", - }, - EnvoyExtensions: []capi.EnvoyExtension{ - { - Name: "aws_request_signing", - Arguments: map[string]interface{}{ - "AWSServiceName": "s3", - "Region": "us-west-2", - }, - Required: false, - }, - { - Name: "zipkin", - Arguments: map[string]interface{}{ - "ClusterName": "zipkin_cluster", - "Port": "9411", - "CollectorEndpoint": "/api/v2/spans", - }, - Required: true, - }, - }, - FailoverPolicy: &capi.ServiceResolverFailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-1"}, - }, - PrioritizeByLocality: &capi.ServiceResolverPrioritizeByLocality{ - Mode: "failover", - }, }, Matches: true, }, @@ -300,33 +236,6 @@ func TestProxyDefaults_ToConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: MutualTLSModeStrict, - AccessLogs: &AccessLogs{ - Enabled: true, - DisableListenerLogs: true, - Type: FileLogSinkType, - Path: "/var/log/envoy.logs", - TextFormat: "ITS WORKING %START_TIME%", - }, - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: json.RawMessage(`{"ClusterName": "zipkin_cluster", "Port": "9411", "CollectorEndpoint":"/api/v2/spans"}`), - Required: true, - }, - }, - FailoverPolicy: &FailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-1"}, - }, - PrioritizeByLocality: &PrioritizeByLocality{ - Mode: "none", - }, }, }, Exp: &capi.ProxyConfigEntry{ @@ -360,40 +269,6 @@ func TestProxyDefaults_ToConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: capi.MutualTLSModeStrict, - AccessLogs: &capi.AccessLogsConfig{ - Enabled: true, - DisableListenerLogs: true, - Type: capi.FileLogSinkType, - Path: "/var/log/envoy.logs", - TextFormat: "ITS WORKING %START_TIME%", - }, - EnvoyExtensions: []capi.EnvoyExtension{ - { - Name: "aws_request_signing", - Arguments: map[string]interface{}{ - "AWSServiceName": "s3", - "Region": "us-west-2", - }, - Required: false, - }, - { - Name: "zipkin", - Arguments: map[string]interface{}{ - "ClusterName": "zipkin_cluster", - "Port": "9411", - "CollectorEndpoint": "/api/v2/spans", - }, - Required: true, - }, - }, - FailoverPolicy: &capi.ServiceResolverFailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-1"}, - }, - PrioritizeByLocality: &capi.ServiceResolverPrioritizeByLocality{ - Mode: "none", - }, Meta: map[string]string{ common.SourceKey: common.SourceValue, common.DatacenterKey: "datacenter", @@ -418,30 +293,8 @@ func TestProxyDefaults_Validate(t *testing.T) { input *ProxyDefaults expectedErrMsg string }{ - "valid envoyExtension": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: json.RawMessage(`{"ClusterName": "zipkin_cluster", "Port": "9411", "CollectorEndpoint":"/api/v2/spans"}`), - Required: true, - }, - }, - }, - }, - expectedErrMsg: "", - }, "meshgateway.mode": { - input: &ProxyDefaults{ + &ProxyDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "global", }, @@ -451,10 +304,10 @@ func TestProxyDefaults_Validate(t *testing.T) { }, }, }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.meshGateway.mode: Invalid value: "foobar": must be one of "remote", "local", "none", ""`, + `proxydefaults.consul.hashicorp.com "global" is invalid: spec.meshGateway.mode: Invalid value: "foobar": must be one of "remote", "local", "none", ""`, }, "expose.paths[].protocol": { - input: &ProxyDefaults{ + &ProxyDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "global", }, @@ -469,10 +322,10 @@ func TestProxyDefaults_Validate(t *testing.T) { }, }, }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.expose.paths[0].protocol: Invalid value: "invalid-protocol": must be one of "http", "http2"`, + `proxydefaults.consul.hashicorp.com "global" is invalid: spec.expose.paths[0].protocol: Invalid value: "invalid-protocol": must be one of "http", "http2"`, }, "expose.paths[].path": { - input: &ProxyDefaults{ + &ProxyDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "global", }, @@ -487,10 +340,10 @@ func TestProxyDefaults_Validate(t *testing.T) { }, }, }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.expose.paths[0].path: Invalid value: "invalid-path": must begin with a '/'`, + `proxydefaults.consul.hashicorp.com "global" is invalid: spec.expose.paths[0].path: Invalid value: "invalid-path": must begin with a '/'`, }, "transparentProxy.outboundListenerPort": { - input: &ProxyDefaults{ + &ProxyDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "global", }, @@ -500,10 +353,10 @@ func TestProxyDefaults_Validate(t *testing.T) { }, }, }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port", + "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port", }, "mode": { - input: &ProxyDefaults{ + &ProxyDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "global", }, @@ -511,174 +364,10 @@ func TestProxyDefaults_Validate(t *testing.T) { Mode: proxyModeRef("transparent"), }, }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode", - }, - "mutualTLSMode": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - MutualTLSMode: MutualTLSMode("asdf"), - }, - }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.mutualTLSMode: Invalid value: "asdf": Must be one of "", "strict", or "permissive".`, - }, - "accessLogs.type": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - AccessLogs: &AccessLogs{ - Type: "foo", - }, - }, - }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.accessLogs.type: Invalid value: \"foo\": invalid access log type (must be one of \"stdout\", \"stderr\", \"file\"", - }, - "accessLogs.path missing": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - AccessLogs: &AccessLogs{ - Type: "file", - }, - }, - }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.accessLogs.path: Invalid value: \"\": path must be specified when using file type access logs", - }, - "accessLogs.path for wrong type": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - AccessLogs: &AccessLogs{ - Path: "/var/log/envoy.logs", - }, - }, - }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.accessLogs.path: Invalid value: \"/var/log/envoy.logs\": path is only valid for file type access logs", - }, - "accessLogs.jsonFormat": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - AccessLogs: &AccessLogs{ - JSONFormat: "{ \"start_time\": \"%START_TIME\"", // intentionally missing the closing brace - }, - }, - }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.accessLogs.jsonFormat: Invalid value: \"{ \\\"start_time\\\": \\\"%START_TIME\\\"\": invalid access log json", - }, - "accessLogs.textFormat": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - AccessLogs: &AccessLogs{ - JSONFormat: "{ \"start_time\": \"%START_TIME\" }", - TextFormat: "MY START TIME %START_TIME", - }, - }, - }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.accessLogs.textFormat: Invalid value: \"MY START TIME %START_TIME\": cannot specify both access log jsonFormat and textFormat", - }, - "envoyExtension.arguments single empty": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: nil, - Required: true, - }, - }, - }, - }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.envoyExtensions.envoyExtension[1].arguments: Required value: arguments must be defined`, - }, - "envoyExtension.arguments multi empty": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: nil, - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: nil, - Required: true, - }, - }, - }, - }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: [spec.envoyExtensions.envoyExtension[0].arguments: Required value: arguments must be defined, spec.envoyExtensions.envoyExtension[1].arguments: Required value: arguments must be defined]`, - }, - "envoyExtension.arguments invalid json": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"SOME_INVALID_JSON"}`), - Required: false, - }, - }, - }, - }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.envoyExtensions.envoyExtension[0].arguments: Invalid value: "{\"SOME_INVALID_JSON\"}": must be valid map value: invalid character '}' after object key`, - }, - "failoverPolicy.mode invalid": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - FailoverPolicy: &FailoverPolicy{ - Mode: "wrong-mode", - }, - }, - }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.failoverPolicy.mode: Invalid value: "wrong-mode": must be one of "", "sequential", "order-by-locality"`, - }, - "prioritize by locality invalid": { - input: &ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "global", - }, - Spec: ProxyDefaultsSpec{ - PrioritizeByLocality: &PrioritizeByLocality{ - Mode: "wrong-mode", - }, - }, - }, - expectedErrMsg: `proxydefaults.consul.hashicorp.com "global" is invalid: spec.prioritizeByLocality.mode: Invalid value: "wrong-mode": must be one of "", "none", "failover"`, + "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode", }, "multi-error": { - input: &ProxyDefaults{ + &ProxyDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "global", }, @@ -697,14 +386,10 @@ func TestProxyDefaults_Validate(t *testing.T) { TransparentProxy: &TransparentProxy{ OutboundListenerPort: 1000, }, - AccessLogs: &AccessLogs{ - JSONFormat: "{ \"start_time\": \"%START_TIME\" }", - TextFormat: "MY START TIME %START_TIME", - }, Mode: proxyModeRef("transparent"), }, }, - expectedErrMsg: "proxydefaults.consul.hashicorp.com \"global\" is invalid: [spec.meshGateway.mode: Invalid value: \"invalid-mode\": must be one of \"remote\", \"local\", \"none\", \"\", spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port, spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode, spec.accessLogs.textFormat: Invalid value: \"MY START TIME %START_TIME\": cannot specify both access log jsonFormat and textFormat, spec.expose.paths[0].path: Invalid value: \"invalid-path\": must begin with a '/', spec.expose.paths[0].protocol: Invalid value: \"invalid-protocol\": must be one of \"http\", \"http2\"]", + "proxydefaults.consul.hashicorp.com \"global\" is invalid: [spec.meshGateway.mode: Invalid value: \"invalid-mode\": must be one of \"remote\", \"local\", \"none\", \"\", spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port, spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode, spec.expose.paths[0].path: Invalid value: \"invalid-path\": must begin with a '/', spec.expose.paths[0].protocol: Invalid value: \"invalid-protocol\": must be one of \"http\", \"http2\"]", }, } for name, testCase := range cases { diff --git a/control-plane/api/v1alpha1/proxydefaults_webhook.go b/control-plane/api/v1alpha1/proxydefaults_webhook.go index ced4853b12..3873516074 100644 --- a/control-plane/api/v1alpha1/proxydefaults_webhook.go +++ b/control-plane/api/v1alpha1/proxydefaults_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/proxydefaults_webhook_test.go b/control-plane/api/v1alpha1/proxydefaults_webhook_test.go index ade806b7e3..c1aebe3e11 100644 --- a/control-plane/api/v1alpha1/proxydefaults_webhook_test.go +++ b/control-plane/api/v1alpha1/proxydefaults_webhook_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -49,7 +46,7 @@ func TestValidateProxyDefault(t *testing.T) { }, expAllow: false, // This error message is because the value "1" is valid JSON but is an invalid map - expErrMessage: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.config: Invalid value: \"1\": must be valid map value: json: cannot unmarshal number into Go value of type map[string]interface {}", + expErrMessage: "proxydefaults.consul.hashicorp.com \"global\" is invalid: spec.config: Invalid value: json.RawMessage{0x31}: must be valid map value: json: cannot unmarshal number into Go value of type map[string]interface {}", }, "proxy default exists": { existingResources: []runtime.Object{&ProxyDefaults{ diff --git a/control-plane/api/v1alpha1/routeretryfilter_types.go b/control-plane/api/v1alpha1/routeretryfilter_types.go deleted file mode 100644 index 79fa85c608..0000000000 --- a/control-plane/api/v1alpha1/routeretryfilter_types.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func init() { - SchemeBuilder.Register(&RouteRetryFilter{}, &RouteRetryFilterList{}) -} - -const RouteRetryFilterKind = "RouteRetryFilter" - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// RouteRetryFilter is the Schema for the routeretryfilters API -// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" -// +kubebuilder:printcolumn:name="Last Synced",type="date",JSONPath=".status.lastSyncedTime",description="The last successful synced time of the resource with Consul" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" -type RouteRetryFilter struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec RouteRetryFilterSpec `json:"spec,omitempty"` - Status `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// RouteRetryFilterList contains a list of RouteRetryFilter. -type RouteRetryFilterList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []RouteRetryFilter `json:"items"` -} - -// RouteRetryFilterSpec defines the desired state of RouteRetryFilter. -type RouteRetryFilterSpec struct { - // +kubebuilder:validation:Minimum:=0 - // +kubebuilder:validation:Optional - NumRetries *uint32 `json:"numRetries"` - // +kubebuilder:validation:Optional - RetryOn []string `json:"retryOn"` - // +kubebuilder:validation:Optional - RetryOnStatusCodes []uint32 `json:"retryOnStatusCodes"` - // +kubebuilder:validation:Optional - RetryOnConnectFailure *bool `json:"retryOnConnectFailure"` -} - -func (h *RouteRetryFilter) GetNamespace() string { - return h.Namespace -} diff --git a/control-plane/api/v1alpha1/routetimeoutfilter_types.go b/control-plane/api/v1alpha1/routetimeoutfilter_types.go deleted file mode 100644 index 59b25f62ea..0000000000 --- a/control-plane/api/v1alpha1/routetimeoutfilter_types.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "time" -) - -func init() { - SchemeBuilder.Register(&RouteTimeoutFilter{}, &RouteTimeoutFilterList{}) -} - -const RouteTimeoutFilterKind = "RouteTimeoutFilter" - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// RouteTimeoutFilter is the Schema for the httproutetimeoutfilters API -// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" -// +kubebuilder:printcolumn:name="Last Synced",type="date",JSONPath=".status.lastSyncedTime",description="The last successful synced time of the resource with Consul" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" -type RouteTimeoutFilter struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec RouteTimeoutFilterSpec `json:"spec,omitempty"` - Status `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// RouteTimeoutFilterList contains a list of RouteTimeoutFilter. -type RouteTimeoutFilterList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []RouteTimeoutFilter `json:"items"` -} - -// RouteTimeoutFilterSpec defines the desired state of RouteTimeoutFilter. -type RouteTimeoutFilterSpec struct { - // +kubebuilder:validation:Optional - RequestTimeout time.Duration `json:"requestTimeout"` - - // +kubebuilder:validation:Optional - IdleTimeout time.Duration `json:"idleTimeout"` -} - -func (h *RouteTimeoutFilter) GetNamespace() string { - return h.Namespace -} diff --git a/control-plane/api/v1alpha1/samenessgroup_types.go b/control-plane/api/v1alpha1/samenessgroup_types.go deleted file mode 100644 index 86b02445f6..0000000000 --- a/control-plane/api/v1alpha1/samenessgroup_types.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "encoding/json" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/hashicorp/consul-k8s/control-plane/api/common" - "github.com/hashicorp/consul/api" - capi "github.com/hashicorp/consul/api" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -const ( - SamenessGroupKubeKind string = "samenessgroup" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -func init() { - SchemeBuilder.Register(&SamenessGroup{}, &SamenessGroupList{}) -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status - -// SamenessGroup is the Schema for the samenessgroups API -// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" -// +kubebuilder:printcolumn:name="Last Synced",type="date",JSONPath=".status.lastSyncedTime",description="The last successful synced time of the resource with Consul" -// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" -// +kubebuilder:resource:shortName="sameness-group" -type SamenessGroup struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - Spec SamenessGroupSpec `json:"spec,omitempty"` - Status `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// SamenessGroupList contains a list of SamenessGroup. -type SamenessGroupList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []SamenessGroup `json:"items"` -} - -// SamenessGroupSpec defines the desired state of SamenessGroup. -type SamenessGroupSpec struct { - // DefaultForFailover indicates that upstream requests to members of the given sameness group will implicitly failover between members of this sameness group. - // When DefaultForFailover is true, the local partition must be a member of the sameness group or IncludeLocal must be set to true. - DefaultForFailover bool `json:"defaultForFailover,omitempty"` - // IncludeLocal is used to include the local partition as the first member of the sameness group. - // The local partition can only be a member of a single sameness group. - IncludeLocal bool `json:"includeLocal,omitempty"` - // Members are the partitions and peers that are part of the sameness group. - // If a member of a sameness group does not exist, it will be ignored. - Members []SamenessGroupMember `json:"members,omitempty"` -} - -type SamenessGroupMember struct { - // The partitions and peers that are part of the sameness group. - // A sameness group member cannot define both peer and partition at the same time. - Partition string `json:"partition,omitempty"` - Peer string `json:"peer,omitempty"` -} - -func (in *SamenessGroup) GetObjectMeta() metav1.ObjectMeta { - return in.ObjectMeta -} - -func (in *SamenessGroup) AddFinalizer(name string) { - in.ObjectMeta.Finalizers = append(in.Finalizers(), name) -} - -func (in *SamenessGroup) RemoveFinalizer(name string) { - var newFinalizers []string - for _, oldF := range in.Finalizers() { - if oldF != name { - newFinalizers = append(newFinalizers, oldF) - } - } - in.ObjectMeta.Finalizers = newFinalizers -} - -func (in *SamenessGroup) Finalizers() []string { - return in.ObjectMeta.Finalizers -} - -func (in *SamenessGroup) ConsulKind() string { - return capi.SamenessGroup -} - -func (in *SamenessGroup) ConsulGlobalResource() bool { - return false -} - -func (in *SamenessGroup) ConsulMirroringNS() string { - return common.DefaultConsulNamespace -} - -func (in *SamenessGroup) KubeKind() string { - return SamenessGroupKubeKind -} - -func (in *SamenessGroup) ConsulName() string { - return in.ObjectMeta.Name -} - -func (in *SamenessGroup) KubernetesName() string { - return in.ObjectMeta.Name -} - -func (in *SamenessGroup) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { - in.Status.Conditions = Conditions{ - { - Type: ConditionSynced, - Status: status, - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: message, - }, - } -} - -func (in *SamenessGroup) SetLastSyncedTime(time *metav1.Time) { - in.Status.LastSyncedTime = time -} - -func (in *SamenessGroup) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { - cond := in.Status.GetCondition(ConditionSynced) - if cond == nil { - return corev1.ConditionUnknown, "", "" - } - return cond.Status, cond.Reason, cond.Message -} - -func (in *SamenessGroup) SyncedConditionStatus() corev1.ConditionStatus { - cond := in.Status.GetCondition(ConditionSynced) - if cond == nil { - return corev1.ConditionUnknown - } - return cond.Status -} - -func (in *SamenessGroup) ToConsul(datacenter string) api.ConfigEntry { - return &capi.SamenessGroupConfigEntry{ - Kind: in.ConsulKind(), - Name: in.ConsulName(), - DefaultForFailover: in.Spec.DefaultForFailover, - IncludeLocal: in.Spec.IncludeLocal, - Members: SamenessGroupMembers(in.Spec.Members).toConsul(), - Meta: meta(datacenter), - } -} - -func (in *SamenessGroup) MatchesConsul(candidate api.ConfigEntry) bool { - configEntry, ok := candidate.(*capi.SamenessGroupConfigEntry) - if !ok { - return false - } - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.SamenessGroupConfigEntry{}, "Partition", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty(), - cmp.Comparer(transparentProxyConfigComparer)) -} - -func (in *SamenessGroup) Validate(consulMeta common.ConsulMeta) error { - var allErrs field.ErrorList - path := field.NewPath("spec") - - if in == nil { - return nil - } - if in.Name == "" { - allErrs = append(allErrs, field.Invalid(path.Child("name"), in.Name, "sameness groups must have a name defined")) - } - - partition := consulMeta.Partition - includesLocal := in.Spec.IncludeLocal - - if in.ObjectMeta.Namespace != "default" && in.ObjectMeta.Namespace != "" { - allErrs = append(allErrs, field.Invalid(path.Child("name"), consulMeta.DestinationNamespace, "sameness groups must reside in the default namespace")) - } - - if len(in.Spec.Members) == 0 { - asJSON, _ := json.Marshal(in.Spec.Members) - allErrs = append(allErrs, field.Invalid(path.Child("members"), string(asJSON), "sameness groups must have at least one member")) - } - - seenMembers := make(map[SamenessGroupMember]struct{}) - for i, m := range in.Spec.Members { - if partition == m.Partition { - includesLocal = true - } - if err := m.validate(path.Child("members").Index(i)); err != nil { - allErrs = append(allErrs, err) - } - if _, ok := seenMembers[m]; ok { - asJSON, _ := json.Marshal(m) - allErrs = append(allErrs, field.Invalid(path.Child("members").Index(i), string(asJSON), "sameness group members must be unique")) - } - seenMembers[m] = struct{}{} - - } - - if !includesLocal { - allErrs = append(allErrs, field.Invalid(path.Child("members"), in.Spec.IncludeLocal, "the local partition must be a member of sameness groups")) - } - - if len(allErrs) > 0 { - return apierrors.NewInvalid( - schema.GroupKind{Group: ConsulHashicorpGroup, Kind: SamenessGroupKubeKind}, - in.KubernetesName(), allErrs) - } - - return nil -} - -// DefaultNamespaceFields has no behaviour here as sameness-groups have no namespace specific fields. -func (in *SamenessGroup) DefaultNamespaceFields(_ common.ConsulMeta) { -} - -type SamenessGroupMembers []SamenessGroupMember - -func (in SamenessGroupMembers) toConsul() []capi.SamenessGroupMember { - if in == nil { - return nil - } - - outMembers := make([]capi.SamenessGroupMember, 0, len(in)) - for _, e := range in { - consulMember := capi.SamenessGroupMember{ - Peer: e.Peer, - Partition: e.Partition, - } - outMembers = append(outMembers, consulMember) - } - return outMembers -} - -func (in *SamenessGroupMember) validate(path *field.Path) *field.Error { - asJSON, _ := json.Marshal(in) - - if in == nil { - return field.Invalid(path, string(asJSON), "sameness group member is nil") - } - if in.isEmpty() { - return field.Invalid(path, string(asJSON), "sameness group members must specify either partition or peer") - } - // We do not allow referencing peer connections in other partitions. - if in.Peer != "" && in.Partition != "" { - return field.Invalid(path, string(asJSON), "sameness group members cannot specify both partition and peer in the same entry") - } - return nil -} - -func (in *SamenessGroupMember) isEmpty() bool { - return in.Peer == "" && in.Partition == "" -} diff --git a/control-plane/api/v1alpha1/samenessgroup_types_test.go b/control-plane/api/v1alpha1/samenessgroup_types_test.go deleted file mode 100644 index 0f461701cc..0000000000 --- a/control-plane/api/v1alpha1/samenessgroup_types_test.go +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "github.com/hashicorp/consul-k8s/control-plane/api/common" - capi "github.com/hashicorp/consul/api" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "testing" - "time" -) - -func TestSamenessGroups_ToConsul(t *testing.T) { - cases := map[string]struct { - input *SamenessGroup - expected *capi.SamenessGroupConfigEntry - }{ - "empty fields": { - &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: SamenessGroupSpec{}, - }, - &capi.SamenessGroupConfigEntry{ - Name: "foo", - Kind: capi.SamenessGroup, - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - }, - }, - "every field set": { - &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{ - { - Peer: "peer2", - }, - { - Partition: "p2", - }, - }, - }, - }, - &capi.SamenessGroupConfigEntry{ - Name: "foo", - Kind: capi.SamenessGroup, - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - DefaultForFailover: true, - IncludeLocal: true, - Members: []capi.SamenessGroupMember{ - { - Peer: "peer2", - }, - { - Partition: "p2", - }, - }, - }, - }, - } - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - output := testCase.input.ToConsul("datacenter") - require.Equal(t, testCase.expected, output) - }) - } -} - -func TestSamenessGroups_MatchesConsul(t *testing.T) { - cases := map[string]struct { - internal *SamenessGroup - consul capi.ConfigEntry - matches bool - }{ - "empty fields matches": { - &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-test-sameness-group", - }, - Spec: SamenessGroupSpec{}, - }, - &capi.SamenessGroupConfigEntry{ - Kind: capi.SamenessGroup, - Name: "my-test-sameness-group", - CreateIndex: 1, - ModifyIndex: 2, - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - }, - true, - }, - "all fields populated matches": { - &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-test-sameness-group", - }, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{ - { - Peer: "peer2", - }, - { - Partition: "p2", - }, - }, - }, - }, - &capi.SamenessGroupConfigEntry{ - Kind: capi.SamenessGroup, - Name: "my-test-sameness-group", - Meta: map[string]string{ - common.SourceKey: common.SourceValue, - common.DatacenterKey: "datacenter", - }, - DefaultForFailover: true, - IncludeLocal: true, - Members: []capi.SamenessGroupMember{ - { - Peer: "peer2", - }, - { - Partition: "p2", - }, - }, - }, - true, - }, - } - - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - require.Equal(t, testCase.matches, testCase.internal.MatchesConsul(testCase.consul)) - }) - } -} - -func TestSamenessGroups_Validate(t *testing.T) { - cases := map[string]struct { - input *SamenessGroup - partitionsEnabled bool - expectedErrMsg string - }{ - "valid": { - input: &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-sameness-group", - }, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{ - { - Peer: "peer2", - Partition: "", - }, - { - Peer: "", - Partition: "p2", - }, - }, - }, - }, - partitionsEnabled: true, - expectedErrMsg: "", - }, - "invalid - with peer and partition both": { - input: &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-sameness-group", - }, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{ - { - Peer: "peer2", - Partition: "p2", - }, - }, - }, - }, - partitionsEnabled: true, - expectedErrMsg: "sameness group members cannot specify both partition and peer in the same entry", - }, - "invalid - no name": { - input: &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{}, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{ - { - Peer: "peer2", - }, - { - Partition: "p2", - }, - }, - }, - }, - partitionsEnabled: true, - expectedErrMsg: "sameness groups must have a name defined", - }, - "invalid - empty members": { - input: &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-sameness-group", - }, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{}, - }, - }, - partitionsEnabled: true, - expectedErrMsg: "sameness groups must have at least one member", - }, - "invalid - not unique members": { - input: &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-sameness-group", - }, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{ - { - Peer: "peer2", - }, - { - Peer: "peer2", - }, - }, - }, - }, - partitionsEnabled: true, - expectedErrMsg: "sameness group members must be unique", - }, - "invalid - not in default namespace": { - input: &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-sameness-group", - Namespace: "non-default", - }, - Spec: SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []SamenessGroupMember{ - { - Peer: "peer2", - }, - }, - }, - }, - partitionsEnabled: true, - expectedErrMsg: "sameness groups must reside in the default namespace", - }, - } - - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(common.ConsulMeta{}) - if testCase.expectedErrMsg != "" { - require.ErrorContains(t, err, testCase.expectedErrMsg) - } else { - require.NoError(t, err) - } - }) - } -} - -func TestSamenessGroups_GetObjectMeta(t *testing.T) { - meta := metav1.ObjectMeta{ - Name: "name", - } - samenessGroups := &SamenessGroup{ - ObjectMeta: meta, - } - require.Equal(t, meta, samenessGroups.GetObjectMeta()) -} - -func TestSamenessGroups_AddFinalizer(t *testing.T) { - samenessGroups := &SamenessGroup{} - samenessGroups.AddFinalizer("finalizer") - require.Equal(t, []string{"finalizer"}, samenessGroups.ObjectMeta.Finalizers) -} - -func TestSamenessGroups_RemoveFinalizer(t *testing.T) { - samenessGroups := &SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Finalizers: []string{"f1", "f2"}, - }, - } - samenessGroups.RemoveFinalizer("f1") - require.Equal(t, []string{"f2"}, samenessGroups.ObjectMeta.Finalizers) -} - -func TestSamenessGroups_ConsulKind(t *testing.T) { - require.Equal(t, capi.SamenessGroup, (&SamenessGroup{}).ConsulKind()) -} - -func TestSamenessGroups_ConsulGlobalResource(t *testing.T) { - require.False(t, (&SamenessGroup{}).ConsulGlobalResource()) -} - -func TestSamenessGroups_ConsulMirroringNS(t *testing.T) { - -} - -func TestSamenessGroups_KubeKind(t *testing.T) { - require.Equal(t, "samenessgroup", (&SamenessGroup{}).KubeKind()) -} - -func TestSamenessGroups_ConsulName(t *testing.T) { - require.Equal(t, "foo", (&SamenessGroup{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) -} - -func TestSamenessGroups_KubernetesName(t *testing.T) { - require.Equal(t, "foo", (&SamenessGroup{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) -} - -func TestSamenessGroups_SetSyncedCondition(t *testing.T) { - samenessGroups := &SamenessGroup{} - samenessGroups.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") - - require.Equal(t, corev1.ConditionTrue, samenessGroups.Status.Conditions[0].Status) - require.Equal(t, "reason", samenessGroups.Status.Conditions[0].Reason) - require.Equal(t, "message", samenessGroups.Status.Conditions[0].Message) - now := metav1.Now() - require.True(t, samenessGroups.Status.Conditions[0].LastTransitionTime.Before(&now)) -} - -func TestSamenessGroups_SetLastSyncedTime(t *testing.T) { - samenessGroups := &SamenessGroup{} - syncedTime := metav1.NewTime(time.Now()) - samenessGroups.SetLastSyncedTime(&syncedTime) - - require.Equal(t, &syncedTime, samenessGroups.Status.LastSyncedTime) -} - -func TestSamenessGroups_GetSyncedConditionStatus(t *testing.T) { - cases := []corev1.ConditionStatus{ - corev1.ConditionUnknown, - corev1.ConditionFalse, - corev1.ConditionTrue, - } - for _, status := range cases { - t.Run(string(status), func(t *testing.T) { - samenessGroups := &SamenessGroup{ - Status: Status{ - Conditions: []Condition{{ - Type: ConditionSynced, - Status: status, - }}, - }, - } - - require.Equal(t, status, samenessGroups.SyncedConditionStatus()) - }) - } -} - -func TestSamenessGroups_SyncedConditionStatusWhenStatusNil(t *testing.T) { - require.Equal(t, corev1.ConditionUnknown, (&SamenessGroup{}).SyncedConditionStatus()) -} - -func TestSamenessGroups_SyncedConditionWhenStatusNil(t *testing.T) { - status, reason, message := (&SamenessGroup{}).SyncedCondition() - require.Equal(t, corev1.ConditionUnknown, status) - require.Equal(t, "", reason) - require.Equal(t, "", message) -} diff --git a/control-plane/api/v1alpha1/samenessgroup_webhook.go b/control-plane/api/v1alpha1/samenessgroup_webhook.go deleted file mode 100644 index 6c1da5cba2..0000000000 --- a/control-plane/api/v1alpha1/samenessgroup_webhook.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v1alpha1 - -import ( - "context" - "net/http" - - "github.com/go-logr/logr" - "github.com/hashicorp/consul-k8s/control-plane/api/common" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// +kubebuilder:object:generate=false - -type SamenessGroupWebhook struct { - Logger logr.Logger - - // ConsulMeta contains metadata specific to the Consul installation. - ConsulMeta common.ConsulMeta - - decoder *admission.Decoder - client.Client -} - -// NOTE: The path value in the below line is the path to the webhook. -// If it is updated, run code-gen, update subcommand/controller/command.go -// and the consul-helm value for the path to the webhook. -// -// NOTE: The below line cannot be combined with any other comment. If it is it will break the code generation. -// -// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-samenessgroups,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=samenessgroups,versions=v1alpha1,name=mutate-samenessgroup.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 - -func (v *SamenessGroupWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { - var resource SamenessGroup - err := v.decoder.Decode(req, &resource) - if err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - return common.ValidateConfigEntry(ctx, req, v.Logger, v, &resource, v.ConsulMeta) -} - -func (v *SamenessGroupWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { - var resourceList SamenessGroupList - if err := v.Client.List(ctx, &resourceList); err != nil { - return nil, err - } - var entries []common.ConfigEntryResource - for _, item := range resourceList.Items { - entries = append(entries, common.ConfigEntryResource(&item)) - } - return entries, nil -} - -func (v *SamenessGroupWebhook) InjectDecoder(d *admission.Decoder) error { - v.decoder = d - return nil -} diff --git a/control-plane/api/v1alpha1/servicedefaults_types.go b/control-plane/api/v1alpha1/servicedefaults_types.go index 15e55a95a1..22f509ae9d 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types.go +++ b/control-plane/api/v1alpha1/servicedefaults_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( @@ -11,15 +8,14 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/hashicorp/consul-k8s/control-plane/api/common" + capi "github.com/hashicorp/consul/api" "github.com/miekg/dns" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/validation/field" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" - capi "github.com/hashicorp/consul/api" ) const ( @@ -74,17 +70,6 @@ type ServiceDefaultsSpec struct { // Note: This cannot be set using the CRD and should be set using annotations on the // services that are part of the mesh. TransparentProxy *TransparentProxy `json:"transparentProxy,omitempty"` - // MutualTLSMode controls whether mutual TLS is required for all incoming - // connections when transparent proxy is enabled. This can be set to - // "permissive" or "strict". "strict" is the default which requires mutual - // TLS for incoming connections. In the insecure "permissive" mode, - // connections to the sidecar proxy public listener port require mutual - // TLS, but connections to the service port do not require mutual TLS and - // are proxied to the application unmodified. Note: Intentions are not - // enforced for non-mTLS connections. To keep your services secure, we - // recommend using "strict" mode whenever possible and enabling - // "permissive" mode only when necessary. - MutualTLSMode MutualTLSMode `json:"mutualTLSMode,omitempty"` // MeshGateway controls the default mesh gateway configuration for this service. MeshGateway MeshGateway `json:"meshGateway,omitempty"` // Expose controls the default expose path configuration for Envoy. @@ -104,19 +89,13 @@ type ServiceDefaultsSpec struct { // MaxInboundConnections is the maximum number of concurrent inbound connections to // each service instance. Defaults to 0 (using consul's default) if not set. MaxInboundConnections int `json:"maxInboundConnections,omitempty"` - // LocalConnectTimeoutMs is the number of milliseconds allowed to make connections to the local application + // The number of milliseconds allowed to make connections to the local application // instance before timing out. Defaults to 5000. LocalConnectTimeoutMs int `json:"localConnectTimeoutMs,omitempty"` - // LocalRequestTimeoutMs is the timeout for HTTP requests to the local application instance in milliseconds. + // In milliseconds, the timeout for HTTP requests to the local application instance. // Applies to HTTP-based protocols only. If not specified, inherits the Envoy default for // route timeouts (15s). LocalRequestTimeoutMs int `json:"localRequestTimeoutMs,omitempty"` - // BalanceInboundConnections sets the strategy for allocating inbound connections to the service across - // proxy threads. The only supported value is exact_balance. By default, no connection balancing is used. - // Refer to the Envoy Connection Balance config for details. - BalanceInboundConnections string `json:"balanceInboundConnections,omitempty"` - // EnvoyExtensions are a list of extensions to modify Envoy proxy configuration. - EnvoyExtensions EnvoyExtensions `json:"envoyExtensions,omitempty"` } type Upstreams struct { @@ -129,14 +108,12 @@ type Upstreams struct { } type Upstream struct { - // Name is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides config entry. + // Name is only accepted within a service-defaults config entry. Name string `json:"name,omitempty"` - // Namespace is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides config entry. + // Namespace is only accepted within a service-defaults config entry. Namespace string `json:"namespace,omitempty"` - // Partition is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides config entry. + // Partition is only accepted within a service-defaults config entry. Partition string `json:"partition,omitempty"` - // Peer is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides config entry. - Peer string `json:"peer,omitempty"` // EnvoyListenerJSON is a complete override ("escape hatch") for the upstream's // listener. // Note: This escape hatch is NOT compatible with the discovery chain and @@ -291,22 +268,19 @@ func (in *ServiceDefaults) SyncedConditionStatus() corev1.ConditionStatus { // ToConsul converts the entry into it's Consul equivalent struct. func (in *ServiceDefaults) ToConsul(datacenter string) capi.ConfigEntry { return &capi.ServiceConfigEntry{ - Kind: in.ConsulKind(), - Name: in.ConsulName(), - Protocol: in.Spec.Protocol, - MeshGateway: in.Spec.MeshGateway.toConsul(), - Expose: in.Spec.Expose.toConsul(), - ExternalSNI: in.Spec.ExternalSNI, - TransparentProxy: in.Spec.TransparentProxy.toConsul(), - MutualTLSMode: in.Spec.MutualTLSMode.toConsul(), - UpstreamConfig: in.Spec.UpstreamConfig.toConsul(), - Destination: in.Spec.Destination.toConsul(), - Meta: meta(datacenter), - MaxInboundConnections: in.Spec.MaxInboundConnections, - LocalConnectTimeoutMs: in.Spec.LocalConnectTimeoutMs, - LocalRequestTimeoutMs: in.Spec.LocalRequestTimeoutMs, - BalanceInboundConnections: in.Spec.BalanceInboundConnections, - EnvoyExtensions: in.Spec.EnvoyExtensions.toConsul(), + Kind: in.ConsulKind(), + Name: in.ConsulName(), + Protocol: in.Spec.Protocol, + MeshGateway: in.Spec.MeshGateway.toConsul(), + Expose: in.Spec.Expose.toConsul(), + ExternalSNI: in.Spec.ExternalSNI, + TransparentProxy: in.Spec.TransparentProxy.toConsul(), + UpstreamConfig: in.Spec.UpstreamConfig.toConsul(), + Destination: in.Spec.Destination.toConsul(), + Meta: meta(datacenter), + MaxInboundConnections: in.Spec.MaxInboundConnections, + LocalConnectTimeoutMs: in.Spec.LocalConnectTimeoutMs, + LocalRequestTimeoutMs: in.Spec.LocalRequestTimeoutMs, } } @@ -326,9 +300,6 @@ func (in *ServiceDefaults) Validate(consulMeta common.ConsulMeta) error { if err := in.Spec.TransparentProxy.validate(path.Child("transparentProxy")); err != nil { allErrs = append(allErrs, err) } - if err := in.Spec.MutualTLSMode.validate(); err != nil { - allErrs = append(allErrs, field.Invalid(path.Child("mutualTLSMode"), in.Spec.MutualTLSMode, err.Error())) - } if err := in.Spec.Mode.validate(path.Child("mode")); err != nil { allErrs = append(allErrs, err) } @@ -348,13 +319,8 @@ func (in *ServiceDefaults) Validate(consulMeta common.ConsulMeta) error { allErrs = append(allErrs, field.Invalid(path.Child("localRequestTimeoutMs"), in.Spec.LocalRequestTimeoutMs, "LocalRequestTimeoutMs must be > 0")) } - if in.Spec.BalanceInboundConnections != "" && in.Spec.BalanceInboundConnections != "exact_balance" { - allErrs = append(allErrs, field.Invalid(path.Child("balanceInboundConnections"), in.Spec.BalanceInboundConnections, "BalanceInboundConnections must be an empty string or exact_balance")) - } - allErrs = append(allErrs, in.Spec.UpstreamConfig.validate(path.Child("upstreamConfig"), consulMeta.PartitionsEnabled)...) allErrs = append(allErrs, in.Spec.Expose.validate(path.Child("expose"))...) - allErrs = append(allErrs, in.Spec.EnvoyExtensions.validate(path.Child("envoyExtensions"))...) if len(allErrs) > 0 { return apierrors.NewInvalid( @@ -403,25 +369,10 @@ func (in *Upstream) validate(path *field.Path, kind string, partitionsEnabled bo if in.Name != "" { errs = append(errs, field.Invalid(path.Child("name"), in.Name, "upstream.name for a default upstream must be \"\"")) } - if in.Namespace != "" { - errs = append(errs, field.Invalid(path.Child("namespace"), in.Namespace, "upstream.namespace for a default upstream must be \"\"")) - } - if in.Partition != "" { - errs = append(errs, field.Invalid(path.Child("partition"), in.Partition, "upstream.partition for a default upstream must be \"\"")) - } - if in.Peer != "" { - errs = append(errs, field.Invalid(path.Child("peer"), in.Peer, "upstream.peer for a default upstream must be \"\"")) - } } else if kind == overrideUpstream { if in.Name == "" { errs = append(errs, field.Invalid(path.Child("name"), in.Name, "upstream.name for an override upstream cannot be \"\"")) } - if in.Namespace != "" && in.Peer != "" { - errs = append(errs, field.Invalid(path, in, "both namespace and peer cannot be specified.")) - } - if in.Partition != "" && in.Peer != "" { - errs = append(errs, field.Invalid(path, in, "both partition and peer cannot be specified.")) - } } if !partitionsEnabled && in.Partition != "" { errs = append(errs, field.Invalid(path.Child("partition"), in.Partition, "Consul Enterprise Admin Partitions must be enabled to set upstream.partition")) @@ -440,7 +391,6 @@ func (in *Upstream) toConsul() *capi.UpstreamConfig { Name: in.Name, Namespace: in.Namespace, Partition: in.Partition, - Peer: in.Peer, EnvoyListenerJSON: in.EnvoyListenerJSON, EnvoyClusterJSON: in.EnvoyClusterJSON, Protocol: in.Protocol, diff --git a/control-plane/api/v1alpha1/servicedefaults_types_test.go b/control-plane/api/v1alpha1/servicedefaults_types_test.go index 31a41f3f06..78ff6ce692 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types_test.go +++ b/control-plane/api/v1alpha1/servicedefaults_types_test.go @@ -1,20 +1,15 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( - "encoding/json" "testing" "time" + "github.com/hashicorp/consul-k8s/control-plane/api/common" capi "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" ) func TestServiceDefaults_ToConsul(t *testing.T) { @@ -70,7 +65,6 @@ func TestServiceDefaults_ToConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: MutualTLSModePermissive, UpstreamConfig: &Upstreams{ Defaults: &Upstream{ Name: "upstream-default", @@ -159,19 +153,6 @@ func TestServiceDefaults_ToConsul(t *testing.T) { }, }, }, - BalanceInboundConnections: "exact_balance", - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: json.RawMessage(`{"ClusterName": "zipkin_cluster", "Port": "9411", "CollectorEndpoint":"/api/v2/spans"}`), - Required: true, - }, - }, Destination: &ServiceDefaultsDestination{ Addresses: []string{"api.google.com"}, Port: 443, @@ -210,7 +191,6 @@ func TestServiceDefaults_ToConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: capi.MutualTLSModePermissive, UpstreamConfig: &capi.UpstreamConfiguration{ Defaults: &capi.UpstreamConfig{ Name: "upstream-default", @@ -287,26 +267,6 @@ func TestServiceDefaults_ToConsul(t *testing.T) { }, }, }, - BalanceInboundConnections: "exact_balance", - EnvoyExtensions: []capi.EnvoyExtension{ - { - Name: "aws_request_signing", - Arguments: map[string]interface{}{ - "AWSServiceName": "s3", - "Region": "us-west-2", - }, - Required: false, - }, - { - Name: "zipkin", - Arguments: map[string]interface{}{ - "ClusterName": "zipkin_cluster", - "Port": "9411", - "CollectorEndpoint": "/api/v2/spans", - }, - Required: true, - }, - }, Destination: &capi.DestinationConfig{ Addresses: []string{"api.google.com"}, Port: 443, @@ -472,7 +432,6 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: MutualTLSModeStrict, UpstreamConfig: &Upstreams{ Defaults: &Upstream{ Name: "upstream-default", @@ -558,19 +517,6 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { }, }, }, - BalanceInboundConnections: "exact_balance", - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: json.RawMessage(`{"ClusterName": "zipkin_cluster", "Port": "9411", "CollectorEndpoint":"/api/v2/spans"}`), - Required: true, - }, - }, Destination: &ServiceDefaultsDestination{ Addresses: []string{"api.google.com"}, Port: 443, @@ -605,7 +551,6 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { OutboundListenerPort: 1000, DialedDirectly: true, }, - MutualTLSMode: capi.MutualTLSModeStrict, UpstreamConfig: &capi.UpstreamConfiguration{ Defaults: &capi.UpstreamConfig{ Name: "upstream-default", @@ -679,26 +624,6 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { }, }, }, - BalanceInboundConnections: "exact_balance", - EnvoyExtensions: []capi.EnvoyExtension{ - { - Name: "aws_request_signing", - Arguments: map[string]interface{}{ - "AWSServiceName": "s3", - "Region": "us-west-2", - }, - Required: false, - }, - { - Name: "zipkin", - Arguments: map[string]interface{}{ - "ClusterName": "zipkin_cluster", - "Port": "9411", - "CollectorEndpoint": "/api/v2/spans", - }, - Required: true, - }, - }, Destination: &capi.DestinationConfig{ Addresses: []string{"api.google.com"}, Port: 443, @@ -805,7 +730,6 @@ func TestServiceDefaults_Validate(t *testing.T) { MeshGateway: MeshGateway{ Mode: "remote", }, - MutualTLSMode: MutualTLSModePermissive, Expose: Expose{ Checks: false, Paths: []ExposePath{ @@ -835,39 +759,6 @@ func TestServiceDefaults_Validate(t *testing.T) { }, expectedErrMsg: "", }, - "valid - balanceInboundConnections": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - BalanceInboundConnections: "exact_balance", - }, - }, - expectedErrMsg: "", - }, - "valid - envoyExtension": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: json.RawMessage(`{"ClusterName": "zipkin_cluster", "Port": "9411", "CollectorEndpoint":"/api/v2/spans"}`), - Required: true, - }, - }, - }, - }, - expectedErrMsg: "", - }, "protocol": { input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ @@ -941,17 +832,6 @@ func TestServiceDefaults_Validate(t *testing.T) { }, expectedErrMsg: "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port", }, - "mutualTLSMode": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - MutualTLSMode: MutualTLSMode("asdf"), - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.mutualTLSMode: Invalid value: "asdf": Must be one of "", "strict", or "permissive".`, - }, "mode": { input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ @@ -995,21 +875,6 @@ func TestServiceDefaults_Validate(t *testing.T) { }, expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.name: Invalid value: "foobar": upstream.name for a default upstream must be ""`, }, - "upstreamConfig.defaults.namespace": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - UpstreamConfig: &Upstreams{ - Defaults: &Upstream{ - Namespace: "foobar", - }, - }, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.namespace: Invalid value: "foobar": upstream.namespace for a default upstream must be ""`, - }, "upstreamConfig.defaults.partition": { input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ @@ -1024,22 +889,7 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, partitionsEnabled: false, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: [spec.upstreamConfig.defaults.partition: Invalid value: "upstream": upstream.partition for a default upstream must be "", spec.upstreamConfig.defaults.partition: Invalid value: "upstream": Consul Enterprise Admin Partitions must be enabled to set upstream.partition]`, - }, - "upstreamConfig.defaults.peer": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - UpstreamConfig: &Upstreams{ - Defaults: &Upstream{ - Peer: "foobar", - }, - }, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.peer: Invalid value: "foobar": upstream.peer for a default upstream must be ""`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.partition: Invalid value: "upstream": Consul Enterprise Admin Partitions must be enabled to set upstream.partition`, }, "upstreamConfig.overrides.meshGateway": { input: &ServiceDefaults{ @@ -1096,44 +946,6 @@ func TestServiceDefaults_Validate(t *testing.T) { }, expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.overrides[0].partition: Invalid value: "upstream": Consul Enterprise Admin Partitions must be enabled to set upstream.partition`, }, - "upstreamConfig.overrides.partition and namespace": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - UpstreamConfig: &Upstreams{ - Overrides: []*Upstream{ - { - Name: "service", - Namespace: "namespace", - Peer: "peer", - }, - }, - }, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.overrides[0]: Invalid value: v1alpha1.Upstream{Name:"service", Namespace:"namespace", Partition:"", Peer:"peer", EnvoyListenerJSON:"", EnvoyClusterJSON:"", Protocol:"", ConnectTimeoutMs:0, Limits:(*v1alpha1.UpstreamLimits)(nil), PassiveHealthCheck:(*v1alpha1.PassiveHealthCheck)(nil), MeshGateway:v1alpha1.MeshGateway{Mode:""}}: both namespace and peer cannot be specified.`, - }, - "upstreamConfig.overrides.partition and peer": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - UpstreamConfig: &Upstreams{ - Overrides: []*Upstream{ - { - Name: "service", - Partition: "upstream", - Peer: "peer", - }, - }, - }, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: [spec.upstreamConfig.overrides[0]: Invalid value: v1alpha1.Upstream{Name:"service", Namespace:"", Partition:"upstream", Peer:"peer", EnvoyListenerJSON:"", EnvoyClusterJSON:"", Protocol:"", ConnectTimeoutMs:0, Limits:(*v1alpha1.UpstreamLimits)(nil), PassiveHealthCheck:(*v1alpha1.PassiveHealthCheck)(nil), MeshGateway:v1alpha1.MeshGateway{Mode:""}}: both partition and peer cannot be specified., spec.upstreamConfig.overrides[0].partition: Invalid value: "upstream": Consul Enterprise Admin Partitions must be enabled to set upstream.partition]`, - }, "multi-error": { input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ @@ -1224,111 +1036,6 @@ func TestServiceDefaults_Validate(t *testing.T) { }, expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.destination.port: Invalid value: 0x0: invalid port number`, }, - "MaxInboundConnections (invalid value)": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - MaxInboundConnections: -1, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.maxinboundconnections: Invalid value: -1: MaxInboundConnections must be > 0`, - }, - "LocalConnectTimeoutMs (invalid value)": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - LocalConnectTimeoutMs: -1, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.localConnectTimeoutMs: Invalid value: -1: LocalConnectTimeoutMs must be > 0`, - }, - "LocalRequestTimeoutMs (invalid value)": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - LocalRequestTimeoutMs: -1, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.localRequestTimeoutMs: Invalid value: -1: LocalRequestTimeoutMs must be > 0`, - }, - "balanceInboundConnections (invalid value)": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - BalanceInboundConnections: "not_exact_balance", - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.balanceInboundConnections: Invalid value: "not_exact_balance": BalanceInboundConnections must be an empty string or exact_balance`, - }, - "envoyExtension.arguments (single empty)": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"AWSServiceName": "s3", "Region": "us-west-2"}`), - Required: false, - }, - EnvoyExtension{ - Name: "zipkin", - Arguments: nil, - Required: true, - }, - }, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.envoyExtensions.envoyExtension[1].arguments: Required value: arguments must be defined`, - }, - "envoyExtension.arguments (multi empty)": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: nil, - Required: false, - }, - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: nil, - Required: false, - }, - }, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: [spec.envoyExtensions.envoyExtension[0].arguments: Required value: arguments must be defined, spec.envoyExtensions.envoyExtension[1].arguments: Required value: arguments must be defined]`, - }, - "envoyExtension.arguments (invalid json)": { - input: &ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-service", - }, - Spec: ServiceDefaultsSpec{ - EnvoyExtensions: EnvoyExtensions{ - EnvoyExtension{ - Name: "aws_request_signing", - Arguments: json.RawMessage(`{"SOME_INVALID_JSON"}`), - Required: false, - }, - }, - }, - }, - expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.envoyExtensions.envoyExtension[0].arguments: Invalid value: "{\"SOME_INVALID_JSON\"}": must be valid map value: invalid character '}' after object key`, - }, } for name, testCase := range cases { @@ -1433,7 +1140,7 @@ func TestServiceDefaults_ConsulName(t *testing.T) { } func TestServiceDefaults_KubernetesName(t *testing.T) { - require.Equal(t, "foo", (&ServiceDefaults{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) + require.Equal(t, "foo", (&ServiceDefaults{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) } func TestServiceDefaults_ConsulNamespace(t *testing.T) { diff --git a/control-plane/api/v1alpha1/servicedefaults_webhook.go b/control-plane/api/v1alpha1/servicedefaults_webhook.go index 124aeff5f6..f79e68bcde 100644 --- a/control-plane/api/v1alpha1/servicedefaults_webhook.go +++ b/control-plane/api/v1alpha1/servicedefaults_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/serviceintentions_types.go b/control-plane/api/v1alpha1/serviceintentions_types.go index d393f72a2d..1a41caa289 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types.go +++ b/control-plane/api/v1alpha1/serviceintentions_types.go @@ -1,11 +1,7 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( "encoding/json" - "fmt" "net/http" "strings" @@ -59,8 +55,6 @@ type ServiceIntentionsSpec struct { // The order of this list does not matter, but out of convenience Consul will always store this // reverse sorted by intention precedence, as that is the order that they will be evaluated at enforcement time. Sources SourceIntentions `json:"sources,omitempty"` - // JWT specifies the configuration to validate a JSON Web Token for all incoming requests. - JWT *IntentionJWTRequirement `json:"jwt,omitempty"` } type IntentionDestination struct { @@ -84,12 +78,10 @@ type SourceIntention struct { Name string `json:"name,omitempty"` // Namespace is the namespace for the Name parameter. Namespace string `json:"namespace,omitempty"` - // Peer is the peer name for the Name parameter. + // [Experimental] Peer is the peer name for the Name parameter. Peer string `json:"peer,omitempty"` // Partition is the Admin Partition for the Name parameter. Partition string `json:"partition,omitempty"` - // SamenessGroup is the name of the sameness group, if applicable. - SamenessGroup string `json:"samenessGroup,omitempty"` // Action is required for an L4 intention, and should be set to one of // "allow" or "deny" for the action that should be taken if this intention matches a request. Action IntentionAction `json:"action,omitempty"` @@ -110,8 +102,6 @@ type IntentionPermission struct { Action IntentionAction `json:"action,omitempty"` // HTTP is a set of HTTP-specific authorization criteria. HTTP *IntentionHTTPPermission `json:"http,omitempty"` - // JWT specifies configuration to validate a JSON Web Token for incoming requests. - JWT *IntentionJWTRequirement `json:"jwt,omitempty"` } type IntentionHTTPPermission struct { @@ -146,30 +136,6 @@ type IntentionHTTPHeaderPermission struct { Invert bool `json:"invert,omitempty"` } -type IntentionJWTRequirement struct { - // Providers is a list of providers to consider when verifying a JWT. - Providers []*IntentionJWTProvider `json:"providers,omitempty"` -} - -type IntentionJWTProvider struct { - // Name is the name of the JWT provider. There MUST be a corresponding - // "jwt-provider" config entry with this name. - Name string `json:"name,omitempty"` - - // VerifyClaims is a list of additional claims to verify in a JWT's payload. - VerifyClaims []*IntentionJWTClaimVerification `json:"verifyClaims,omitempty"` -} - -type IntentionJWTClaimVerification struct { - // Path is the path to the claim in the token JSON. - Path []string `json:"path,omitempty"` - - // Value is the expected value at the given path. If the type at the path - // is a list then we verify that this value is contained in the list. If - // the type at the path is a string then we verify that this value matches. - Value string `json:"value,omitempty"` -} - // IntentionAction is the action that the intention represents. This // can be "allow" or "deny" to allowlist or denylist intentions. type IntentionAction string @@ -254,7 +220,6 @@ func (in *ServiceIntentions) ToConsul(datacenter string) api.ConfigEntry { Name: in.Spec.Destination.Name, Namespace: in.Spec.Destination.Namespace, Sources: in.Spec.Sources.toConsul(), - JWT: in.Spec.JWT.toConsul(), Meta: meta(datacenter), } } @@ -321,12 +286,10 @@ func (in *ServiceIntentions) Validate(consulMeta common.ConsulMeta) error { } else { errs = append(errs, source.Permissions.validate(path.Child("sources").Index(i))...) } - errs = append(errs, source.validate(path.Child("sources").Index(i), consulMeta.PartitionsEnabled)...) } errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) - - errs = append(errs, in.Spec.JWT.validate(path.Child("jwt"))...) + errs = append(errs, in.validateSourcePeerAndPartitions(consulMeta.PartitionsEnabled)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -336,46 +299,6 @@ func (in *ServiceIntentions) Validate(consulMeta common.ConsulMeta) error { return nil } -func (in *SourceIntention) validate(path *field.Path, partitionsEnabled bool) field.ErrorList { - var errs field.ErrorList - - if in.Name == "" { - errs = append(errs, field.Required(path.Child("name"), "name is required.")) - } - - if strings.Contains(in.Partition, WildcardSpecifier) { - errs = append(errs, field.Invalid(path.Child("partition"), in.Partition, "partition cannot use or contain wildcard '*'")) - } - if strings.Contains(in.Peer, WildcardSpecifier) { - errs = append(errs, field.Invalid(path.Child("peer"), in.Peer, "peer cannot use or contain wildcard '*'")) - } - if strings.Contains(in.SamenessGroup, WildcardSpecifier) { - errs = append(errs, field.Invalid(path.Child("samenessgroup"), in.SamenessGroup, "samenessgroup cannot use or contain wildcard '*'")) - } - - if in.Partition != "" && !partitionsEnabled { - errs = append(errs, field.Invalid(path.Child("partition"), in.Partition, `Consul Enterprise Admin Partitions must be enabled to set source.partition`)) - } - - if in.Peer != "" && in.Partition != "" { - errs = append(errs, field.Invalid(path, *in, "cannot set peer and partition at the same time.")) - } - - if in.SamenessGroup != "" && in.Partition != "" { - errs = append(errs, field.Invalid(path, *in, "cannot set samenessgroup and partition at the same time.")) - } - - if in.SamenessGroup != "" && in.Peer != "" { - errs = append(errs, field.Invalid(path, *in, "cannot set samenessgroup and peer at the same time.")) - } - - if len(in.Description) > metaValueMaxLength { - errs = append(errs, field.Invalid(path, "", fmt.Sprintf("description exceeds maximum length %d", metaValueMaxLength))) - } - - return errs -} - // DefaultNamespaceFields sets the namespace field on spec.destination to their default values if namespaces are enabled. func (in *ServiceIntentions) DefaultNamespaceFields(consulMeta common.ConsulMeta) { // If namespaces are enabled we want to set the destination namespace field to it's @@ -404,14 +327,13 @@ func (in *SourceIntention) toConsul() *capi.SourceIntention { return nil } return &capi.SourceIntention{ - Name: in.Name, - Namespace: in.Namespace, - Partition: in.Partition, - Peer: in.Peer, - SamenessGroup: in.SamenessGroup, - Action: in.Action.toConsul(), - Permissions: in.Permissions.toConsul(), - Description: in.Description, + Name: in.Name, + Namespace: in.Namespace, + Partition: in.Partition, + Peer: in.Peer, + Action: in.Action.toConsul(), + Permissions: in.Permissions.toConsul(), + Description: in.Description, } } @@ -425,7 +347,6 @@ func (in IntentionPermissions) toConsul() []*capi.IntentionPermission { consulIntentionPermissions = append(consulIntentionPermissions, &capi.IntentionPermission{ Action: permission.Action.toConsul(), HTTP: permission.HTTP.toConsul(), - JWT: permission.JWT.toConsul(), }) } return consulIntentionPermissions @@ -461,54 +382,15 @@ func (in IntentionHTTPHeaderPermissions) toConsul() []capi.IntentionHTTPHeaderPe return headerPermissions } -func (in *IntentionJWTRequirement) toConsul() *capi.IntentionJWTRequirement { - if in == nil { - return nil - } - var providers []*capi.IntentionJWTProvider - for _, p := range in.Providers { - providers = append(providers, p.toConsul()) - } - return &capi.IntentionJWTRequirement{ - Providers: providers, - } -} - -func (in *IntentionJWTProvider) toConsul() *capi.IntentionJWTProvider { - if in == nil { - return nil - } - var claims []*capi.IntentionJWTClaimVerification - for _, c := range in.VerifyClaims { - claims = append(claims, c.toConsul()) - } - return &capi.IntentionJWTProvider{ - Name: in.Name, - VerifyClaims: claims, - } -} - -func (in *IntentionJWTClaimVerification) toConsul() *capi.IntentionJWTClaimVerification { - if in == nil { - return nil - } - return &capi.IntentionJWTClaimVerification{ - Path: in.Path, - Value: in.Value, - } -} - func (in IntentionPermissions) validate(path *field.Path) field.ErrorList { var errs field.ErrorList for i, permission := range in { - permPath := path.Child("permissions").Index(i) - if err := permission.Action.validate(permPath); err != nil { + if err := permission.Action.validate(path.Child("permissions").Index(i)); err != nil { errs = append(errs, err) } if permission.HTTP != nil { - errs = append(errs, permission.HTTP.validate(permPath)...) + errs = append(errs, permission.HTTP.validate(path.Child("permissions").Index(i))...) } - errs = append(errs, permission.JWT.validate(permPath.Child("jwt"))...) } return errs } @@ -593,6 +475,21 @@ func (in *ServiceIntentions) validateNamespaces(namespacesEnabled bool) field.Er return errs } +func (in *ServiceIntentions) validateSourcePeerAndPartitions(partitionsEnabled bool) field.ErrorList { + var errs field.ErrorList + path := field.NewPath("spec") + for i, source := range in.Spec.Sources { + if source.Partition != "" && !partitionsEnabled { + errs = append(errs, field.Invalid(path.Child("sources").Index(i).Child("partition"), source.Partition, `Consul Enterprise Admin Partitions must be enabled to set source.partition`)) + } + + if source.Peer != "" && source.Partition != "" { + errs = append(errs, field.Invalid(path.Child("sources").Index(i), source, `Both source.peer and source.partition cannot be set.`)) + } + } + return errs +} + func (in IntentionAction) validate(path *field.Path) *field.Error { actions := []string{"allow", "deny"} if !sliceContains(actions, string(in)) { @@ -611,27 +508,6 @@ func numNotEmpty(ss ...string) int { return count } -func (in *IntentionJWTRequirement) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if in == nil { - return errs - } - - for i, p := range in.Providers { - if err := p.validate(path.Child("providers").Index(i)); err != nil { - errs = append(errs, err) - } - } - return errs -} - -func (in *IntentionJWTProvider) validate(path *field.Path) *field.Error { - if in != nil && in.Name == "" { - return field.Invalid(path.Child("name"), in.Name, "JWT provider name is required") - } - return nil -} - // sourceIntentionSortKey returns a string that can be used to sort intention // sources. func sourceIntentionSortKey(ixn *capi.SourceIntention) string { diff --git a/control-plane/api/v1alpha1/serviceintentions_types_test.go b/control-plane/api/v1alpha1/serviceintentions_types_test.go index 8d0a6d907a..01199f74d1 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types_test.go +++ b/control-plane/api/v1alpha1/serviceintentions_types_test.go @@ -1,10 +1,6 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( - "strings" "testing" "time" @@ -165,37 +161,11 @@ func TestServiceIntentions_MatchesConsul(t *testing.T) { "PUT", }, }, - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "okta-nested", - VerifyClaims: []*IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin-nested", - }, - }, - }, - }, - }, }, }, Description: "an L7 config", }, }, - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "okta", - VerifyClaims: []*IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin", - }, - }, - }, - }, - }, }, }, Theirs: &capi.ServiceIntentionsConfigEntry{ @@ -246,37 +216,11 @@ func TestServiceIntentions_MatchesConsul(t *testing.T) { "PUT", }, }, - JWT: &capi.IntentionJWTRequirement{ - Providers: []*capi.IntentionJWTProvider{ - { - Name: "okta-nested", - VerifyClaims: []*capi.IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin-nested", - }, - }, - }, - }, - }, }, }, Description: "an L7 config", }, }, - JWT: &capi.IntentionJWTRequirement{ - Providers: []*capi.IntentionJWTProvider{ - { - Name: "okta", - VerifyClaims: []*capi.IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin", - }, - }, - }, - }, - }, Meta: nil, }, Matches: true, @@ -394,13 +338,6 @@ func TestServiceIntentions_ToConsul(t *testing.T) { Action: "deny", Description: "disallow access from namespace not-test", }, - { - Name: "*", - Namespace: "ns1", - SamenessGroup: "sg2", - Action: "deny", - Description: "disallow access from namespace ns1", - }, { Name: "svc-2", Namespace: "bar", @@ -428,37 +365,11 @@ func TestServiceIntentions_ToConsul(t *testing.T) { "PUT", }, }, - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "okta-nested", - VerifyClaims: []*IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin-nested", - }, - }, - }, - }, - }, }, }, Description: "an L7 config", }, }, - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "okta", - VerifyClaims: []*IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin", - }, - }, - }, - }, - }, }, }, Exp: &capi.ServiceIntentionsConfigEntry{ @@ -480,13 +391,6 @@ func TestServiceIntentions_ToConsul(t *testing.T) { Action: "deny", Description: "disallow access from namespace not-test", }, - { - Name: "*", - Namespace: "ns1", - SamenessGroup: "sg2", - Action: "deny", - Description: "disallow access from namespace ns1", - }, { Name: "svc-2", Namespace: "bar", @@ -514,37 +418,11 @@ func TestServiceIntentions_ToConsul(t *testing.T) { "PUT", }, }, - JWT: &capi.IntentionJWTRequirement{ - Providers: []*capi.IntentionJWTProvider{ - { - Name: "okta-nested", - VerifyClaims: []*capi.IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin-nested", - }, - }, - }, - }, - }, }, }, Description: "an L7 config", }, }, - JWT: &capi.IntentionJWTRequirement{ - Providers: []*capi.IntentionJWTProvider{ - { - Name: "okta", - VerifyClaims: []*capi.IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin", - }, - }, - }, - }, - }, Meta: map[string]string{ common.SourceKey: common.SourceValue, common.DatacenterKey: "datacenter", @@ -793,8 +671,6 @@ func TestServiceIntentions_DefaultNamespaceFields(t *testing.T) { } func TestServiceIntentions_Validate(t *testing.T) { - longDescription := strings.Repeat("x", metaValueMaxLength+1) - cases := map[string]struct { input *ServiceIntentions namespacesEnabled bool @@ -845,37 +721,11 @@ func TestServiceIntentions_Validate(t *testing.T) { "PUT", }, }, - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "okta-nested", - VerifyClaims: []*IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin-nested", - }, - }, - }, - }, - }, }, }, Description: "an L7 config", }, }, - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "okta", - VerifyClaims: []*IntentionJWTClaimVerification{ - { - Path: []string{"perms", "role"}, - Value: "admin", - }, - }, - }, - }, - }, }, }, namespacesEnabled: true, @@ -1343,54 +1193,6 @@ func TestServiceIntentions_Validate(t *testing.T) { `serviceintentions.consul.hashicorp.com "does-not-matter" is invalid: spec.sources[0]: Invalid value: "{\"name\":\"svc-2\",\"namespace\":\"bar\",\"action\":\"deny\",\"permissions\":[{\"action\":\"allow\",\"http\":{\"pathExact\":\"/bar\"}}]}": action and permissions are mutually exclusive and only one of them can be specified`, }, }, - "name not specified": { - input: &ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "does-not-matter", - }, - Spec: ServiceIntentionsSpec{ - Destination: IntentionDestination{ - Name: "dest-service", - Namespace: "namespace", - }, - Sources: SourceIntentions{ - { - Namespace: "bar", - Action: "deny", - }, - }, - }, - }, - namespacesEnabled: true, - expectedErrMsgs: []string{ - `serviceintentions.consul.hashicorp.com "does-not-matter" is invalid: spec.sources[0].name: Required value: name is required.`, - }, - }, - "description is too long": { - input: &ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "does-not-matter", - }, - Spec: ServiceIntentionsSpec{ - Destination: IntentionDestination{ - Name: "dest-service", - Namespace: "namespace", - }, - Sources: SourceIntentions{ - { - Name: "foo", - Namespace: "bar", - Action: "deny", - Description: longDescription, - }, - }, - }, - }, - namespacesEnabled: true, - expectedErrMsgs: []string{ - `serviceintentions.consul.hashicorp.com "does-not-matter" is invalid: spec.sources[0]: Invalid value: "": description exceeds maximum length 512`, - }, - }, "namespaces disabled: destination namespace specified": { input: &ServiceIntentions{ ObjectMeta: metav1.ObjectMeta{ @@ -1610,71 +1412,7 @@ func TestServiceIntentions_Validate(t *testing.T) { namespacesEnabled: true, partitionsEnabled: true, expectedErrMsgs: []string{ - `cannot set peer and partition at the same time.`, - }, - }, - "single source samenessgroup and partition specified": { - input: &ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "does-not-matter", - }, - Spec: ServiceIntentionsSpec{ - Destination: IntentionDestination{ - Name: "dest-service", - Namespace: "namespace-a", - }, - Sources: SourceIntentions{ - { - Name: "web", - Action: "allow", - Namespace: "namespace-b", - Partition: "partition-other", - SamenessGroup: "sg2", - }, - { - Name: "db", - Action: "deny", - Namespace: "namespace-c", - }, - }, - }, - }, - namespacesEnabled: true, - partitionsEnabled: true, - expectedErrMsgs: []string{ - `cannot set samenessgroup and partition at the same time.`, - }, - }, - "single source samenessgroup and peer specified": { - input: &ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "does-not-matter", - }, - Spec: ServiceIntentionsSpec{ - Destination: IntentionDestination{ - Name: "dest-service", - Namespace: "namespace-a", - }, - Sources: SourceIntentions{ - { - Name: "web", - Action: "allow", - Namespace: "namespace-b", - Peer: "p2", - SamenessGroup: "sg2", - }, - { - Name: "db", - Action: "deny", - Namespace: "namespace-c", - }, - }, - }, - }, - namespacesEnabled: true, - partitionsEnabled: true, - expectedErrMsgs: []string{ - `cannot set samenessgroup and peer at the same time.`, + `spec.sources[0]: Invalid value: v1alpha1.SourceIntention{Name:"web", Namespace:"namespace-b", Peer:"peer-other", Partition:"partition-other", Action:"allow", Permissions:v1alpha1.IntentionPermissions(nil), Description:""}: Both source.peer and source.partition cannot be set.`, }, }, "multiple source peer and partition specified": { @@ -1708,108 +1446,8 @@ func TestServiceIntentions_Validate(t *testing.T) { namespacesEnabled: true, partitionsEnabled: true, expectedErrMsgs: []string{ - `spec.sources[0]: Invalid value: v1alpha1.SourceIntention{Name:"web", Namespace:"namespace-b", Peer:"peer-other", Partition:"partition-other", SamenessGroup:"", Action:"allow", Permissions:v1alpha1.IntentionPermissions(nil), Description:""}: cannot set peer and partition at the same time.`, - `spec.sources[1]: Invalid value: v1alpha1.SourceIntention{Name:"db", Namespace:"namespace-c", Peer:"peer-2", Partition:"partition-2", SamenessGroup:"", Action:"deny", Permissions:v1alpha1.IntentionPermissions(nil), Description:""}: cannot set peer and partition at the same time.`, - }, - }, - "multiple errors: wildcard peer and partition and samenessgroup specified": { - input: &ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "does-not-matter", - }, - Spec: ServiceIntentionsSpec{ - Destination: IntentionDestination{ - Name: "dest-service", - Namespace: "namespace-a", - }, - Sources: SourceIntentions{ - { - Name: "web", - Action: "allow", - Namespace: "namespace-b", - Partition: "*", - }, - { - Name: "db", - Action: "deny", - Namespace: "namespace-c", - Peer: "*", - }, - { - Name: "db2", - Action: "deny", - Namespace: "namespace-d", - SamenessGroup: "*", - }, - }, - }, - }, - namespacesEnabled: true, - partitionsEnabled: true, - expectedErrMsgs: []string{ - `partition cannot use or contain wildcard '*'`, - `peer cannot use or contain wildcard '*'`, - `samenessgroup cannot use or contain wildcard '*'`, - }, - }, - "invalid empty jwt provider name at top-level": { - input: &ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "does-not-matter", - }, - Spec: ServiceIntentionsSpec{ - Destination: IntentionDestination{ - Name: "dest-service", - }, - Sources: SourceIntentions{ - { - Name: "bar", - Action: "allow", - }, - }, - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "", - }, - }, - }, - }, - }, - expectedErrMsgs: []string{ - `spec.jwt.providers[0].name: Invalid value: "": JWT provider name is required`, - }, - }, - "invalid empty jwt provider name in permissions": { - input: &ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "does-not-matter", - }, - Spec: ServiceIntentionsSpec{ - Destination: IntentionDestination{ - Name: "dest-service", - }, - Sources: SourceIntentions{ - { - Name: "bar", - Permissions: IntentionPermissions{ - { - Action: "allow", - JWT: &IntentionJWTRequirement{ - Providers: []*IntentionJWTProvider{ - { - Name: "", - }, - }, - }, - }, - }, - }, - }, - }, - }, - expectedErrMsgs: []string{ - `spec.sources[0].permissions[0].jwt.providers[0].name: Invalid value: "": JWT provider name is required`, + `spec.sources[0]: Invalid value: v1alpha1.SourceIntention{Name:"web", Namespace:"namespace-b", Peer:"peer-other", Partition:"partition-other", Action:"allow", Permissions:v1alpha1.IntentionPermissions(nil), Description:""}: Both source.peer and source.partition cannot be set.`, + `spec.sources[1]: Invalid value: v1alpha1.SourceIntention{Name:"db", Namespace:"namespace-c", Peer:"peer-2", Partition:"partition-2", Action:"deny", Permissions:v1alpha1.IntentionPermissions(nil), Description:""}: Both source.peer and source.partition cannot be set.`, }, }, } diff --git a/control-plane/api/v1alpha1/serviceintentions_webhook.go b/control-plane/api/v1alpha1/serviceintentions_webhook.go index fef2401fb3..ddc6488690 100644 --- a/control-plane/api/v1alpha1/serviceintentions_webhook.go +++ b/control-plane/api/v1alpha1/serviceintentions_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/serviceintentions_webhook_test.go b/control-plane/api/v1alpha1/serviceintentions_webhook_test.go index 238ff7f33e..2df10ad11d 100644 --- a/control-plane/api/v1alpha1/serviceintentions_webhook_test.go +++ b/control-plane/api/v1alpha1/serviceintentions_webhook_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/serviceresolver_types.go b/control-plane/api/v1alpha1/serviceresolver_types.go index 3a8e907222..4fc637b35f 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types.go +++ b/control-plane/api/v1alpha1/serviceresolver_types.go @@ -1,23 +1,17 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( "encoding/json" - "regexp" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/hashicorp/consul-k8s/control-plane/api/common" + capi "github.com/hashicorp/consul/api" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/validation/field" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" - capi "github.com/hashicorp/consul/api" - "github.com/hashicorp/go-bexpr" ) const ServiceResolverKubeKind string = "serviceresolver" @@ -76,15 +70,9 @@ type ServiceResolverSpec struct { // ConnectTimeout is the timeout for establishing new network connections // to this service. ConnectTimeout metav1.Duration `json:"connectTimeout,omitempty"` - // RequestTimeout is the timeout for receiving an HTTP response from this - // service before the connection is terminated. - RequestTimeout metav1.Duration `json:"requestTimeout,omitempty"` // LoadBalancer determines the load balancing policy and configuration for services // issuing requests to this upstream service. LoadBalancer *LoadBalancer `json:"loadBalancer,omitempty"` - // PrioritizeByLocality controls whether the locality of services within the - // local partition will be used to prioritize connectivity. - PrioritizeByLocality *PrioritizeByLocality `json:"prioritizeByLocality,omitempty"` } type ServiceResolverRedirect struct { @@ -106,8 +94,6 @@ type ServiceResolverRedirect struct { // Peer is the name of the cluster peer to resolve the service from instead // of the current one. Peer string `json:"peer,omitempty"` - // SamenessGroup is the name of the sameness group to resolve the service from instead of the current one. - SamenessGroup string `json:"samenessGroup,omitempty"` } type ServiceResolverSubsetMap map[string]ServiceResolverSubset @@ -142,10 +128,6 @@ type ServiceResolverFailover struct { Datacenters []string `json:"datacenters,omitempty"` // Targets specifies a fixed list of failover targets to try during failover. Targets []ServiceResolverFailoverTarget `json:"targets,omitempty"` - // Policy specifies the exact mechanism used for failover. - Policy *FailoverPolicy `json:"policy,omitempty"` - // SamenessGroup is the name of the sameness group to try during failover. - SamenessGroup string `json:"samenessGroup,omitempty"` } type ServiceResolverFailoverTarget struct { @@ -306,17 +288,15 @@ func (in *ServiceResolver) SyncedConditionStatus() corev1.ConditionStatus { // ToConsul converts the entry into its Consul equivalent struct. func (in *ServiceResolver) ToConsul(datacenter string) capi.ConfigEntry { return &capi.ServiceResolverConfigEntry{ - Kind: in.ConsulKind(), - Name: in.ConsulName(), - DefaultSubset: in.Spec.DefaultSubset, - Subsets: in.Spec.Subsets.toConsul(), - Redirect: in.Spec.Redirect.toConsul(), - Failover: in.Spec.Failover.toConsul(), - ConnectTimeout: in.Spec.ConnectTimeout.Duration, - RequestTimeout: in.Spec.RequestTimeout.Duration, - LoadBalancer: in.Spec.LoadBalancer.toConsul(), - PrioritizeByLocality: in.Spec.PrioritizeByLocality.toConsul(), - Meta: meta(datacenter), + Kind: in.ConsulKind(), + Name: in.ConsulName(), + DefaultSubset: in.Spec.DefaultSubset, + Subsets: in.Spec.Subsets.toConsul(), + Redirect: in.Spec.Redirect.toConsul(), + Failover: in.Spec.Failover.toConsul(), + ConnectTimeout: in.Spec.ConnectTimeout.Duration, + LoadBalancer: in.Spec.LoadBalancer.toConsul(), + Meta: meta(datacenter), } } @@ -337,18 +317,14 @@ func (in *ServiceResolver) Validate(consulMeta common.ConsulMeta) error { var errs field.ErrorList path := field.NewPath("spec") - for subset, f := range in.Spec.Failover { - errs = append(errs, f.validate(path.Child("failover").Key(subset), consulMeta)...) - } - if len(in.Spec.Failover) > 0 && in.Spec.Redirect != nil { - asJSON, _ := json.Marshal(in) - errs = append(errs, field.Invalid(path, string(asJSON), "service resolver redirect and failover cannot both be set")) + for k, v := range in.Spec.Failover { + if err := v.validate(path.Child("failover").Key(k)); err != nil { + errs = append(errs, err) + } } - errs = append(errs, in.Spec.Redirect.validate(path.Child("redirect"), consulMeta)...) - errs = append(errs, in.Spec.PrioritizeByLocality.validate(path.Child("prioritizeByLocality"))...) - errs = append(errs, in.Spec.Subsets.validate(path.Child("subsets"))...) errs = append(errs, in.Spec.LoadBalancer.validate(path.Child("loadBalancer"))...) + errs = append(errs, in.validateEnterprise(consulMeta)...) if len(errs) > 0 { @@ -375,31 +351,6 @@ func (in ServiceResolverSubsetMap) toConsul() map[string]capi.ServiceResolverSub return m } -func (in ServiceResolverSubsetMap) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if len(in) == 0 { - return nil - } - validServiceSubset := regexp.MustCompile(`^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`) - - for name, subset := range in { - indexPath := path.Key(name) - - if name == "" { - errs = append(errs, field.Invalid(indexPath, name, "subset defined with empty name")) - } - if !validServiceSubset.MatchString(name) { - errs = append(errs, field.Invalid(indexPath, name, "subset name must begin or end with lower case alphanumeric characters, and contain lower case alphanumeric characters or '-' in between")) - } - if subset.Filter != "" { - if _, err := bexpr.CreateEvaluator(subset.Filter, nil); err != nil { - errs = append(errs, field.Invalid(indexPath.Child("filter"), subset.Filter, "filter for subset is not a valid expression")) - } - } - } - return errs -} - func (in ServiceResolverSubset) toConsul() capi.ServiceResolverSubset { return capi.ServiceResolverSubset{ Filter: in.Filter, @@ -418,74 +369,7 @@ func (in *ServiceResolverRedirect) toConsul() *capi.ServiceResolverRedirect { Datacenter: in.Datacenter, Partition: in.Partition, Peer: in.Peer, - SamenessGroup: in.SamenessGroup, - } -} - -func (in *ServiceResolverRedirect) validate(path *field.Path, consulMeta common.ConsulMeta) field.ErrorList { - var errs field.ErrorList - if in == nil { - return nil - } - - asJSON, _ := json.Marshal(in) - if in.isEmpty() { - errs = append(errs, field.Invalid(path, "{}", - "service resolver redirect cannot be empty")) - } - - if consulMeta.Partition != "default" && consulMeta.Partition != "" && in.Datacenter != "" { - errs = append(errs, field.Invalid(path.Child("datacenter"), in.Datacenter, - "cross-datacenter redirect is only supported in the default partition")) - } - if consulMeta.Partition != in.Partition && in.Datacenter != "" { - errs = append(errs, field.Invalid(path.Child("partition"), in.Partition, - "cross-datacenter and cross-partition redirect is not supported")) - } - - switch { - case in.SamenessGroup != "" && in.ServiceSubset != "": - errs = append(errs, field.Invalid(path, string(asJSON), - "samenessGroup cannot be set with serviceSubset")) - case in.SamenessGroup != "" && in.Partition != "": - errs = append(errs, field.Invalid(path, string(asJSON), - "partition cannot be set with samenessGroup")) - case in.SamenessGroup != "" && in.Datacenter != "": - errs = append(errs, field.Invalid(path, string(asJSON), - "samenessGroup cannot be set with datacenter")) - case in.Peer != "" && in.ServiceSubset != "": - errs = append(errs, field.Invalid(path, string(asJSON), - "peer cannot be set with serviceSubset")) - case in.Peer != "" && in.Partition != "": - errs = append(errs, field.Invalid(path, string(asJSON), - "partition cannot be set with peer")) - case in.Peer != "" && in.Datacenter != "": - errs = append(errs, field.Invalid(path, string(asJSON), - "peer cannot be set with datacenter")) - case in.Service == "": - if in.ServiceSubset != "" { - errs = append(errs, field.Invalid(path, string(asJSON), - "serviceSubset defined without service")) - } - if in.Namespace != "" { - errs = append(errs, field.Invalid(path, string(asJSON), - "namespace defined without service")) - } - if in.Partition != "" { - errs = append(errs, field.Invalid(path, string(asJSON), - "partition defined without service")) - } - if in.Peer != "" { - errs = append(errs, field.Invalid(path, string(asJSON), - "peer defined without service")) - } } - - return errs -} - -func (in *ServiceResolverRedirect) isEmpty() bool { - return in.Service == "" && in.ServiceSubset == "" && in.Namespace == "" && in.Partition == "" && in.Datacenter == "" && in.Peer == "" && in.SamenessGroup == "" } func (in ServiceResolverFailoverMap) toConsul() map[string]capi.ServiceResolverFailover { @@ -494,38 +378,23 @@ func (in ServiceResolverFailoverMap) toConsul() map[string]capi.ServiceResolverF } m := make(map[string]capi.ServiceResolverFailover) for k, v := range in { - if f := v.toConsul(); f != nil { - m[k] = *f - } + m[k] = v.toConsul() } return m } -func (in *ServiceResolverFailover) toConsul() *capi.ServiceResolverFailover { - if in == nil { - return nil - } +func (in ServiceResolverFailover) toConsul() capi.ServiceResolverFailover { var targets []capi.ServiceResolverFailoverTarget for _, target := range in.Targets { targets = append(targets, target.toConsul()) } - var policy *capi.ServiceResolverFailoverPolicy - if in.Policy != nil { - policy = &capi.ServiceResolverFailoverPolicy{ - Mode: in.Policy.Mode, - Regions: in.Policy.Regions, - } - } - - return &capi.ServiceResolverFailover{ + return capi.ServiceResolverFailover{ Service: in.Service, ServiceSubset: in.ServiceSubset, Namespace: in.Namespace, Datacenters: in.Datacenters, Targets: targets, - Policy: policy, - SamenessGroup: in.SamenessGroup, } } @@ -635,79 +504,17 @@ func (in *ServiceResolver) validateEnterprise(consulMeta common.ConsulMeta) fiel } func (in *ServiceResolverFailover) isEmpty() bool { - return in.Service == "" && in.ServiceSubset == "" && in.Namespace == "" && len(in.Datacenters) == 0 && len(in.Targets) == 0 && in.Policy == nil && in.SamenessGroup == "" + return in.Service == "" && in.ServiceSubset == "" && in.Namespace == "" && len(in.Datacenters) == 0 && len(in.Targets) == 0 } -func (in *ServiceResolverFailover) validate(path *field.Path, consulMeta common.ConsulMeta) field.ErrorList { - var errs field.ErrorList +func (in *ServiceResolverFailover) validate(path *field.Path) *field.Error { if in.isEmpty() { // NOTE: We're passing "{}" here as our value because we know that the // error is we have an empty object. - errs = append(errs, field.Invalid(path, "{}", - "service, serviceSubset, namespace, datacenters, policy, and targets cannot all be empty at once")) - } - - if consulMeta.Partition != "default" && len(in.Datacenters) != 0 { - errs = append(errs, field.Invalid(path.Child("datacenters"), in.Datacenters, - "cross-datacenter failover is only supported in the default partition")) - } - - errs = append(errs, in.Policy.validate(path.Child("policy"))...) - - asJSON, _ := json.Marshal(in) - if in.SamenessGroup != "" { - switch { - case len(in.Datacenters) > 0: - errs = append(errs, field.Invalid(path, string(asJSON), - "samenessGroup cannot be set with datacenters")) - case in.ServiceSubset != "": - errs = append(errs, field.Invalid(path, string(asJSON), - "samenessGroup cannot be set with serviceSubset")) - case len(in.Targets) > 0: - errs = append(errs, field.Invalid(path, string(asJSON), - "samenessGroup cannot be set with targets")) - } + return field.Invalid(path, "{}", + "service, serviceSubset, namespace, datacenters, and targets cannot all be empty at once") } - - if len(in.Datacenters) != 0 && len(in.Targets) != 0 { - errs = append(errs, field.Invalid(path, string(asJSON), - "targets cannot be set with datacenters")) - } - - if in.ServiceSubset != "" && len(in.Targets) != 0 { - errs = append(errs, field.Invalid(path, string(asJSON), - "targets cannot be set with serviceSubset")) - } - - if in.Service != "" && len(in.Targets) != 0 { - errs = append(errs, field.Invalid(path, string(asJSON), - "targets cannot be set with service")) - } - - for i, target := range in.Targets { - asJSON, _ := json.Marshal(target) - switch { - case target.Peer != "" && target.ServiceSubset != "": - errs = append(errs, field.Invalid(path.Child("targets").Index(i), string(asJSON), - "target.peer cannot be set with target.serviceSubset")) - case target.Peer != "" && target.Partition != "": - errs = append(errs, field.Invalid(path.Child("targets").Index(i), string(asJSON), - "target.partition cannot be set with target.peer")) - case target.Peer != "" && target.Datacenter != "": - errs = append(errs, field.Invalid(path.Child("targets").Index(i), string(asJSON), - "target.peer cannot be set with target.datacenter")) - case target.Partition != "" && target.Datacenter != "": - errs = append(errs, field.Invalid(path.Child("targets").Index(i), string(asJSON), - "target.partition cannot be set with target.datacenter")) - } - } - - for i, dc := range in.Datacenters { - if dc == "" { - errs = append(errs, field.Invalid(path.Child("datacenters").Index(i), "", "found empty datacenter")) - } - } - return errs + return nil } func (in *LoadBalancer) validate(path *field.Path) field.ErrorList { diff --git a/control-plane/api/v1alpha1/serviceresolver_types_test.go b/control-plane/api/v1alpha1/serviceresolver_types_test.go index 3fbc2b4fce..fd4fc25a60 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types_test.go +++ b/control-plane/api/v1alpha1/serviceresolver_types_test.go @@ -1,10 +1,6 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( - "strings" "testing" "time" @@ -13,7 +9,6 @@ import ( "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/validation/field" ) func TestServiceResolver_MatchesConsul(t *testing.T) { @@ -66,45 +61,27 @@ func TestServiceResolver_MatchesConsul(t *testing.T) { Datacenter: "redirect_datacenter", Peer: "redirect_peer", }, - PrioritizeByLocality: &PrioritizeByLocality{ - Mode: "failover", - }, Failover: map[string]ServiceResolverFailover{ "failover1": { Service: "failover1", ServiceSubset: "failover_subset1", Namespace: "failover_namespace1", Datacenters: []string{"failover1_dc1", "failover1_dc2"}, - Policy: &FailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-2"}, - }, - SamenessGroup: "sg2", }, "failover2": { Service: "failover2", ServiceSubset: "failover_subset2", Namespace: "failover_namespace2", Datacenters: []string{"failover2_dc1", "failover2_dc2"}, - Policy: &FailoverPolicy{ - Mode: "", - Regions: []string{"us-west-1"}, - }, - SamenessGroup: "sg3", }, "failover3": { Targets: []ServiceResolverFailoverTarget{ {Peer: "failover_peer3"}, {Partition: "failover_partition3", Namespace: "failover_namespace3"}, }, - Policy: &FailoverPolicy{ - Mode: "order-by-locality", - Regions: []string{"us-east-1"}, - }, }, }, ConnectTimeout: metav1.Duration{Duration: 1 * time.Second}, - RequestTimeout: metav1.Duration{Duration: 1 * time.Second}, LoadBalancer: &LoadBalancer{ Policy: "policy", RingHashConfig: &RingHashConfig{ @@ -151,45 +128,27 @@ func TestServiceResolver_MatchesConsul(t *testing.T) { Datacenter: "redirect_datacenter", Peer: "redirect_peer", }, - PrioritizeByLocality: &capi.ServiceResolverPrioritizeByLocality{ - Mode: "failover", - }, Failover: map[string]capi.ServiceResolverFailover{ "failover1": { Service: "failover1", ServiceSubset: "failover_subset1", Namespace: "failover_namespace1", Datacenters: []string{"failover1_dc1", "failover1_dc2"}, - Policy: &capi.ServiceResolverFailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-2"}, - }, - SamenessGroup: "sg2", }, "failover2": { Service: "failover2", ServiceSubset: "failover_subset2", Namespace: "failover_namespace2", Datacenters: []string{"failover2_dc1", "failover2_dc2"}, - Policy: &capi.ServiceResolverFailoverPolicy{ - Mode: "", - Regions: []string{"us-west-1"}, - }, - SamenessGroup: "sg3", }, "failover3": { Targets: []capi.ServiceResolverFailoverTarget{ {Peer: "failover_peer3"}, {Partition: "failover_partition3", Namespace: "failover_namespace3"}, }, - Policy: &capi.ServiceResolverFailoverPolicy{ - Mode: "order-by-locality", - Regions: []string{"us-east-1"}, - }, }, }, ConnectTimeout: 1 * time.Second, - RequestTimeout: 1 * time.Second, LoadBalancer: &capi.LoadBalancer{ Policy: "policy", RingHashConfig: &capi.RingHashConfig{ @@ -285,45 +244,27 @@ func TestServiceResolver_ToConsul(t *testing.T) { Datacenter: "redirect_datacenter", Partition: "redirect_partition", }, - PrioritizeByLocality: &PrioritizeByLocality{ - Mode: "none", - }, Failover: map[string]ServiceResolverFailover{ "failover1": { Service: "failover1", ServiceSubset: "failover_subset1", Namespace: "failover_namespace1", Datacenters: []string{"failover1_dc1", "failover1_dc2"}, - Policy: &FailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-2"}, - }, - SamenessGroup: "sg2", }, "failover2": { Service: "failover2", ServiceSubset: "failover_subset2", Namespace: "failover_namespace2", Datacenters: []string{"failover2_dc1", "failover2_dc2"}, - Policy: &FailoverPolicy{ - Mode: "", - Regions: []string{"us-west-1"}, - }, - SamenessGroup: "sg3", }, "failover3": { Targets: []ServiceResolverFailoverTarget{ {Peer: "failover_peer3"}, {Partition: "failover_partition3", Namespace: "failover_namespace3"}, }, - Policy: &FailoverPolicy{ - Mode: "order-by-locality", - Regions: []string{"us-east-1"}, - }, }, }, ConnectTimeout: metav1.Duration{Duration: 1 * time.Second}, - RequestTimeout: metav1.Duration{Duration: 1 * time.Second}, LoadBalancer: &LoadBalancer{ Policy: "policy", RingHashConfig: &RingHashConfig{ @@ -370,45 +311,27 @@ func TestServiceResolver_ToConsul(t *testing.T) { Datacenter: "redirect_datacenter", Partition: "redirect_partition", }, - PrioritizeByLocality: &capi.ServiceResolverPrioritizeByLocality{ - Mode: "none", - }, Failover: map[string]capi.ServiceResolverFailover{ "failover1": { Service: "failover1", ServiceSubset: "failover_subset1", Namespace: "failover_namespace1", Datacenters: []string{"failover1_dc1", "failover1_dc2"}, - Policy: &capi.ServiceResolverFailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-2"}, - }, - SamenessGroup: "sg2", }, "failover2": { Service: "failover2", ServiceSubset: "failover_subset2", Namespace: "failover_namespace2", Datacenters: []string{"failover2_dc1", "failover2_dc2"}, - Policy: &capi.ServiceResolverFailoverPolicy{ - Mode: "", - Regions: []string{"us-west-1"}, - }, - SamenessGroup: "sg3", }, "failover3": { Targets: []capi.ServiceResolverFailoverTarget{ {Peer: "failover_peer3"}, {Partition: "failover_partition3", Namespace: "failover_namespace3"}, }, - Policy: &capi.ServiceResolverFailoverPolicy{ - Mode: "order-by-locality", - Regions: []string{"us-east-1"}, - }, }, }, ConnectTimeout: 1 * time.Second, - RequestTimeout: 1 * time.Second, LoadBalancer: &capi.LoadBalancer{ Policy: "policy", RingHashConfig: &capi.RingHashConfig{ @@ -569,15 +492,16 @@ func TestServiceResolver_Validate(t *testing.T) { Name: "foo", }, Spec: ServiceResolverSpec{ + Redirect: &ServiceResolverRedirect{ + Service: "bar", + Namespace: "namespace-a", + }, Failover: map[string]ServiceResolverFailover{ - "v1": { + "failA": { Service: "baz", Namespace: "namespace-b", }, }, - Subsets: map[string]ServiceResolverSubset{ - "v1": {Filter: "Service.Meta.version == v1"}, - }, }, }, namespacesEnabled: true, @@ -593,8 +517,10 @@ func TestServiceResolver_Validate(t *testing.T) { Redirect: &ServiceResolverRedirect{ Service: "bar", }, - Subsets: map[string]ServiceResolverSubset{ - "v1": {Filter: "Service.Meta.version == v1"}, + Failover: map[string]ServiceResolverFailover{ + "failA": { + Service: "baz", + }, }, }, }, @@ -608,15 +534,17 @@ func TestServiceResolver_Validate(t *testing.T) { Name: "foo", }, Spec: ServiceResolverSpec{ + Redirect: &ServiceResolverRedirect{ + Service: "bar", + Namespace: "namespace-a", + Partition: "other", + }, Failover: map[string]ServiceResolverFailover{ - "v1": { + "failA": { Service: "baz", Namespace: "namespace-b", }, }, - Subsets: map[string]ServiceResolverSubset{ - "v1": {Filter: "Service.Meta.version == v1"}, - }, }, }, namespacesEnabled: true, @@ -632,6 +560,11 @@ func TestServiceResolver_Validate(t *testing.T) { Redirect: &ServiceResolverRedirect{ Service: "bar", }, + Failover: map[string]ServiceResolverFailover{ + "failA": { + Service: "baz", + }, + }, }, }, namespacesEnabled: false, @@ -645,13 +578,13 @@ func TestServiceResolver_Validate(t *testing.T) { }, Spec: ServiceResolverSpec{ Failover: map[string]ServiceResolverFailover{ - "v1": { + "failA": { Service: "", ServiceSubset: "", Namespace: "", Datacenters: nil, }, - "v2": { + "failB": { Service: "", ServiceSubset: "", Namespace: "", @@ -662,32 +595,10 @@ func TestServiceResolver_Validate(t *testing.T) { }, namespacesEnabled: false, expectedErrMsgs: []string{ - "spec.failover[v1]: Invalid value: \"{}\": service, serviceSubset, namespace, datacenters, policy, and targets cannot all be empty at once", - "spec.failover[v2]: Invalid value: \"{}\": service, serviceSubset, namespace, datacenters, policy, and targets cannot all be empty at once", + "spec.failover[failA]: Invalid value: \"{}\": service, serviceSubset, namespace, datacenters, and targets cannot all be empty at once", + "spec.failover[failB]: Invalid value: \"{}\": service, serviceSubset, namespace, datacenters, and targets cannot all be empty at once", }, }, - "service resolver redirect and failover cannot both be set": { - input: &ServiceResolver{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: ServiceResolverSpec{ - Redirect: &ServiceResolverRedirect{ - Service: "bar", - Namespace: "namespace-a", - }, - Failover: map[string]ServiceResolverFailover{ - "failA": { - Service: "baz", - Namespace: "namespace-b", - }, - }, - }, - }, - namespacesEnabled: true, - partitionsEnabled: false, - expectedErrMsgs: []string{"service resolver redirect and failover cannot both be set"}, - }, "hashPolicy.field invalid": { input: &ServiceResolver{ ObjectMeta: metav1.ObjectMeta{ @@ -761,19 +672,11 @@ func TestServiceResolver_Validate(t *testing.T) { }, }, }, - Subsets: map[string]ServiceResolverSubset{ - "": { - Filter: "random string", - }, - }, }, }, namespacesEnabled: false, expectedErrMsgs: []string{ - `spec.loadBalancer.hashPolicies[0]: Invalid value: "{\"field\":\"header\",\"sourceIP\":true}": cannot set both field and sourceIP`, - `subset defined with empty name`, - `subset name must begin or end with lower case alphanumeric characters, and contain lower case alphanumeric characters or '-' in between`, - `filter for subset is not a valid expression`, + `serviceresolver.consul.hashicorp.com "foo" is invalid: spec.loadBalancer.hashPolicies[0]: Invalid value: "{\"field\":\"header\",\"sourceIP\":true}": cannot set both field and sourceIP`, }, }, "hashPolicy nothing set is valid": { @@ -824,7 +727,6 @@ func TestServiceResolver_Validate(t *testing.T) { }, Spec: ServiceResolverSpec{ Redirect: &ServiceResolverRedirect{ - Service: "bar", Namespace: "namespace-a", }, }, @@ -841,7 +743,6 @@ func TestServiceResolver_Validate(t *testing.T) { }, Spec: ServiceResolverSpec{ Redirect: &ServiceResolverRedirect{ - Service: "bar", Namespace: "namespace-a", Partition: "other", }, @@ -860,19 +761,14 @@ func TestServiceResolver_Validate(t *testing.T) { }, Spec: ServiceResolverSpec{ Failover: map[string]ServiceResolverFailover{ - "v1": { + "failA": { Namespace: "namespace-a", }, }, - Subsets: map[string]ServiceResolverSubset{ - "v1": { - Filter: "Service.Meta.version == v1", - }, - }, }, }, expectedErrMsgs: []string{ - "serviceresolver.consul.hashicorp.com \"foo\" is invalid: spec.failover[v1].namespace: Invalid value: \"namespace-a\": Consul Enterprise namespaces must be enabled to set failover.namespace", + "serviceresolver.consul.hashicorp.com \"foo\" is invalid: spec.failover[failA].namespace: Invalid value: \"namespace-a\": Consul Enterprise namespaces must be enabled to set failover.namespace", }, namespacesEnabled: false, }, @@ -898,22 +794,6 @@ func TestServiceResolver_Validate(t *testing.T) { "spec.failover[failB].namespace: Invalid value: \"namespace-b\": Consul Enterprise namespaces must be enabled to set failover.namespace", }, }, - "prioritize by locality invalid": { - input: &ServiceResolver{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - }, - Spec: ServiceResolverSpec{ - PrioritizeByLocality: &PrioritizeByLocality{ - Mode: "bad", - }, - }, - }, - namespacesEnabled: false, - expectedErrMsgs: []string{ - "serviceresolver.consul.hashicorp.com \"foo\" is invalid: spec.prioritizeByLocality.mode: Invalid value: \"bad\": must be one of \"\", \"none\", \"failover\"", - }, - }, } for name, testCase := range cases { t.Run(name, func(t *testing.T) { @@ -929,497 +809,3 @@ func TestServiceResolver_Validate(t *testing.T) { }) } } - -func TestServiceResolverRedirect_ToConsul(t *testing.T) { - cases := map[string]struct { - Ours *ServiceResolverRedirect - Exp *capi.ServiceResolverRedirect - }{ - "nil": { - Ours: nil, - Exp: nil, - }, - "empty fields": { - Ours: &ServiceResolverRedirect{}, - Exp: &capi.ServiceResolverRedirect{}, - }, - "every field set": { - Ours: &ServiceResolverRedirect{ - Service: "foo", - ServiceSubset: "v1", - Namespace: "ns1", - Datacenter: "dc1", - Partition: "default", - Peer: "peer1", - SamenessGroup: "sg1", - }, - Exp: &capi.ServiceResolverRedirect{ - Service: "foo", - ServiceSubset: "v1", - Namespace: "ns1", - Datacenter: "dc1", - Partition: "default", - Peer: "peer1", - SamenessGroup: "sg1", - }, - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - actual := c.Ours.toConsul() - require.Equal(t, c.Exp, actual) - }) - } -} - -func TestServiceResolverRedirect_Validate(t *testing.T) { - cases := map[string]struct { - input *ServiceResolverRedirect - consulMeta common.ConsulMeta - expectedErrMsgs []string - }{ - "empty redirect": { - input: &ServiceResolverRedirect{}, - consulMeta: common.ConsulMeta{}, - expectedErrMsgs: []string{ - "service resolver redirect cannot be empty", - }, - }, - "cross-datacenter redirect is only supported in the default partition": { - input: &ServiceResolverRedirect{ - Datacenter: "dc2", - Partition: "p2", - Service: "foo", - }, - consulMeta: common.ConsulMeta{ - Partition: "p2", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "cross-datacenter redirect is only supported in the default partition", - }, - }, - "cross-datacenter and cross-partition redirect is not supported": { - input: &ServiceResolverRedirect{ - Partition: "p1", - Datacenter: "dc2", - Service: "foo", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "cross-datacenter and cross-partition redirect is not supported", - }, - }, - "samenessGroup cannot be set with serviceSubset": { - input: &ServiceResolverRedirect{ - Service: "foo", - ServiceSubset: "v1", - SamenessGroup: "sg2", - }, - expectedErrMsgs: []string{ - "samenessGroup cannot be set with serviceSubset", - }, - }, - "samenessGroup cannot be set with partition": { - input: &ServiceResolverRedirect{ - Partition: "default", - Service: "foo", - SamenessGroup: "sg2", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "partition cannot be set with samenessGroup", - }, - }, - "samenessGroup cannot be set with datacenter": { - input: &ServiceResolverRedirect{ - Datacenter: "dc2", - Service: "foo", - SamenessGroup: "sg2", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "cross-datacenter and cross-partition redirect is not supported", - "samenessGroup cannot be set with datacenter", - }, - }, - "peer cannot be set with serviceSubset": { - input: &ServiceResolverRedirect{ - Peer: "p2", - Service: "foo", - ServiceSubset: "v1", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "peer cannot be set with serviceSubset", - }, - }, - "partition cannot be set with peer": { - input: &ServiceResolverRedirect{ - Partition: "default", - Peer: "p2", - Service: "foo", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "partition cannot be set with peer", - }, - }, - "peer cannot be set with datacenter": { - input: &ServiceResolverRedirect{ - Peer: "p2", - Service: "foo", - Datacenter: "dc2", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "peer cannot be set with datacenter", - "cross-datacenter and cross-partition redirect is not supported", - }, - }, - "serviceSubset defined without service": { - input: &ServiceResolverRedirect{ - ServiceSubset: "v1", - }, - consulMeta: common.ConsulMeta{ - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "serviceSubset defined without service", - }, - }, - "namespace defined without service": { - input: &ServiceResolverRedirect{ - Namespace: "ns1", - }, - consulMeta: common.ConsulMeta{ - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "namespace defined without service", - }, - }, - "partition defined without service": { - input: &ServiceResolverRedirect{ - Partition: "default", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "partition defined without service", - }, - }, - "peer defined without service": { - input: &ServiceResolverRedirect{ - Peer: "p2", - }, - consulMeta: common.ConsulMeta{ - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "peer defined without service", - }, - }, - } - - path := field.NewPath("spec.redirect") - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - errList := testCase.input.validate(path, testCase.consulMeta) - compareErrorLists(t, testCase.expectedErrMsgs, errList) - }) - } -} - -func compareErrorLists(t *testing.T, expectedErrMsgs []string, errList field.ErrorList) { - if len(expectedErrMsgs) != 0 { - require.Equal(t, len(expectedErrMsgs), len(errList)) - for _, m := range expectedErrMsgs { - found := false - for _, e := range errList { - errMsg := e.ErrorBody() - if strings.Contains(errMsg, m) { - found = true - break - } - } - require.Equal(t, true, found) - } - } else { - require.Equal(t, 0, len(errList)) - } -} - -func TestServiceResolverFailover_ToConsul(t *testing.T) { - cases := map[string]struct { - Ours *ServiceResolverFailover - Exp *capi.ServiceResolverFailover - }{ - "nil": { - Ours: nil, - Exp: nil, - }, - "empty fields": { - Ours: &ServiceResolverFailover{}, - Exp: &capi.ServiceResolverFailover{}, - }, - "every field set": { - Ours: &ServiceResolverFailover{ - Service: "foo", - ServiceSubset: "v1", - Namespace: "ns1", - Datacenters: []string{"dc1"}, - Targets: []ServiceResolverFailoverTarget{ - { - Peer: "p2", - }, - }, - Policy: &FailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-2"}, - }, - SamenessGroup: "sg1", - }, - Exp: &capi.ServiceResolverFailover{ - Service: "foo", - ServiceSubset: "v1", - Namespace: "ns1", - Datacenters: []string{"dc1"}, - Targets: []capi.ServiceResolverFailoverTarget{ - { - Peer: "p2", - }, - }, - Policy: &capi.ServiceResolverFailoverPolicy{ - Mode: "sequential", - Regions: []string{"us-west-2"}, - }, - SamenessGroup: "sg1", - }, - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - actual := c.Ours.toConsul() - require.Equal(t, c.Exp, actual) - }) - } -} - -func TestServiceResolverFailover_Validate(t *testing.T) { - cases := map[string]struct { - input *ServiceResolverFailover - consulMeta common.ConsulMeta - expectedErrMsgs []string - }{ - "empty failover": { - input: &ServiceResolverFailover{}, - consulMeta: common.ConsulMeta{}, - expectedErrMsgs: []string{ - "service, serviceSubset, namespace, datacenters, policy, and targets cannot all be empty at once", - }, - }, - "cross-datacenter failover is only supported in the default partition": { - input: &ServiceResolverFailover{ - Datacenters: []string{"dc2"}, - Service: "foo", - }, - consulMeta: common.ConsulMeta{ - Partition: "p2", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "cross-datacenter failover is only supported in the default partition", - }, - }, - "samenessGroup cannot be set with datacenters": { - input: &ServiceResolverFailover{ - Service: "foo", - Datacenters: []string{"dc2"}, - SamenessGroup: "sg2", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "samenessGroup cannot be set with datacenters", - }, - }, - "samenessGroup cannot be set with serviceSubset": { - input: &ServiceResolverFailover{ - ServiceSubset: "v1", - Service: "foo", - SamenessGroup: "sg2", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "samenessGroup cannot be set with serviceSubset", - }, - }, - "samenessGroup cannot be set with targets": { - input: &ServiceResolverFailover{ - Targets: []ServiceResolverFailoverTarget{ - { - Peer: "p2", - }, - }, - SamenessGroup: "sg2", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "samenessGroup cannot be set with targets", - }, - }, - "targets cannot be set with datacenters": { - input: &ServiceResolverFailover{ - Targets: []ServiceResolverFailoverTarget{ - { - Peer: "p2", - }, - }, - Datacenters: []string{"dc1"}, - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "targets cannot be set with datacenters", - }, - }, - "targets cannot be set with serviceSubset or service": { - input: &ServiceResolverFailover{ - Targets: []ServiceResolverFailoverTarget{ - { - Peer: "p2", - }, - }, - ServiceSubset: "v1", - Service: "foo", - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "targets cannot be set with serviceSubset", - "targets cannot be set with service", - }, - }, - "target.peer cannot be set with target.serviceSubset": { - input: &ServiceResolverFailover{ - Targets: []ServiceResolverFailoverTarget{ - { - Peer: "p2", - ServiceSubset: "v1", - }, - }, - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "target.peer cannot be set with target.serviceSubset", - }, - }, - "target.partition cannot be set with target.peer": { - input: &ServiceResolverFailover{ - Targets: []ServiceResolverFailoverTarget{ - { - Peer: "p2", - Partition: "partition2", - }, - }, - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "target.partition cannot be set with target.peer", - }, - }, - "target.peer cannot be set with target.datacenter": { - input: &ServiceResolverFailover{ - Targets: []ServiceResolverFailoverTarget{ - { - Peer: "p2", - Datacenter: "dc2", - }, - }, - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "target.peer cannot be set with target.datacenter", - }, - }, - "target.partition cannot be set with target.datacenter": { - input: &ServiceResolverFailover{ - Targets: []ServiceResolverFailoverTarget{ - { - Partition: "p2", - Datacenter: "dc2", - }, - }, - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "target.partition cannot be set with target.datacenter", - }, - }, - "found empty datacenter": { - input: &ServiceResolverFailover{ - Datacenters: []string{""}, - }, - consulMeta: common.ConsulMeta{ - Partition: "default", - PartitionsEnabled: true, - }, - expectedErrMsgs: []string{ - "found empty datacenter", - }, - }, - } - - path := field.NewPath("spec.redirect") - for name, testCase := range cases { - t.Run(name, func(t *testing.T) { - errList := testCase.input.validate(path, testCase.consulMeta) - compareErrorLists(t, testCase.expectedErrMsgs, errList) - }) - } -} diff --git a/control-plane/api/v1alpha1/serviceresolver_webhook.go b/control-plane/api/v1alpha1/serviceresolver_webhook.go index 88996e2f8d..ca5f9d9482 100644 --- a/control-plane/api/v1alpha1/serviceresolver_webhook.go +++ b/control-plane/api/v1alpha1/serviceresolver_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/servicerouter_types.go b/control-plane/api/v1alpha1/servicerouter_types.go index 43e7353bf5..931d5ccb3a 100644 --- a/control-plane/api/v1alpha1/servicerouter_types.go +++ b/control-plane/api/v1alpha1/servicerouter_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/servicerouter_types_test.go b/control-plane/api/v1alpha1/servicerouter_types_test.go index 653bdc26c1..3110922210 100644 --- a/control-plane/api/v1alpha1/servicerouter_types_test.go +++ b/control-plane/api/v1alpha1/servicerouter_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/servicerouter_webhook.go b/control-plane/api/v1alpha1/servicerouter_webhook.go index cdcc3ba439..f6837fcf7b 100644 --- a/control-plane/api/v1alpha1/servicerouter_webhook.go +++ b/control-plane/api/v1alpha1/servicerouter_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/servicesplitter_types.go b/control-plane/api/v1alpha1/servicesplitter_types.go index d94dbb7120..b61b1a320b 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types.go +++ b/control-plane/api/v1alpha1/servicesplitter_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/servicesplitter_types_test.go b/control-plane/api/v1alpha1/servicesplitter_types_test.go index e2ade99f1c..48e9eeac54 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types_test.go +++ b/control-plane/api/v1alpha1/servicesplitter_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/servicesplitter_webhook.go b/control-plane/api/v1alpha1/servicesplitter_webhook.go index 42dbbbf54a..c0020c88b8 100644 --- a/control-plane/api/v1alpha1/servicesplitter_webhook.go +++ b/control-plane/api/v1alpha1/servicesplitter_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/shared_types.go b/control-plane/api/v1alpha1/shared_types.go index 148376a393..9b884cf476 100644 --- a/control-plane/api/v1alpha1/shared_types.go +++ b/control-plane/api/v1alpha1/shared_types.go @@ -1,10 +1,6 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( - "encoding/json" "fmt" "strings" @@ -16,9 +12,6 @@ import ( // This file contains structs that are shared between multiple config entries. -// metaValueMaxLength is the maximum allowed string length of a metadata value. -const metaValueMaxLength = 512 - type MeshGatewayMode string // Expose describes HTTP paths to expose through Envoy outside of Connect. @@ -58,35 +51,6 @@ type TransparentProxy struct { DialedDirectly bool `json:"dialedDirectly,omitempty"` } -type MutualTLSMode string - -const ( - // MutualTLSModeDefault represents no specific mode and should - // be used to indicate that a different layer of the configuration - // chain should take precedence. - MutualTLSModeDefault MutualTLSMode = "" - - // MutualTLSModeStrict requires mTLS for incoming traffic. - MutualTLSModeStrict MutualTLSMode = "strict" - - // MutualTLSModePermissive allows incoming non-mTLS traffic. - MutualTLSModePermissive MutualTLSMode = "permissive" -) - -func (m MutualTLSMode) validate() error { - switch m { - case MutualTLSModeDefault, MutualTLSModeStrict, MutualTLSModePermissive: - return nil - } - return fmt.Errorf("Must be one of %q, %q, or %q.", - MutualTLSModeDefault, MutualTLSModeStrict, MutualTLSModePermissive, - ) -} - -func (m MutualTLSMode) toConsul() capi.MutualTLSMode { - return capi.MutualTLSMode(m) -} - // MeshGateway controls how Mesh Gateways are used for upstream Connect // services. type MeshGateway struct { @@ -115,19 +79,6 @@ type HTTPHeaderModifiers struct { Remove []string `json:"remove,omitempty"` } -// EnvoyExtension has configuration for an extension that patches Envoy resources. -type EnvoyExtension struct { - Name string `json:"name,omitempty"` - Required bool `json:"required,omitempty"` - // +kubebuilder:validation:Type=object - // +kubebuilder:validation:Schemaless - // +kubebuilder:pruning:PreserveUnknownFields - Arguments json.RawMessage `json:"arguments,omitempty"` -} - -// EnvoyExtensions represents a list of the EnvoyExtension configuration. -type EnvoyExtensions []EnvoyExtension - func (in MeshGateway) toConsul() capi.MeshGatewayConfig { mode := capi.MeshGatewayMode(in.Mode) switch mode { @@ -225,122 +176,6 @@ func (in *HTTPHeaderModifiers) toConsul() *capi.HTTPHeaderModifiers { } } -func (in EnvoyExtensions) toConsul() []capi.EnvoyExtension { - if in == nil { - return nil - } - - outConfig := make([]capi.EnvoyExtension, 0) - - for _, e := range in { - consulExtension := capi.EnvoyExtension{ - Name: e.Name, - Required: e.Required, - } - - // We already validate that arguments is present - var args map[string]interface{} - _ = json.Unmarshal(e.Arguments, &args) - consulExtension.Arguments = args - outConfig = append(outConfig, consulExtension) - } - - return outConfig -} - -func (in EnvoyExtensions) validate(path *field.Path) field.ErrorList { - if len(in) == 0 { - return nil - } - - var errs field.ErrorList - for i, e := range in { - if err := e.validate(path.Child("envoyExtension").Index(i)); err != nil { - errs = append(errs, err) - } - } - - return errs -} - -func (in EnvoyExtension) validate(path *field.Path) *field.Error { - // Validate that the arguments are not nil - if in.Arguments == nil { - err := field.Required(path.Child("arguments"), "arguments must be defined") - return err - } - // Validate that the arguments are valid json - var outConfig map[string]interface{} - if err := json.Unmarshal(in.Arguments, &outConfig); err != nil { - return field.Invalid(path.Child("arguments"), string(in.Arguments), fmt.Sprintf(`must be valid map value: %s`, err)) - } - return nil -} - -// FailoverPolicy specifies the exact mechanism used for failover. -type FailoverPolicy struct { - // Mode specifies the type of failover that will be performed. Valid values are - // "sequential", "" (equivalent to "sequential") and "order-by-locality". - Mode string `json:"mode,omitempty"` - // Regions is the ordered list of the regions of the failover targets. - // Valid values can be "us-west-1", "us-west-2", and so on. - Regions []string `json:"regions,omitempty"` -} - -func (in *FailoverPolicy) toConsul() *capi.ServiceResolverFailoverPolicy { - if in == nil { - return nil - } - - return &capi.ServiceResolverFailoverPolicy{ - Mode: in.Mode, - Regions: in.Regions, - } -} - -func (in *FailoverPolicy) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if in == nil { - return nil - } - modes := []string{"", "sequential", "order-by-locality"} - if !sliceContains(modes, in.Mode) { - errs = append(errs, field.Invalid(path.Child("mode"), in.Mode, notInSliceMessage(modes))) - } - return errs -} - -// PrioritizeByLocality controls whether the locality of services within the -// local partition will be used to prioritize connectivity. -type PrioritizeByLocality struct { - // Mode specifies the type of prioritization that will be performed - // when selecting nodes in the local partition. - // Valid values are: "" (default "none"), "none", and "failover". - Mode string `json:"mode,omitempty"` -} - -func (in *PrioritizeByLocality) toConsul() *capi.ServiceResolverPrioritizeByLocality { - if in == nil { - return nil - } - - return &capi.ServiceResolverPrioritizeByLocality{ - Mode: in.Mode, - } -} - -func (in *PrioritizeByLocality) validate(path *field.Path) field.ErrorList { - var errs field.ErrorList - if in == nil { - return nil - } - modes := []string{"", "none", "failover"} - if !sliceContains(modes, in.Mode) { - errs = append(errs, field.Invalid(path.Child("mode"), in.Mode, notInSliceMessage(modes))) - } - return errs -} - func notInSliceMessage(slice []string) string { return fmt.Sprintf(`must be one of "%s"`, strings.Join(slice, `", "`)) } diff --git a/control-plane/api/v1alpha1/status.go b/control-plane/api/v1alpha1/status.go index 0e11bf930b..d7cd0e0b78 100644 --- a/control-plane/api/v1alpha1/status.go +++ b/control-plane/api/v1alpha1/status.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/terminatinggateway_types.go b/control-plane/api/v1alpha1/terminatinggateway_types.go index cf453160ff..6e708b5d44 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_types.go +++ b/control-plane/api/v1alpha1/terminatinggateway_types.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/terminatinggateway_types_test.go b/control-plane/api/v1alpha1/terminatinggateway_types_test.go index 2daf93c6a4..9d8ba9948d 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_types_test.go +++ b/control-plane/api/v1alpha1/terminatinggateway_types_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/terminatinggateway_webhook.go b/control-plane/api/v1alpha1/terminatinggateway_webhook.go index 481a1a1f15..b0427b87ca 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_webhook.go +++ b/control-plane/api/v1alpha1/terminatinggateway_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package v1alpha1 import ( diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index 6786b38004..9131d5aeef 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -7,26 +7,10 @@ package v1alpha1 import ( "encoding/json" - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AccessLogs) DeepCopyInto(out *AccessLogs) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AccessLogs. -func (in *AccessLogs) DeepCopy() *AccessLogs { - if in == nil { - return nil - } - out := new(AccessLogs) - 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 @@ -64,146 +48,6 @@ func (in Conditions) DeepCopy() Conditions { return *out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ControlPlaneRequestLimit) DeepCopyInto(out *ControlPlaneRequestLimit) { - *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 ControlPlaneRequestLimit. -func (in *ControlPlaneRequestLimit) DeepCopy() *ControlPlaneRequestLimit { - if in == nil { - return nil - } - out := new(ControlPlaneRequestLimit) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ControlPlaneRequestLimit) 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 *ControlPlaneRequestLimitList) DeepCopyInto(out *ControlPlaneRequestLimitList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]ControlPlaneRequestLimit, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneRequestLimitList. -func (in *ControlPlaneRequestLimitList) DeepCopy() *ControlPlaneRequestLimitList { - if in == nil { - return nil - } - out := new(ControlPlaneRequestLimitList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ControlPlaneRequestLimitList) 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 *ControlPlaneRequestLimitSpec) DeepCopyInto(out *ControlPlaneRequestLimitSpec) { - *out = *in - out.ReadWriteRatesConfig = in.ReadWriteRatesConfig - if in.ACL != nil { - in, out := &in.ACL, &out.ACL - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.Catalog != nil { - in, out := &in.Catalog, &out.Catalog - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.ConfigEntry != nil { - in, out := &in.ConfigEntry, &out.ConfigEntry - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.ConnectCA != nil { - in, out := &in.ConnectCA, &out.ConnectCA - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.Coordinate != nil { - in, out := &in.Coordinate, &out.Coordinate - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.DiscoveryChain != nil { - in, out := &in.DiscoveryChain, &out.DiscoveryChain - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.Health != nil { - in, out := &in.Health, &out.Health - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.Intention != nil { - in, out := &in.Intention, &out.Intention - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.KV != nil { - in, out := &in.KV, &out.KV - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.Tenancy != nil { - in, out := &in.Tenancy, &out.Tenancy - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.PreparedQuery != nil { - in, out := &in.PreparedQuery, &out.PreparedQuery - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.Session != nil { - in, out := &in.Session, &out.Session - *out = new(ReadWriteRatesConfig) - **out = **in - } - if in.Txn != nil { - in, out := &in.Txn, &out.Txn - *out = new(ReadWriteRatesConfig) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneRequestLimitSpec. -func (in *ControlPlaneRequestLimitSpec) DeepCopy() *ControlPlaneRequestLimitSpec { - if in == nil { - return nil - } - out := new(ControlPlaneRequestLimitSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CookieConfig) DeepCopyInto(out *CookieConfig) { *out = *in @@ -220,102 +64,6 @@ func (in *CookieConfig) DeepCopy() *CookieConfig { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CopyAnnotationsSpec) DeepCopyInto(out *CopyAnnotationsSpec) { - *out = *in - if in.Service != nil { - in, out := &in.Service, &out.Service - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CopyAnnotationsSpec. -func (in *CopyAnnotationsSpec) DeepCopy() *CopyAnnotationsSpec { - if in == nil { - return nil - } - out := new(CopyAnnotationsSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { - *out = *in - if in.DefaultInstances != nil { - in, out := &in.DefaultInstances, &out.DefaultInstances - *out = new(int32) - **out = **in - } - if in.MaxInstances != nil { - in, out := &in.MaxInstances, &out.MaxInstances - *out = new(int32) - **out = **in - } - if in.MinInstances != nil { - in, out := &in.MinInstances, &out.MinInstances - *out = new(int32) - **out = **in - } - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = new(v1.ResourceRequirements) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentSpec. -func (in *DeploymentSpec) DeepCopy() *DeploymentSpec { - if in == nil { - return nil - } - out := new(DeploymentSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EnvoyExtension) DeepCopyInto(out *EnvoyExtension) { - *out = *in - if in.Arguments != nil { - in, out := &in.Arguments, &out.Arguments - *out = make(json.RawMessage, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyExtension. -func (in *EnvoyExtension) DeepCopy() *EnvoyExtension { - if in == nil { - return nil - } - out := new(EnvoyExtension) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in EnvoyExtensions) DeepCopyInto(out *EnvoyExtensions) { - { - in := &in - *out = make(EnvoyExtensions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyExtensions. -func (in EnvoyExtensions) DeepCopy() EnvoyExtensions { - if in == nil { - return nil - } - out := new(EnvoyExtensions) - in.DeepCopyInto(out) - return *out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ExportedService) DeepCopyInto(out *ExportedService) { *out = *in @@ -452,120 +200,6 @@ func (in *ExposePath) DeepCopy() *ExposePath { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FailoverPolicy) DeepCopyInto(out *FailoverPolicy) { - *out = *in - if in.Regions != nil { - in, out := &in.Regions, &out.Regions - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailoverPolicy. -func (in *FailoverPolicy) DeepCopy() *FailoverPolicy { - if in == nil { - return nil - } - out := new(FailoverPolicy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GatewayClassConfig) DeepCopyInto(out *GatewayClassConfig) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayClassConfig. -func (in *GatewayClassConfig) DeepCopy() *GatewayClassConfig { - if in == nil { - return nil - } - out := new(GatewayClassConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *GatewayClassConfig) 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 *GatewayClassConfigList) DeepCopyInto(out *GatewayClassConfigList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]GatewayClassConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayClassConfigList. -func (in *GatewayClassConfigList) DeepCopy() *GatewayClassConfigList { - if in == nil { - return nil - } - out := new(GatewayClassConfigList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *GatewayClassConfigList) 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 *GatewayClassConfigSpec) DeepCopyInto(out *GatewayClassConfigSpec) { - *out = *in - if in.ServiceType != nil { - in, out := &in.ServiceType, &out.ServiceType - *out = new(v1.ServiceType) - **out = **in - } - if in.NodeSelector != nil { - in, out := &in.NodeSelector, &out.NodeSelector - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.Tolerations != nil { - in, out := &in.Tolerations, &out.Tolerations - *out = make([]v1.Toleration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.DeploymentSpec.DeepCopyInto(&out.DeploymentSpec) - in.CopyAnnotations.DeepCopyInto(&out.CopyAnnotations) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayClassConfigSpec. -func (in *GatewayClassConfigSpec) DeepCopy() *GatewayClassConfigSpec { - if in == nil { - return nil - } - out := new(GatewayClassConfigSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayServiceTLSConfig) DeepCopyInto(out *GatewayServiceTLSConfig) { *out = *in @@ -935,98 +569,21 @@ func (in *IntentionHTTPPermission) DeepCopy() *IntentionHTTPPermission { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IntentionJWTClaimVerification) DeepCopyInto(out *IntentionJWTClaimVerification) { +func (in *IntentionPermission) DeepCopyInto(out *IntentionPermission) { *out = *in - if in.Path != nil { - in, out := &in.Path, &out.Path - *out = make([]string, len(*in)) - copy(*out, *in) + if in.HTTP != nil { + in, out := &in.HTTP, &out.HTTP + *out = new(IntentionHTTPPermission) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntentionJWTClaimVerification. -func (in *IntentionJWTClaimVerification) DeepCopy() *IntentionJWTClaimVerification { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntentionPermission. +func (in *IntentionPermission) DeepCopy() *IntentionPermission { if in == nil { return nil } - out := new(IntentionJWTClaimVerification) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IntentionJWTProvider) DeepCopyInto(out *IntentionJWTProvider) { - *out = *in - if in.VerifyClaims != nil { - in, out := &in.VerifyClaims, &out.VerifyClaims - *out = make([]*IntentionJWTClaimVerification, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(IntentionJWTClaimVerification) - (*in).DeepCopyInto(*out) - } - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntentionJWTProvider. -func (in *IntentionJWTProvider) DeepCopy() *IntentionJWTProvider { - if in == nil { - return nil - } - out := new(IntentionJWTProvider) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IntentionJWTRequirement) DeepCopyInto(out *IntentionJWTRequirement) { - *out = *in - if in.Providers != nil { - in, out := &in.Providers, &out.Providers - *out = make([]*IntentionJWTProvider, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(IntentionJWTProvider) - (*in).DeepCopyInto(*out) - } - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntentionJWTRequirement. -func (in *IntentionJWTRequirement) DeepCopy() *IntentionJWTRequirement { - if in == nil { - return nil - } - out := new(IntentionJWTRequirement) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IntentionPermission) DeepCopyInto(out *IntentionPermission) { - *out = *in - if in.HTTP != nil { - in, out := &in.HTTP, &out.HTTP - *out = new(IntentionHTTPPermission) - (*in).DeepCopyInto(*out) - } - if in.JWT != nil { - in, out := &in.JWT, &out.JWT - *out = new(IntentionJWTRequirement) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntentionPermission. -func (in *IntentionPermission) DeepCopy() *IntentionPermission { - if in == nil { - return nil - } - out := new(IntentionPermission) + out := new(IntentionPermission) in.DeepCopyInto(out) return out } @@ -1057,182 +614,69 @@ func (in IntentionPermissions) DeepCopy() IntentionPermissions { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JSONWebKeySet) DeepCopyInto(out *JSONWebKeySet) { - *out = *in - if in.Local != nil { - in, out := &in.Local, &out.Local - *out = new(LocalJWKS) - **out = **in - } - if in.Remote != nil { - in, out := &in.Remote, &out.Remote - *out = new(RemoteJWKS) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONWebKeySet. -func (in *JSONWebKeySet) DeepCopy() *JSONWebKeySet { - if in == nil { - return nil - } - out := new(JSONWebKeySet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWKSRetryPolicy) DeepCopyInto(out *JWKSRetryPolicy) { - *out = *in - if in.RetryPolicyBackOff != nil { - in, out := &in.RetryPolicyBackOff, &out.RetryPolicyBackOff - *out = new(RetryPolicyBackOff) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWKSRetryPolicy. -func (in *JWKSRetryPolicy) DeepCopy() *JWKSRetryPolicy { - if in == nil { - return nil - } - out := new(JWKSRetryPolicy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTCacheConfig) DeepCopyInto(out *JWTCacheConfig) { +func (in *LeastRequestConfig) DeepCopyInto(out *LeastRequestConfig) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTCacheConfig. -func (in *JWTCacheConfig) DeepCopy() *JWTCacheConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeastRequestConfig. +func (in *LeastRequestConfig) DeepCopy() *LeastRequestConfig { if in == nil { return nil } - out := new(JWTCacheConfig) + out := new(LeastRequestConfig) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTForwardingConfig) DeepCopyInto(out *JWTForwardingConfig) { +func (in *LinkedService) DeepCopyInto(out *LinkedService) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTForwardingConfig. -func (in *JWTForwardingConfig) DeepCopy() *JWTForwardingConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinkedService. +func (in *LinkedService) DeepCopy() *LinkedService { if in == nil { return nil } - out := new(JWTForwardingConfig) + out := new(LinkedService) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTLocation) DeepCopyInto(out *JWTLocation) { +func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { *out = *in - if in.Header != nil { - in, out := &in.Header, &out.Header - *out = new(JWTLocationHeader) - **out = **in - } - if in.QueryParam != nil { - in, out := &in.QueryParam, &out.QueryParam - *out = new(JWTLocationQueryParam) + if in.RingHashConfig != nil { + in, out := &in.RingHashConfig, &out.RingHashConfig + *out = new(RingHashConfig) **out = **in } - if in.Cookie != nil { - in, out := &in.Cookie, &out.Cookie - *out = new(JWTLocationCookie) + if in.LeastRequestConfig != nil { + in, out := &in.LeastRequestConfig, &out.LeastRequestConfig + *out = new(LeastRequestConfig) **out = **in } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTLocation. -func (in *JWTLocation) DeepCopy() *JWTLocation { - if in == nil { - return nil - } - out := new(JWTLocation) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTLocationCookie) DeepCopyInto(out *JWTLocationCookie) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTLocationCookie. -func (in *JWTLocationCookie) DeepCopy() *JWTLocationCookie { - if in == nil { - return nil - } - out := new(JWTLocationCookie) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTLocationHeader) DeepCopyInto(out *JWTLocationHeader) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTLocationHeader. -func (in *JWTLocationHeader) DeepCopy() *JWTLocationHeader { - if in == nil { - return nil - } - out := new(JWTLocationHeader) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTLocationQueryParam) DeepCopyInto(out *JWTLocationQueryParam) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTLocationQueryParam. -func (in *JWTLocationQueryParam) DeepCopy() *JWTLocationQueryParam { - if in == nil { - return nil - } - out := new(JWTLocationQueryParam) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in JWTLocations) DeepCopyInto(out *JWTLocations) { - { - in := &in - *out = make(JWTLocations, len(*in)) + if in.HashPolicies != nil { + in, out := &in.HashPolicies, &out.HashPolicies + *out = make([]HashPolicy, len(*in)) for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(JWTLocation) - (*in).DeepCopyInto(*out) - } + (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTLocations. -func (in JWTLocations) DeepCopy() JWTLocations { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancer. +func (in *LoadBalancer) DeepCopy() *LoadBalancer { if in == nil { return nil } - out := new(JWTLocations) + out := new(LoadBalancer) in.DeepCopyInto(out) - return *out + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTProvider) DeepCopyInto(out *JWTProvider) { +func (in *Mesh) DeepCopyInto(out *Mesh) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -1240,50 +684,18 @@ func (in *JWTProvider) DeepCopyInto(out *JWTProvider) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTProvider. -func (in *JWTProvider) DeepCopy() *JWTProvider { - if in == nil { - return nil - } - out := new(JWTProvider) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *JWTProvider) 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 *JWTProviderList) DeepCopyInto(out *JWTProviderList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]JWTProvider, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTProviderList. -func (in *JWTProviderList) DeepCopy() *JWTProviderList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mesh. +func (in *Mesh) DeepCopy() *Mesh { if in == nil { return nil } - out := new(JWTProviderList) + out := new(Mesh) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *JWTProviderList) DeepCopyObject() runtime.Object { +func (in *Mesh) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1291,225 +703,75 @@ func (in *JWTProviderList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JWTProviderSpec) DeepCopyInto(out *JWTProviderSpec) { +func (in *MeshDirectionalTLSConfig) DeepCopyInto(out *MeshDirectionalTLSConfig) { *out = *in - if in.JSONWebKeySet != nil { - in, out := &in.JSONWebKeySet, &out.JSONWebKeySet - *out = new(JSONWebKeySet) - (*in).DeepCopyInto(*out) - } - if in.Audiences != nil { - in, out := &in.Audiences, &out.Audiences + if in.CipherSuites != nil { + in, out := &in.CipherSuites, &out.CipherSuites *out = make([]string, len(*in)) copy(*out, *in) } - if in.Locations != nil { - in, out := &in.Locations, &out.Locations - *out = make([]*JWTLocation, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(JWTLocation) - (*in).DeepCopyInto(*out) - } - } - } - if in.Forwarding != nil { - in, out := &in.Forwarding, &out.Forwarding - *out = new(JWTForwardingConfig) - **out = **in - } - if in.CacheConfig != nil { - in, out := &in.CacheConfig, &out.CacheConfig - *out = new(JWTCacheConfig) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTProviderSpec. -func (in *JWTProviderSpec) DeepCopy() *JWTProviderSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshDirectionalTLSConfig. +func (in *MeshDirectionalTLSConfig) DeepCopy() *MeshDirectionalTLSConfig { if in == nil { return nil } - out := new(JWTProviderSpec) + out := new(MeshDirectionalTLSConfig) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LeastRequestConfig) DeepCopyInto(out *LeastRequestConfig) { +func (in *MeshGateway) DeepCopyInto(out *MeshGateway) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeastRequestConfig. -func (in *LeastRequestConfig) DeepCopy() *LeastRequestConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshGateway. +func (in *MeshGateway) DeepCopy() *MeshGateway { if in == nil { return nil } - out := new(LeastRequestConfig) + out := new(MeshGateway) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LinkedService) DeepCopyInto(out *LinkedService) { +func (in *MeshHTTPConfig) DeepCopyInto(out *MeshHTTPConfig) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinkedService. -func (in *LinkedService) DeepCopy() *LinkedService { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshHTTPConfig. +func (in *MeshHTTPConfig) DeepCopy() *MeshHTTPConfig { if in == nil { return nil } - out := new(LinkedService) + out := new(MeshHTTPConfig) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { +func (in *MeshList) DeepCopyInto(out *MeshList) { *out = *in - if in.RingHashConfig != nil { - in, out := &in.RingHashConfig, &out.RingHashConfig - *out = new(RingHashConfig) - **out = **in - } - if in.LeastRequestConfig != nil { - in, out := &in.LeastRequestConfig, &out.LeastRequestConfig - *out = new(LeastRequestConfig) - **out = **in - } - if in.HashPolicies != nil { - in, out := &in.HashPolicies, &out.HashPolicies - *out = make([]HashPolicy, len(*in)) + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Mesh, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancer. -func (in *LoadBalancer) DeepCopy() *LoadBalancer { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshList. +func (in *MeshList) DeepCopy() *MeshList { if in == nil { return nil } - out := new(LoadBalancer) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LocalJWKS) DeepCopyInto(out *LocalJWKS) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalJWKS. -func (in *LocalJWKS) DeepCopy() *LocalJWKS { - if in == nil { - return nil - } - out := new(LocalJWKS) - 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 - 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 Mesh. -func (in *Mesh) DeepCopy() *Mesh { - if in == nil { - return nil - } - out := new(Mesh) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Mesh) 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 *MeshDirectionalTLSConfig) DeepCopyInto(out *MeshDirectionalTLSConfig) { - *out = *in - if in.CipherSuites != nil { - in, out := &in.CipherSuites, &out.CipherSuites - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshDirectionalTLSConfig. -func (in *MeshDirectionalTLSConfig) DeepCopy() *MeshDirectionalTLSConfig { - if in == nil { - return nil - } - out := new(MeshDirectionalTLSConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MeshGateway) DeepCopyInto(out *MeshGateway) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshGateway. -func (in *MeshGateway) DeepCopy() *MeshGateway { - if in == nil { - return nil - } - out := new(MeshGateway) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MeshHTTPConfig) DeepCopyInto(out *MeshHTTPConfig) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshHTTPConfig. -func (in *MeshHTTPConfig) DeepCopy() *MeshHTTPConfig { - if in == nil { - return nil - } - out := new(MeshHTTPConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MeshList) DeepCopyInto(out *MeshList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Mesh, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshList. -func (in *MeshList) DeepCopy() *MeshList { - if in == nil { - return nil - } - out := new(MeshList) + out := new(MeshList) in.DeepCopyInto(out) return out } @@ -1518,635 +780,119 @@ func (in *MeshList) DeepCopy() *MeshList { func (in *MeshList) 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 *MeshService) DeepCopyInto(out *MeshService) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshService. -func (in *MeshService) DeepCopy() *MeshService { - if in == nil { - return nil - } - out := new(MeshService) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MeshService) 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 *MeshServiceList) DeepCopyInto(out *MeshServiceList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MeshService, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshServiceList. -func (in *MeshServiceList) DeepCopy() *MeshServiceList { - if in == nil { - return nil - } - out := new(MeshServiceList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MeshServiceList) 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 *MeshServiceSpec) DeepCopyInto(out *MeshServiceSpec) { - *out = *in - if in.Peer != nil { - in, out := &in.Peer, &out.Peer - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshServiceSpec. -func (in *MeshServiceSpec) DeepCopy() *MeshServiceSpec { - if in == nil { - return nil - } - out := new(MeshServiceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MeshSpec) DeepCopyInto(out *MeshSpec) { - *out = *in - out.TransparentProxy = in.TransparentProxy - if in.TLS != nil { - in, out := &in.TLS, &out.TLS - *out = new(MeshTLSConfig) - (*in).DeepCopyInto(*out) - } - if in.HTTP != nil { - in, out := &in.HTTP, &out.HTTP - *out = new(MeshHTTPConfig) - **out = **in - } - if in.Peering != nil { - in, out := &in.Peering, &out.Peering - *out = new(PeeringMeshConfig) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshSpec. -func (in *MeshSpec) DeepCopy() *MeshSpec { - if in == nil { - return nil - } - out := new(MeshSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MeshTLSConfig) DeepCopyInto(out *MeshTLSConfig) { - *out = *in - if in.Incoming != nil { - in, out := &in.Incoming, &out.Incoming - *out = new(MeshDirectionalTLSConfig) - (*in).DeepCopyInto(*out) - } - if in.Outgoing != nil { - in, out := &in.Outgoing, &out.Outgoing - *out = new(MeshDirectionalTLSConfig) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshTLSConfig. -func (in *MeshTLSConfig) DeepCopy() *MeshTLSConfig { - if in == nil { - return nil - } - out := new(MeshTLSConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PassiveHealthCheck) DeepCopyInto(out *PassiveHealthCheck) { - *out = *in - out.Interval = in.Interval - if in.EnforcingConsecutive5xx != nil { - in, out := &in.EnforcingConsecutive5xx, &out.EnforcingConsecutive5xx - *out = new(uint32) - **out = **in - } - if in.MaxEjectionPercent != nil { - in, out := &in.MaxEjectionPercent, &out.MaxEjectionPercent - *out = new(uint32) - **out = **in - } - if in.BaseEjectionTime != nil { - in, out := &in.BaseEjectionTime, &out.BaseEjectionTime - *out = new(metav1.Duration) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassiveHealthCheck. -func (in *PassiveHealthCheck) DeepCopy() *PassiveHealthCheck { - if in == nil { - return nil - } - out := new(PassiveHealthCheck) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Peer) DeepCopyInto(out *Peer) { - *out = *in - if in.Secret != nil { - in, out := &in.Secret, &out.Secret - *out = new(Secret) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Peer. -func (in *Peer) DeepCopy() *Peer { - if in == nil { - return nil - } - out := new(Peer) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PeeringAcceptor) DeepCopyInto(out *PeeringAcceptor) { - *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 PeeringAcceptor. -func (in *PeeringAcceptor) DeepCopy() *PeeringAcceptor { - if in == nil { - return nil - } - out := new(PeeringAcceptor) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PeeringAcceptor) 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 *PeeringAcceptorList) DeepCopyInto(out *PeeringAcceptorList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PeeringAcceptor, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringAcceptorList. -func (in *PeeringAcceptorList) DeepCopy() *PeeringAcceptorList { - if in == nil { - return nil - } - out := new(PeeringAcceptorList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PeeringAcceptorList) 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 *PeeringAcceptorSpec) DeepCopyInto(out *PeeringAcceptorSpec) { - *out = *in - if in.Peer != nil { - in, out := &in.Peer, &out.Peer - *out = new(Peer) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringAcceptorSpec. -func (in *PeeringAcceptorSpec) DeepCopy() *PeeringAcceptorSpec { - if in == nil { - return nil - } - out := new(PeeringAcceptorSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PeeringAcceptorStatus) DeepCopyInto(out *PeeringAcceptorStatus) { - *out = *in - if in.LatestPeeringVersion != nil { - in, out := &in.LatestPeeringVersion, &out.LatestPeeringVersion - *out = new(uint64) - **out = **in - } - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(SecretRefStatus) - **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 PeeringAcceptorStatus. -func (in *PeeringAcceptorStatus) DeepCopy() *PeeringAcceptorStatus { - if in == nil { - return nil - } - out := new(PeeringAcceptorStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PeeringDialer) DeepCopyInto(out *PeeringDialer) { - *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 PeeringDialer. -func (in *PeeringDialer) DeepCopy() *PeeringDialer { - if in == nil { - return nil - } - out := new(PeeringDialer) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PeeringDialer) 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 *PeeringDialerList) DeepCopyInto(out *PeeringDialerList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PeeringDialer, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringDialerList. -func (in *PeeringDialerList) DeepCopy() *PeeringDialerList { - if in == nil { - return nil - } - out := new(PeeringDialerList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PeeringDialerList) 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 *PeeringDialerSpec) DeepCopyInto(out *PeeringDialerSpec) { - *out = *in - if in.Peer != nil { - in, out := &in.Peer, &out.Peer - *out = new(Peer) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringDialerSpec. -func (in *PeeringDialerSpec) DeepCopy() *PeeringDialerSpec { - if in == nil { - return nil - } - out := new(PeeringDialerSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PeeringDialerStatus) DeepCopyInto(out *PeeringDialerStatus) { - *out = *in - if in.LatestPeeringVersion != nil { - in, out := &in.LatestPeeringVersion, &out.LatestPeeringVersion - *out = new(uint64) - **out = **in - } - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(SecretRefStatus) - **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 PeeringDialerStatus. -func (in *PeeringDialerStatus) DeepCopy() *PeeringDialerStatus { - if in == nil { - return nil - } - out := new(PeeringDialerStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PeeringMeshConfig) DeepCopyInto(out *PeeringMeshConfig) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringMeshConfig. -func (in *PeeringMeshConfig) DeepCopy() *PeeringMeshConfig { - if in == nil { - return nil - } - out := new(PeeringMeshConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PrioritizeByLocality) DeepCopyInto(out *PrioritizeByLocality) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrioritizeByLocality. -func (in *PrioritizeByLocality) DeepCopy() *PrioritizeByLocality { - if in == nil { - return nil - } - out := new(PrioritizeByLocality) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProxyDefaults) DeepCopyInto(out *ProxyDefaults) { - *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 ProxyDefaults. -func (in *ProxyDefaults) DeepCopy() *ProxyDefaults { - if in == nil { - return nil - } - out := new(ProxyDefaults) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProxyDefaults) 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 *ProxyDefaultsList) DeepCopyInto(out *ProxyDefaultsList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]ProxyDefaults, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyDefaultsList. -func (in *ProxyDefaultsList) DeepCopy() *ProxyDefaultsList { - if in == nil { - return nil - } - out := new(ProxyDefaultsList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProxyDefaultsList) 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 *ProxyDefaultsSpec) DeepCopyInto(out *ProxyDefaultsSpec) { - *out = *in - if in.Mode != nil { - in, out := &in.Mode, &out.Mode - *out = new(ProxyMode) - **out = **in - } - if in.TransparentProxy != nil { - in, out := &in.TransparentProxy, &out.TransparentProxy - *out = new(TransparentProxy) - **out = **in - } - if in.Config != nil { - in, out := &in.Config, &out.Config - *out = make(json.RawMessage, len(*in)) - copy(*out, *in) - } - out.MeshGateway = in.MeshGateway - in.Expose.DeepCopyInto(&out.Expose) - if in.AccessLogs != nil { - in, out := &in.AccessLogs, &out.AccessLogs - *out = new(AccessLogs) - **out = **in - } - if in.EnvoyExtensions != nil { - in, out := &in.EnvoyExtensions, &out.EnvoyExtensions - *out = make(EnvoyExtensions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.FailoverPolicy != nil { - in, out := &in.FailoverPolicy, &out.FailoverPolicy - *out = new(FailoverPolicy) - (*in).DeepCopyInto(*out) - } - if in.PrioritizeByLocality != nil { - in, out := &in.PrioritizeByLocality, &out.PrioritizeByLocality - *out = new(PrioritizeByLocality) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyDefaultsSpec. -func (in *ProxyDefaultsSpec) DeepCopy() *ProxyDefaultsSpec { - if in == nil { - return nil - } - out := new(ProxyDefaultsSpec) - in.DeepCopyInto(out) - return out + } + return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReadWriteRatesConfig) DeepCopyInto(out *ReadWriteRatesConfig) { +func (in *MeshSpec) DeepCopyInto(out *MeshSpec) { *out = *in + out.TransparentProxy = in.TransparentProxy + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(MeshTLSConfig) + (*in).DeepCopyInto(*out) + } + if in.HTTP != nil { + in, out := &in.HTTP, &out.HTTP + *out = new(MeshHTTPConfig) + **out = **in + } + if in.Peering != nil { + in, out := &in.Peering, &out.Peering + *out = new(PeeringMeshConfig) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadWriteRatesConfig. -func (in *ReadWriteRatesConfig) DeepCopy() *ReadWriteRatesConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshSpec. +func (in *MeshSpec) DeepCopy() *MeshSpec { if in == nil { return nil } - out := new(ReadWriteRatesConfig) + out := new(MeshSpec) 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) { +func (in *MeshTLSConfig) DeepCopyInto(out *MeshTLSConfig) { *out = *in - if in.RetryPolicy != nil { - in, out := &in.RetryPolicy, &out.RetryPolicy - *out = new(JWKSRetryPolicy) + if in.Incoming != nil { + in, out := &in.Incoming, &out.Incoming + *out = new(MeshDirectionalTLSConfig) + (*in).DeepCopyInto(*out) + } + if in.Outgoing != nil { + in, out := &in.Outgoing, &out.Outgoing + *out = new(MeshDirectionalTLSConfig) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteJWKS. -func (in *RemoteJWKS) DeepCopy() *RemoteJWKS { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshTLSConfig. +func (in *MeshTLSConfig) DeepCopy() *MeshTLSConfig { if in == nil { return nil } - out := new(RemoteJWKS) + out := new(MeshTLSConfig) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RetryPolicyBackOff) DeepCopyInto(out *RetryPolicyBackOff) { +func (in *PassiveHealthCheck) DeepCopyInto(out *PassiveHealthCheck) { *out = *in + out.Interval = in.Interval + if in.EnforcingConsecutive5xx != nil { + in, out := &in.EnforcingConsecutive5xx, &out.EnforcingConsecutive5xx + *out = new(uint32) + **out = **in + } + if in.MaxEjectionPercent != nil { + in, out := &in.MaxEjectionPercent, &out.MaxEjectionPercent + *out = new(uint32) + **out = **in + } + if in.BaseEjectionTime != nil { + in, out := &in.BaseEjectionTime, &out.BaseEjectionTime + *out = new(v1.Duration) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RetryPolicyBackOff. -func (in *RetryPolicyBackOff) DeepCopy() *RetryPolicyBackOff { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PassiveHealthCheck. +func (in *PassiveHealthCheck) DeepCopy() *PassiveHealthCheck { if in == nil { return nil } - out := new(RetryPolicyBackOff) + out := new(PassiveHealthCheck) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RingHashConfig) DeepCopyInto(out *RingHashConfig) { +func (in *Peer) DeepCopyInto(out *Peer) { *out = *in + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(Secret) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RingHashConfig. -func (in *RingHashConfig) DeepCopy() *RingHashConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Peer. +func (in *Peer) DeepCopy() *Peer { if in == nil { return nil } - out := new(RingHashConfig) + out := new(Peer) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteRetryFilter) DeepCopyInto(out *RouteRetryFilter) { +func (in *PeeringAcceptor) DeepCopyInto(out *PeeringAcceptor) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -2154,18 +900,18 @@ func (in *RouteRetryFilter) DeepCopyInto(out *RouteRetryFilter) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteRetryFilter. -func (in *RouteRetryFilter) DeepCopy() *RouteRetryFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringAcceptor. +func (in *PeeringAcceptor) DeepCopy() *PeeringAcceptor { if in == nil { return nil } - out := new(RouteRetryFilter) + out := new(PeeringAcceptor) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RouteRetryFilter) DeepCopyObject() runtime.Object { +func (in *PeeringAcceptor) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2173,31 +919,31 @@ func (in *RouteRetryFilter) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteRetryFilterList) DeepCopyInto(out *RouteRetryFilterList) { +func (in *PeeringAcceptorList) DeepCopyInto(out *PeeringAcceptorList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]RouteRetryFilter, len(*in)) + *out = make([]PeeringAcceptor, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteRetryFilterList. -func (in *RouteRetryFilterList) DeepCopy() *RouteRetryFilterList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringAcceptorList. +func (in *PeeringAcceptorList) DeepCopy() *PeeringAcceptorList { if in == nil { return nil } - out := new(RouteRetryFilterList) + out := new(PeeringAcceptorList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RouteRetryFilterList) DeepCopyObject() runtime.Object { +func (in *PeeringAcceptorList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2205,61 +951,82 @@ func (in *RouteRetryFilterList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteRetryFilterSpec) DeepCopyInto(out *RouteRetryFilterSpec) { +func (in *PeeringAcceptorSpec) DeepCopyInto(out *PeeringAcceptorSpec) { *out = *in - if in.NumRetries != nil { - in, out := &in.NumRetries, &out.NumRetries - *out = new(uint32) - **out = **in + if in.Peer != nil { + in, out := &in.Peer, &out.Peer + *out = new(Peer) + (*in).DeepCopyInto(*out) } - if in.RetryOn != nil { - in, out := &in.RetryOn, &out.RetryOn - *out = make([]string, len(*in)) - copy(*out, *in) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringAcceptorSpec. +func (in *PeeringAcceptorSpec) DeepCopy() *PeeringAcceptorSpec { + if in == nil { + return nil } - if in.RetryOnStatusCodes != nil { - in, out := &in.RetryOnStatusCodes, &out.RetryOnStatusCodes - *out = make([]uint32, len(*in)) - copy(*out, *in) + out := new(PeeringAcceptorSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PeeringAcceptorStatus) DeepCopyInto(out *PeeringAcceptorStatus) { + *out = *in + if in.LatestPeeringVersion != nil { + in, out := &in.LatestPeeringVersion, &out.LatestPeeringVersion + *out = new(uint64) + **out = **in } - if in.RetryOnConnectFailure != nil { - in, out := &in.RetryOnConnectFailure, &out.RetryOnConnectFailure - *out = new(bool) + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretRefStatus) **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 RouteRetryFilterSpec. -func (in *RouteRetryFilterSpec) DeepCopy() *RouteRetryFilterSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringAcceptorStatus. +func (in *PeeringAcceptorStatus) DeepCopy() *PeeringAcceptorStatus { if in == nil { return nil } - out := new(RouteRetryFilterSpec) + out := new(PeeringAcceptorStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteTimeoutFilter) DeepCopyInto(out *RouteTimeoutFilter) { +func (in *PeeringDialer) DeepCopyInto(out *PeeringDialer) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteTimeoutFilter. -func (in *RouteTimeoutFilter) DeepCopy() *RouteTimeoutFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringDialer. +func (in *PeeringDialer) DeepCopy() *PeeringDialer { if in == nil { return nil } - out := new(RouteTimeoutFilter) + out := new(PeeringDialer) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RouteTimeoutFilter) DeepCopyObject() runtime.Object { +func (in *PeeringDialer) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2267,31 +1034,31 @@ func (in *RouteTimeoutFilter) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteTimeoutFilterList) DeepCopyInto(out *RouteTimeoutFilterList) { +func (in *PeeringDialerList) DeepCopyInto(out *PeeringDialerList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]RouteTimeoutFilter, len(*in)) + *out = make([]PeeringDialer, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteTimeoutFilterList. -func (in *RouteTimeoutFilterList) DeepCopy() *RouteTimeoutFilterList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringDialerList. +func (in *PeeringDialerList) DeepCopy() *PeeringDialerList { if in == nil { return nil } - out := new(RouteTimeoutFilterList) + out := new(PeeringDialerList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RouteTimeoutFilterList) DeepCopyObject() runtime.Object { +func (in *PeeringDialerList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2299,22 +1066,78 @@ func (in *RouteTimeoutFilterList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteTimeoutFilterSpec) DeepCopyInto(out *RouteTimeoutFilterSpec) { +func (in *PeeringDialerSpec) DeepCopyInto(out *PeeringDialerSpec) { + *out = *in + if in.Peer != nil { + in, out := &in.Peer, &out.Peer + *out = new(Peer) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringDialerSpec. +func (in *PeeringDialerSpec) DeepCopy() *PeeringDialerSpec { + if in == nil { + return nil + } + out := new(PeeringDialerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PeeringDialerStatus) DeepCopyInto(out *PeeringDialerStatus) { + *out = *in + if in.LatestPeeringVersion != nil { + in, out := &in.LatestPeeringVersion, &out.LatestPeeringVersion + *out = new(uint64) + **out = **in + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(SecretRefStatus) + **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 PeeringDialerStatus. +func (in *PeeringDialerStatus) DeepCopy() *PeeringDialerStatus { + if in == nil { + return nil + } + out := new(PeeringDialerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PeeringMeshConfig) DeepCopyInto(out *PeeringMeshConfig) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteTimeoutFilterSpec. -func (in *RouteTimeoutFilterSpec) DeepCopy() *RouteTimeoutFilterSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeeringMeshConfig. +func (in *PeeringMeshConfig) DeepCopy() *PeeringMeshConfig { if in == nil { return nil } - out := new(RouteTimeoutFilterSpec) + out := new(PeeringMeshConfig) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamenessGroup) DeepCopyInto(out *SamenessGroup) { +func (in *ProxyDefaults) DeepCopyInto(out *ProxyDefaults) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -2322,18 +1145,18 @@ func (in *SamenessGroup) DeepCopyInto(out *SamenessGroup) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroup. -func (in *SamenessGroup) DeepCopy() *SamenessGroup { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyDefaults. +func (in *ProxyDefaults) DeepCopy() *ProxyDefaults { if in == nil { return nil } - out := new(SamenessGroup) + out := new(ProxyDefaults) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SamenessGroup) DeepCopyObject() runtime.Object { +func (in *ProxyDefaults) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2341,31 +1164,31 @@ func (in *SamenessGroup) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamenessGroupList) DeepCopyInto(out *SamenessGroupList) { +func (in *ProxyDefaultsList) DeepCopyInto(out *ProxyDefaultsList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]SamenessGroup, len(*in)) + *out = make([]ProxyDefaults, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupList. -func (in *SamenessGroupList) DeepCopy() *SamenessGroupList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyDefaultsList. +func (in *ProxyDefaultsList) DeepCopy() *ProxyDefaultsList { if in == nil { return nil } - out := new(SamenessGroupList) + out := new(ProxyDefaultsList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SamenessGroupList) DeepCopyObject() runtime.Object { +func (in *ProxyDefaultsList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2373,55 +1196,48 @@ func (in *SamenessGroupList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamenessGroupMember) DeepCopyInto(out *SamenessGroupMember) { +func (in *ProxyDefaultsSpec) DeepCopyInto(out *ProxyDefaultsSpec) { *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupMember. -func (in *SamenessGroupMember) DeepCopy() *SamenessGroupMember { - if in == nil { - return nil + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(ProxyMode) + **out = **in } - out := new(SamenessGroupMember) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in SamenessGroupMembers) DeepCopyInto(out *SamenessGroupMembers) { - { - in := &in - *out = make(SamenessGroupMembers, len(*in)) + if in.TransparentProxy != nil { + in, out := &in.TransparentProxy, &out.TransparentProxy + *out = new(TransparentProxy) + **out = **in + } + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = make(json.RawMessage, len(*in)) copy(*out, *in) } + out.MeshGateway = in.MeshGateway + in.Expose.DeepCopyInto(&out.Expose) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupMembers. -func (in SamenessGroupMembers) DeepCopy() SamenessGroupMembers { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyDefaultsSpec. +func (in *ProxyDefaultsSpec) DeepCopy() *ProxyDefaultsSpec { if in == nil { return nil } - out := new(SamenessGroupMembers) + out := new(ProxyDefaultsSpec) in.DeepCopyInto(out) - return *out + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamenessGroupSpec) DeepCopyInto(out *SamenessGroupSpec) { +func (in *RingHashConfig) DeepCopyInto(out *RingHashConfig) { *out = *in - if in.Members != nil { - in, out := &in.Members, &out.Members - *out = make([]SamenessGroupMember, len(*in)) - copy(*out, *in) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupSpec. -func (in *SamenessGroupSpec) DeepCopy() *SamenessGroupSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RingHashConfig. +func (in *RingHashConfig) DeepCopy() *RingHashConfig { if in == nil { return nil } - out := new(SamenessGroupSpec) + out := new(RingHashConfig) in.DeepCopyInto(out) return out } @@ -2576,13 +1392,6 @@ func (in *ServiceDefaultsSpec) DeepCopyInto(out *ServiceDefaultsSpec) { *out = new(ServiceDefaultsDestination) (*in).DeepCopyInto(*out) } - if in.EnvoyExtensions != nil { - in, out := &in.EnvoyExtensions, &out.EnvoyExtensions - *out = make(EnvoyExtensions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceDefaultsSpec. @@ -2669,11 +1478,6 @@ func (in *ServiceIntentionsSpec) DeepCopyInto(out *ServiceIntentionsSpec) { } } } - if in.JWT != nil { - in, out := &in.JWT, &out.JWT - *out = new(IntentionJWTRequirement) - (*in).DeepCopyInto(*out) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceIntentionsSpec. @@ -2726,11 +1530,6 @@ func (in *ServiceResolverFailover) DeepCopyInto(out *ServiceResolverFailover) { *out = make([]ServiceResolverFailoverTarget, len(*in)) copy(*out, *in) } - if in.Policy != nil { - in, out := &in.Policy, &out.Policy - *out = new(FailoverPolicy) - (*in).DeepCopyInto(*out) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceResolverFailover. @@ -2849,17 +1648,11 @@ func (in *ServiceResolverSpec) DeepCopyInto(out *ServiceResolverSpec) { } } out.ConnectTimeout = in.ConnectTimeout - out.RequestTimeout = in.RequestTimeout if in.LoadBalancer != nil { in, out := &in.LoadBalancer, &out.LoadBalancer *out = new(LoadBalancer) (*in).DeepCopyInto(*out) } - if in.PrioritizeByLocality != nil { - in, out := &in.PrioritizeByLocality, &out.PrioritizeByLocality - *out = new(PrioritizeByLocality) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceResolverSpec. diff --git a/control-plane/build-support/controller/README.md b/control-plane/build-support/controller/README.md new file mode 100644 index 0000000000..0d24937531 --- /dev/null +++ b/control-plane/build-support/controller/README.md @@ -0,0 +1,5 @@ +## Overview + +`boilerplate.go.txt` is a file required by `operator-sdk` when it performs code-generation. + +It's contents provide the headers to the generated files but as we do not require headers for the files we generate, it has been left intentionally blank. diff --git a/control-plane/build-support/controller/boilerplate.go.txt b/control-plane/build-support/controller/boilerplate.go.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/control-plane/build-support/functions/00-vars.sh b/control-plane/build-support/functions/00-vars.sh index 484344703c..1f03013c32 100644 --- a/control-plane/build-support/functions/00-vars.sh +++ b/control-plane/build-support/functions/00-vars.sh @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # GPG Key ID to use for publically released builds HASHICORP_GPG_KEY="348FFC4C" diff --git a/control-plane/build-support/functions/10-util.sh b/control-plane/build-support/functions/10-util.sh index 3bc87124d9..2706c69be8 100644 --- a/control-plane/build-support/functions/10-util.sh +++ b/control-plane/build-support/functions/10-util.sh @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - function err { if test "${COLORIZE}" -eq 1; then tput bold @@ -619,6 +616,7 @@ function update_version_helm { local vfile="$1/values.yaml" local cfile="$1/Chart.yaml" local version="$2" + local consul_version="$5" local prerelease="$3" local full_version="$2" local full_consul_version="$5" diff --git a/control-plane/build-support/functions/20-build.sh b/control-plane/build-support/functions/20-build.sh index dac626b88f..ddde7b6acf 100644 --- a/control-plane/build-support/functions/20-build.sh +++ b/control-plane/build-support/functions/20-build.sh @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - function refresh_docker_images { # Arguments: # $1 - Path to top level Consul source @@ -180,7 +177,7 @@ function build_consul_local { # * - error # # Note: - # The GOLDFLAGS, GOEXPERIMENT, and GOTAGS environment variables will be used if set + # The GOLDFLAGS and GOTAGS environment variables will be used if set # If the CONSUL_DEV environment var is truthy only the local platform/architecture is built. # If the XC_OS or the XC_ARCH environment vars are present then only those platforms/architectures # will be built. Otherwise all supported platform/architectures are built @@ -188,14 +185,6 @@ function build_consul_local { # build with go install. # The GOXPARALLEL environment variable is used if set - if [ "${GOTAGS:-}" == "fips" ]; then - CGO_ENABLED=1 - else - CGO_ENABLED=0 - fi - - echo "GOEXPERIMENT: $GOEXPERIMENT, GOTAGS: $GOTAGS CGO_ENABLED: $CGO_ENABLED" >> ~/debug.txt - if ! test -d "$1" then err "ERROR: '$1' is not a directory. build_consul must be called with the path to the top level source as the first argument'" @@ -250,7 +239,7 @@ function build_consul_local { then status "Using gox for concurrent compilation" - CGO_ENABLED=${CGO_ENABLED} GOEXPERIMENT=${GOEXPERIMENT} gox \ + CGO_ENABLED=0 gox \ -os="${build_os}" \ -arch="${build_arch}" \ -ldflags="${GOLDFLAGS}" \ @@ -298,7 +287,7 @@ function build_consul_local { else OS_BIN_EXTENSION="" fi - CGO_ENABLED=${CGO_ENABLED} GOEXPERIMENT=${GOEXPERIMENT} GOOS=${os} GOARCH=${arch} go build -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}" -o "${outdir}/${bin_name}" + CGO_ENABLED=0 GOOS=${os} GOARCH=${arch} go build -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}" -o "${outdir}/${bin_name}" if test $? -ne 0 then err "ERROR: Failed to build Consul for ${osarch}" diff --git a/control-plane/build-support/functions/40-publish.sh b/control-plane/build-support/functions/40-publish.sh index aae9a5f719..975c835bc0 100644 --- a/control-plane/build-support/functions/40-publish.sh +++ b/control-plane/build-support/functions/40-publish.sh @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - function hashicorp_release { # Arguments: # $1 - Path to directory containing all of the release artifacts diff --git a/control-plane/build-support/scripts/build-local.sh b/control-plane/build-support/scripts/build-local.sh index 7325e025b7..95d18e0ba6 100755 --- a/control-plane/build-support/scripts/build-local.sh +++ b/control-plane/build-support/scripts/build-local.sh @@ -1,7 +1,4 @@ #!/bin/bash -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - SCRIPT_NAME="$(basename ${BASH_SOURCE[0]})" pushd $(dirname ${BASH_SOURCE[0]}) > /dev/null SCRIPT_DIR=$(pwd) @@ -35,8 +32,6 @@ Options: -a | --arch ARCH Space separated string of architectures to build. - --fips FIPS Whether to use FIPS cryptography. - -h | --help Print this help text. EOF } @@ -96,11 +91,6 @@ function main { build_arch="$2" shift 2 ;; - --fips ) - GOTAGS="fips" - GOEXPERIMENT="boringcrypto" - shift 1 - ;; * ) err_usage "ERROR: Unknown argument: '$1'" return 1 diff --git a/control-plane/build-support/scripts/consul-enterprise-version.sh b/control-plane/build-support/scripts/consul-enterprise-version.sh index 37df85dfc5..24adb6a793 100755 --- a/control-plane/build-support/scripts/consul-enterprise-version.sh +++ b/control-plane/build-support/scripts/consul-enterprise-version.sh @@ -10,4 +10,5 @@ elif [[ !"${VERSION}" == *"hashicorp/consul:"* ]]; then VERSION=$(echo ${VERSION} | sed "s/consul:/consul-enterprise:/g" | sed "s/$/-ent/g") fi + echo "${VERSION}" diff --git a/control-plane/build-support/scripts/functions.sh b/control-plane/build-support/scripts/functions.sh index 590666eb7d..0301c0d3a1 100644 --- a/control-plane/build-support/scripts/functions.sh +++ b/control-plane/build-support/scripts/functions.sh @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # # NOTE: This file is meant to be sourced from other bash scripts/shells # diff --git a/control-plane/build-support/scripts/terraformfmtcheck.sh b/control-plane/build-support/scripts/terraformfmtcheck.sh index 8608a88e30..0f962a1c1b 100755 --- a/control-plane/build-support/scripts/terraformfmtcheck.sh +++ b/control-plane/build-support/scripts/terraformfmtcheck.sh @@ -1,7 +1,4 @@ #!/usr/bin/env bash -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # Check terraform fmt echo "==> Checking that code complies with terraform fmt requirements..." diff --git a/control-plane/build-support/scripts/version.sh b/control-plane/build-support/scripts/version.sh index fce325e03c..f91b0c3917 100755 --- a/control-plane/build-support/scripts/version.sh +++ b/control-plane/build-support/scripts/version.sh @@ -1,7 +1,4 @@ #!/usr/bin/env bash -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - version_file=$1 version=$(awk '$1 == "Version" && $2 == "=" { gsub(/"/, "", $3); print $3 }' < "${version_file}") diff --git a/control-plane/catalog/to-consul/annotation.go b/control-plane/catalog/to-consul/annotation.go index edca70b60c..5df5ab71f4 100644 --- a/control-plane/catalog/to-consul/annotation.go +++ b/control-plane/catalog/to-consul/annotation.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog const ( diff --git a/control-plane/catalog/to-consul/resource.go b/control-plane/catalog/to-consul/resource.go index 2d29d6c15a..8d6fa9b82b 100644 --- a/control-plane/catalog/to-consul/resource.go +++ b/control-plane/catalog/to-consul/resource.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( @@ -512,7 +509,7 @@ func (t *ServiceResource) generateRegistrations(key string) { r.Service.ID = serviceID(r.Service.Service, ip) r.Service.Address = ip // Adding information about service weight. - // Overrides the existing weight if present. + // Overrides the existing weight if present if weight, ok := svc.Annotations[annotationServiceWeight]; ok && weight != "" { weightI, err := getServiceWeight(weight) if err == nil { @@ -561,7 +558,7 @@ func (t *ServiceResource) generateRegistrations(key string) { r.Service.Address = addr // Adding information about service weight. - // Overrides the existing weight if present. + // Overrides the existing weight if present if weight, ok := svc.Annotations[annotationServiceWeight]; ok && weight != "" { weightI, err := getServiceWeight(weight) if err == nil { @@ -1028,7 +1025,7 @@ func consulHealthCheckID(k8sNS string, serviceID string) string { // Calculates the passing service weight. func getServiceWeight(weight string) (int, error) { - // error validation if the input param is a number. + // error validation if the input param is a number weightI, err := strconv.Atoi(weight) if err != nil { return -1, err diff --git a/control-plane/catalog/to-consul/resource_test.go b/control-plane/catalog/to-consul/resource_test.go index 3b8fb78497..680c052823 100644 --- a/control-plane/catalog/to-consul/resource_test.go +++ b/control-plane/catalog/to-consul/resource_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-consul/service_id.go b/control-plane/catalog/to-consul/service_id.go index 8300871b73..1aa3071497 100644 --- a/control-plane/catalog/to-consul/service_id.go +++ b/control-plane/catalog/to-consul/service_id.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-consul/syncer.go b/control-plane/catalog/to-consul/syncer.go index 9f1df18ba6..19e0aaca6f 100644 --- a/control-plane/catalog/to-consul/syncer.go +++ b/control-plane/catalog/to-consul/syncer.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-consul/syncer_ent_test.go b/control-plane/catalog/to-consul/syncer_ent_test.go index 5dfb158d23..fbe2cbd494 100644 --- a/control-plane/catalog/to-consul/syncer_ent_test.go +++ b/control-plane/catalog/to-consul/syncer_ent_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package catalog diff --git a/control-plane/catalog/to-consul/syncer_test.go b/control-plane/catalog/to-consul/syncer_test.go index 3fae7a3d16..d8d9b0f402 100644 --- a/control-plane/catalog/to-consul/syncer_test.go +++ b/control-plane/catalog/to-consul/syncer_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-consul/testing.go b/control-plane/catalog/to-consul/testing.go index 5f19017cbe..e6541c6ba1 100644 --- a/control-plane/catalog/to-consul/testing.go +++ b/control-plane/catalog/to-consul/testing.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-k8s/sink.go b/control-plane/catalog/to-k8s/sink.go index 6e201253df..fa8821989e 100644 --- a/control-plane/catalog/to-k8s/sink.go +++ b/control-plane/catalog/to-k8s/sink.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-k8s/sink_test.go b/control-plane/catalog/to-k8s/sink_test.go index cfba502268..fbce7bbaaf 100644 --- a/control-plane/catalog/to-k8s/sink_test.go +++ b/control-plane/catalog/to-k8s/sink_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-k8s/source.go b/control-plane/catalog/to-k8s/source.go index ab34089d8e..5a384e760a 100644 --- a/control-plane/catalog/to-k8s/source.go +++ b/control-plane/catalog/to-k8s/source.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-k8s/source_test.go b/control-plane/catalog/to-k8s/source_test.go index 66afb4b608..ca00a1e954 100644 --- a/control-plane/catalog/to-k8s/source_test.go +++ b/control-plane/catalog/to-k8s/source_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/catalog/to-k8s/testing.go b/control-plane/catalog/to-k8s/testing.go index 1eb731a17f..d7181bdbea 100644 --- a/control-plane/catalog/to-k8s/testing.go +++ b/control-plane/catalog/to-k8s/testing.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package catalog import ( diff --git a/control-plane/cni/config/config.go b/control-plane/cni/config/config.go index a9dafd0ab7..f22d3ff79b 100644 --- a/control-plane/cni/config/config.go +++ b/control-plane/cni/config/config.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package config const ( diff --git a/control-plane/cni/go.mod b/control-plane/cni/go.mod index e8fcc980ef..d1e0f62f2c 100644 --- a/control-plane/cni/go.mod +++ b/control-plane/cni/go.mod @@ -3,9 +3,9 @@ module github.com/hashicorp/consul-k8s/control-plane/cni require ( github.com/containernetworking/cni v1.1.1 github.com/containernetworking/plugins v1.1.1 - github.com/hashicorp/consul/sdk v0.13.1 - github.com/hashicorp/go-hclog v1.2.1 - github.com/stretchr/testify v1.7.2 + github.com/hashicorp/consul/sdk v0.13.0 + github.com/hashicorp/go-hclog v0.16.1 + github.com/stretchr/testify v1.7.1 k8s.io/api v0.22.2 k8s.io/apimachinery v0.22.2 k8s.io/client-go v0.22.2 @@ -14,7 +14,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/fatih/color v1.12.0 // indirect github.com/go-logr/logr v0.4.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect @@ -23,8 +23,8 @@ require ( github.com/googleapis/gnostic v0.5.5 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/json-iterator/go v1.1.11 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -37,10 +37,10 @@ require ( golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.26.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/klog/v2 v2.9.0 // indirect k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect @@ -50,4 +50,4 @@ require ( replace github.com/hashicorp/consul/sdk => github.com/hashicorp/consul/sdk v0.4.1-0.20221021205723-cc843c4be892 -go 1.20 +go 1.19 diff --git a/control-plane/cni/go.sum b/control-plane/cni/go.sum index 8f4c0668ea..727657541e 100644 --- a/control-plane/cni/go.sum +++ b/control-plane/cni/go.sum @@ -57,8 +57,8 @@ github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCv github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -135,8 +135,8 @@ github.com/hashicorp/consul/sdk v0.4.1-0.20221021205723-cc843c4be892 h1:jw0NwPmN github.com/hashicorp/consul/sdk v0.4.1-0.20221021205723-cc843c4be892/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw= -github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v0.16.1 h1:IVQwpTGNRRIHafnTs2dQLIk4ENtneRIEEJWOVDqz99o= +github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -162,15 +162,14 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -218,8 +217,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -335,10 +334,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -451,9 +447,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -474,9 +469,8 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/control-plane/cni/main.go b/control-plane/cni/main.go index e35f5ad811..7b05b5c6cd 100644 --- a/control-plane/cni/main.go +++ b/control-plane/cni/main.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( diff --git a/control-plane/cni/main_test.go b/control-plane/cni/main_test.go index 7c289a9825..740e15c646 100644 --- a/control-plane/cni/main_test.go +++ b/control-plane/cni/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( diff --git a/control-plane/commands.go b/control-plane/commands.go index e2bcb0f693..ec3b7ca612 100644 --- a/control-plane/commands.go +++ b/control-plane/commands.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( @@ -11,9 +8,6 @@ import ( cmdConsulLogout "github.com/hashicorp/consul-k8s/control-plane/subcommand/consul-logout" cmdCreateFederationSecret "github.com/hashicorp/consul-k8s/control-plane/subcommand/create-federation-secret" cmdDeleteCompletedJob "github.com/hashicorp/consul-k8s/control-plane/subcommand/delete-completed-job" - cmdFetchServerRegion "github.com/hashicorp/consul-k8s/control-plane/subcommand/fetch-server-region" - cmdGatewayCleanup "github.com/hashicorp/consul-k8s/control-plane/subcommand/gateway-cleanup" - cmdGatewayResources "github.com/hashicorp/consul-k8s/control-plane/subcommand/gateway-resources" cmdGetConsulClientCA "github.com/hashicorp/consul-k8s/control-plane/subcommand/get-consul-client-ca" cmdGossipEncryptionAutogenerate "github.com/hashicorp/consul-k8s/control-plane/subcommand/gossip-encryption-autogenerate" cmdInjectConnect "github.com/hashicorp/consul-k8s/control-plane/subcommand/inject-connect" @@ -51,14 +45,6 @@ func init() { return &cmdConsulLogout.Command{UI: ui}, nil }, - "gateway-cleanup": func() (cli.Command, error) { - return &cmdGatewayCleanup.Command{UI: ui}, nil - }, - - "gateway-resources": func() (cli.Command, error) { - return &cmdGatewayResources.Command{UI: ui}, nil - }, - "server-acl-init": func() (cli.Command, error) { return &cmdServerACLInit.Command{UI: ui}, nil }, @@ -101,9 +87,6 @@ func init() { "install-cni": func() (cli.Command, error) { return &cmdInstallCNI.Command{UI: ui}, nil }, - "fetch-server-region": func() (cli.Command, error) { - return &cmdFetchServerRegion.Command{UI: ui}, nil - }, } } diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_controlplanerequestlimits.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_controlplanerequestlimits.yaml deleted file mode 100644 index 11da54e9ac..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_controlplanerequestlimits.yaml +++ /dev/null @@ -1,198 +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.8.0 - creationTimestamp: null - name: controlplanerequestlimits.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: ControlPlaneRequestLimit - listKind: ControlPlaneRequestLimitList - plural: controlplanerequestlimits - singular: controlplanerequestlimit - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: ControlPlaneRequestLimit is the Schema for the controlplanerequestlimits - API. - 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: ControlPlaneRequestLimitSpec defines the desired state of - ControlPlaneRequestLimit. - properties: - acl: - properties: - readRate: - type: number - writeRate: - type: number - type: object - catalog: - properties: - readRate: - type: number - writeRate: - type: number - type: object - configEntry: - properties: - readRate: - type: number - writeRate: - type: number - type: object - connectCA: - properties: - readRate: - type: number - writeRate: - type: number - type: object - coordinate: - properties: - readRate: - type: number - writeRate: - type: number - type: object - discoveryChain: - properties: - readRate: - type: number - writeRate: - type: number - type: object - health: - properties: - readRate: - type: number - writeRate: - type: number - type: object - intention: - properties: - readRate: - type: number - writeRate: - type: number - type: object - kv: - properties: - readRate: - type: number - writeRate: - type: number - type: object - mode: - type: string - perparedQuery: - properties: - readRate: - type: number - writeRate: - type: number - type: object - readRate: - type: number - session: - properties: - readRate: - type: number - writeRate: - type: number - type: object - tenancy: - properties: - readRate: - type: number - writeRate: - type: number - type: object - txn: - properties: - readRate: - type: number - writeRate: - type: number - type: object - writeRate: - type: number - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml index 0b6b969856..da1a66fd74 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -72,12 +69,8 @@ spec: the service to. type: string peer: - description: Peer is the name of the peer to export the - service to. - type: string - samenessGroup: - description: SamenessGroup is the name of the sameness - group to export the service to. + description: '[Experimental] Peer is the name of the peer + to export the service to.' type: string type: object type: array diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_gatewayclassconfigs.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_gatewayclassconfigs.yaml deleted file mode 100644 index c4a510ffad..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_gatewayclassconfigs.yaml +++ /dev/null @@ -1,204 +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.8.0 - creationTimestamp: null - name: gatewayclassconfigs.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: GatewayClassConfig - listKind: GatewayClassConfigList - plural: gatewayclassconfigs - singular: gatewayclassconfig - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: GatewayClassConfig defines the values that may be set on a GatewayClass - for Consul API Gateway. - 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 GatewayClassConfig. - properties: - copyAnnotations: - description: Annotation Information to copy to services or deployments - properties: - service: - description: List of annotations to copy to the gateway service. - items: - type: string - type: array - type: object - deployment: - description: Deployment defines the deployment configuration for the - gateway. - properties: - defaultInstances: - default: 1 - description: Number of gateway instances that should be deployed - by default - format: int32 - maximum: 8 - minimum: 1 - type: integer - maxInstances: - default: 8 - description: Max allowed number of gateway instances - format: int32 - maximum: 8 - minimum: 1 - type: integer - minInstances: - default: 1 - description: Minimum allowed number of gateway instances - format: int32 - maximum: 8 - minimum: 1 - type: integer - resources: - description: Resources defines the resource requirements for the - gateway. - properties: - claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be - set for containers." - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: Name must match the name of one entry in - pod.spec.resourceClaims of the Pod where this field - is used. It makes that resource available inside a - container. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - 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. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - type: object - mapPrivilegedContainerPorts: - description: The value to add to privileged ports ( ports < 1024) - for gateway containers - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: 'NodeSelector is a selector which must be true for the - pod to fit on a node. Selector which must match a node''s labels - for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' - type: object - openshiftSCCName: - description: The name of the OpenShift SecurityContextConstraints - resource for this gateway class to use. - type: string - podSecurityPolicy: - description: The name of an existing Kubernetes PodSecurityPolicy - to bind to the managed ServiceAccount if ACLs are managed. - type: string - serviceType: - description: Service Type string describes ingress methods for a service - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - tolerations: - description: 'Tolerations allow the scheduler to schedule nodes with - matching taints. More Info: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/' - items: - description: The pod this Toleration is attached to tolerates any - taint that matches the triple using the matching - operator . - properties: - effect: - description: Effect indicates the taint effect to match. Empty - means match all taint effects. When specified, allowed values - are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: Key is the taint key that the toleration applies - to. Empty means match all taint keys. If the key is empty, - operator must be Exists; this combination means to match all - values and all keys. - type: string - operator: - description: Operator represents a key's relationship to the - value. Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod - can tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: TolerationSeconds represents the period of time - the toleration (which must be of effect NoExecute, otherwise - this field is ignored) tolerates the taint. By default, it - is not set, which means tolerate the taint forever (do not - evict). Zero and negative values will be treated as 0 (evict - immediately) by the system. - format: int64 - type: integer - value: - description: Value is the taint value the toleration matches - to. If the operator is Exists, the value should be empty, - otherwise just a regular string. - type: string - type: object - type: array - type: object - type: object - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml index 80f161c1ee..56179a1c45 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_jwtproviders.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_jwtproviders.yaml deleted file mode 100644 index 2e8ac24330..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_jwtproviders.yaml +++ /dev/null @@ -1,260 +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.8.0 - creationTimestamp: null - name: jwtproviders.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: JWTProvider - listKind: JWTProviderList - plural: jwtproviders - singular: jwtprovider - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: JWTProvider is the Schema for the jwtproviders API. - 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: JWTProviderSpec defines the desired state of JWTProvider - properties: - audiences: - description: Audiences is the set of audiences the JWT is allowed - to access. If specified, all JWTs verified with this provider must - address at least one of these to be considered valid. - items: - type: string - type: array - cacheConfig: - description: CacheConfig defines configuration for caching the validation - result for previously seen JWTs. Caching results can speed up verification - when individual tokens are expected to be handled multiple times. - properties: - size: - description: "Size specifies the maximum number of JWT verification - results to cache. \n Defaults to 0, meaning that JWT caching - is disabled." - type: integer - type: object - clockSkewSeconds: - description: "ClockSkewSeconds specifies the maximum allowable time - difference from clock skew when validating the \"exp\" (Expiration) - and \"nbf\" (Not Before) claims. \n Default value is 30 seconds." - type: integer - forwarding: - description: Forwarding defines rules for forwarding verified JWTs - to the backend. - properties: - headerName: - description: "HeaderName is a header name to use when forwarding - a verified JWT to the backend. The verified JWT could have been - extracted from any location (query param, header, or cookie). - \n The header value will be base64-URL-encoded, and will not - be padded unless PadForwardPayloadHeader is true." - type: string - padForwardPayloadHeader: - description: "PadForwardPayloadHeader determines whether padding - should be added to the base64 encoded token forwarded with ForwardPayloadHeader. - \n Default value is false." - type: boolean - type: object - issuer: - description: Issuer is the entity that must have issued the JWT. This - value must match the "iss" claim of the token. - type: string - jsonWebKeySet: - description: JSONWebKeySet defines a JSON Web Key Set, its location - on disk, or the means with which to fetch a key set from a remote - server. - properties: - local: - description: Local specifies a local source for the key set. - properties: - filename: - description: Filename configures a location on disk where - the JWKS can be found. If specified, the file must be present - on the disk of ALL proxies with intentions referencing this - provider. - type: string - jwks: - description: JWKS contains a base64 encoded JWKS. - type: string - type: object - remote: - description: Remote specifies how to fetch a key set from a remote - server. - properties: - cacheDuration: - description: "CacheDuration is the duration after which cached - keys should be expired. \n Default value is 5 minutes." - format: int64 - type: integer - fetchAsynchronously: - description: "FetchAsynchronously indicates that the JWKS - should be fetched when a client request arrives. Client - requests will be paused until the JWKS is fetched. If false, - the proxy listener will wait for the JWKS to be fetched - before being activated. \n Default value is false." - type: boolean - requestTimeoutMs: - description: RequestTimeoutMs is the number of milliseconds - to time out when making a request for the JWKS. - type: integer - retryPolicy: - description: "RetryPolicy defines a retry policy for fetching - JWKS. \n There is no retry by default." - properties: - numRetries: - description: "NumRetries is the number of times to retry - fetching the JWKS. The retry strategy uses jittered - exponential backoff with a base interval of 1s and max - of 10s. \n Default value is 0." - type: integer - retryPolicyBackOff: - description: "Backoff policy \n Defaults to Envoy's backoff - policy" - properties: - baseInterval: - description: "BaseInterval to be used for the next - back off computation \n The default value from envoy - is 1s" - format: int64 - type: integer - maxInterval: - description: "MaxInternal to be used to specify the - maximum interval between retries. Optional but should - be greater or equal to BaseInterval. \n Defaults - to 10 times BaseInterval" - format: int64 - type: integer - type: object - type: object - uri: - description: URI is the URI of the server to query for the - JWKS. - type: string - type: object - type: object - locations: - description: 'Locations where the JWT will be present in requests. - Envoy will check all of these locations to extract a JWT. If no - locations are specified Envoy will default to: 1. Authorization - header with Bearer schema: "Authorization: Bearer " 2. accessToken - query parameter.' - items: - description: "JWTLocation is a location where the JWT could be present - in requests. \n Only one of Header, QueryParam, or Cookie can - be specified." - properties: - cookie: - description: Cookie defines how to extract a JWT from an HTTP - request cookie. - properties: - name: - description: Name is the name of the cookie containing the - token. - type: string - type: object - header: - description: Header defines how to extract a JWT from an HTTP - request header. - properties: - forward: - description: "Forward defines whether the header with the - JWT should be forwarded after the token has been verified. - If false, the header will not be forwarded to the backend. - \n Default value is false." - type: boolean - name: - description: Name is the name of the header containing the - token. - type: string - valuePrefix: - description: 'ValuePrefix is an optional prefix that precedes - the token in the header value. For example, "Bearer " - is a standard value prefix for a header named "Authorization", - but the prefix is not part of the token itself: "Authorization: - Bearer "' - type: string - type: object - queryParam: - description: QueryParam defines how to extract a JWT from an - HTTP request query parameter. - properties: - name: - description: Name is the name of the query param containing - the token. - type: string - type: object - type: object - type: array - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml index adbb12bba6..7ad173afbf 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -51,11 +48,6 @@ spec: spec: description: MeshSpec defines the desired state of Mesh. properties: - allowEnablingPermissiveMutualTLS: - description: AllowEnablingPermissiveMutualTLS must be true in order - to allow setting MutualTLSMode=permissive in either service-defaults - or proxy-defaults. - type: boolean http: description: HTTP defines the HTTP configuration for the service mesh. properties: diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_meshservices.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_meshservices.yaml deleted file mode 100644 index 04f8f493e7..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_meshservices.yaml +++ /dev/null @@ -1,59 +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.8.0 - creationTimestamp: null - name: meshservices.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: MeshService - listKind: MeshServiceList - plural: meshservices - singular: meshservice - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: MeshService holds a reference to an externally managed Consul - Service Mesh service. - 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 MeshService. - properties: - name: - description: Name holds the service name for a Consul service. - type: string - peer: - description: Peer optionally specifies the name of the peer exporting - the Consul service. If not specified, the Consul service is assumed - to be in the local datacenter. - type: string - type: object - type: object - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml index 50df179f04..e782ef472f 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml index 01e4363f14..d5103252a5 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml index 25e61a51ee..6b9628cd74 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -53,60 +50,12 @@ spec: spec: description: ProxyDefaultsSpec defines the desired state of ProxyDefaults. properties: - accessLogs: - description: AccessLogs controls all envoy instances' access logging - configuration. - properties: - disableListenerLogs: - description: DisableListenerLogs turns off just listener logs - for connections rejected by Envoy because they don't have a - matching listener filter. - type: boolean - enabled: - description: Enabled turns on all access logging - type: boolean - jsonFormat: - description: 'JSONFormat is a JSON-formatted string of an Envoy - access log format dictionary. See for more info on formatting: - https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#format-dictionaries - Defining JSONFormat and TextFormat is invalid.' - type: string - path: - description: Path is the output file to write logs for file-type - logging - type: string - textFormat: - description: 'TextFormat is a representation of Envoy access logs - format. See for more info on formatting: https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#format-strings - Defining JSONFormat and TextFormat is invalid.' - type: string - type: - description: Type selects the output for logs one of "file", "stderr". - "stdout" - type: string - type: object config: description: Config is an arbitrary map of configuration values used by Connect proxies. Any values that your proxy allows can be configured globally here. Supports JSON config values. See https://www.consul.io/docs/connect/proxies/envoy#configuration-formatting type: object x-kubernetes-preserve-unknown-fields: true - envoyExtensions: - description: EnvoyExtensions are a list of extensions to modify Envoy - proxy configuration. - items: - description: EnvoyExtension has configuration for an extension that - patches Envoy resources. - properties: - arguments: - type: object - x-kubernetes-preserve-unknown-fields: true - name: - type: string - required: - type: boolean - type: object - type: array expose: description: Expose controls the default expose path configuration for Envoy. @@ -139,32 +88,6 @@ spec: type: object type: array type: object - failoverPolicy: - description: FailoverPolicy specifies the exact mechanism used for - failover. - properties: - mode: - description: Mode specifies the type of failover that will be - performed. Valid values are "sequential", "" (equivalent to - "sequential") and "order-by-locality". - type: string - regions: - description: Regions is the ordered list of the regions of the - failover targets. Valid values can be "us-west-1", "us-west-2", - and so on. - items: - type: string - type: array - type: object - prioritizeByLocality: - description: PrioritizeByLocality contains the configuration for - locality aware routing. - properties: - mode: - description: Mode specifies the behavior of PrioritizeByLocality - routing. Valid values are "", "none", and "failover". - type: string - type: object meshGateway: description: MeshGateway controls the default mesh gateway configuration for this service. @@ -185,18 +108,6 @@ spec: CRD and should be set using annotations on the services that are part of the mesh.' type: string - mutualTLSMode: - description: 'MutualTLSMode controls whether mutual TLS is required - for all incoming connections when transparent proxy is enabled. - This can be set to "permissive" or "strict". "strict" is the default - which requires mutual TLS for incoming connections. In the insecure - "permissive" mode, connections to the sidecar proxy public listener - port require mutual TLS, but connections to the service port do - not require mutual TLS and are proxied to the application unmodified. - Note: Intentions are not enforced for non-mTLS connections. To keep - your services secure, we recommend using "strict" mode whenever - possible and enabling "permissive" mode only when necessary.' - type: string transparentProxy: description: 'TransparentProxy controls configuration specific to proxies in transparent mode. Note: This cannot be set using the diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_routeretryfilters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_routeretryfilters.yaml deleted file mode 100644 index 5928864ac5..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_routeretryfilters.yaml +++ /dev/null @@ -1,112 +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.9.2 - creationTimestamp: null - name: routeretryfilters.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: RouteRetryFilter - listKind: RouteRetryFilterList - plural: routeretryfilters - singular: routeretryfilter - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The last successful synced time of the resource with Consul - jsonPath: .status.lastSyncedTime - name: Last Synced - type: date - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: RouteRetryFilter is the Schema for the routeretryfilters API - 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: RouteRetryFilterSpec defines the desired state of RouteRetryFilter - properties: - numRetries: - format: int32 - minimum: 0 - type: integer - retryOn: - items: - type: string - type: array - retryOnConnectFailure: - type: boolean - retryOnStatusCodes: - items: - format: int32 - type: integer - type: array - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_routetimeoutfilters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_routetimeoutfilters.yaml deleted file mode 100644 index e671ecd9b9..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_routetimeoutfilters.yaml +++ /dev/null @@ -1,110 +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.9.2 - creationTimestamp: null - name: routetimeoutfilters.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: RouteTimeoutFilter - listKind: RouteTimeoutFilterList - plural: routetimeoutfilters - singular: routetimeoutfilter - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The last successful synced time of the resource with Consul - jsonPath: .status.lastSyncedTime - name: Last Synced - type: date - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: RouteTimeoutFilter is the Schema for the httproutetimeoutfilters - API - 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: RouteTimeoutFilterSpec defines the desired state of RouteTimeoutFilter - properties: - idleTimeout: - description: A Duration represents the elapsed time between two instants - as an int64 nanosecond count. The representation limits the largest - representable duration to approximately 290 years. - format: int64 - type: integer - requestTimeout: - description: A Duration represents the elapsed time between two instants - as an int64 nanosecond count. The representation limits the largest - representable duration to approximately 290 years. - format: int64 - type: integer - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml deleted file mode 100644 index c71a211f63..0000000000 --- a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml +++ /dev/null @@ -1,132 +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.8.0 - creationTimestamp: null - name: samenessgroups.consul.hashicorp.com -spec: - group: consul.hashicorp.com - names: - kind: SamenessGroup - listKind: SamenessGroupList - plural: samenessgroups - shortNames: - - sameness-group - singular: samenessgroup - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: The sync status of the resource with Consul - jsonPath: .status.conditions[?(@.type=="Synced")].status - name: Synced - type: string - - description: The last successful synced time of the resource with Consul - jsonPath: .status.lastSyncedTime - name: Last Synced - type: date - - description: The age of the resource - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: SamenessGroup is the Schema for the samenessgroups API - 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: SamenessGroupSpec defines the desired state of SamenessGroup. - properties: - defaultForFailover: - description: DefaultForFailover indicates that upstream requests to - members of the given sameness group will implicitly failover between - members of this sameness group. When DefaultForFailover is true, - the local partition must be a member of the sameness group or IncludeLocal - must be set to true. - type: boolean - includeLocal: - description: IncludeLocal is used to include the local partition as - the first member of the sameness group. The local partition can - only be a member of a single sameness group. - type: boolean - members: - description: Members are the partitions and peers that are part of - the sameness group. If a member of a sameness group does not exist, - it will be ignored. - items: - properties: - partition: - description: The partitions and peers that are part of the sameness - group. A sameness group member cannot define both peer and - partition at the same time. - type: string - peer: - type: string - type: object - type: array - type: object - 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 - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml index 5a2c7a58fd..7324f0a296 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -53,12 +50,6 @@ spec: spec: description: ServiceDefaultsSpec defines the desired state of ServiceDefaults. properties: - balanceInboundConnections: - description: BalanceInboundConnections sets the strategy for allocating - inbound connections to the service across proxy threads. The only - supported value is exact_balance. By default, no connection balancing - is used. Refer to the Envoy Connection Balance config for details. - type: string destination: description: Destination is an address(es)/port combination that represents an endpoint outside the mesh. This is only valid when the mesh is @@ -78,22 +69,6 @@ spec: format: int32 type: integer type: object - envoyExtensions: - description: EnvoyExtensions are a list of extensions to modify Envoy - proxy configuration. - items: - description: EnvoyExtension has configuration for an extension that - patches Envoy resources. - properties: - arguments: - type: object - x-kubernetes-preserve-unknown-fields: true - name: - type: string - required: - type: boolean - type: object - type: array expose: description: Expose controls the default expose path configuration for Envoy. @@ -132,15 +107,15 @@ spec: with an external system. type: string localConnectTimeoutMs: - description: LocalConnectTimeoutMs is the number of milliseconds allowed - to make connections to the local application instance before timing - out. Defaults to 5000. + description: The number of milliseconds allowed to make connections + to the local application instance before timing out. Defaults to + 5000. type: integer localRequestTimeoutMs: - description: LocalRequestTimeoutMs is the timeout for HTTP requests - to the local application instance in milliseconds. Applies to HTTP-based - protocols only. If not specified, inherits the Envoy default for - route timeouts (15s). + description: In milliseconds, the timeout for HTTP requests to the + local application instance. Applies to HTTP-based protocols only. + If not specified, inherits the Envoy default for route timeouts + (15s). type: integer maxInboundConnections: description: MaxInboundConnections is the maximum number of concurrent @@ -167,18 +142,6 @@ spec: CRD and should be set using annotations on the services that are part of the mesh.' type: string - mutualTLSMode: - description: 'MutualTLSMode controls whether mutual TLS is required - for all incoming connections when transparent proxy is enabled. - This can be set to "permissive" or "strict". "strict" is the default - which requires mutual TLS for incoming connections. In the insecure - "permissive" mode, connections to the sidecar proxy public listener - port require mutual TLS, but connections to the service port do - not require mutual TLS and are proxied to the application unmodified. - Note: Intentions are not enforced for non-mTLS connections. To keep - your services secure, we recommend using "strict" mode whenever - possible and enabling "permissive" mode only when necessary.' - type: string protocol: description: Protocol sets the protocol of the service. This is used by Connect proxies for things like observability features and to @@ -266,15 +229,15 @@ spec: type: string type: object name: - description: Name is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Name is only accepted within a service-defaults config entry. type: string namespace: - description: Namespace is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Namespace is only accepted within a service-defaults config entry. type: string partition: - description: Partition is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Partition is only accepted within a service-defaults config entry. type: string passiveHealthCheck: @@ -313,10 +276,6 @@ spec: format: int32 type: integer type: object - peer: - description: Peer is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides - config entry. - type: string protocol: description: Protocol describes the upstream's service protocol. Valid values are "tcp", "http" and "grpc". Anything else @@ -383,15 +342,15 @@ spec: type: string type: object name: - description: Name is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Name is only accepted within a service-defaults config entry. type: string namespace: - description: Namespace is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Namespace is only accepted within a service-defaults config entry. type: string partition: - description: Partition is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides + description: Partition is only accepted within a service-defaults config entry. type: string passiveHealthCheck: @@ -432,10 +391,6 @@ spec: format: int32 type: integer type: object - peer: - description: Peer is only accepted within service ServiceDefaultsSpec.UpstreamConfig.Overrides - config entry. - type: string protocol: description: Protocol describes the upstream's service protocol. Valid values are "tcp", "http" and "grpc". Anything else diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml index a4efd6e958..a0cc7a6343 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -70,43 +67,6 @@ spec: have intentions defined. type: string type: object - jwt: - description: JWT specifies the configuration to validate a JSON Web - Token for all incoming requests. - properties: - providers: - description: Providers is a list of providers to consider when - verifying a JWT. - items: - properties: - name: - description: Name is the name of the JWT provider. There - MUST be a corresponding "jwt-provider" config entry with - this name. - type: string - verifyClaims: - description: VerifyClaims is a list of additional claims - to verify in a JWT's payload. - items: - properties: - path: - description: Path is the path to the claim in the - token JSON. - items: - type: string - type: array - value: - description: Value is the expected value at the given - path. If the type at the path is a list then we - verify that this value is contained in the list. - If the type at the path is a string then we verify - that this value matches. - type: string - type: object - type: array - type: object - type: array - type: object sources: description: Sources is the list of all intention sources and the authorization granted to those sources. The order of this list does @@ -135,7 +95,8 @@ spec: description: Partition is the Admin Partition for the Name parameter. type: string peer: - description: Peer is the peer name for the Name parameter. + description: '[Experimental] Peer is the peer name for the Name + parameter.' type: string permissions: description: Permissions is the list of all additional L7 attributes @@ -216,50 +177,8 @@ spec: match on the HTTP request path. type: string type: object - jwt: - description: JWT specifies configuration to validate a - JSON Web Token for incoming requests. - properties: - providers: - description: Providers is a list of providers to consider - when verifying a JWT. - items: - properties: - name: - description: Name is the name of the JWT provider. - There MUST be a corresponding "jwt-provider" - config entry with this name. - type: string - verifyClaims: - description: VerifyClaims is a list of additional - claims to verify in a JWT's payload. - items: - properties: - path: - description: Path is the path to the claim - in the token JSON. - items: - type: string - type: array - value: - description: Value is the expected value - at the given path. If the type at the - path is a list then we verify that this - value is contained in the list. If the - type at the path is a string then we - verify that this value matches. - type: string - type: object - type: array - type: object - type: array - type: object type: object type: array - samenessGroup: - description: SamenessGroup is the name of the sameness group, - if applicable. - type: string type: object type: array type: object diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml index 0146eca982..a84fc0bd88 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -75,26 +72,6 @@ spec: service from to form the failover group of instances. If empty the current namespace is used. type: string - policy: - description: Policy specifies the exact mechanism used for failover. - properties: - mode: - description: Mode specifies the type of failover that will - be performed. Valid values are "sequential", "" (equivalent - to "sequential") and "order-by-locality". - type: string - regions: - description: Regions is the ordered list of the regions - of the failover targets. Valid values can be "us-west-1", - "us-west-2", and so on. - items: - type: string - type: array - type: object - samenessGroup: - description: SamenessGroup is the name of the sameness group - to try during failover. - type: string service: description: Service is the service to resolve instead of the default as the failover group of instances during failover. @@ -223,16 +200,6 @@ spec: type: integer type: object type: object - prioritizeByLocality: - description: PrioritizeByLocality controls whether the locality of - services within the local partition will be used to prioritize connectivity. - properties: - mode: - description: 'Mode specifies the type of prioritization that will - be performed when selecting nodes in the local partition. Valid - values are: "" (default "none"), "none", and "failover".' - type: string - type: object redirect: description: Redirect when configured, all attempts to resolve the service this resolver defines will be substituted for the supplied @@ -258,10 +225,6 @@ spec: description: Peer is the name of the cluster peer to resolve the service from instead of the current one. type: string - samenessGroup: - description: SamenessGroup is the name of the sameness group to - resolve the service from instead of the current one. - type: string service: description: Service is a service to resolve instead of the current service. @@ -272,10 +235,6 @@ spec: If empty the default subset is used. type: string type: object - requestTimeout: - description: RequestTimeout is the timeout for receiving an HTTP response - from this service before the connection is terminated. - type: string subsets: additionalProperties: properties: diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml index 31f5ee2924..8b55692bd2 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml index aa2b592c94..df8bbbfbdf 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml index b465cd9494..8e6c449ef8 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/external/gatewayclasses.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/gatewayclasses.gateway.networking.k8s.io.yaml deleted file mode 100644 index 044c7af939..0000000000 --- a/control-plane/config/crd/external/gatewayclasses.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,323 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: gatewayclasses.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: GatewayClass - listKind: GatewayClassList - plural: gatewayclasses - shortNames: - - gc - singular: gatewayclass - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .spec.controllerName - name: Controller - type: string - - jsonPath: .status.conditions[?(@.type=="Accepted")].status - name: Accepted - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - jsonPath: .spec.description - name: Description - priority: 1 - type: string - deprecated: true - deprecationWarning: The v1alpha2 version of GatewayClass has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1. - name: v1alpha2 - schema: - openAPIV3Schema: - description: "GatewayClass describes a class of Gateways available to the user for creating Gateway resources. \n It is recommended that this resource be used as a template for Gateways. This means that a Gateway is based on the state of the GatewayClass at the time it was created and changes to the GatewayClass or associated parameters are not propagated down to existing Gateways. This recommendation is intended to limit the blast radius of changes to GatewayClass or associated parameters. If implementations choose to propagate GatewayClass changes to existing Gateways, that MUST be clearly documented by the implementation. \n Whenever one or more Gateways are using a GatewayClass, implementations MUST add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the associated GatewayClass. This ensures that a GatewayClass associated with a Gateway is not deleted while in use. \n GatewayClass is a Cluster level resource." - 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 GatewayClass. - properties: - controllerName: - description: "ControllerName is the name of the controller that is managing Gateways of this class. The value of this field MUST be a domain prefixed path. \n Example: \"example.net/gateway-controller\". \n This field is not mutable and cannot be empty. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - description: - description: Description helps describe a GatewayClass with more details. - maxLength: 64 - type: string - parametersRef: - description: "ParametersRef is a reference to a resource that contains the configuration parameters corresponding to the GatewayClass. This is optional if the controller does not require any additional configuration. \n ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, or an implementation-specific custom resource. The resource can be cluster-scoped or namespace-scoped. \n If the referent cannot be found, the GatewayClass's \"InvalidParameters\" status condition will be true. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. This field is required when referring to a Namespace-scoped resource and MUST be unset when referring to a Cluster-scoped resource. - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - required: - - controllerName - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: Unknown - type: Accepted - description: Status defines the current state of GatewayClass. - properties: - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - description: "Conditions is the current status from the controller for this GatewayClass. \n Controllers should prefer to publish conditions using values of GatewayClassConditionType for the type of each Condition." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.controllerName - name: Controller - type: string - - jsonPath: .status.conditions[?(@.type=="Accepted")].status - name: Accepted - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - jsonPath: .spec.description - name: Description - priority: 1 - type: string - name: v1beta1 - schema: - openAPIV3Schema: - description: "GatewayClass describes a class of Gateways available to the user for creating Gateway resources. \n It is recommended that this resource be used as a template for Gateways. This means that a Gateway is based on the state of the GatewayClass at the time it was created and changes to the GatewayClass or associated parameters are not propagated down to existing Gateways. This recommendation is intended to limit the blast radius of changes to GatewayClass or associated parameters. If implementations choose to propagate GatewayClass changes to existing Gateways, that MUST be clearly documented by the implementation. \n Whenever one or more Gateways are using a GatewayClass, implementations MUST add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the associated GatewayClass. This ensures that a GatewayClass associated with a Gateway is not deleted while in use. \n GatewayClass is a Cluster level resource." - 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 GatewayClass. - properties: - controllerName: - description: "ControllerName is the name of the controller that is managing Gateways of this class. The value of this field MUST be a domain prefixed path. \n Example: \"example.net/gateway-controller\". \n This field is not mutable and cannot be empty. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - description: - description: Description helps describe a GatewayClass with more details. - maxLength: 64 - type: string - parametersRef: - description: "ParametersRef is a reference to a resource that contains the configuration parameters corresponding to the GatewayClass. This is optional if the controller does not require any additional configuration. \n ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, or an implementation-specific custom resource. The resource can be cluster-scoped or namespace-scoped. \n If the referent cannot be found, the GatewayClass's \"InvalidParameters\" status condition will be true. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. This field is required when referring to a Namespace-scoped resource and MUST be unset when referring to a Cluster-scoped resource. - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - required: - - controllerName - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: Unknown - type: Accepted - description: Status defines the current state of GatewayClass. - properties: - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - description: "Conditions is the current status from the controller for this GatewayClass. \n Controllers should prefer to publish conditions using values of GatewayClassConditionType for the type of each Condition." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/external/gateways.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/gateways.gateway.networking.k8s.io.yaml deleted file mode 100644 index b7a7c8a7d1..0000000000 --- a/control-plane/config/crd/external/gateways.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,877 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: gateways.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: Gateway - listKind: GatewayList - plural: gateways - shortNames: - - gtw - singular: gateway - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.gatewayClassName - name: Class - type: string - - jsonPath: .status.addresses[*].value - name: Address - type: string - - jsonPath: .status.conditions[?(@.type=="Programmed")].status - name: Programmed - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - deprecated: true - deprecationWarning: The v1alpha2 version of Gateway has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1. - name: v1alpha2 - schema: - openAPIV3Schema: - description: Gateway represents an instance of a service-traffic handling infrastructure by binding Listeners to a set of IP addresses. - 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 Gateway. - properties: - addresses: - description: "Addresses requested for this Gateway. This is optional and behavior can depend on the implementation. If a value is set in the spec and the requested address is invalid or unavailable, the implementation MUST indicate this in the associated entry in GatewayStatus.Addresses. \n The Addresses field represents a request for the address(es) on the \"outside of the Gateway\", that traffic bound for this Gateway will use. This could be the IP address or hostname of an external load balancer or other networking infrastructure, or some other address that traffic will be sent to. \n The .listener.hostname field is used to route traffic that has already arrived at the Gateway to the correct in-cluster destination. \n If no Addresses are specified, the implementation MAY schedule the Gateway in an implementation-specific manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. \n Support: Extended" - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - gatewayClassName: - description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. - maxLength: 253 - minLength: 1 - type: string - listeners: - description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At least one Listener MUST be specified. \n Each listener in a Gateway must have a unique combination of Hostname, Port, and Protocol. \n An implementation MAY group Listeners by Port and then collapse each group of Listeners into a single Listener if the implementation determines that the Listeners in the group are \"compatible\". An implementation MAY also group together and collapse compatible Listeners belonging to different Gateways. \n For example, an implementation might consider Listeners to be compatible with each other if all of the following conditions are met: \n 1. Either each Listener within the group specifies the \"HTTP\" Protocol or each Listener within the group specifies either the \"HTTPS\" or \"TLS\" Protocol. \n 2. Each Listener within the group specifies a Hostname that is unique within the group. \n 3. As a special case, one Listener within a group may omit Hostname, in which case this Listener matches when no other Listener matches. \n If the implementation does collapse compatible Listeners, the hostname provided in the incoming client request MUST be matched to a Listener to find the correct set of Routes. The incoming hostname MUST be matched using the Hostname field for each Listener in order of most to least specific. That is, exact matches must be processed before wildcard matches. \n If this field specifies multiple Listeners that have the same Port value but are not compatible, the implementation must raise a \"Conflicted\" condition in the Listener status. \n Support: Core" - items: - description: Listener embodies the concept of a logical endpoint where a Gateway accepts network connections. - properties: - allowedRoutes: - default: - namespaces: - from: Same - description: "AllowedRoutes defines the types of routes that MAY be attached to a Listener and the trusted namespaces where those Route resources MAY be present. \n Although a client request may match multiple route rules, only one rule may ultimately receive the request. Matching precedence MUST be determined in order of the following criteria: \n * The most specific match as defined by the Route type. * The oldest Route based on creation timestamp. For example, a Route with a creation timestamp of \"2020-09-08 01:02:03\" is given precedence over a Route with a creation timestamp of \"2020-09-08 01:02:04\". * If everything else is equivalent, the Route appearing first in alphabetical order (namespace/name) should be given precedence. For example, foo/bar is given precedence over foo/baz. \n All valid rules within a Route attached to this Listener should be implemented. Invalid Route rules can be ignored (sometimes that will mean the full Route). If a Route rule transitions from valid to invalid, support for that Route rule should be dropped to ensure consistency. For example, even if a filter specified by a Route rule is invalid, the rest of the rules within that Route should still be supported. \n Support: Core" - properties: - kinds: - description: "Kinds specifies the groups and kinds of Routes that are allowed to bind to this Gateway Listener. When unspecified or empty, the kinds of Routes selected are determined using the Listener protocol. \n A RouteGroupKind MUST correspond to kinds of Routes that are compatible with the application protocol specified in the Listener's Protocol field. If an implementation does not support or recognize this resource type, it MUST set the \"ResolvedRefs\" condition to False for this Listener with the \"InvalidRouteKinds\" reason. \n Support: Core" - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - namespaces: - default: - from: Same - description: "Namespaces indicates namespaces from which Routes may be attached to this Listener. This is restricted to the namespace of this Gateway by default. \n Support: Core" - properties: - from: - default: Same - description: "From indicates where Routes will be selected for this Gateway. Possible values are: * All: Routes in all namespaces may be used by this Gateway. * Selector: Routes in namespaces selected by the selector may be used by this Gateway. * Same: Only Routes in the same namespace may be used by this Gateway. \n Support: Core" - enum: - - All - - Selector - - Same - type: string - selector: - description: "Selector must be specified when From is set to \"Selector\". In that case, only Routes in Namespaces matching this Selector will be selected by this Gateway. This field is ignored for other values of \"From\". \n Support: Core" - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - type: object - type: object - hostname: - description: "Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified, all hostnames are matched. This field is ignored for protocols that don't require hostname based matching. \n Implementations MUST apply Hostname matching appropriately for each of the following protocols: \n * TLS: The Listener Hostname MUST match the SNI. * HTTP: The Listener Hostname MUST match the Host header of the request. * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP protocol layers as described above. If an implementation does not ensure that both the SNI and Host header match the Listener hostname, it MUST clearly document that. \n For HTTPRoute and TLSRoute resources, there is an interaction with the `spec.hostnames` array. When both listener and route specify hostnames, there MUST be an intersection between the values for a Route to be accepted. For more information, refer to the Route specific Hostnames documentation. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - name: - description: "Name is the name of the Listener. This name MUST be unique within a Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - port: - description: "Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - description: "Protocol specifies the network protocol this listener expects to receive. \n Support: Core" - maxLength: 255 - minLength: 1 - pattern: ^[a-zA-Z0-9]([-a-zSA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ - type: string - tls: - description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\". \n The association of SNIs to Certificate defined in GatewayTLSConfig is defined based on the Hostname field for this listener. \n The GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake. \n Support: Core" - properties: - certificateRefs: - description: "CertificateRefs contains a series of references to Kubernetes objects that contains TLS certificates and private keys. These certificates are used to establish a TLS handshake for requests that match the hostname of the associated listener. \n A single CertificateRef to a Kubernetes Secret has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a Listener, but this behavior is implementation-specific. \n References to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason. \n This field is required to have at least one element when the mode is set to \"Terminate\" (default) and is optional otherwise. \n CertificateRefs can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources. \n Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls \n Support: Implementation-specific (More than one reference or other resource types)" - items: - description: "SecretObjectReference identifies an API object including its namespace, defaulting to Secret. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid. \n References to objects with invalid Group and Kind are not valid, and must be rejected by the implementation, with appropriate Conditions set on the containing object." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Secret - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - name - type: object - maxItems: 64 - type: array - mode: - default: Terminate - description: "Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes: \n - Terminate: The TLS session between the downstream client and the Gateway is terminated at the Gateway. This mode requires certificateRefs to be set and contain at least one element. - Passthrough: The TLS session is NOT terminated by the Gateway. This implies that the Gateway can't decipher the TLS stream except for the ClientHello message of the TLS protocol. CertificateRefs field is ignored in this mode. \n Support: Core" - enum: - - Terminate - - Passthrough - type: string - options: - additionalProperties: - description: AnnotationValue is the value of an annotation in Gateway API. This is used for validation of maps such as TLS options. This roughly matches Kubernetes annotation validation, although the length validation in that case is based on the entire size of the annotations struct. - maxLength: 4096 - minLength: 0 - type: string - description: "Options are a list of key/value pairs to enable extended TLS configuration for each implementation. For example, configuring the minimum TLS version or supported cipher suites. \n A set of common keys MAY be defined by the API in the future. To avoid any ambiguity, implementation-specific definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. Un-prefixed names are reserved for key names defined by Gateway API. \n Support: Implementation-specific" - maxProperties: 16 - type: object - type: object - required: - - name - - port - - protocol - type: object - maxItems: 64 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - gatewayClassName - - listeners - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: Unknown - type: Accepted - description: Status defines the current state of Gateway. - properties: - addresses: - description: Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address from a reserved pool. - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Programmed - description: "Conditions describe the current conditions of the Gateway. \n Implementations should prefer to express Gateway conditions using the `GatewayConditionType` and `GatewayConditionReason` constants so that operators and tools can converge on a common vocabulary to describe Gateway state. \n Known condition types are: \n * \"Accepted\" * \"Ready\"" - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - listeners: - description: Listeners provide status for each unique listener port defined in the Spec. - items: - description: ListenerStatus is the status associated with a Listener. - properties: - attachedRoutes: - description: AttachedRoutes represents the total number of Routes that have been successfully attached to this Listener. - format: int32 - type: integer - conditions: - description: Conditions describe the current condition of this listener. - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - name: - description: Name is the name of the Listener that this status corresponds to. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - supportedKinds: - description: "SupportedKinds is the list indicating the Kinds supported by this listener. This MUST represent the kinds an implementation supports for that Listener configuration. \n If kinds are specified in Spec that are not supported, they MUST NOT appear in this list and an implementation MUST set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" reason. If both valid and invalid Route kinds are specified, the implementation MUST reference the valid Route kinds that have been specified." - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - required: - - attachedRoutes - - conditions - - name - - supportedKinds - type: object - maxItems: 64 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.gatewayClassName - name: Class - type: string - - jsonPath: .status.addresses[*].value - name: Address - type: string - - jsonPath: .status.conditions[?(@.type=="Programmed")].status - name: Programmed - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1beta1 - schema: - openAPIV3Schema: - description: Gateway represents an instance of a service-traffic handling infrastructure by binding Listeners to a set of IP addresses. - 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 Gateway. - properties: - addresses: - description: "Addresses requested for this Gateway. This is optional and behavior can depend on the implementation. If a value is set in the spec and the requested address is invalid or unavailable, the implementation MUST indicate this in the associated entry in GatewayStatus.Addresses. \n The Addresses field represents a request for the address(es) on the \"outside of the Gateway\", that traffic bound for this Gateway will use. This could be the IP address or hostname of an external load balancer or other networking infrastructure, or some other address that traffic will be sent to. \n The .listener.hostname field is used to route traffic that has already arrived at the Gateway to the correct in-cluster destination. \n If no Addresses are specified, the implementation MAY schedule the Gateway in an implementation-specific manner, assigning an appropriate set of Addresses. \n The implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses. \n Support: Extended" - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - gatewayClassName: - description: GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. - maxLength: 253 - minLength: 1 - type: string - listeners: - description: "Listeners associated with this Gateway. Listeners define logical endpoints that are bound on this Gateway's addresses. At least one Listener MUST be specified. \n Each listener in a Gateway must have a unique combination of Hostname, Port, and Protocol. \n An implementation MAY group Listeners by Port and then collapse each group of Listeners into a single Listener if the implementation determines that the Listeners in the group are \"compatible\". An implementation MAY also group together and collapse compatible Listeners belonging to different Gateways. \n For example, an implementation might consider Listeners to be compatible with each other if all of the following conditions are met: \n 1. Either each Listener within the group specifies the \"HTTP\" Protocol or each Listener within the group specifies either the \"HTTPS\" or \"TLS\" Protocol. \n 2. Each Listener within the group specifies a Hostname that is unique within the group. \n 3. As a special case, one Listener within a group may omit Hostname, in which case this Listener matches when no other Listener matches. \n If the implementation does collapse compatible Listeners, the hostname provided in the incoming client request MUST be matched to a Listener to find the correct set of Routes. The incoming hostname MUST be matched using the Hostname field for each Listener in order of most to least specific. That is, exact matches must be processed before wildcard matches. \n If this field specifies multiple Listeners that have the same Port value but are not compatible, the implementation must raise a \"Conflicted\" condition in the Listener status. \n Support: Core" - items: - description: Listener embodies the concept of a logical endpoint where a Gateway accepts network connections. - properties: - allowedRoutes: - default: - namespaces: - from: Same - description: "AllowedRoutes defines the types of routes that MAY be attached to a Listener and the trusted namespaces where those Route resources MAY be present. \n Although a client request may match multiple route rules, only one rule may ultimately receive the request. Matching precedence MUST be determined in order of the following criteria: \n * The most specific match as defined by the Route type. * The oldest Route based on creation timestamp. For example, a Route with a creation timestamp of \"2020-09-08 01:02:03\" is given precedence over a Route with a creation timestamp of \"2020-09-08 01:02:04\". * If everything else is equivalent, the Route appearing first in alphabetical order (namespace/name) should be given precedence. For example, foo/bar is given precedence over foo/baz. \n All valid rules within a Route attached to this Listener should be implemented. Invalid Route rules can be ignored (sometimes that will mean the full Route). If a Route rule transitions from valid to invalid, support for that Route rule should be dropped to ensure consistency. For example, even if a filter specified by a Route rule is invalid, the rest of the rules within that Route should still be supported. \n Support: Core" - properties: - kinds: - description: "Kinds specifies the groups and kinds of Routes that are allowed to bind to this Gateway Listener. When unspecified or empty, the kinds of Routes selected are determined using the Listener protocol. \n A RouteGroupKind MUST correspond to kinds of Routes that are compatible with the application protocol specified in the Listener's Protocol field. If an implementation does not support or recognize this resource type, it MUST set the \"ResolvedRefs\" condition to False for this Listener with the \"InvalidRouteKinds\" reason. \n Support: Core" - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - namespaces: - default: - from: Same - description: "Namespaces indicates namespaces from which Routes may be attached to this Listener. This is restricted to the namespace of this Gateway by default. \n Support: Core" - properties: - from: - default: Same - description: "From indicates where Routes will be selected for this Gateway. Possible values are: * All: Routes in all namespaces may be used by this Gateway. * Selector: Routes in namespaces selected by the selector may be used by this Gateway. * Same: Only Routes in the same namespace may be used by this Gateway. \n Support: Core" - enum: - - All - - Selector - - Same - type: string - selector: - description: "Selector must be specified when From is set to \"Selector\". In that case, only Routes in Namespaces matching this Selector will be selected by this Gateway. This field is ignored for other values of \"From\". \n Support: Core" - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. - properties: - key: - description: key is the label key that the selector applies to. - type: string - operator: - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - type: object - type: object - hostname: - description: "Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified, all hostnames are matched. This field is ignored for protocols that don't require hostname based matching. \n Implementations MUST apply Hostname matching appropriately for each of the following protocols: \n * TLS: The Listener Hostname MUST match the SNI. * HTTP: The Listener Hostname MUST match the Host header of the request. * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP protocol layers as described above. If an implementation does not ensure that both the SNI and Host header match the Listener hostname, it MUST clearly document that. \n For HTTPRoute and TLSRoute resources, there is an interaction with the `spec.hostnames` array. When both listener and route specify hostnames, there MUST be an intersection between the values for a Route to be accepted. For more information, refer to the Route specific Hostnames documentation. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - name: - description: "Name is the name of the Listener. This name MUST be unique within a Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - port: - description: "Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - description: "Protocol specifies the network protocol this listener expects to receive. \n Support: Core" - maxLength: 255 - minLength: 1 - pattern: ^[a-zA-Z0-9]([-a-zSA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ - type: string - tls: - description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\". \n The association of SNIs to Certificate defined in GatewayTLSConfig is defined based on the Hostname field for this listener. \n The GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake. \n Support: Core" - properties: - certificateRefs: - description: "CertificateRefs contains a series of references to Kubernetes objects that contains TLS certificates and private keys. These certificates are used to establish a TLS handshake for requests that match the hostname of the associated listener. \n A single CertificateRef to a Kubernetes Secret has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a Listener, but this behavior is implementation-specific. \n References to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason. \n This field is required to have at least one element when the mode is set to \"Terminate\" (default) and is optional otherwise. \n CertificateRefs can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources. \n Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls \n Support: Implementation-specific (More than one reference or other resource types)" - items: - description: "SecretObjectReference identifies an API object including its namespace, defaulting to Secret. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid. \n References to objects with invalid Group and Kind are not valid, and must be rejected by the implementation, with appropriate Conditions set on the containing object." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Secret - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - name - type: object - maxItems: 64 - type: array - mode: - default: Terminate - description: "Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes: \n - Terminate: The TLS session between the downstream client and the Gateway is terminated at the Gateway. This mode requires certificateRefs to be set and contain at least one element. - Passthrough: The TLS session is NOT terminated by the Gateway. This implies that the Gateway can't decipher the TLS stream except for the ClientHello message of the TLS protocol. CertificateRefs field is ignored in this mode. \n Support: Core" - enum: - - Terminate - - Passthrough - type: string - options: - additionalProperties: - description: AnnotationValue is the value of an annotation in Gateway API. This is used for validation of maps such as TLS options. This roughly matches Kubernetes annotation validation, although the length validation in that case is based on the entire size of the annotations struct. - maxLength: 4096 - minLength: 0 - type: string - description: "Options are a list of key/value pairs to enable extended TLS configuration for each implementation. For example, configuring the minimum TLS version or supported cipher suites. \n A set of common keys MAY be defined by the API in the future. To avoid any ambiguity, implementation-specific definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. Un-prefixed names are reserved for key names defined by Gateway API. \n Support: Implementation-specific" - maxProperties: 16 - type: object - type: object - required: - - name - - port - - protocol - type: object - maxItems: 64 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - gatewayClassName - - listeners - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: Unknown - type: Accepted - description: Status defines the current state of Gateway. - properties: - addresses: - description: Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address from a reserved pool. - items: - description: GatewayAddress describes an address that can be bound to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - maxLength: 253 - minLength: 1 - pattern: ^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - value: - description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Accepted - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Pending - status: Unknown - type: Programmed - description: "Conditions describe the current conditions of the Gateway. \n Implementations should prefer to express Gateway conditions using the `GatewayConditionType` and `GatewayConditionReason` constants so that operators and tools can converge on a common vocabulary to describe Gateway state. \n Known condition types are: \n * \"Accepted\" * \"Ready\"" - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - listeners: - description: Listeners provide status for each unique listener port defined in the Spec. - items: - description: ListenerStatus is the status associated with a Listener. - properties: - attachedRoutes: - description: AttachedRoutes represents the total number of Routes that have been successfully attached to this Listener. - format: int32 - type: integer - conditions: - description: Conditions describe the current condition of this listener. - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - name: - description: Name is the name of the Listener that this status corresponds to. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - supportedKinds: - description: "SupportedKinds is the list indicating the Kinds supported by this listener. This MUST represent the kinds an implementation supports for that Listener configuration. \n If kinds are specified in Spec that are not supported, they MUST NOT appear in this list and an implementation MUST set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" reason. If both valid and invalid Route kinds are specified, the implementation MUST reference the valid Route kinds that have been specified." - items: - description: RouteGroupKind indicates the group and kind of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - required: - - attachedRoutes - - conditions - - name - - supportedKinds - type: object - maxItems: 64 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/external/grpcroutes.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/grpcroutes.gateway.networking.k8s.io.yaml deleted file mode 100644 index 8f3ab6d385..0000000000 --- a/control-plane/config/crd/external/grpcroutes.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,761 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: grpcroutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: GRPCRoute - listKind: GRPCRouteList - plural: grpcroutes - singular: grpcroute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "GRPCRoute provides a way to route gRPC requests. This includes the capability to match requests by hostname, gRPC service, gRPC method, or HTTP/2 header. Filters can be used to specify additional processing steps. Backends specify where matching requests will be routed. \n GRPCRoute falls under extended support within the Gateway API. Within the following specification, the word \"MUST\" indicates that an implementation supporting GRPCRoute must conform to the indicated requirement, but an implementation not supporting this route type need not follow the requirement unless explicitly indicated. \n Implementations supporting `GRPCRoute` with the `HTTPS` `ProtocolType` MUST accept HTTP/2 connections without an initial upgrade from HTTP/1.1, i.e. via ALPN. If the implementation does not support this, then it MUST set the \"Accepted\" condition to \"False\" for the affected listener with a reason of \"UnsupportedProtocol\". Implementations MAY also accept HTTP/2 connections with an upgrade from HTTP/1. \n Implementations supporting `GRPCRoute` with the `HTTP` `ProtocolType` MUST support HTTP/2 over cleartext TCP (h2c, https://www.rfc-editor.org/rfc/rfc7540#section-3.1) without an initial upgrade from HTTP/1.1, i.e. with prior knowledge (https://www.rfc-editor.org/rfc/rfc7540#section-3.4). If the implementation does not support this, then it MUST set the \"Accepted\" condition to \"False\" for the affected listener with a reason of \"UnsupportedProtocol\". Implementations MAY also accept HTTP/2 connections with an upgrade from HTTP/1, i.e. without prior knowledge. \n Support: Extended" - 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 GRPCRoute. - properties: - hostnames: - description: "Hostnames defines a set of hostnames to match against the GRPC Host header to select a GRPCRoute to process the request. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label MUST appear by itself as the first label. \n If a hostname is specified by both the Listener and GRPCRoute, there MUST be at least one intersecting hostname for the GRPCRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches GRPCRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches GRPCRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `test.example.com` and `*.example.com` would both match. On the other hand, `example.com` and `test.example.net` would not match. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n If both the Listener and GRPCRoute have specified hostnames, any GRPCRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the GRPCRoute specified `test.example.com` and `test.example.net`, `test.example.net` MUST NOT be considered for a match. \n If both the Listener and GRPCRoute have specified hostnames, and none match with the criteria above, then the GRPCRoute MUST NOT be accepted by the implementation. The implementation MUST raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n If a Route (A) of type HTTPRoute or GRPCRoute is attached to a Listener and that listener already has another Route (B) of the other type attached and the intersection of the hostnames of A and B is non-empty, then the implementation MUST accept exactly one of these two routes, determined by the following criteria, in order: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n The rejected Route MUST raise an 'Accepted' condition with a status of 'False' in the corresponding RouteParentStatus. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - default: - - matches: - - method: - type: Exact - description: Rules are a list of GRPC matchers, filters and actions. - items: - description: GRPCRouteRule defines the semantics for matching an gRPC request based on conditions (matches), processing it (filters), and forwarding the request to an API object (backendRefs). - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. \n Failure behavior here depends on how many BackendRefs are specified and how many are invalid. \n If *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive an `UNAVAILABLE` status. \n See the GRPCBackendRef definition for the rules about what makes a single GRPCBackendRef invalid. \n When a GRPCBackendRef is invalid, `UNAVAILABLE` statuses MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive an `UNAVAILABLE` status. \n For example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic MUST receive an `UNAVAILABLE` status. Implementations may choose how that 50 percent is determined. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Core" - items: - description: GRPCBackendRef defines how a GRPCRoute forwards a gRPC request. - properties: - filters: - description: "Filters defined at this level MUST be executed if and only if the request is being forwarded to the backend defined here. \n Support: Implementation-specific (For broader support of filters, use the Filters field in GRPCRouteRule.)" - items: - description: GRPCRouteFilter defines processing steps that must be completed during the request or response lifecycle. GRPCRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations supporting GRPCRoute MUST support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` MUST be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n " - enum: - - ResponseHeaderModifier - - RequestHeaderModifier - - RequestMirror - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - type: array - filters: - description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: \n - ALL core filters MUST be supported by all implementations that support GRPCRoute. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or implementation-specific conformance. Support: Core" - items: - description: GRPCRouteFilter defines processing steps that must be completed during the request or response lifecycle. GRPCRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations supporting GRPCRoute MUST support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` MUST be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n " - enum: - - ResponseHeaderModifier - - RequestHeaderModifier - - RequestMirror - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - matches: - default: - - method: - type: Exact - description: "Matches define conditions used for matching the rule against incoming gRPC requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - method: service: foo.bar headers: values: version: 2 - method: service: foo.bar.v2 ``` \n For a request to match against this rule, it MUST satisfy EITHER of the two conditions: \n - service of foo.bar AND contains the header `version: 2` - service of foo.bar.v2 \n See the documentation for GRPCRouteMatch on how to specify multiple match conditions to be ANDed together. \n If no matches are specified, the implementation MUST match every gRPC request. \n Proxy or Load Balancer routing configuration generated from GRPCRoutes MUST prioritize rules based on the following criteria, continuing on ties. Merging MUST not be done between GRPCRoutes and HTTPRoutes. Precedence MUST be given to the rule with the largest number of: \n * Characters in a matching non-wildcard hostname. * Characters in a matching hostname. * Characters in a matching service. * Characters in a matching method. * Header matches. \n If ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n If ties still exist within the Route that has been given precedence, matching precedence MUST be granted to the first matching rule meeting the above criteria." - items: - description: "GRPCRouteMatch defines the predicate used to match requests to a given action. Multiple match types are ANDed together, i.e. the match will evaluate to true only if all conditions are satisfied. \n For example, the match below will match a gRPC request only if its service is `foo` AND it contains the `version: v1` header: \n ``` matches: - method: type: Exact service: \"foo\" headers: - name: \"version\" value \"v1\" \n ```" - properties: - headers: - description: Headers specifies gRPC request header matchers. Multiple match values are ANDed together, meaning, a request MUST match all the specified headers to select the route. - items: - description: GRPCHeaderMatch describes how to select a gRPC route by matching gRPC request headers. - properties: - name: - description: "Name is the name of the gRPC Header to be matched. \n If multiple entries specify equivalent header names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: Type specifies how to match against the value of the header. - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of the gRPC Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - method: - default: - type: Exact - description: Method specifies a gRPC request service/method matcher. If this field is not specified, all services and methods will match. - properties: - method: - description: "Value of the method to match against. If left empty or omitted, will match all services. \n At least one of Service and Method MUST be a non-empty string. \n A GRPC Method must be a valid Protobuf Method (https://protobuf.com/docs/language-spec#methods)." - maxLength: 1024 - pattern: ^[A-Za-z_][A-Za-z_0-9]*$ - type: string - service: - description: "Value of the service to match against. If left empty or omitted, will match any service. \n At least one of Service and Method MUST be a non-empty string. \n A GRPC Service must be a valid Protobuf Type Name (https://protobuf.com/docs/language-spec#type-references)." - maxLength: 1024 - pattern: ^(?i)\.?[a-z_][a-z_0-9]*(\.[a-z_][a-z_0-9]*)*$ - type: string - type: - default: Exact - description: "Type specifies how to match against the service and/or method. Support: Core (Exact with service and method specified) \n Support: Implementation-specific (Exact with method specified but no service specified) \n Support: Implementation-specific (RegularExpression)" - enum: - - Exact - - RegularExpression - type: string - type: object - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - type: object - status: - description: Status defines the current state of GRPCRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/external/httproutes.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/httproutes.gateway.networking.k8s.io.yaml deleted file mode 100644 index b455d788de..0000000000 --- a/control-plane/config/crd/external/httproutes.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,1909 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: httproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: HTTPRoute - listKind: HTTPRouteList - plural: httproutes - singular: httproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - deprecated: true - deprecationWarning: The v1alpha2 version of HTTPRoute has been deprecated and will be removed in a future release of the API. Please upgrade to v1beta1. - name: v1alpha2 - schema: - openAPIV3Schema: - description: HTTPRoute provides a way to route HTTP requests. This includes the capability to match requests by hostname, path, header, or query param. Filters can be used to specify additional processing steps. Backends specify where matching requests should be routed. - 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 HTTPRoute. - properties: - hostnames: - description: "Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n If a hostname is specified by both the Listener and HTTPRoute, there must be at least one intersecting hostname for the HTTPRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `*.example.com`, `test.example.com`, and `foo.test.example.com` would all match. On the other hand, `example.com` and `test.example.net` would not match. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n If both the Listener and HTTPRoute have specified hostnames, any HTTPRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the HTTPRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match. \n If both the Listener and HTTPRoute have specified hostnames, and none match with the criteria above, then the HTTPRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. overlapping wildcard matching and exact matching hostnames), precedence must be given to rules from the HTTPRoute with the largest number of: \n * Characters in a matching non-wildcard hostname. * Characters in a matching hostname. \n If ties exist across multiple Routes, the matching precedence rules for HTTPRouteMatches takes over. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - default: - - matches: - - path: - type: PathPrefix - value: / - description: Rules are a list of HTTP matchers, filters and actions. - items: - description: HTTPRouteRule defines semantics for matching an HTTP request based on conditions (matches), processing it (filters), and forwarding the request to an API object (backendRefs). - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. \n Failure behavior here depends on how many BackendRefs are specified and how many are invalid. \n If *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive a 500 status code. \n See the HTTPBackendRef definition for the rules about what makes a single HTTPBackendRef invalid. \n When a HTTPBackendRef is invalid, 500 status codes MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive a 500 status code. \n For example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic must receive a 500. Implementations may choose how that 50 percent is determined. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Core" - items: - description: HTTPBackendRef defines how a HTTPRoute should forward an HTTP request. - properties: - filters: - description: "Filters defined at this level should be executed if and only if the request is being forwarded to the backend defined here. \n Support: Implementation-specific (For broader support of filters, use the Filters field in HTTPRouteRule.)" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - type: array - filters: - description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: \n - ALL core filters MUST be supported by all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or implementation-specific conformance. \n All filters are expected to be compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In all cases where incompatible or unsupported filters are specified, implementations MUST add a warning condition to status. \n Support: Core" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - default: - - path: - type: PathPrefix - value: / - description: "Matches define conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - path: value: \"/foo\" headers: - name: \"version\" value: \"v2\" - path: value: \"/v2/foo\" ``` \n For a request to match against this rule, a request must satisfy EITHER of the two conditions: \n - path prefixed with `/foo` AND contains the header `version: v2` - path prefix of `/v2/foo` \n See the documentation for HTTPRouteMatch on how to specify multiple match conditions that should be ANDed together. \n If no matches are specified, the default is a prefix path match on \"/\", which has the effect of matching every HTTP request. \n Proxy or Load Balancer routing configuration generated from HTTPRoutes MUST prioritize matches based on the following criteria, continuing on ties. Across all rules specified on applicable Routes, precedence must be given to the match with the largest number of: \n * Characters in a matching path. * Header matches. * Query param matches. \n If ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n If ties still exist within an HTTPRoute, matching precedence MUST be granted to the FIRST matching rule (in list order) with a match meeting the above criteria. \n When no rules matching a request have been successfully attached to the parent a request is coming from, a HTTP 404 status code MUST be returned." - items: - description: "HTTPRouteMatch defines the predicate used to match requests to a given action. Multiple match types are ANDed together, i.e. the match will evaluate to true only if all conditions are satisfied. \n For example, the match below will match a HTTP request only if its path starts with `/foo` AND it contains the `version: v1` header: \n ``` match: \n \tpath: \t value: \"/foo\" \theaders: \t- name: \"version\" \t value \"v1\" \n ```" - properties: - headers: - description: Headers specifies HTTP request header matchers. Multiple match values are ANDed together, meaning, a request must match all the specified headers to select the route. - items: - description: HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request headers. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent. \n When a header is repeated in an HTTP request, it is implementation-specific behavior as to how this is represented. Generally, proxies should follow the guidance from the RFC: https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding processing a repeated header, with special handling for \"Set-Cookie\"." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the header. \n Support: Core (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression HeaderMatchType has implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - method: - description: "Method specifies HTTP method matcher. When specified, this route will be matched only if the request has the specified method. \n Support: Extended" - enum: - - GET - - HEAD - - POST - - PUT - - DELETE - - CONNECT - - OPTIONS - - TRACE - - PATCH - type: string - path: - default: - type: PathPrefix - value: / - description: Path specifies a HTTP request path matcher. If this field is not specified, a default prefix match on the "/" path is provided. - properties: - type: - default: PathPrefix - description: "Type specifies how to match against the path Value. \n Support: Core (Exact, PathPrefix) \n Support: Implementation-specific (RegularExpression)" - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, meaning, a request must match all the specified query parameters to select the route. \n Support: Extended" - items: - description: HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP query parameters. - properties: - name: - description: "Name is the name of the HTTP query param to be matched. This must be an exact string match. (See https://tools.ietf.org/html/rfc7230#section-2.7.3). \n If multiple entries specify equivalent query param names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent query param name MUST be ignored. \n If a query param is repeated in an HTTP request, the behavior is purposely left undefined, since different data planes have different capabilities. However, it is *recommended* that implementations should match against the first value of the param if the data plane supports it, as this behavior is expected in other load balancing contexts outside of the Gateway API. \n Users SHOULD NOT route traffic based on repeated query params to guard themselves against potential differences in the implementations." - maxLength: 256 - minLength: 1 - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the query parameter. \n Support: Extended (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression QueryParamMatchType has Implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - type: object - status: - description: Status defines the current state of HTTPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: false - subresources: - status: {} - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1beta1 - schema: - openAPIV3Schema: - description: HTTPRoute provides a way to route HTTP requests. This includes the capability to match requests by hostname, path, header, or query param. Filters can be used to specify additional processing steps. Backends specify where matching requests should be routed. - 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 HTTPRoute. - properties: - hostnames: - description: "Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n If a hostname is specified by both the Listener and HTTPRoute, there must be at least one intersecting hostname for the HTTPRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches HTTPRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `*.example.com`, `test.example.com`, and `foo.test.example.com` would all match. On the other hand, `example.com` and `test.example.net` would not match. \n Hostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`. \n If both the Listener and HTTPRoute have specified hostnames, any HTTPRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the HTTPRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match. \n If both the Listener and HTTPRoute have specified hostnames, and none match with the criteria above, then the HTTPRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. overlapping wildcard matching and exact matching hostnames), precedence must be given to rules from the HTTPRoute with the largest number of: \n * Characters in a matching non-wildcard hostname. * Characters in a matching hostname. \n If ties exist across multiple Routes, the matching precedence rules for HTTPRouteMatches takes over. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - default: - - matches: - - path: - type: PathPrefix - value: / - description: Rules are a list of HTTP matchers, filters and actions. - items: - description: HTTPRouteRule defines semantics for matching an HTTP request based on conditions (matches), processing it (filters), and forwarding the request to an API object (backendRefs). - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. \n Failure behavior here depends on how many BackendRefs are specified and how many are invalid. \n If *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive a 500 status code. \n See the HTTPBackendRef definition for the rules about what makes a single HTTPBackendRef invalid. \n When a HTTPBackendRef is invalid, 500 status codes MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive a 500 status code. \n For example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic must receive a 500. Implementations may choose how that 50 percent is determined. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Core" - items: - description: HTTPBackendRef defines how a HTTPRoute should forward an HTTP request. - properties: - filters: - description: "Filters defined at this level should be executed if and only if the request is being forwarded to the backend defined here. \n Support: Implementation-specific (For broader support of filters, use the Filters field in HTTPRouteRule.)" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - type: array - filters: - description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: \n - ALL core filters MUST be supported by all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or implementation-specific conformance. \n All filters are expected to be compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation can not support other combinations of filters, they must clearly document that limitation. In all cases where incompatible or unsupported filters are specified, implementations MUST add a warning condition to status. \n Support: Core" - items: - description: HTTPRouteFilter defines processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for a filter that modifies request headers. \n Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where mirrored requests are sent. \n If the referent cannot be found, this BackendRef is invalid and must be dropped from the Gateway. The controller must ensure the \"ResolvedRefs\" condition on the Route status is set to `status: False` and not configure this backend in the underlying implementation. \n If there is a cross-namespace reference to an *existing* object that is not allowed by a ReferenceGrant, the controller must ensure the \"ResolvedRefs\" condition on the Route is set to `status: False`, with the \"RefNotPermitted\" reason and not configure this backend in the underlying implementation. \n In either error case, the Message of the `ResolvedRefs` Condition should be used to provide more detail about the problem. \n Support: Extended for Kubernetes Service \n Support: Implementation-specific for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter that responds to the request with an HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used in the value of the `Location` header in the response. When empty, the hostname of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines parameters used to modify the path of the incoming request. The modified path is then used to construct the `Location` header. When empty, the request path is used as-is. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - port: - description: "Port is the port to be used in the value of the `Location` header in the response. When empty, port (if specified) of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the value of the `Location` header in the response. When empty, the scheme of the request is used. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to be used in response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - responseHeaderModifier: - description: "ResponseHeaderModifier defines a schema for a filter that modifies response headers. \n Support: Extended \n " - properties: - add: - description: "Add adds the given header(s) (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: - name: \"my-header\" value: \"bar,baz\" \n Output: GET /foo HTTP/1.1 my-header: foo,bar,baz" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the HTTP request before the action. The value of Remove is a list of HTTP header names. Note that the header names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: - name: \"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - type: - description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Implementation-specific: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior. \n If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - RequestHeaderModifier - - ResponseHeaderModifier - - RequestMirror - - RequestRedirect - - URLRewrite - - ExtensionRef - type: string - urlRewrite: - description: "URLRewrite defines a schema for a filter that modifies a request during forwarding. \n Support: Extended \n " - properties: - hostname: - description: "Hostname is the value to be used to replace the Host header value during forwarding. \n Support: Extended \n " - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - path: - description: "Path defines a path rewrite. \n Support: Extended \n " - properties: - replaceFullPath: - description: "ReplaceFullPath specifies the value with which to replace the full path of a request during a rewrite or redirect. \n " - maxLength: 1024 - type: string - replacePrefixMatch: - description: "ReplacePrefixMatch specifies the value with which to replace the prefix match of a request during a rewrite or redirect. For example, a request to \"/foo/bar\" with a prefix match of \"/foo\" would be modified to \"/bar\". \n Note that this matches the behavior of the PathPrefix match type. This matches full path elements. A path element refers to the list of labels in the path split by the `/` separator. When specified, a trailing `/` is ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all match the prefix `/abc`, but the path `/abcd` would not. \n " - maxLength: 1024 - type: string - type: - description: "Type defines the type of path modifier. Additional types may be added in a future release of the API. \n Note that values may be added to this enum, implementations must ensure that unknown values will not cause a crash. \n Unknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`. \n " - enum: - - ReplaceFullPath - - ReplacePrefixMatch - type: string - required: - - type - type: object - type: object - required: - - type - type: object - maxItems: 16 - type: array - matches: - default: - - path: - type: PathPrefix - value: / - description: "Matches define conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - path: value: \"/foo\" headers: - name: \"version\" value: \"v2\" - path: value: \"/v2/foo\" ``` \n For a request to match against this rule, a request must satisfy EITHER of the two conditions: \n - path prefixed with `/foo` AND contains the header `version: v2` - path prefix of `/v2/foo` \n See the documentation for HTTPRouteMatch on how to specify multiple match conditions that should be ANDed together. \n If no matches are specified, the default is a prefix path match on \"/\", which has the effect of matching every HTTP request. \n Proxy or Load Balancer routing configuration generated from HTTPRoutes MUST prioritize matches based on the following criteria, continuing on ties. Across all rules specified on applicable Routes, precedence must be given to the match with the largest number of: \n * Characters in a matching path. * Header matches. * Query param matches. \n If ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties: \n * The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by \"{namespace}/{name}\". \n If ties still exist within an HTTPRoute, matching precedence MUST be granted to the FIRST matching rule (in list order) with a match meeting the above criteria. \n When no rules matching a request have been successfully attached to the parent a request is coming from, a HTTP 404 status code MUST be returned." - items: - description: "HTTPRouteMatch defines the predicate used to match requests to a given action. Multiple match types are ANDed together, i.e. the match will evaluate to true only if all conditions are satisfied. \n For example, the match below will match a HTTP request only if its path starts with `/foo` AND it contains the `version: v1` header: \n ``` match: \n \tpath: \t value: \"/foo\" \theaders: \t- name: \"version\" \t value \"v1\" \n ```" - properties: - headers: - description: Headers specifies HTTP request header matchers. Multiple match values are ANDed together, meaning, a request must match all the specified headers to select the route. - items: - description: HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request headers. - properties: - name: - description: "Name is the name of the HTTP Header to be matched. Name matching MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). \n If multiple entries specify equivalent header names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent header name MUST be ignored. Due to the case-insensitivity of header names, \"foo\" and \"Foo\" are considered equivalent. \n When a header is repeated in an HTTP request, it is implementation-specific behavior as to how this is represented. Generally, proxies should follow the guidance from the RFC: https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding processing a repeated header, with special handling for \"Set-Cookie\"." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the header. \n Support: Core (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression HeaderMatchType has implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - method: - description: "Method specifies HTTP method matcher. When specified, this route will be matched only if the request has the specified method. \n Support: Extended" - enum: - - GET - - HEAD - - POST - - PUT - - DELETE - - CONNECT - - OPTIONS - - TRACE - - PATCH - type: string - path: - default: - type: PathPrefix - value: / - description: Path specifies a HTTP request path matcher. If this field is not specified, a default prefix match on the "/" path is provided. - properties: - type: - default: PathPrefix - description: "Type specifies how to match against the path Value. \n Support: Core (Exact, PathPrefix) \n Support: Implementation-specific (RegularExpression)" - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: "QueryParams specifies HTTP query parameter matchers. Multiple match values are ANDed together, meaning, a request must match all the specified query parameters to select the route. \n Support: Extended" - items: - description: HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP query parameters. - properties: - name: - description: "Name is the name of the HTTP query param to be matched. This must be an exact string match. (See https://tools.ietf.org/html/rfc7230#section-2.7.3). \n If multiple entries specify equivalent query param names, only the first entry with an equivalent name MUST be considered for a match. Subsequent entries with an equivalent query param name MUST be ignored. \n If a query param is repeated in an HTTP request, the behavior is purposely left undefined, since different data planes have different capabilities. However, it is *recommended* that implementations should match against the first value of the param if the data plane supports it, as this behavior is expected in other load balancing contexts outside of the Gateway API. \n Users SHOULD NOT route traffic based on repeated query params to guard themselves against potential differences in the implementations." - maxLength: 256 - minLength: 1 - type: string - type: - default: Exact - description: "Type specifies how to match against the value of the query parameter. \n Support: Extended (Exact) \n Support: Implementation-specific (RegularExpression) \n Since RegularExpression QueryParamMatchType has Implementation-specific conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - type: object - status: - description: Status defines the current state of HTTPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/external/kustomization.yaml b/control-plane/config/crd/external/kustomization.yaml deleted file mode 100644 index a1a0e349ff..0000000000 --- a/control-plane/config/crd/external/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -# This file is Helm ignored. It is only used for the `make generate-external-crds` command. - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: - - github.com/kubernetes-sigs/gateway-api/config/crd/experimental?ref=v0.6.2 diff --git a/control-plane/config/crd/external/referencegrants.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/referencegrants.gateway.networking.k8s.io.yaml deleted file mode 100644 index cd39b9c12a..0000000000 --- a/control-plane/config/crd/external/referencegrants.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: referencegrants.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: ReferenceGrant - listKind: ReferenceGrantList - plural: referencegrants - shortNames: - - refgrant - singular: referencegrant - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "ReferenceGrant identifies kinds of resources in other namespaces that are trusted to reference the specified kinds of resources in the same namespace as the policy. \n Each ReferenceGrant can be used to represent a unique trust relationship. Additional Reference Grants can be used to add to the set of trusted sources of inbound references for the namespace they are defined within. \n All cross-namespace references in Gateway API (with the exception of cross-namespace Gateway-route attachment) require a ReferenceGrant. \n ReferenceGrant is a form of runtime verification allowing users to assert which cross-namespace object references are permitted. Implementations that support ReferenceGrant MUST NOT permit cross-namespace references which have no grant, and MUST respond to the removal of a grant by revoking the access that the grant allowed. \n Support: Core" - 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 ReferenceGrant. - properties: - from: - description: "From describes the trusted namespaces and kinds that can reference the resources described in \"To\". Each entry in this list MUST be considered to be an additional place that references can be valid from, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantFrom describes trusted namespaces and kinds. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field. \n When used to permit a SecretObjectReference: \n * Gateway \n When used to permit a BackendObjectReference: \n * GRPCRoute * HTTPRoute * TCPRoute * TLSRoute * UDPRoute" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - namespace: - description: "Namespace is the namespace of the referent. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - namespace - type: object - maxItems: 16 - minItems: 1 - type: array - to: - description: "To describes the resources that may be referenced by the resources described in \"From\". Each entry in this list MUST be considered to be an additional place that references can be valid to, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantTo describes what Kinds are allowed as targets of the references. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field: \n * Secret when used to permit a SecretObjectReference * Service when used to permit a BackendObjectReference" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. When unspecified, this policy refers to all resources of the specified Group and Kind in the local namespace. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - from - - to - type: object - type: object - served: true - storage: true - subresources: {} - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1beta1 - schema: - openAPIV3Schema: - description: "ReferenceGrant identifies kinds of resources in other namespaces that are trusted to reference the specified kinds of resources in the same namespace as the policy. \n Each ReferenceGrant can be used to represent a unique trust relationship. Additional Reference Grants can be used to add to the set of trusted sources of inbound references for the namespace they are defined within. \n All cross-namespace references in Gateway API (with the exception of cross-namespace Gateway-route attachment) require a ReferenceGrant. \n ReferenceGrant is a form of runtime verification allowing users to assert which cross-namespace object references are permitted. Implementations that support ReferenceGrant MUST NOT permit cross-namespace references which have no grant, and MUST respond to the removal of a grant by revoking the access that the grant allowed. \n Support: Core" - 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 ReferenceGrant. - properties: - from: - description: "From describes the trusted namespaces and kinds that can reference the resources described in \"To\". Each entry in this list MUST be considered to be an additional place that references can be valid from, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantFrom describes trusted namespaces and kinds. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field. \n When used to permit a SecretObjectReference: \n * Gateway \n When used to permit a BackendObjectReference: \n * GRPCRoute * HTTPRoute * TCPRoute * TLSRoute * UDPRoute" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - namespace: - description: "Namespace is the namespace of the referent. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - namespace - type: object - maxItems: 16 - minItems: 1 - type: array - to: - description: "To describes the resources that may be referenced by the resources described in \"From\". Each entry in this list MUST be considered to be an additional place that references can be valid to, or to put this another way, entries MUST be combined using OR. \n Support: Core" - items: - description: ReferenceGrantTo describes what Kinds are allowed as targets of the references. - properties: - group: - description: "Group is the group of the referent. When empty, the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations may support additional resources, the following types are part of the \"Core\" support level for this field: \n * Secret when used to permit a SecretObjectReference * Service when used to permit a BackendObjectReference" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. When unspecified, this policy refers to all resources of the specified Group and Kind in the local namespace. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - from - - to - type: object - type: object - served: true - storage: false - subresources: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/external/tcproutes.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/tcproutes.gateway.networking.k8s.io.yaml deleted file mode 100644 index 906b442d31..0000000000 --- a/control-plane/config/crd/external/tcproutes.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,276 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: tcproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: TCPRoute - listKind: TCPRouteList - plural: tcproutes - singular: tcproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: TCPRoute provides a way to route TCP requests. When combined with a Gateway listener, it can be used to forward connections on the port specified by the listener to a set of backends specified by the TCPRoute. - 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 TCPRoute. - properties: - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of TCP matchers and actions. - items: - description: TCPRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a non-existent resource or a Service with no endpoints), the underlying implementation MUST actively reject connection attempts to this backend. Connection rejections must respect weight; if an invalid backend is requested to have 80% of connections, then 80% of connections must be rejected instead. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward a request to a Kubernetes resource. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TCPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/external/tlsroutes.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/tlsroutes.gateway.networking.k8s.io.yaml deleted file mode 100644 index 2e22b04ef0..0000000000 --- a/control-plane/config/crd/external/tlsroutes.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,286 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: tlsroutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: TLSRoute - listKind: TLSRouteList - plural: tlsroutes - singular: tlsroute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "The TLSRoute resource is similar to TCPRoute, but can be configured to match against TLS-specific metadata. This allows more flexibility in matching streams for a given TLS listener. \n If you need to forward traffic to a single target for a TLS listener, you could choose to use a TCPRoute with a TLS listener." - 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 TLSRoute. - properties: - hostnames: - description: "Hostnames defines a set of SNI names that should match against the SNI attribute of TLS ClientHello message in TLS handshake. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed in SNI names per RFC 6066. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n If a hostname is specified by both the Listener and TLSRoute, there must be at least one intersecting hostname for the TLSRoute to be attached to the Listener. For example: \n * A Listener with `test.example.com` as the hostname matches TLSRoutes that have either not specified any hostnames, or have specified at least one of `test.example.com` or `*.example.com`. * A Listener with `*.example.com` as the hostname matches TLSRoutes that have either not specified any hostnames or have specified at least one hostname that matches the Listener hostname. For example, `test.example.com` and `*.example.com` would both match. On the other hand, `example.com` and `test.example.net` would not match. \n If both the Listener and TLSRoute have specified hostnames, any TLSRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the TLSRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match. \n If both the Listener and TLSRoute have specified hostnames, and none match with the criteria above, then the TLSRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network host. This matches the RFC 1123 definition of a hostname with 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard label must appear by itself as the first label. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). \n Note that as per RFC1035 and RFC1123, a *label* must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of TLS matchers and actions. - items: - description: TLSRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a non-existent resource or a Service with no endpoints), the rule performs no forwarding; if no filters are specified that would result in a response being sent, the underlying implementation must actively reject request attempts to this backend, by rejecting the connection or returning a 500 status code. Request rejections must respect weight; if an invalid backend is requested to have 80% of requests, then 80% of requests must be rejected instead. \n Support: Core for Kubernetes Service \n Support: Implementation-specific for any other resource \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward a request to a Kubernetes resource. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TLSRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/external/udproutes.gateway.networking.k8s.io.yaml b/control-plane/config/crd/external/udproutes.gateway.networking.k8s.io.yaml deleted file mode 100644 index 19b03dcd0b..0000000000 --- a/control-plane/config/crd/external/udproutes.gateway.networking.k8s.io.yaml +++ /dev/null @@ -1,276 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/1538 - gateway.networking.k8s.io/bundle-version: v0.6.2 - gateway.networking.k8s.io/channel: experimental - creationTimestamp: null - name: udproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: UDPRoute - listKind: UDPRouteList - plural: udproutes - singular: udproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: UDPRoute provides a way to route UDP traffic. When combined with a Gateway listener, it can be used to forward traffic on the port specified by the listener to a set of backends specified by the UDPRoute. - 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 UDPRoute. - properties: - parentRefs: - description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. \n The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources such as one of the route kinds. \n It is invalid to reference an identical parent more than once. It is valid to reference multiple distinct sections within the same parent resource, such as 2 Listeners within a Gateway. \n It is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged. \n Note that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference." - items: - description: "ParentReference identifies an API object (usually a Gateway) that can be considered a parent of this resource (usually a route). The only kind of parent resource with \"Core\" support is Gateway. This API may be extended in the future to support additional kinds of parent resources, such as HTTPRoute. \n The API object must be valid in the cluster; the Group and Kind must be registered in the cluster for this reference to be valid." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of UDP matchers and actions. - items: - description: UDPRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a non-existent resource or a Service with no endpoints), the underlying implementation MUST actively reject connection attempts to this backend. Packet drops must respect weight; if an invalid backend is requested to have 80% of the packets, then 80% of packets must be dropped instead. \n Support: Core for Kubernetes Service Support: Implementation-specific for any other resource \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward a request to a Kubernetes resource. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, "gateway.networking.k8s.io". When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example "HTTPRoute" or "Service". Defaults to "Service" when not specified. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. When unspecified, the local namespace is inferred. \n Note that when a namespace is specified, a ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number to use for this resource. Port is required when the referent is a Kubernetes Service. In this case, the port number is the service port number, not the target port. For other resources, destination port might be derived from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests forwarded to the referenced backend. This is computed as weight/(sum of all weights in this BackendRefs list). For non-zero values, there may be some epsilon from the exact proportion defined here depending on the precision an implementation supports. Weight is not a percentage and the sum of weights does not need to equal 100. \n If only one backend is specified and it has a weight greater than 0, 100% of the traffic is forwarded to that backend. If weight is set to 0, no traffic should be forwarded for this entry. If unspecified, weight defaults to 1. \n Support for this field varies based on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of UDPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified. \n Note that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for. \n A maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway." - items: - description: RouteParentStatus describes the status of a route with respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status. \n If the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why. \n A Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway. \n There are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when: \n * The Route refers to a non-existent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to." - items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates the name of the controller that wrote this status. This corresponds with the controllerName field on GatewayClass. \n Example: \"example.net/gateway-controller\". \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Controllers MUST populate this field when writing status. Controllers should ensure that entries to status populated with their ControllerName are cleaned up when they are no longer necessary." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. When unspecified, \"gateway.networking.k8s.io\" is inferred. To set the core API group (such as for a \"Service\" kind referent), Group must be explicitly set to \"\" (empty string). \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core (Gateway) \n Support: Implementation-specific (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When unspecified, this refers to the local namespace of the Route. \n Note that there are specific rules for ParentRefs which cross namespace boundaries. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example: Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable any other kind of cross-namespace reference. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: "Port is the network port this Route targets. It can be interpreted differently based on the type of parent resource. \n When the parent resource is a Gateway, this targets all listeners listening on the specified port that also support this kind of Route(and select this Route). It's not recommended to set `Port` unless the networking behaviors specified in a Route must apply to a specific port as opposed to a listener(s) whose port(s) may be changed. When both Port and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support other parent resources. Implementations supporting other types of parent resources MUST clearly document how/if Port is interpreted. \n For the purpose of status, an attachment is considered successful as long as the parent resource accepts it partially. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Extended \n " - format: int32 - maximum: 65535 - minimum: 1 - type: integer - sectionName: - description: "SectionName is the name of a section within the target resource. In the following resources, SectionName is interpreted as the following: \n * Gateway: Listener Name. When both Port (experimental) and SectionName are specified, the name and port of the selected listener must match both specified values. \n Implementations MAY choose to support attaching Routes to other resources. If that is the case, they MUST clearly document how SectionName is interpreted. \n When unspecified (empty string), this will reference the entire resource. For the purpose of status, an attachment is considered successful if at least one section in the parent resource accepts it. For example, Gateway listeners can restrict which Routes can attach to them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from the referencing Route, the Route MUST be considered successfully attached. If no Gateway listeners accept attachment from this Route, the Route MUST be considered detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/control-plane/config/crd/kustomization.yaml b/control-plane/config/crd/kustomization.yaml deleted file mode 100644 index cbb41bc60c..0000000000 --- a/control-plane/config/crd/kustomization.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -# This kustomization.yaml is not intended to be run by itself, -# since it depends on service name and namespace that are out of this kustomize package. -# It should be run by config/default -resources: -- bases/consul.hashicorp.com_controlplanerequestlimits.yaml -#+kubebuilder:scaffold:crdkustomizeresource - -patches: -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. -# patches here are for enabling the conversion webhook for each CRD -#- patches/webhook_in_controlplanerequestlimits.yaml -#+kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_controlplanerequestlimits.yaml -#+kubebuilder:scaffold:crdkustomizecainjectionpatch - -# the following config is for teaching kustomize how to do kustomization for CRDs. -configurations: -- kustomizeconfig.yaml diff --git a/control-plane/config/crd/kustomizeconfig.yaml b/control-plane/config/crd/kustomizeconfig.yaml deleted file mode 100644 index 5d1332c4bf..0000000000 --- a/control-plane/config/crd/kustomizeconfig.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -# This file is for teaching kustomize how to substitute name and namespace reference in CRD -nameReference: -- kind: Service - version: v1 - fieldSpecs: - - kind: CustomResourceDefinition - group: apiextensions.k8s.io - path: spec/conversion/webhookClientConfig/service/name - -namespace: -- kind: CustomResourceDefinition - group: apiextensions.k8s.io - path: spec/conversion/webhookClientConfig/service/namespace - create: false - -varReference: -- path: metadata/annotations diff --git a/control-plane/config/rbac/role.yaml b/control-plane/config/rbac/role.yaml index 7f90780e02..8daf050ec0 100644 --- a/control-plane/config/rbac/role.yaml +++ b/control-plane/config/rbac/role.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -26,26 +23,6 @@ rules: - secrets/status verbs: - get -- apiGroups: - - consul.hashicorp.com - resources: - - controlplanerequestlimits - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - controlplanerequestlimits/status - verbs: - - get - - patch - - update - apiGroups: - consul.hashicorp.com resources: @@ -86,26 +63,6 @@ rules: - get - patch - update -- apiGroups: - - consul.hashicorp.com - resources: - - jwtproviders - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - jwtproviders/status - verbs: - - get - - patch - - update - apiGroups: - consul.hashicorp.com resources: @@ -186,26 +143,6 @@ rules: - get - patch - update -- apiGroups: - - consul.hashicorp.com - resources: - - samenessgroups - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - samenessgroups/status - verbs: - - get - - patch - - update - apiGroups: - consul.hashicorp.com resources: diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index 0861f9253a..c1ffb5e0fe 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration @@ -8,27 +5,6 @@ metadata: creationTimestamp: null name: mutating-webhook-configuration webhooks: -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /mutate-v1alpha1-controlplanerequestlimits - failurePolicy: Fail - name: mutate-controlplanerequestlimits.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - controlplanerequestlimits - sideEffects: None - admissionReviewVersions: - v1beta1 - v1 @@ -71,27 +47,6 @@ webhooks: resources: - ingressgateways sideEffects: None -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /mutate-v1alpha1-jwtprovider - failurePolicy: Fail - name: mutate-jwtprovider.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - jwtproviders - sideEffects: None - admissionReviewVersions: - v1beta1 - v1 @@ -176,27 +131,6 @@ webhooks: resources: - proxydefaults sideEffects: None -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /mutate-v1alpha1-samenessgroups - failurePolicy: Fail - name: mutate-samenessgroup.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - samenessgroups - sideEffects: None - admissionReviewVersions: - v1beta1 - v1 diff --git a/control-plane/connect-inject/common/common.go b/control-plane/connect-inject/common/common.go index a99d9fd12e..0ebf829666 100644 --- a/control-plane/connect-inject/common/common.go +++ b/control-plane/connect-inject/common/common.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/control-plane/connect-inject/common/common_test.go b/control-plane/connect-inject/common/common_test.go index 79a9294fe2..155f6b892d 100644 --- a/control-plane/connect-inject/common/common_test.go +++ b/control-plane/connect-inject/common/common_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/control-plane/connect-inject/constants/annotations_and_labels.go b/control-plane/connect-inject/constants/annotations_and_labels.go index 4efcc24c74..8767de33b3 100644 --- a/control-plane/connect-inject/constants/annotations_and_labels.go +++ b/control-plane/connect-inject/constants/annotations_and_labels.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package constants const ( diff --git a/control-plane/connect-inject/constants/constants.go b/control-plane/connect-inject/constants/constants.go index ca6fe23606..673a64eabc 100644 --- a/control-plane/connect-inject/constants/constants.go +++ b/control-plane/connect-inject/constants/constants.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package constants const ( @@ -16,15 +13,6 @@ const ( // MetaKeyKubeNS is the meta key name for Kubernetes namespace used for the Consul services. MetaKeyKubeNS = "k8s-namespace" - // MetaKeyKubeName is the meta key name for Kubernetes object name used for a Consul object. - MetaKeyKubeName = "k8s-name" - - // MetaKeyDatacenter is the datacenter that this object was registered from. - MetaKeyDatacenter = "datacenter" - - // MetaKeyKubeServiceName is the meta key name for Kubernetes service name used for the Consul services. - MetaKeyKubeServiceName = "k8s-service-name" - // MetaKeyPodName is the meta key name for Kubernetes pod name used for the Consul services. MetaKeyPodName = "pod-name" diff --git a/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks.go b/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks.go index c71ee9ba55..f54fb71d11 100644 --- a/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks.go +++ b/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package endpoints import ( diff --git a/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks_test.go b/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks_test.go index 36ad222d68..7f4978c133 100644 --- a/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks_test.go +++ b/control-plane/connect-inject/controllers/endpoints/consul_client_health_checks_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package endpoints import ( diff --git a/control-plane/connect-inject/controllers/endpoints/endpoints_controller.go b/control-plane/connect-inject/controllers/endpoints/endpoints_controller.go index 3f139c2662..b971406f68 100644 --- a/control-plane/connect-inject/controllers/endpoints/endpoints_controller.go +++ b/control-plane/connect-inject/controllers/endpoints/endpoints_controller.go @@ -1,5 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 package endpoints import ( @@ -44,10 +42,9 @@ const ( terminatingGateway = "terminating-gateway" ingressGateway = "ingress-gateway" - kubernetesSuccessReasonMsg = "Kubernetes health checks passing" - envoyPrometheusBindAddr = "envoy_prometheus_bind_addr" - envoyTelemetryCollectorBindSocketDir = "envoy_telemetry_collector_bind_socket_dir" - defaultNS = "default" + kubernetesSuccessReasonMsg = "Kubernetes health checks passing" + envoyPrometheusBindAddr = "envoy_prometheus_bind_addr" + defaultNS = "default" // clusterIPTaggedAddressName is the key for the tagged address to store the service's cluster IP and service port // in Consul. Note: This value should not be changed without a corresponding change in Consul. @@ -120,10 +117,6 @@ type Controller struct { // to Consul client agents. EnableAutoEncrypt bool - // EnableTelemetryCollector controls whether the proxy service should be registered - // with config to enable telemetry forwarding. - EnableTelemetryCollector bool - MetricsConfig metrics.Config Log logr.Logger @@ -298,14 +291,6 @@ func (r *Controller) registerServicesAndHealthCheck(apiClient *api.Client, pod c return err } - // Add manual ip to the VIP table - r.Log.Info("adding manual ip to virtual ip table in Consul", "name", serviceRegistration.Service.Service, - "id", serviceRegistration.ID) - err = assignServiceVirtualIP(r.Context, apiClient, serviceRegistration.Service) - if err != nil { - r.Log.Error(err, "failed to add ip to virtual ip table", "name", serviceRegistration.Service.Service) - } - // Register the proxy service instance with Consul. r.Log.Info("registering proxy service with Consul", "name", proxyServiceRegistration.Service.Service) _, err = apiClient.Catalog().Register(proxyServiceRegistration, nil) @@ -317,20 +302,6 @@ func (r *Controller) registerServicesAndHealthCheck(apiClient *api.Client, pod c return nil } -func parseLocality(node corev1.Node) *api.Locality { - region := node.Labels[corev1.LabelTopologyRegion] - zone := node.Labels[corev1.LabelTopologyZone] - - if region == "" { - return nil - } - - return &api.Locality{ - Region: region, - Zone: zone, - } -} - // registerGateway creates Consul registrations for the Connect Gateways and registers them with Consul. // It also upserts a Kubernetes health check for the service based on whether the endpoint address is ready. func (r *Controller) registerGateway(apiClient *api.Client, pod corev1.Pod, serviceEndpoints corev1.Endpoints, healthStatus string, endpointAddressMap map[string]bool) error { @@ -418,11 +389,6 @@ func (r *Controller) createServiceRegistrations(pod corev1.Pod, serviceEndpoints } } - var node corev1.Node - // Ignore errors because we don't want failures to block running services. - _ = r.Client.Get(context.Background(), types.NamespacedName{Name: pod.Spec.NodeName, Namespace: pod.Namespace}, &node) - locality := parseLocality(node) - // We only want that annotation to be present when explicitly overriding the consul svc name // Otherwise, the Consul service name should equal the Kubernetes Service name. // The service name in Consul defaults to the Endpoints object name, and is overridden by the pod @@ -458,7 +424,6 @@ func (r *Controller) createServiceRegistrations(pod corev1.Pod, serviceEndpoints Meta: meta, Namespace: consulNS, Tags: tags, - Locality: locality, } serviceRegistration := &api.CatalogRegistration{ Node: common.ConsulNodeNameFromK8sNode(pod.Spec.NodeName), @@ -506,10 +471,6 @@ func (r *Controller) createServiceRegistrations(pod corev1.Pod, serviceEndpoints proxyConfig.Config[envoyPrometheusBindAddr] = prometheusScrapeListener } - if r.EnableTelemetryCollector && proxyConfig.Config != nil { - proxyConfig.Config[envoyTelemetryCollectorBindSocketDir] = "/consul/connect-inject" - } - if consulServicePort > 0 { proxyConfig.LocalServiceAddress = "127.0.0.1" proxyConfig.LocalServicePort = consulServicePort @@ -535,8 +496,6 @@ func (r *Controller) createServiceRegistrations(pod corev1.Pod, serviceEndpoints Namespace: consulNS, Proxy: proxyConfig, Tags: tags, - // Sidecar locality (not proxied service locality) is used for locality-aware routing. - Locality: locality, } // A user can enable/disable tproxy for an entire namespace. @@ -692,9 +651,6 @@ func (r *Controller) createGatewayRegistrations(pod corev1.Pod, serviceEndpoints ID: pod.Name, Address: pod.Status.PodIP, Meta: meta, - Proxy: &api.AgentServiceConnectProxyConfig{ - Config: map[string]interface{}{}, - }, } gatewayServiceName, ok := pod.Annotations[constants.AnnotationGatewayConsulServiceName] @@ -794,10 +750,6 @@ func (r *Controller) createGatewayRegistrations(pod corev1.Pod, serviceEndpoints } } - if r.EnableTelemetryCollector && service.Proxy != nil && service.Proxy.Config != nil { - service.Proxy.Config[envoyTelemetryCollectorBindSocketDir] = "/consul/service" - } - serviceRegistration := &api.CatalogRegistration{ Node: common.ConsulNodeNameFromK8sNode(pod.Spec.NodeName), Address: pod.Status.HostIP, @@ -1319,26 +1271,6 @@ func (r *Controller) appendNodeMeta(registration *api.CatalogRegistration) { } } -// assignServiceVirtualIPs manually assigns the ClusterIP to the virtual IP table so that transparent proxy routing works. -func assignServiceVirtualIP(ctx context.Context, apiClient *api.Client, svc *api.AgentService) error { - ip := svc.TaggedAddresses[clusterIPTaggedAddressName].Address - if ip == "" { - return nil - } - - _, _, err := apiClient.Internal().AssignServiceVirtualIP(ctx, svc.Service, []string{ip}, &api.WriteOptions{Namespace: svc.Namespace, Partition: svc.Partition}) - if err != nil { - // Maintain backwards compatibility with older versions of Consul that do not support the VIP improvements. Tproxy - // will not work 100% correctly but the mesh will still work - if strings.Contains(err.Error(), "404") { - return fmt.Errorf("failed to add ip for service %s to virtual ip table. Please upgrade Consul to version 1.16 or higher", svc.Service) - } else { - return err - } - } - return nil -} - // hasBeenInjected checks the value of the status annotation and returns true if the Pod has been injected. func hasBeenInjected(pod corev1.Pod) bool { if anno, ok := pod.Annotations[constants.KeyInjectStatus]; ok && anno == constants.Injected { diff --git a/control-plane/connect-inject/controllers/endpoints/endpoints_controller_ent_test.go b/control-plane/connect-inject/controllers/endpoints/endpoints_controller_ent_test.go index e0c7f034b1..12fabdf13d 100644 --- a/control-plane/connect-inject/controllers/endpoints/endpoints_controller_ent_test.go +++ b/control-plane/connect-inject/controllers/endpoints/endpoints_controller_ent_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package endpoints @@ -11,7 +8,7 @@ import ( "testing" mapset "github.com/deckarep/golang-set" - logrtest "github.com/go-logr/logr/testing" + logrtest "github.com/go-logr/logr/testr" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" @@ -226,7 +223,7 @@ func TestReconcileCreateEndpointWithNamespaces(t *testing.T) { // Create the endpoints controller. ep := &Controller{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, AllowK8sNamespacesSet: mapset.NewSetWith("*"), @@ -487,7 +484,7 @@ func TestReconcileCreateGatewayWithNamespaces(t *testing.T) { // Create the endpoints controller. ep := &Controller{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, AllowK8sNamespacesSet: mapset.NewSetWith("*"), @@ -1494,7 +1491,7 @@ func TestReconcileUpdateEndpointWithNamespaces(t *testing.T) { // Create the endpoints controller. ep := &Controller{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, AllowK8sNamespacesSet: mapset.NewSetWith("*"), @@ -1564,7 +1561,7 @@ func TestReconcileUpdateEndpointWithNamespaces(t *testing.T) { // Read the token from Consul. token, _, err := consulClient.ACL().TokenRead(tokenID, nil) if deregisteredServices.Contains(serviceID) { - require.Contains(t, err.Error(), "ACL not found") + require.EqualError(t, err, "Unexpected response code: 403 (ACL not found)") } else { require.NoError(t, err, "token should exist for service instance: "+serviceID) require.NotNil(t, token) @@ -1780,7 +1777,7 @@ func TestReconcileDeleteEndpointWithNamespaces(t *testing.T) { // Create the endpoints controller. ep := &Controller{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, AllowK8sNamespacesSet: mapset.NewSetWith("*"), @@ -1822,7 +1819,7 @@ func TestReconcileDeleteEndpointWithNamespaces(t *testing.T) { if tt.enableACLs { _, _, err = consulClient.ACL().TokenRead(token.AccessorID, nil) - require.Contains(t, err.Error(), "ACL not found") + require.EqualError(t, err, "Unexpected response code: 403 (ACL not found)") } }) } @@ -2074,7 +2071,7 @@ func TestReconcileDeleteGatewayWithNamespaces(t *testing.T) { // Create the endpoints controller. ep := &Controller{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, AllowK8sNamespacesSet: mapset.NewSetWith("*"), @@ -2107,7 +2104,7 @@ func TestReconcileDeleteGatewayWithNamespaces(t *testing.T) { if tt.enableACLs { _, _, err = consulClient.ACL().TokenRead(token.AccessorID, nil) - require.Contains(t, err.Error(), "ACL not found") + require.EqualError(t, err, "Unexpected response code: 403 (ACL not found)") } }) } diff --git a/control-plane/connect-inject/controllers/endpoints/endpoints_controller_test.go b/control-plane/connect-inject/controllers/endpoints/endpoints_controller_test.go index 2cec69dd0a..e6694d6718 100644 --- a/control-plane/connect-inject/controllers/endpoints/endpoints_controller_test.go +++ b/control-plane/connect-inject/controllers/endpoints/endpoints_controller_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package endpoints import ( @@ -999,7 +996,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { expectedProxySvcInstances []*api.CatalogService expectedHealthChecks []*api.HealthCheck metricsEnabled bool - telemetryCollectorDisabled bool nodeMeta map[string]string expErr string }{ @@ -1082,7 +1078,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { DestinationServiceID: "pod1-service-created", LocalServiceAddress: "", LocalServicePort: 0, - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/connect-inject")}, }, ServiceMeta: map[string]string{constants.MetaKeyPodName: "pod1", metaKeyKubeServiceName: "service-created", constants.MetaKeyKubeNS: "default", metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true"}, ServiceTags: []string{}, @@ -1168,9 +1163,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { Port: 443, }, }, - ServiceProxy: &api.AgentServiceConnectProxyConfig{ - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/service")}, - }, + ServiceProxy: &api.AgentServiceConnectProxyConfig{}, NodeMeta: map[string]string{ "synthetic-node": "true", "test-node": "true", @@ -1223,80 +1216,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { } return []runtime.Object{gateway, endpoint} }, - expectedConsulSvcInstances: []*api.CatalogService{ - { - ServiceID: "mesh-gateway", - ServiceName: "mesh-gateway", - ServiceAddress: "1.2.3.4", - ServicePort: 8443, - ServiceMeta: map[string]string{constants.MetaKeyPodName: "mesh-gateway", metaKeyKubeServiceName: "mesh-gateway", constants.MetaKeyKubeNS: "default", metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true"}, - ServiceTags: []string{}, - ServiceTaggedAddresses: map[string]api.ServiceAddress{ - "lan": { - Address: "1.2.3.4", - Port: 8443, - }, - "wan": { - Address: "2.3.4.5", - Port: 443, - }, - }, - ServiceProxy: &api.AgentServiceConnectProxyConfig{ - Config: map[string]interface{}{ - "envoy_prometheus_bind_addr": "1.2.3.4:20200", - "envoy_telemetry_collector_bind_socket_dir": "/consul/service", - }, - }, - }, - }, - expectedHealthChecks: []*api.HealthCheck{ - { - CheckID: "default/mesh-gateway", - ServiceName: "mesh-gateway", - ServiceID: "mesh-gateway", - Name: consulKubernetesCheckName, - Status: api.HealthPassing, - Output: kubernetesSuccessReasonMsg, - Type: consulKubernetesCheckType, - }, - }, - metricsEnabled: true, - }, - { - name: "Mesh_Gateway_with_Metrics_enabled_and_telemetry_collector_disabled", - svcName: "mesh-gateway", - consulSvcName: "mesh-gateway", - telemetryCollectorDisabled: true, - k8sObjects: func() []runtime.Object { - gateway := createGatewayPod("mesh-gateway", "1.2.3.4", map[string]string{ - constants.AnnotationGatewayConsulServiceName: "mesh-gateway", - constants.AnnotationGatewayWANSource: "Static", - constants.AnnotationGatewayWANAddress: "2.3.4.5", - constants.AnnotationGatewayWANPort: "443", - constants.AnnotationMeshGatewayContainerPort: "8443", - constants.AnnotationGatewayKind: meshGateway}) - endpoint := &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "mesh-gateway", - Namespace: "default", - }, - Subsets: []corev1.EndpointSubset{ - { - Addresses: []corev1.EndpointAddress{ - { - IP: "1.2.3.4", - TargetRef: &corev1.ObjectReference{ - Kind: "Pod", - Name: "mesh-gateway", - Namespace: "default", - }, - }, - }, - }, - }, - } - return []runtime.Object{gateway, endpoint} - }, expectedConsulSvcInstances: []*api.CatalogService{ { ServiceID: "mesh-gateway", @@ -1379,10 +1298,8 @@ func TestReconcileCreateEndpoint(t *testing.T) { metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true", }, - ServiceTags: []string{}, - ServiceProxy: &api.AgentServiceConnectProxyConfig{ - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/service")}, - }, + ServiceTags: []string{}, + ServiceProxy: &api.AgentServiceConnectProxyConfig{}, }, }, expectedHealthChecks: []*api.HealthCheck{ @@ -1445,8 +1362,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { ServiceTags: []string{}, ServiceProxy: &api.AgentServiceConnectProxyConfig{ Config: map[string]interface{}{ - "envoy_prometheus_bind_addr": "1.2.3.4:20200", - "envoy_telemetry_collector_bind_socket_dir": "/consul/service", + "envoy_prometheus_bind_addr": "1.2.3.4:20200", }, }, }, @@ -1546,7 +1462,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { "address": "0.0.0.0", }, }, - "envoy_telemetry_collector_bind_socket_dir": "/consul/service", }, }, }, @@ -1647,8 +1562,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { "address": "0.0.0.0", }, }, - "envoy_prometheus_bind_addr": "1.2.3.4:20200", - "envoy_telemetry_collector_bind_socket_dir": "/consul/service", + "envoy_prometheus_bind_addr": "1.2.3.4:20200", }, }, }, @@ -1733,7 +1647,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { DestinationServiceID: "pod1-service-created", LocalServiceAddress: "", LocalServicePort: 0, - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/connect-inject")}, }, ServiceMeta: map[string]string{constants.MetaKeyPodName: "pod1", metaKeyKubeServiceName: "service-created", constants.MetaKeyKubeNS: "default", metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true"}, ServiceTags: []string{}, @@ -1748,7 +1661,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { DestinationServiceID: "pod2-service-created", LocalServiceAddress: "", LocalServicePort: 0, - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/connect-inject")}, }, ServiceMeta: map[string]string{constants.MetaKeyPodName: "pod2", metaKeyKubeServiceName: "service-created", constants.MetaKeyKubeNS: "default", metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true"}, ServiceTags: []string{}, @@ -1874,7 +1786,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { DestinationServiceID: "pod1-service-created", LocalServiceAddress: "", LocalServicePort: 0, - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/connect-inject")}, }, ServiceMeta: map[string]string{constants.MetaKeyPodName: "pod1", metaKeyKubeServiceName: "service-created", constants.MetaKeyKubeNS: "default", metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true"}, ServiceTags: []string{}, @@ -1889,7 +1800,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { DestinationServiceID: "pod2-service-created", LocalServiceAddress: "", LocalServicePort: 0, - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/connect-inject")}, }, ServiceMeta: map[string]string{constants.MetaKeyPodName: "pod2", metaKeyKubeServiceName: "service-created", constants.MetaKeyKubeNS: "default", metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true"}, ServiceTags: []string{}, @@ -1941,17 +1851,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { pod1.Annotations[constants.AnnotationUpstreams] = "upstream1:1234" pod1.Annotations[constants.AnnotationEnableMetrics] = "true" pod1.Annotations[constants.AnnotationPrometheusScrapePort] = "12345" - pod1.Spec.NodeName = "my-node" - node := &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node", - Namespace: "default", - Labels: map[string]string{ - corev1.LabelTopologyRegion: "us-west-1", - corev1.LabelTopologyZone: "us-west-1a", - }, - }, - } endpoint := &corev1.Endpoints{ ObjectMeta: metav1.ObjectMeta{ Name: "service-created", @@ -1972,7 +1871,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { }, }, } - return []runtime.Object{pod1, node, endpoint} + return []runtime.Object{pod1, endpoint} }, expectedConsulSvcInstances: []*api.CatalogService{ { @@ -1992,10 +1891,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { }, ServiceTags: []string{"abc,123", "pod1"}, ServiceProxy: &api.AgentServiceConnectProxyConfig{}, - ServiceLocality: &api.Locality{ - Region: "us-west-1", - Zone: "us-west-1a", - }, }, }, expectedProxySvcInstances: []*api.CatalogService{ @@ -2017,14 +1912,9 @@ func TestReconcileCreateEndpoint(t *testing.T) { }, }, Config: map[string]interface{}{ - "envoy_prometheus_bind_addr": "0.0.0.0:12345", - "envoy_telemetry_collector_bind_socket_dir": "/consul/connect-inject", + "envoy_prometheus_bind_addr": "0.0.0.0:12345", }, }, - ServiceLocality: &api.Locality{ - Region: "us-west-1", - Zone: "us-west-1a", - }, ServiceMeta: map[string]string{ "name": "abc", "version": "2", @@ -2123,7 +2013,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { DestinationServiceID: "pod1-service-created", LocalServiceAddress: "", LocalServicePort: 0, - Config: map[string]any{"envoy_telemetry_collector_bind_socket_dir": string("/consul/connect-inject")}, }, ServiceMeta: map[string]string{constants.MetaKeyPodName: "pod1", metaKeyKubeServiceName: "service-created", constants.MetaKeyKubeNS: "default", metaKeyManagedBy: constants.ManagedByValue, metaKeySyntheticNode: "true"}, ServiceTags: []string{}, @@ -2183,9 +2072,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { EnableGatewayMetrics: true, } } - - ep.EnableTelemetryCollector = !tt.telemetryCollectorDisabled - namespacedName := types.NamespacedName{ Namespace: "default", Name: tt.svcName, @@ -2212,7 +2098,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { require.Equal(t, tt.expectedConsulSvcInstances[i].ServicePort, instance.ServicePort) require.Equal(t, tt.expectedConsulSvcInstances[i].ServiceMeta, instance.ServiceMeta) require.Equal(t, tt.expectedConsulSvcInstances[i].ServiceTags, instance.ServiceTags) - require.Equal(t, tt.expectedConsulSvcInstances[i].ServiceLocality, instance.ServiceLocality) require.Equal(t, tt.expectedConsulSvcInstances[i].ServiceTaggedAddresses, instance.ServiceTaggedAddresses) require.Equal(t, tt.expectedConsulSvcInstances[i].ServiceProxy, instance.ServiceProxy) if tt.nodeMeta != nil { @@ -2229,7 +2114,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { require.Equal(t, tt.expectedProxySvcInstances[i].ServicePort, instance.ServicePort) require.Equal(t, tt.expectedProxySvcInstances[i].ServiceMeta, instance.ServiceMeta) require.Equal(t, tt.expectedProxySvcInstances[i].ServiceTags, instance.ServiceTags) - require.Equal(t, tt.expectedProxySvcInstances[i].ServiceLocality, instance.ServiceLocality) if tt.nodeMeta != nil { require.Equal(t, tt.expectedProxySvcInstances[i].NodeMeta, instance.NodeMeta) } @@ -2260,36 +2144,6 @@ func TestReconcileCreateEndpoint(t *testing.T) { } } -func TestParseLocality(t *testing.T) { - t.Run("no labels", func(t *testing.T) { - n := corev1.Node{} - require.Nil(t, parseLocality(n)) - }) - - t.Run("zone only", func(t *testing.T) { - n := corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - corev1.LabelTopologyZone: "us-west-1a", - }, - }, - } - require.Nil(t, parseLocality(n)) - }) - - t.Run("everything", func(t *testing.T) { - n := corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - corev1.LabelTopologyRegion: "us-west-1", - corev1.LabelTopologyZone: "us-west-1a", - }, - }, - } - require.Equal(t, &api.Locality{Region: "us-west-1", Zone: "us-west-1a"}, parseLocality(n)) - }) -} - // Tests updating an Endpoints object. // - Tests updates via the register codepath: // - When an address in an Endpoint is updated, that the corresponding service instance in Consul is updated. @@ -3690,7 +3544,7 @@ func TestReconcileUpdateEndpoint(t *testing.T) { // Read the token from Consul. token, _, err := consulClient.ACL().TokenRead(tokenID, nil) if deregisteredServices.Contains(sID) { - require.Contains(t, err.Error(), "ACL not found") + require.EqualError(t, err, "Unexpected response code: 403 (ACL not found)") } else { require.NoError(t, err, "token should exist for service instance: "+sID) require.NotNil(t, token) @@ -4291,7 +4145,7 @@ func TestReconcileDeleteEndpoint(t *testing.T) { if tt.enableACLs { _, _, err = consulClient.ACL().TokenRead(token.AccessorID, nil) - require.Contains(t, err.Error(), "ACL not found") + require.EqualError(t, err, "Unexpected response code: 403 (ACL not found)") } }) } @@ -6674,54 +6528,3 @@ func createGatewayPod(name, ip string, annotations map[string]string) *corev1.Po } return pod } - -func TestReconcileAssignServiceVirtualIP(t *testing.T) { - t.Parallel() - ctx := context.Background() - cases := []struct { - name string - service *api.AgentService - expectErr bool - }{ - { - name: "valid service", - service: &api.AgentService{ - ID: "", - Service: "foo", - Port: 80, - Address: "1.2.3.4", - TaggedAddresses: map[string]api.ServiceAddress{ - "virtual": { - Address: "1.2.3.4", - Port: 80, - }, - }, - Meta: map[string]string{constants.MetaKeyKubeNS: "default"}, - }, - expectErr: false, - }, - { - name: "service missing IP should not error", - service: &api.AgentService{ - ID: "", - Service: "bar", - Meta: map[string]string{constants.MetaKeyKubeNS: "default"}, - }, - expectErr: false, - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - - // Create test consulServer server. - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - apiClient := testClient.APIClient - err := assignServiceVirtualIP(ctx, apiClient, c.service) - if err != nil { - require.True(t, c.expectErr) - } else { - require.False(t, c.expectErr) - } - }) - } -} diff --git a/control-plane/connect-inject/controllers/peering/peering_acceptor_controller.go b/control-plane/connect-inject/controllers/peering/peering_acceptor_controller.go index 3a1251aae6..044de55998 100644 --- a/control-plane/connect-inject/controllers/peering/peering_acceptor_controller.go +++ b/control-plane/connect-inject/controllers/peering/peering_acceptor_controller.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package peering import ( diff --git a/control-plane/connect-inject/controllers/peering/peering_acceptor_controller_test.go b/control-plane/connect-inject/controllers/peering/peering_acceptor_controller_test.go index 601be1a833..30db612602 100644 --- a/control-plane/connect-inject/controllers/peering/peering_acceptor_controller_test.go +++ b/control-plane/connect-inject/controllers/peering/peering_acceptor_controller_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package peering import ( diff --git a/control-plane/connect-inject/controllers/peering/peering_dialer_controller.go b/control-plane/connect-inject/controllers/peering/peering_dialer_controller.go index 37de792cb6..98646b1654 100644 --- a/control-plane/connect-inject/controllers/peering/peering_dialer_controller.go +++ b/control-plane/connect-inject/controllers/peering/peering_dialer_controller.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package peering import ( diff --git a/control-plane/connect-inject/controllers/peering/peering_dialer_controller_test.go b/control-plane/connect-inject/controllers/peering/peering_dialer_controller_test.go index c142cd9eee..3bc959ab0a 100644 --- a/control-plane/connect-inject/controllers/peering/peering_dialer_controller_test.go +++ b/control-plane/connect-inject/controllers/peering/peering_dialer_controller_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package peering import ( diff --git a/control-plane/connect-inject/metrics/metrics_configuration.go b/control-plane/connect-inject/metrics/metrics_configuration.go index 6f9c29c85b..09f01a4c87 100644 --- a/control-plane/connect-inject/metrics/metrics_configuration.go +++ b/control-plane/connect-inject/metrics/metrics_configuration.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package metrics import ( diff --git a/control-plane/connect-inject/metrics/metrics_configuration_test.go b/control-plane/connect-inject/metrics/metrics_configuration_test.go index 12045e28d1..ea232576b5 100644 --- a/control-plane/connect-inject/metrics/metrics_configuration_test.go +++ b/control-plane/connect-inject/metrics/metrics_configuration_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package metrics import ( diff --git a/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go b/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go index ad2e07fffa..c1fae3eff9 100644 --- a/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go +++ b/control-plane/connect-inject/webhook/consul_dataplane_sidecar.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/consul_dataplane_sidecar_test.go b/control-plane/connect-inject/webhook/consul_dataplane_sidecar_test.go index f89703d5ad..e6ce27bab1 100644 --- a/control-plane/connect-inject/webhook/consul_dataplane_sidecar_test.go +++ b/control-plane/connect-inject/webhook/consul_dataplane_sidecar_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/container_env.go b/control-plane/connect-inject/webhook/container_env.go index 2b2d7f5471..7c65dcd77c 100644 --- a/control-plane/connect-inject/webhook/container_env.go +++ b/control-plane/connect-inject/webhook/container_env.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/container_env_test.go b/control-plane/connect-inject/webhook/container_env_test.go index 50d38832c0..62200e7bbd 100644 --- a/control-plane/connect-inject/webhook/container_env_test.go +++ b/control-plane/connect-inject/webhook/container_env_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/container_init.go b/control-plane/connect-inject/webhook/container_init.go index 88962f771e..db13485489 100644 --- a/control-plane/connect-inject/webhook/container_init.go +++ b/control-plane/connect-inject/webhook/container_init.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/container_init_test.go b/control-plane/connect-inject/webhook/container_init_test.go index fa2a95dbf9..5f14f44bc2 100644 --- a/control-plane/connect-inject/webhook/container_init_test.go +++ b/control-plane/connect-inject/webhook/container_init_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/container_volume.go b/control-plane/connect-inject/webhook/container_volume.go index 76ba461c7b..b33567469b 100644 --- a/control-plane/connect-inject/webhook/container_volume.go +++ b/control-plane/connect-inject/webhook/container_volume.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/dns.go b/control-plane/connect-inject/webhook/dns.go index 3f73928ece..ed4e95703b 100644 --- a/control-plane/connect-inject/webhook/dns.go +++ b/control-plane/connect-inject/webhook/dns.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/dns_test.go b/control-plane/connect-inject/webhook/dns_test.go index e8d718557e..d6392c5317 100644 --- a/control-plane/connect-inject/webhook/dns_test.go +++ b/control-plane/connect-inject/webhook/dns_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/health_checks_test.go b/control-plane/connect-inject/webhook/health_checks_test.go index 53e2781509..9279d8f140 100644 --- a/control-plane/connect-inject/webhook/health_checks_test.go +++ b/control-plane/connect-inject/webhook/health_checks_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/heath_checks.go b/control-plane/connect-inject/webhook/heath_checks.go index 8986f9e985..42d6da08e1 100644 --- a/control-plane/connect-inject/webhook/heath_checks.go +++ b/control-plane/connect-inject/webhook/heath_checks.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/connect-inject/webhook/mesh_webhook.go b/control-plane/connect-inject/webhook/mesh_webhook.go index 523200b96c..c8d412184b 100644 --- a/control-plane/connect-inject/webhook/mesh_webhook.go +++ b/control-plane/connect-inject/webhook/mesh_webhook.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( @@ -15,6 +12,13 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/go-logr/logr" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/lifecycle" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/namespaces" + "github.com/hashicorp/consul-k8s/control-plane/version" "gomodules.xyz/jsonpatch/v2" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -23,14 +27,6 @@ import ( "k8s.io/client-go/kubernetes" _ "k8s.io/client-go/plugin/pkg/client/auth" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/lifecycle" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" - "github.com/hashicorp/consul-k8s/control-plane/version" ) const ( @@ -295,10 +291,7 @@ func (w *MeshWebhook) Handle(ctx context.Context, req admission.Request) admissi // port. annotatedSvcNames := w.annotatedServiceNames(pod) multiPort := len(annotatedSvcNames) > 1 - lifecycleEnabled, ok := w.LifecycleConfig.EnableProxyLifecycle(pod) - if ok != nil { - w.Log.Error(err, "unable to get lifecycle enabled status") - } + // For single port pods, add the single init container and envoy sidecar. if !multiPort { // Add the init container that registers the service and sets up the Envoy configuration. @@ -315,14 +308,8 @@ func (w *MeshWebhook) Handle(ctx context.Context, req admission.Request) admissi w.Log.Error(err, "error configuring injection sidecar container", "request name", req.Name) return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection sidecar container: %s", err)) } - //Append the Envoy sidecar before the application container only if lifecycle enabled. - - if lifecycleEnabled && ok == nil { - pod.Spec.Containers = append([]corev1.Container{envoySidecar}, pod.Spec.Containers...) - } else { - pod.Spec.Containers = append(pod.Spec.Containers, envoySidecar) - } - + // TODO: invert to start the Envoy sidecar before the application container + pod.Spec.Containers = append(pod.Spec.Containers, envoySidecar) } else { // For multi port pods, check for unsupported cases, mount all relevant service account tokens, and mount an init // container and envoy sidecar per port. Tproxy, metrics, and metrics merging are not supported for multi port pods. @@ -337,10 +324,6 @@ func (w *MeshWebhook) Handle(ctx context.Context, req admission.Request) admissi w.Log.Error(err, "checking unsupported cases for multi port pods") return admission.Errored(http.StatusInternalServerError, err) } - - //List of sidecar containers for each service. Build as a list to preserve correct ordering in relation - //to services. - sidecarContainers := []corev1.Container{} for i, svc := range annotatedSvcNames { w.Log.Info(fmt.Sprintf("service: %s", svc)) if w.AuthMethod != "" { @@ -396,20 +379,9 @@ func (w *MeshWebhook) Handle(ctx context.Context, req admission.Request) admissi w.Log.Error(err, "error configuring injection sidecar container", "request name", req.Name) return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection sidecar container: %s", err)) } - // If Lifecycle is enabled, add to the list of sidecar containers to be added - // to pod containers at the end in order to preserve relative ordering. - if lifecycleEnabled { - sidecarContainers = append(sidecarContainers, envoySidecar) - } else { - pod.Spec.Containers = append(pod.Spec.Containers, envoySidecar) - - } - - } - - //Add sidecar containers first if lifecycle enabled. - if lifecycleEnabled { - pod.Spec.Containers = append(sidecarContainers, pod.Spec.Containers...) + // TODO: invert to start the Envoy sidecar container before the + // application container + pod.Spec.Containers = append(pod.Spec.Containers, envoySidecar) } } @@ -534,24 +506,20 @@ func (w *MeshWebhook) overwriteProbes(ns corev1.Namespace, pod *corev1.Pod) erro } if tproxyEnabled && overwriteProbes { - // We don't use the loop index because this needs to line up w.withiptablesConfigJSON, - // which is performed before the sidecar is injected. - idx := 0 - for _, container := range pod.Spec.Containers { + for i, container := range pod.Spec.Containers { // skip the "envoy-sidecar" container from having it's probes overridden if container.Name == sidecarContainer { continue } if container.LivenessProbe != nil && container.LivenessProbe.HTTPGet != nil { - container.LivenessProbe.HTTPGet.Port = intstr.FromInt(exposedPathsLivenessPortsRangeStart + idx) + container.LivenessProbe.HTTPGet.Port = intstr.FromInt(exposedPathsLivenessPortsRangeStart + i) } if container.ReadinessProbe != nil && container.ReadinessProbe.HTTPGet != nil { - container.ReadinessProbe.HTTPGet.Port = intstr.FromInt(exposedPathsReadinessPortsRangeStart + idx) + container.ReadinessProbe.HTTPGet.Port = intstr.FromInt(exposedPathsReadinessPortsRangeStart + i) } if container.StartupProbe != nil && container.StartupProbe.HTTPGet != nil { - container.StartupProbe.HTTPGet.Port = intstr.FromInt(exposedPathsStartupPortsRangeStart + idx) + container.StartupProbe.HTTPGet.Port = intstr.FromInt(exposedPathsStartupPortsRangeStart + i) } - idx++ } } return nil diff --git a/control-plane/connect-inject/webhook/mesh_webhook_ent_test.go b/control-plane/connect-inject/webhook/mesh_webhook_ent_test.go index 860694dcef..3f6b668c6b 100644 --- a/control-plane/connect-inject/webhook/mesh_webhook_ent_test.go +++ b/control-plane/connect-inject/webhook/mesh_webhook_ent_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package webhook @@ -9,8 +6,8 @@ import ( "context" "testing" - "github.com/deckarep/golang-set" - logrtest "github.com/go-logr/logr/testing" + mapset "github.com/deckarep/golang-set" + logrtest "github.com/go-logr/logr/testr" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" "github.com/hashicorp/consul-k8s/control-plane/helper/test" "github.com/hashicorp/consul/api" @@ -52,7 +49,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "single destination namespace 'default' from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -74,7 +71,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "single destination namespace 'default' from k8s 'non-default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -96,7 +93,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "single destination namespace 'dest' from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -118,7 +115,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "single destination namespace 'dest' from k8s 'non-default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -140,7 +137,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "mirroring from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -163,7 +160,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "mirroring from k8s 'dest'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -186,7 +183,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "mirroring with prefix from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -210,7 +207,7 @@ func TestHandler_MutateWithNamespaces(t *testing.T) { { Name: "mirroring with prefix from k8s 'dest'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -298,7 +295,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + single destination namespace 'default' from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -321,7 +318,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + single destination namespace 'default' from k8s 'non-default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -344,7 +341,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + single destination namespace 'dest' from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -367,7 +364,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + single destination namespace 'dest' from k8s 'non-default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -390,7 +387,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + mirroring from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -414,7 +411,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + mirroring from k8s 'dest'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -438,7 +435,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + mirroring with prefix from k8s 'default'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -463,7 +460,7 @@ func TestHandler_MutateWithNamespaces_ACLs(t *testing.T) { { Name: "acls + mirroring with prefix from k8s 'dest'", Webhook: MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, @@ -603,7 +600,7 @@ func TestHandler_MutateWithNamespaces_Annotation(t *testing.T) { require.NoError(t, err) webhook := MeshWebhook{ - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), EnableNamespaces: true, diff --git a/control-plane/connect-inject/webhook/mesh_webhook_test.go b/control-plane/connect-inject/webhook/mesh_webhook_test.go index 64dbd21c9a..9761551b85 100644 --- a/control-plane/connect-inject/webhook/mesh_webhook_test.go +++ b/control-plane/connect-inject/webhook/mesh_webhook_test.go @@ -1,18 +1,18 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( "context" "encoding/json" - "strconv" "strings" "testing" mapset "github.com/deckarep/golang-set" logrtest "github.com/go-logr/logr/testr" - "github.com/hashicorp/consul/sdk/iptables" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/namespaces" + "github.com/hashicorp/consul-k8s/control-plane/version" "github.com/stretchr/testify/require" "gomodules.xyz/jsonpatch/v2" admissionv1 "k8s.io/api/admission/v1" @@ -24,13 +24,6 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/lifecycle" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" - "github.com/hashicorp/consul-k8s/control-plane/version" ) func TestHandlerHandle(t *testing.T) { @@ -142,73 +135,6 @@ func TestHandlerHandle(t *testing.T) { }, }, }, - { - "empty pod basic with lifecycle", - MeshWebhook{ - Log: logrtest.New(t), - AllowK8sNamespacesSet: mapset.NewSetWith("*"), - DenyK8sNamespacesSet: mapset.NewSet(), - decoder: decoder, - Clientset: defaultTestClientWithNamespace(), - LifecycleConfig: lifecycle.Config{DefaultEnableProxyLifecycle: true}, - }, - admission.Request{ - AdmissionRequest: admissionv1.AdmissionRequest{ - Namespace: namespaces.DefaultNamespace, - Object: encodeRaw(t, &corev1.Pod{ - Spec: basicSpec, - }), - }, - }, - "", - []jsonpatch.Operation{ - { - Operation: "add", - Path: "/metadata/labels", - }, - { - Operation: "add", - Path: "/metadata/annotations", - }, - { - Operation: "add", - Path: "/spec/volumes", - }, - { - Operation: "add", - Path: "/spec/initContainers", - }, - { - Operation: "add", - Path: "/spec/containers/1", - }, - - { - Operation: "add", - Path: "/spec/containers/0/readinessProbe", - }, - { - Operation: "add", - Path: "/spec/containers/0/securityContext", - }, - { - Operation: "replace", - Path: "/spec/containers/0/name", - }, - { - Operation: "add", - Path: "/spec/containers/0/args", - }, - { - Operation: "add", - Path: "/spec/containers/0/env", - }, - { - Operation: "add", - Path: "/spec/containers/0/volumeMounts", - }, - }, - }, { "pod with upstreams specified", @@ -882,91 +808,6 @@ func TestHandlerHandle(t *testing.T) { }, }, }, - { - "multiport pod kube < 1.24 with AuthMethod, serviceaccount has secret ref, lifecycle enabled", - MeshWebhook{ - Log: logrtest.New(t), - AllowK8sNamespacesSet: mapset.NewSetWith("*"), - DenyK8sNamespacesSet: mapset.NewSet(), - decoder: decoder, - Clientset: testClientWithServiceAccountAndSecretRefs(), - AuthMethod: "k8s", - LifecycleConfig: lifecycle.Config{DefaultEnableProxyLifecycle: true}, - }, - admission.Request{ - AdmissionRequest: admissionv1.AdmissionRequest{ - Namespace: namespaces.DefaultNamespace, - Object: encodeRaw(t, &corev1.Pod{ - Spec: basicSpec, - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - constants.AnnotationService: "web,web-admin", - }, - }, - }), - }, - }, - "", - []jsonpatch.Operation{ - { - Operation: "add", - Path: "/spec/containers/0/env", - }, - { - Operation: "add", - Path: "/spec/containers/0/volumeMounts", - }, - { - Operation: "add", - Path: "/spec/containers/0/readinessProbe", - }, - { - Operation: "add", - Path: "/spec/containers/0/securityContext", - }, - { - Operation: "replace", - Path: "/spec/containers/0/name", - }, - { - Operation: "add", - Path: "/spec/containers/0/args", - }, - - { - Operation: "add", - Path: "/spec/volumes", - }, - { - Operation: "add", - Path: "/spec/initContainers", - }, - { - Operation: "add", - Path: "/spec/containers/1", - }, - { - Operation: "add", - Path: "/spec/containers/2", - }, - { - Operation: "add", - Path: "/metadata/annotations/" + escapeJSONPointer(constants.KeyInjectStatus), - }, - { - Operation: "add", - Path: "/metadata/annotations/" + escapeJSONPointer(constants.AnnotationOriginalPod), - }, - { - Operation: "add", - Path: "/metadata/annotations/" + escapeJSONPointer(constants.AnnotationConsulK8sVersion), - }, - { - Operation: "add", - Path: "/metadata/labels", - }, - }, - }, { "dns redirection enabled", MeshWebhook{ @@ -1132,220 +973,6 @@ func TestHandlerHandle(t *testing.T) { } } -// This test validates that overwrite probes match the iptables configuration fromiptablesConfigJSON() -// Because they happen at different points in the injection, the port numbers can get out of sync. -func TestHandlerHandle_ValidateOverwriteProbes(t *testing.T) { - t.Parallel() - s := runtime.NewScheme() - s.AddKnownTypes(schema.GroupVersion{ - Group: "", - Version: "v1", - }, &corev1.Pod{}) - decoder, err := admission.NewDecoder(s) - require.NoError(t, err) - - cases := []struct { - Name string - Webhook MeshWebhook - Req admission.Request - Err string // expected error string, not exact - Patches []jsonpatch.Operation - }{ - { - "tproxy with overwriteProbes is enabled", - MeshWebhook{ - Log: logrtest.New(t), - AllowK8sNamespacesSet: mapset.NewSetWith("*"), - DenyK8sNamespacesSet: mapset.NewSet(), - EnableTransparentProxy: true, - TProxyOverwriteProbes: true, - LifecycleConfig: lifecycle.Config{DefaultEnableProxyLifecycle: true}, - decoder: decoder, - Clientset: defaultTestClientWithNamespace(), - }, - admission.Request{ - AdmissionRequest: admissionv1.AdmissionRequest{ - Namespace: namespaces.DefaultNamespace, - Object: encodeRaw(t, &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{}, - // We're setting an existing annotation so that we can assert on the - // specific annotations that are set as a result of probes being overwritten. - Annotations: map[string]string{"foo": "bar"}, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "web", - LivenessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Port: intstr.FromInt(8080), - }, - }, - }, - ReadinessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Port: intstr.FromInt(8081), - }, - }, - }, - StartupProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Port: intstr.FromInt(8082), - }, - }, - }, - }, - }, - }, - }), - }, - }, - "", - []jsonpatch.Operation{ - { - Operation: "add", - Path: "/spec/volumes", - }, - { - Operation: "add", - Path: "/spec/initContainers", - }, - { - Operation: "add", - Path: "/spec/containers/1", - }, - { - Operation: "replace", - Path: "/spec/containers/0/name", - }, - { - Operation: "add", - Path: "/spec/containers/0/args", - }, - { - Operation: "add", - Path: "/spec/containers/0/env", - }, - { - Operation: "add", - Path: "/spec/containers/0/volumeMounts", - }, - { - Operation: "add", - Path: "/spec/containers/0/readinessProbe/tcpSocket", - }, - { - Operation: "add", - Path: "/spec/containers/0/readinessProbe/initialDelaySeconds", - }, - { - Operation: "remove", - Path: "/spec/containers/0/readinessProbe/httpGet", - }, - { - Operation: "add", - Path: "/spec/containers/0/securityContext", - }, - { - Operation: "remove", - Path: "/spec/containers/0/startupProbe", - }, - { - Operation: "remove", - Path: "/spec/containers/0/livenessProbe", - }, - { - Operation: "add", - Path: "/metadata/labels", - }, - { - Operation: "add", - Path: "/metadata/annotations/" + escapeJSONPointer(constants.KeyInjectStatus), - }, - { - Operation: "add", - Path: "/metadata/annotations/" + escapeJSONPointer(constants.KeyTransparentProxyStatus), - }, - - { - Operation: "add", - Path: "/metadata/annotations/" + escapeJSONPointer(constants.AnnotationOriginalPod), - }, - { - Operation: "add", - Path: "/metadata/annotations/" + escapeJSONPointer(constants.AnnotationConsulK8sVersion), - }, - }, - }, - } - - for _, tt := range cases { - t.Run(tt.Name, func(t *testing.T) { - tt.Webhook.ConsulConfig = &consul.Config{HTTPPort: 8500} - ctx := context.Background() - resp := tt.Webhook.Handle(ctx, tt.Req) - if (tt.Err == "") != resp.Allowed { - t.Fatalf("allowed: %v, expected err: %v", resp.Allowed, tt.Err) - } - if tt.Err != "" { - require.Contains(t, resp.Result.Message, tt.Err) - return - } - - var iptablesCfg iptables.Config - var overwritePorts []string - actual := resp.Patches - if len(actual) > 0 { - for i := range actual { - - // We want to grab the iptables configuration from the connect-init container's - // environment. - if actual[i].Path == "/spec/initContainers" { - value := actual[i].Value.([]any) - valueMap := value[0].(map[string]any) - envs := valueMap["env"].([]any) - redirectEnv := envs[8].(map[string]any) - require.Equal(t, redirectEnv["name"].(string), "CONSUL_REDIRECT_TRAFFIC_CONFIG") - iptablesJson := redirectEnv["value"].(string) - - err := json.Unmarshal([]byte(iptablesJson), &iptablesCfg) - require.NoError(t, err) - } - - // We want to accumulate the httpGet Probes from the application container to - // compare them to the iptables rules. This is now the second container in the spec - if strings.Contains(actual[i].Path, "/spec/containers/1") { - valueMap, ok := actual[i].Value.(map[string]any) - require.True(t, ok) - - for k, v := range valueMap { - if strings.Contains(k, "Probe") { - probe := v.(map[string]any) - httpProbe := probe["httpGet"] - httpProbeMap := httpProbe.(map[string]any) - port := httpProbeMap["port"] - portNum := port.(float64) - - overwritePorts = append(overwritePorts, strconv.Itoa(int(portNum))) - } - } - } - - // nil out all the patch values to just compare the keys changing. - actual[i].Value = nil - } - } - // Make sure the iptables excluded ports match the ports on the container - require.ElementsMatch(t, iptablesCfg.ExcludeInboundPorts, overwritePorts) - require.ElementsMatch(t, tt.Patches, actual) - }) - } -} - func TestHandlerDefaultAnnotations(t *testing.T) { cases := []struct { Name string diff --git a/control-plane/connect-inject/webhook/redirect_traffic.go b/control-plane/connect-inject/webhook/redirect_traffic.go index f928df4afd..8ae8fce068 100644 --- a/control-plane/connect-inject/webhook/redirect_traffic.go +++ b/control-plane/connect-inject/webhook/redirect_traffic.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( @@ -8,11 +5,10 @@ import ( "fmt" "strconv" - "github.com/hashicorp/consul/sdk/iptables" - corev1 "k8s.io/api/core/v1" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" + "github.com/hashicorp/consul/sdk/iptables" + corev1 "k8s.io/api/core/v1" ) // addRedirectTrafficConfigAnnotation creates an iptables.Config in JSON format based on proxy configuration. @@ -63,24 +59,20 @@ func (w *MeshWebhook) iptablesConfigJSON(pod corev1.Pod, ns corev1.Namespace) (s } if overwriteProbes { - // We don't use the loop index because this needs to line up w.overwriteProbes(), - // which is performed after the sidecar is injected. - idx := 0 - for _, container := range pod.Spec.Containers { - // skip the "consul-dataplane" container from having its probes overridden + for i, container := range pod.Spec.Containers { + // skip the "envoy-sidecar" container from having its probes overridden if container.Name == sidecarContainer { continue } if container.LivenessProbe != nil && container.LivenessProbe.HTTPGet != nil { - cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsLivenessPortsRangeStart+idx)) + cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsLivenessPortsRangeStart+i)) } if container.ReadinessProbe != nil && container.ReadinessProbe.HTTPGet != nil { - cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsReadinessPortsRangeStart+idx)) + cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsReadinessPortsRangeStart+i)) } if container.StartupProbe != nil && container.StartupProbe.HTTPGet != nil { - cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsStartupPortsRangeStart+idx)) + cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsStartupPortsRangeStart+i)) } - idx++ } } diff --git a/control-plane/connect-inject/webhook/redirect_traffic_test.go b/control-plane/connect-inject/webhook/redirect_traffic_test.go index bfa8ad8f2a..38aad20578 100644 --- a/control-plane/connect-inject/webhook/redirect_traffic_test.go +++ b/control-plane/connect-inject/webhook/redirect_traffic_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhook import ( diff --git a/control-plane/consul/consul.go b/control-plane/consul/consul.go index 8dea334607..bb46308ff8 100644 --- a/control-plane/consul/consul.go +++ b/control-plane/consul/consul.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consul import ( @@ -8,10 +5,9 @@ import ( "net/http" "time" + "github.com/hashicorp/consul-k8s/control-plane/version" "github.com/hashicorp/consul-server-connection-manager/discovery" capi "github.com/hashicorp/consul/api" - - "github.com/hashicorp/consul-k8s/control-plane/version" ) //go:generate mockery --name ServerConnectionManager --inpkg @@ -21,7 +17,7 @@ type ServerConnectionManager interface { Stop() } -// NewClient returns a V1 Consul API client. It adds a required User-Agent +// NewClient returns a Consul API client. It adds a required User-Agent // header that describes the version of consul-k8s making the call. func NewClient(config *capi.Config, consulAPITimeout time.Duration) (*capi.Client, error) { if consulAPITimeout <= 0 { @@ -70,7 +66,7 @@ type Config struct { } // todo (ishustava): replace all usages of this one. -// NewClientFromConnMgrState creates a new V1 API client with an IP address from the state +// NewClientFromConnMgrState creates a new API client with an IP address from the state // of the consul-server-connection-manager. func NewClientFromConnMgrState(config *Config, state discovery.State) (*capi.Client, error) { ipAddress := state.Address.IP @@ -81,7 +77,7 @@ func NewClientFromConnMgrState(config *Config, state discovery.State) (*capi.Cli return NewClient(config.APIClientConfig, config.APITimeout) } -// NewClientFromConnMgr creates a new V1 API client by first getting the state of the passed watcher. +// NewClientFromConnMgr creates a new API client by first getting the state of the passed watcher. func NewClientFromConnMgr(config *Config, watcher ServerConnectionManager) (*capi.Client, error) { // Create a new consul client. serverState, err := watcher.State() diff --git a/control-plane/consul/consul_test.go b/control-plane/consul/consul_test.go index 04afe08033..02430b0f48 100644 --- a/control-plane/consul/consul_test.go +++ b/control-plane/consul/consul_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consul import ( diff --git a/control-plane/consul/resource_client.go b/control-plane/consul/resource_client.go deleted file mode 100644 index 17dc4a9229..0000000000 --- a/control-plane/consul/resource_client.go +++ /dev/null @@ -1,26 +0,0 @@ -package consul - -import ( - "fmt" - - "github.com/hashicorp/consul-server-connection-manager/discovery" - "github.com/hashicorp/consul/proto-public/pbresource" -) - -// NewResourceServiceClient creates a pbresource.ResourceServiceClient for creating V2 Consul resources. -// It is initialized with a consul-server-connection-manager Watcher to continuously find Consul -// server addresses. -func NewResourceServiceClient(watcher *discovery.Watcher) (pbresource.ResourceServiceClient, error) { - - // We recycle the GRPC connection from the discovery client because it - // should have all the necessary dial options, including the resolver that - // continuously updates Consul server addresses. Otherwise, a lot of code from consul-server-connection-manager - // would need to be duplicated - state, err := watcher.State() - if err != nil { - return nil, fmt.Errorf("unable to get connection manager state: %w", err) - } - resourceClient := pbresource.NewResourceServiceClient(state.GRPCConn) - - return resourceClient, nil -} diff --git a/control-plane/consul/resource_client_test.go b/control-plane/consul/resource_client_test.go deleted file mode 100644 index 29507304b0..0000000000 --- a/control-plane/consul/resource_client_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package consul - -import ( - "context" - "testing" - - "github.com/hashicorp/consul-server-connection-manager/discovery" - pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" - "github.com/hashicorp/consul/proto-public/pbresource" - "github.com/hashicorp/consul/sdk/testutil" - "github.com/hashicorp/go-hclog" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/types/known/anypb" -) - -func Test_NewResourceServiceClient(t *testing.T) { - - var serverConfig *testutil.TestServerConfig - server, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { - c.Experiments = []string{"resource-apis"} - serverConfig = c - }) - require.NoError(t, err) - defer server.Stop() - - server.WaitForLeader(t) - server.WaitForActiveCARoot(t) - - t.Logf("server grpc address on %d", serverConfig.Ports.GRPC) - - // Create discovery configuration - discoverConfig := discovery.Config{ - Addresses: "127.0.0.1", - GRPCPort: serverConfig.Ports.GRPC, - } - - opts := hclog.LoggerOptions{Name: "resource-service-client"} - logger := hclog.New(&opts) - - watcher, err := discovery.NewWatcher(context.Background(), discoverConfig, logger) - require.NoError(t, err) - require.NotNil(t, watcher) - - defer watcher.Stop() - go watcher.Run() - - client, err := NewResourceServiceClient(watcher) - require.NoError(t, err) - require.NotNil(t, client) - require.NotNil(t, watcher) - - req := createWriteRequest(t, "foo") - res, err := client.Write(context.Background(), req) - require.NoError(t, err) - require.NotNil(t, res) - require.Equal(t, "foo", res.GetResource().GetId().GetName()) - - // NOTE: currently it isn't possible to test that the grpc connection responds to changes in the - // discovery server. The discovery response only includes the IP address of the host, so all servers - // for a local test are de-duplicated as a single entry. -} - -func createWriteRequest(t *testing.T, name string) *pbresource.WriteRequest { - - workload := &pbcatalog.Workload{ - Addresses: []*pbcatalog.WorkloadAddress{ - {Host: "10.0.0.1", Ports: []string{"public", "admin", "mesh"}}, - }, - Ports: map[string]*pbcatalog.WorkloadPort{ - "public": { - Port: 80, - Protocol: pbcatalog.Protocol_PROTOCOL_TCP, - }, - "admin": { - Port: 8080, - Protocol: pbcatalog.Protocol_PROTOCOL_TCP, - }, - "mesh": { - Port: 20000, - Protocol: pbcatalog.Protocol_PROTOCOL_MESH, - }, - }, - NodeName: "k8s-node-0-virtual", - Identity: name, - } - - proto, err := anypb.New(workload) - require.NoError(t, err) - - req := &pbresource.WriteRequest{ - Resource: &pbresource.Resource{ - Id: &pbresource.ID{ - Name: name, - Type: &pbresource.Type{ - Group: "catalog", - GroupVersion: "v1alpha1", - Kind: "Workload", - }, - Tenancy: &pbresource.Tenancy{ - Partition: "default", - Namespace: "default", - }, - }, - Data: proto, - }, - } - return req -} diff --git a/control-plane/controllers/configentry_controller.go b/control-plane/controller/configentry_controller.go similarity index 84% rename from control-plane/controllers/configentry_controller.go rename to control-plane/controller/configentry_controller.go index 133afc0a1c..7782d5e9a9 100644 --- a/control-plane/controllers/configentry_controller.go +++ b/control-plane/controller/configentry_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" @@ -199,7 +196,6 @@ func (r *ConfigEntryController) ReconcileEntry(ctx context.Context, crdCtrl Cont return r.syncFailed(ctx, logger, crdCtrl, configEntry, ConsulAgentError, fmt.Errorf("writing config entry to consul: %w", err)) } - logger.Info("config entry created", "request-time", writeMeta.RequestTime) return r.syncSuccessful(ctx, crdCtrl, configEntry) } @@ -268,15 +264,6 @@ func (r *ConfigEntryController) ReconcileEntry(ctx context.Context, crdCtrl Cont return r.syncSuccessful(ctx, crdCtrl, configEntry) } - // For resolvers and splitters, we need to set the ClusterIP of the matching service to Consul so that transparent - // proxy works correctly. Do not fail the reconcile if assigning the virtual IP returns an error. - if needsVirtualIPAssignment(r.DatacenterName, configEntry) { - err = assignServiceVirtualIP(ctx, logger, consulClient, crdCtrl, req.NamespacedName, configEntry, r.DatacenterName) - if err != nil { - logger.Error(err, "failed assigning service virtual ip") - } - } - return ctrl.Result{}, nil } @@ -391,75 +378,6 @@ func (r *ConfigEntryController) nonMatchingMigrationError(kubeEntry common.Confi return fmt.Errorf("migration failed: Kubernetes resource does not match existing Consul config entry: consul=%s, kube=%s", consulJSON, kubeJSON) } -// needsVirtualIPAssignment checks to see if a configEntry type needs to be assigned a virtual IP. -func needsVirtualIPAssignment(datacenterName string, configEntry common.ConfigEntryResource) bool { - switch configEntry.KubeKind() { - case common.ServiceResolver: - return true - case common.ServiceRouter: - return true - case common.ServiceSplitter: - return true - case common.ServiceDefaults: - return true - case common.ServiceIntentions: - entry := configEntry.ToConsul(datacenterName) - intention, ok := entry.(*capi.ServiceIntentionsConfigEntry) - if !ok { - return false - } - // We should not persist virtual ips if the destination is a wildcard - // in any form, since that would target multiple services. - return !strings.Contains(intention.Name, "*") && - !strings.Contains(intention.Namespace, "*") && - !strings.Contains(intention.Partition, "*") - } - return false -} - -// assignServiceVirtualIPs manually sends the ClusterIP for a matching service for ServiceRouter or ServiceSplitter -// CRDs to Consul so that it can be added to the virtual IP table. The assignment is skipped if the matching service -// does not exist or if an older version of Consul is being used. Endpoints Controller, on service registration, also -// manually sends a ClusterIP when a service is created. This increases the chance of a real IP ending up in the -// discovery chain. -func assignServiceVirtualIP(ctx context.Context, logger logr.Logger, consulClient *capi.Client, crdCtrl Controller, namespacedName types.NamespacedName, configEntry common.ConfigEntryResource, datacenter string) error { - service := corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: configEntry.KubernetesName(), - Namespace: namespacedName.Namespace, - }, - } - if err := crdCtrl.Get(ctx, namespacedName, &service); err != nil { - // It is non-fatal if the service does not exist. The ClusterIP will get added when the service is registered in - // the endpoints controller - if k8serr.IsNotFound(err) { - return nil - } - // Something is really wrong with the service - return err - } - - consulType := configEntry.ToConsul(datacenter) - wo := &capi.WriteOptions{ - Namespace: consulType.GetNamespace(), - Partition: consulType.GetPartition(), - } - - logger.Info("adding manual ip to virtual ip table in Consul", "name", service.Name) - _, _, err := consulClient.Internal().AssignServiceVirtualIP(ctx, consulType.GetName(), []string{service.Spec.ClusterIP}, wo) - if err != nil { - // Maintain backwards compatibility with older versions of Consul that do not support the manual VIP improvements. With the older version, the mesh - // will still work. - if isNotFoundErr(err) { - logger.Error(err, "failed to add ip to virtual ip table. Please upgrade Consul to version 1.16 or higher", "name", service.Name) - return nil - } else { - return err - } - } - return nil -} - func isNotFoundErr(err error) bool { return err != nil && strings.Contains(err.Error(), "404") } diff --git a/control-plane/controller/configentry_controller_ent_test.go b/control-plane/controller/configentry_controller_ent_test.go new file mode 100644 index 0000000000..aa59ddaceb --- /dev/null +++ b/control-plane/controller/configentry_controller_ent_test.go @@ -0,0 +1,759 @@ +//go:build enterprise + +package controller_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/go-logr/logr" + logrtest "github.com/go-logr/logr/testr" + "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/controller" + "github.com/hashicorp/consul-k8s/control-plane/helper/test" + capi "github.com/hashicorp/consul/api" + "github.com/stretchr/testify/require" + corev1 "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" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// NOTE: We're not testing each controller type here because that's done in +// the OSS tests and it would result in too many permutations. Instead +// we're only testing with the ServiceDefaults and ProxyDefaults controller which will exercise +// all the namespaces code for config entries that are namespaced and those that +// exist in the global namespace. + +func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T) { + tt.Parallel() + + cases := map[string]struct { + Mirror bool + MirrorPrefix string + SourceKubeNS string + DestConsulNS string + ExpConsulNS string + }{ + "SourceKubeNS=default, DestConsulNS=default": { + SourceKubeNS: "default", + DestConsulNS: "default", + ExpConsulNS: "default", + }, + "SourceKubeNS=kube, DestConsulNS=default": { + SourceKubeNS: "kube", + DestConsulNS: "default", + ExpConsulNS: "default", + }, + "SourceKubeNS=default, DestConsulNS=other": { + SourceKubeNS: "default", + DestConsulNS: "other", + ExpConsulNS: "other", + }, + "SourceKubeNS=kube, DestConsulNS=other": { + SourceKubeNS: "kube", + DestConsulNS: "other", + ExpConsulNS: "other", + }, + "SourceKubeNS=default, Mirror=true": { + SourceKubeNS: "default", + Mirror: true, + ExpConsulNS: "default", + }, + "SourceKubeNS=kube, Mirror=true": { + SourceKubeNS: "kube", + Mirror: true, + ExpConsulNS: "kube", + }, + "SourceKubeNS=default, Mirror=true, Prefix=prefix": { + SourceKubeNS: "default", + Mirror: true, + MirrorPrefix: "prefix-", + ExpConsulNS: "prefix-default", + }, + } + + for name, c := range cases { + configEntryKinds := map[string]struct { + ConsulKind string + ConsulNamespace string + KubeResource common.ConfigEntryResource + GetController func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler + AssertValidConfig func(entry capi.ConfigEntry) bool + }{ + "namespaced": { + ConsulKind: capi.ServiceDefaults, + KubeResource: &v1alpha1.ServiceDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: c.SourceKubeNS, + }, + Spec: v1alpha1.ServiceDefaultsSpec{ + Protocol: "http", + }, + }, + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ServiceDefaultsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + AssertValidConfig: func(cfg capi.ConfigEntry) bool { + configEntry, ok := cfg.(*capi.ServiceConfigEntry) + if !ok { + return false + } + return configEntry.Protocol == "http" + }, + ConsulNamespace: c.ExpConsulNS, + }, + "global": { + ConsulKind: capi.ProxyDefaults, + KubeResource: &v1alpha1.ProxyDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.Global, + Namespace: c.SourceKubeNS, + }, + Spec: v1alpha1.ProxyDefaultsSpec{ + MeshGateway: v1alpha1.MeshGateway{ + Mode: "remote", + }, + }, + }, + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ProxyDefaultsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + AssertValidConfig: func(cfg capi.ConfigEntry) bool { + configEntry, ok := cfg.(*capi.ProxyConfigEntry) + if !ok { + return false + } + return configEntry.MeshGateway.Mode == capi.MeshGatewayModeRemote + }, + ConsulNamespace: common.DefaultConsulNamespace, + }, + "intentions": { + ConsulKind: capi.ServiceIntentions, + KubeResource: &v1alpha1.ServiceIntentions{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: c.SourceKubeNS, + }, + Spec: v1alpha1.ServiceIntentionsSpec{ + Destination: v1alpha1.IntentionDestination{ + Name: "test", + Namespace: c.ExpConsulNS, + }, + Sources: v1alpha1.SourceIntentions{ + &v1alpha1.SourceIntention{ + Name: "baz", + Namespace: "bar", + Action: "allow", + }, + }, + }, + }, + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ServiceIntentionsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + AssertValidConfig: func(cfg capi.ConfigEntry) bool { + configEntry, ok := cfg.(*capi.ServiceIntentionsConfigEntry) + if !ok { + return false + } + return configEntry.Sources[0].Action == capi.IntentionActionAllow + }, + ConsulNamespace: c.ExpConsulNS, + }, + } + + for kind, in := range configEntryKinds { + tt.Run(fmt.Sprintf("%s : %s", name, kind), func(t *testing.T) { + req := require.New(t) + s := runtime.NewScheme() + s.AddKnownTypes(v1alpha1.GroupVersion, in.KubeResource) + ctx := context.Background() + + testClient := test.TestServerWithMockConnMgrWatcher(t, nil) + testClient.TestServer.WaitForServiceIntentions(t) + consulClient := testClient.APIClient + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(in.KubeResource).Build() + + r := in.GetController( + fakeClient, + logrtest.New(t), + s, + &controller.ConfigEntryController{ + ConsulClientConfig: testClient.Cfg, + ConsulServerConnMgr: testClient.Watcher, + EnableConsulNamespaces: true, + EnableNSMirroring: c.Mirror, + NSMirroringPrefix: c.MirrorPrefix, + ConsulDestinationNamespace: c.DestConsulNS, + }, + ) + + resp, err := r.Reconcile(ctx, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: in.KubeResource.KubernetesName(), + }, + }) + req.NoError(err) + req.False(resp.Requeue) + + cfg, _, err := consulClient.ConfigEntries().Get(in.ConsulKind, in.KubeResource.ConsulName(), &capi.QueryOptions{ + Namespace: in.ConsulNamespace, + }) + req.NoError(err) + + result := in.AssertValidConfig(cfg) + req.True(result) + + // Check that the status is "synced". + err = fakeClient.Get(ctx, types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: in.KubeResource.KubernetesName(), + }, in.KubeResource) + req.NoError(err) + conditionSynced := in.KubeResource.SyncedConditionStatus() + req.Equal(conditionSynced, corev1.ConditionTrue) + }) + } + } +} + +func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T) { + tt.Parallel() + + cases := map[string]struct { + Mirror bool + MirrorPrefix string + SourceKubeNS string + DestConsulNS string + ExpConsulNS string + }{ + "SourceKubeNS=default, DestConsulNS=default": { + SourceKubeNS: "default", + DestConsulNS: "default", + ExpConsulNS: "default", + }, + "SourceKubeNS=kube, DestConsulNS=default": { + SourceKubeNS: "kube", + DestConsulNS: "default", + ExpConsulNS: "default", + }, + "SourceKubeNS=default, DestConsulNS=other": { + SourceKubeNS: "default", + DestConsulNS: "other", + ExpConsulNS: "other", + }, + "SourceKubeNS=kube, DestConsulNS=other": { + SourceKubeNS: "kube", + DestConsulNS: "other", + ExpConsulNS: "other", + }, + "SourceKubeNS=default, Mirror=true": { + SourceKubeNS: "default", + Mirror: true, + ExpConsulNS: "default", + }, + "SourceKubeNS=kube, Mirror=true": { + SourceKubeNS: "kube", + Mirror: true, + ExpConsulNS: "kube", + }, + "SourceKubeNS=default, Mirror=true, Prefix=prefix": { + SourceKubeNS: "default", + Mirror: true, + MirrorPrefix: "prefix-", + ExpConsulNS: "prefix-default", + }, + } + + for name, c := range cases { + configEntryKinds := map[string]struct { + ConsulKind string + ConsulNamespace string + KubeResource common.ConfigEntryResource + GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler + AssertValidConfigFunc func(entry capi.ConfigEntry) bool + WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error + UpdateResourceFunc func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error + }{ + "namespaced": { + ConsulKind: capi.ServiceDefaults, + KubeResource: &v1alpha1.ServiceDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + }, + Spec: v1alpha1.ServiceDefaultsSpec{ + Protocol: "http", + }, + }, + ConsulNamespace: c.ExpConsulNS, + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ServiceDefaultsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { + _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceConfigEntry{ + Kind: capi.ServiceDefaults, + Name: "foo", + Protocol: "http", + }, &capi.WriteOptions{Namespace: namespace}) + return err + }, + UpdateResourceFunc: func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error { + svcDefault := in.(*v1alpha1.ServiceDefaults) + svcDefault.Spec.Protocol = "tcp" + return client.Update(ctx, svcDefault) + }, + AssertValidConfigFunc: func(cfg capi.ConfigEntry) bool { + configEntry, ok := cfg.(*capi.ServiceConfigEntry) + if !ok { + return false + } + return configEntry.Protocol == "tcp" + }, + }, + "global": { + ConsulKind: capi.ProxyDefaults, + KubeResource: &v1alpha1.ProxyDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.Global, + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + }, + Spec: v1alpha1.ProxyDefaultsSpec{ + MeshGateway: v1alpha1.MeshGateway{ + Mode: "remote", + }, + }, + }, + ConsulNamespace: common.DefaultConsulNamespace, + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ProxyDefaultsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { + _, _, err := consulClient.ConfigEntries().Set(&capi.ProxyConfigEntry{ + Kind: capi.ProxyDefaults, + Name: common.Global, + MeshGateway: capi.MeshGatewayConfig{ + Mode: capi.MeshGatewayModeRemote, + }, + }, &capi.WriteOptions{Namespace: namespace}) + return err + }, + UpdateResourceFunc: func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error { + proxyDefaults := in.(*v1alpha1.ProxyDefaults) + proxyDefaults.Spec.MeshGateway.Mode = "local" + return client.Update(ctx, proxyDefaults) + }, + AssertValidConfigFunc: func(cfg capi.ConfigEntry) bool { + configEntry, ok := cfg.(*capi.ProxyConfigEntry) + if !ok { + return false + } + return configEntry.MeshGateway.Mode == capi.MeshGatewayModeLocal + }, + }, + "intentions": { + ConsulKind: capi.ServiceIntentions, + KubeResource: &v1alpha1.ServiceIntentions{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + }, + Spec: v1alpha1.ServiceIntentionsSpec{ + Destination: v1alpha1.IntentionDestination{ + Name: "foo", + Namespace: c.ExpConsulNS, + }, + Sources: v1alpha1.SourceIntentions{ + &v1alpha1.SourceIntention{ + Name: "bar", + Namespace: "baz", + Action: "deny", + }, + }, + }, + }, + ConsulNamespace: c.ExpConsulNS, + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ServiceIntentionsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { + _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceIntentionsConfigEntry{ + Kind: capi.ServiceIntentions, + Name: "foo", + Sources: []*capi.SourceIntention{ + { + Name: "bar", + Namespace: "baz", + Action: capi.IntentionActionDeny, + }, + }, + }, &capi.WriteOptions{Namespace: namespace}) + return err + }, + UpdateResourceFunc: func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error { + svcIntention := in.(*v1alpha1.ServiceIntentions) + svcIntention.Spec.Sources[0].Action = "allow" + return client.Update(ctx, svcIntention) + }, + AssertValidConfigFunc: func(cfg capi.ConfigEntry) bool { + configEntry, ok := cfg.(*capi.ServiceIntentionsConfigEntry) + if !ok { + return false + } + return configEntry.Sources[0].Action == capi.IntentionActionAllow + }, + }, + } + for kind, in := range configEntryKinds { + tt.Run(fmt.Sprintf("%s : %s", name, kind), func(t *testing.T) { + req := require.New(t) + s := runtime.NewScheme() + s.AddKnownTypes(v1alpha1.GroupVersion, in.KubeResource) + ctx := context.Background() + + testClient := test.TestServerWithMockConnMgrWatcher(t, nil) + testClient.TestServer.WaitForServiceIntentions(t) + consulClient := testClient.APIClient + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(in.KubeResource).Build() + + r := in.GetControllerFunc( + fakeClient, + logrtest.New(t), + s, + &controller.ConfigEntryController{ + ConsulClientConfig: testClient.Cfg, + ConsulServerConnMgr: testClient.Watcher, + EnableConsulNamespaces: true, + EnableNSMirroring: c.Mirror, + NSMirroringPrefix: c.MirrorPrefix, + ConsulDestinationNamespace: c.DestConsulNS, + }, + ) + + // We haven't run reconcile yet so ensure it's created in Consul. + { + if in.ConsulNamespace != "default" { + _, _, err := consulClient.Namespaces().Create(&capi.Namespace{ + Name: in.ConsulNamespace, + }, nil) + req.NoError(err) + } + + err := in.WriteConfigEntryFunc(consulClient, in.ConsulNamespace) + req.NoError(err) + } + + // Now update it. + { + // First get it so we have the latest revision number. + err := fakeClient.Get(ctx, types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: in.KubeResource.KubernetesName(), + }, in.KubeResource) + req.NoError(err) + + // Update the resource. + err = in.UpdateResourceFunc(fakeClient, ctx, in.KubeResource) + req.NoError(err) + + resp, err := r.Reconcile(ctx, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: in.KubeResource.KubernetesName(), + }, + }) + req.NoError(err) + req.False(resp.Requeue) + + cfg, _, err := consulClient.ConfigEntries().Get(in.ConsulKind, in.KubeResource.ConsulName(), &capi.QueryOptions{ + Namespace: in.ConsulNamespace, + }) + req.NoError(err) + req.True(in.AssertValidConfigFunc(cfg)) + } + }) + } + } +} + +func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T) { + tt.Parallel() + + cases := map[string]struct { + Mirror bool + MirrorPrefix string + SourceKubeNS string + DestConsulNS string + ExpConsulNS string + }{ + "SourceKubeNS=default, DestConsulNS=default": { + SourceKubeNS: "default", + DestConsulNS: "default", + ExpConsulNS: "default", + }, + "SourceKubeNS=kube, DestConsulNS=default": { + SourceKubeNS: "kube", + DestConsulNS: "default", + ExpConsulNS: "default", + }, + "SourceKubeNS=default, DestConsulNS=other": { + SourceKubeNS: "default", + DestConsulNS: "other", + ExpConsulNS: "other", + }, + "SourceKubeNS=kube, DestConsulNS=other": { + SourceKubeNS: "kube", + DestConsulNS: "other", + ExpConsulNS: "other", + }, + "SourceKubeNS=default, Mirror=true": { + SourceKubeNS: "default", + Mirror: true, + ExpConsulNS: "default", + }, + "SourceKubeNS=kube, Mirror=true": { + SourceKubeNS: "kube", + Mirror: true, + ExpConsulNS: "kube", + }, + "SourceKubeNS=default, Mirror=true, Prefix=prefix": { + SourceKubeNS: "default", + Mirror: true, + MirrorPrefix: "prefix-", + ExpConsulNS: "prefix-default", + }, + } + + for name, c := range cases { + configEntryKinds := map[string]struct { + ConsulKind string + ConsulNamespace string + KubeResource common.ConfigEntryResource + GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler + WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error + }{ + "namespaced": { + ConsulKind: capi.ServiceDefaults, + // Create it with the deletion timestamp set to mimic that it's already + // been marked for deletion. + KubeResource: &v1alpha1.ServiceDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Spec: v1alpha1.ServiceDefaultsSpec{ + Protocol: "http", + }, + }, + ConsulNamespace: c.ExpConsulNS, + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ServiceDefaultsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { + _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceConfigEntry{ + Kind: capi.ServiceDefaults, + Name: "foo", + Protocol: "http", + }, &capi.WriteOptions{Namespace: namespace}) + return err + }, + }, + "global": { + ConsulKind: capi.ProxyDefaults, + // Create it with the deletion timestamp set to mimic that it's already + // been marked for deletion. + KubeResource: &v1alpha1.ProxyDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.Global, + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Spec: v1alpha1.ProxyDefaultsSpec{ + MeshGateway: v1alpha1.MeshGateway{ + Mode: "remote", + }, + }, + }, + ConsulNamespace: common.DefaultConsulNamespace, + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ProxyDefaultsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { + _, _, err := consulClient.ConfigEntries().Set(&capi.ProxyConfigEntry{ + Kind: capi.ProxyDefaults, + Name: common.Global, + MeshGateway: capi.MeshGatewayConfig{ + Mode: capi.MeshGatewayModeRemote, + }, + }, &capi.WriteOptions{Namespace: namespace}) + return err + }, + }, + "intentions": { + ConsulKind: capi.ServiceIntentions, + // Create it with the deletion timestamp set to mimic that it's already + // been marked for deletion. + KubeResource: &v1alpha1.ServiceIntentions{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Spec: v1alpha1.ServiceIntentionsSpec{ + Destination: v1alpha1.IntentionDestination{ + Name: "test", + Namespace: c.ExpConsulNS, + }, + Sources: v1alpha1.SourceIntentions{ + &v1alpha1.SourceIntention{ + Name: "bar", + Namespace: "baz", + Action: "deny", + }, + }, + }, + }, + ConsulNamespace: c.ExpConsulNS, + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { + return &controller.ServiceIntentionsController{ + Client: client, + Log: logger, + Scheme: scheme, + ConfigEntryController: cont, + } + }, + WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { + _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceIntentionsConfigEntry{ + Kind: capi.ServiceIntentions, + Name: "test", + Sources: []*capi.SourceIntention{ + { + Name: "bar", + Namespace: "baz", + Action: capi.IntentionActionDeny, + }, + }, + }, &capi.WriteOptions{Namespace: namespace}) + return err + }, + }, + } + for kind, in := range configEntryKinds { + tt.Run(fmt.Sprintf("%s : %s", name, kind), func(t *testing.T) { + req := require.New(t) + + s := runtime.NewScheme() + s.AddKnownTypes(v1alpha1.GroupVersion, in.KubeResource) + + testClient := test.TestServerWithMockConnMgrWatcher(t, nil) + testClient.TestServer.WaitForServiceIntentions(t) + consulClient := testClient.APIClient + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(in.KubeResource).Build() + + r := in.GetControllerFunc( + fakeClient, + logrtest.New(t), + s, + &controller.ConfigEntryController{ + ConsulClientConfig: testClient.Cfg, + ConsulServerConnMgr: testClient.Watcher, + EnableConsulNamespaces: true, + EnableNSMirroring: c.Mirror, + NSMirroringPrefix: c.MirrorPrefix, + ConsulDestinationNamespace: c.DestConsulNS, + }, + ) + + // We haven't run reconcile yet so ensure it's created in Consul. + { + if in.ConsulNamespace != "default" { + _, _, err := consulClient.Namespaces().Create(&capi.Namespace{ + Name: in.ConsulNamespace, + }, nil) + req.NoError(err) + } + + err := in.WriteConfigEntryFunc(consulClient, in.ConsulNamespace) + req.NoError(err) + } + + // Now run reconcile. It's marked for deletion so this should delete it. + { + resp, err := r.Reconcile(context.Background(), ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: in.KubeResource.KubernetesName(), + }, + }) + req.NoError(err) + req.False(resp.Requeue) + + _, _, err = consulClient.ConfigEntries().Get(in.ConsulKind, in.KubeResource.ConsulName(), &capi.QueryOptions{ + Namespace: in.ConsulNamespace, + }) + req.EqualError(err, fmt.Sprintf(`Unexpected response code: 404 (Config entry not found for "%s" / "%s")`, in.ConsulKind, in.KubeResource.ConsulName())) + } + }) + } + } +} diff --git a/control-plane/controllers/configentry_controller_test.go b/control-plane/controller/configentry_controller_test.go similarity index 85% rename from control-plane/controllers/configentry_controller_test.go rename to control-plane/controller/configentry_controller_test.go index 071d67ca6f..3b8ba9e561 100644 --- a/control-plane/controllers/configentry_controller_test.go +++ b/control-plane/controller/configentry_controller_test.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" @@ -22,7 +19,6 @@ import ( corev1 "k8s.io/api/core/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" @@ -432,50 +428,6 @@ func TestConfigEntryControllers_createsConfigEntry(t *testing.T) { require.Equal(t, "sni", resource.Services[0].SNI) }, }, - { - kubeKind: "JWTProvider", - consulKind: capi.JWTProvider, - configEntryResource: &v1alpha1.JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwt-provider", - Namespace: kubeNS, - }, - Spec: v1alpha1.JWTProviderSpec{ - JSONWebKeySet: &v1alpha1.JSONWebKeySet{ - Local: &v1alpha1.LocalJWKS{ - Filename: "jwks.txt", - }, - }, - Issuer: "test-issuer", - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &JWTProviderController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - jwt, ok := consulEntry.(*capi.JWTProviderConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, capi.JWTProvider, jwt.Kind) - require.Equal(t, "test-jwt-provider", jwt.Name) - require.Equal(t, - &capi.JSONWebKeySet{ - Local: &capi.LocalJWKS{ - Filename: "jwks.txt", - }, - }, - jwt.JSONWebKeySet, - ) - require.Equal(t, "test-issuer", jwt.Issuer) - }, - }, } for _, c := range cases { @@ -953,56 +905,6 @@ func TestConfigEntryControllers_updatesConfigEntry(t *testing.T) { require.Equal(t, "new-sni", resource.Services[0].SNI) }, }, - { - kubeKind: "JWTProvider", - consulKind: capi.JWTProvider, - configEntryResource: &v1alpha1.JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-jwt-provider", - Namespace: kubeNS, - }, - Spec: v1alpha1.JWTProviderSpec{ - JSONWebKeySet: &v1alpha1.JSONWebKeySet{ - Local: &v1alpha1.LocalJWKS{ - Filename: "jwks.txt", - }, - }, - Issuer: "test-issuer", - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &JWTProviderController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - updateF: func(resource common.ConfigEntryResource) { - jwt := resource.(*v1alpha1.JWTProvider) - jwt.Spec.Issuer = "test-updated-issuer" - jwt.Spec.Audiences = []string{"aud1"} - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - jwt, ok := consulEntry.(*capi.JWTProviderConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, capi.JWTProvider, jwt.Kind) - require.Equal(t, "test-jwt-provider", jwt.Name) - require.Equal(t, - &capi.JSONWebKeySet{ - Local: &capi.LocalJWKS{ - Filename: "jwks.txt", - }, - }, - jwt.JSONWebKeySet, - ) - require.Equal(t, "test-updated-issuer", jwt.Issuer) - require.Equal(t, []string{"aud1"}, jwt.Audiences) - }, - }, } for _, c := range cases { @@ -1404,37 +1306,6 @@ func TestConfigEntryControllers_deletesConfigEntry(t *testing.T) { } }, }, - { - kubeKind: "JWTProvider", - consulKind: capi.JWTProvider, - configEntryResourceWithDeletion: &v1alpha1.JWTProvider{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.Global, - Namespace: kubeNS, - DeletionTimestamp: &metav1.Time{Time: time.Now()}, - Finalizers: []string{FinalizerName}, - }, - Spec: v1alpha1.JWTProviderSpec{ - JSONWebKeySet: &v1alpha1.JSONWebKeySet{ - Local: &v1alpha1.LocalJWKS{ - Filename: "jwks.txt", - }, - }, - Issuer: "test-issuer", - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &JWTProviderController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - }, } for _, c := range cases { @@ -2017,235 +1888,3 @@ func TestConfigEntryController_Migration(t *testing.T) { }) } } - -func TestConfigEntryControllers_assignServiceVirtualIP(t *testing.T) { - t.Parallel() - kubeNS := "default" - - cases := []struct { - name string - kubeKind string - consulKind string - consulPrereqs []capi.ConfigEntry - configEntryResource common.ConfigEntryResource - service corev1.Service - reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) Controller - expectErr bool - }{ - { - name: "ServiceResolver no error and vip should be assigned", - kubeKind: "ServiceResolver", - consulKind: capi.ServiceRouter, - configEntryResource: &v1alpha1.ServiceRouter{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.ServiceRouterSpec{ - Routes: []v1alpha1.ServiceRoute{ - { - Match: &v1alpha1.ServiceRouteMatch{ - HTTP: &v1alpha1.ServiceRouteHTTPMatch{ - PathPrefix: "/admin", - }, - }, - }, - }, - }, - }, - service: corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: corev1.ServiceSpec{ - ClusterIP: "10.0.0.1", - Ports: []corev1.ServicePort{ - { - Port: 8081, - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) Controller { - return &ServiceRouterController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - expectErr: false, - }, - { - name: "ServiceRouter no error and vip should be assigned", - kubeKind: "ServiceRouter", - consulKind: capi.ServiceRouter, - consulPrereqs: []capi.ConfigEntry{ - &capi.ServiceConfigEntry{ - Kind: capi.ServiceDefaults, - Name: "bar", - Protocol: "http", - }, - }, - configEntryResource: &v1alpha1.ServiceRouter{ - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: kubeNS, - }, - Spec: v1alpha1.ServiceRouterSpec{ - Routes: []v1alpha1.ServiceRoute{ - { - Match: &v1alpha1.ServiceRouteMatch{ - HTTP: &v1alpha1.ServiceRouteHTTPMatch{ - PathPrefix: "/admin", - }, - }, - }, - }, - }, - }, - service: corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: kubeNS, - }, - Spec: corev1.ServiceSpec{ - ClusterIP: "10.0.0.2", - Ports: []corev1.ServicePort{ - { - Port: 8081, - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) Controller { - return &ServiceRouterController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - expectErr: false, - }, - { - name: "ServiceRouter should fail because service does not have a valid IP address", - kubeKind: "ServiceRouter", - consulKind: capi.ServiceRouter, - consulPrereqs: []capi.ConfigEntry{ - &capi.ServiceConfigEntry{ - Kind: capi.ServiceDefaults, - Name: "bar", - Protocol: "http", - }, - }, - configEntryResource: &v1alpha1.ServiceRouter{ - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: kubeNS, - }, - Spec: v1alpha1.ServiceRouterSpec{ - Routes: []v1alpha1.ServiceRoute{ - { - Match: &v1alpha1.ServiceRouteMatch{ - HTTP: &v1alpha1.ServiceRouteHTTPMatch{ - PathPrefix: "/admin", - }, - }, - }, - }, - }, - }, - service: corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: kubeNS, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) Controller { - return &ServiceRouterController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - expectErr: true, - }, - { - name: "ServiceSplitter no error because a matching service does not exist", - kubeKind: "ServiceSplitter", - consulKind: capi.ServiceSplitter, - consulPrereqs: []capi.ConfigEntry{ - &capi.ServiceConfigEntry{ - Kind: capi.ServiceDefaults, - Name: "foo", - Protocol: "http", - }, - }, - configEntryResource: &v1alpha1.ServiceSplitter{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.ServiceSplitterSpec{ - Splits: []v1alpha1.ServiceSplit{ - { - Weight: 100, - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) Controller { - return &ServiceSplitterController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - expectErr: false, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - ctx := context.Background() - - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, c.configEntryResource) - s.AddKnownTypes(schema.GroupVersion{Group: "", Version: "v1"}, &corev1.Service{}) - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(&c.service, c.configEntryResource).Build() - - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - testClient.TestServer.WaitForLeader(t) - consulClient := testClient.APIClient - - ctrl := c.reconciler(fakeClient, testClient.Cfg, testClient.Watcher, logrtest.New(t)) - namespacedName := types.NamespacedName{ - Namespace: kubeNS, - Name: c.configEntryResource.KubernetesName(), - } - - err := assignServiceVirtualIP(ctx, ctrl.Logger(namespacedName), consulClient, ctrl, namespacedName, c.configEntryResource, "dc1") - if err != nil { - require.True(t, c.expectErr) - } else { - require.False(t, c.expectErr) - } - }) - } -} diff --git a/control-plane/controllers/exportedservices_controller.go b/control-plane/controller/exportedservices_controller.go similarity index 94% rename from control-plane/controllers/exportedservices_controller.go rename to control-plane/controller/exportedservices_controller.go index 2e82ed0eae..9466360207 100644 --- a/control-plane/controllers/exportedservices_controller.go +++ b/control-plane/controller/exportedservices_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/exportedservices_controller_ent_test.go b/control-plane/controller/exportedservices_controller_ent_test.go similarity index 93% rename from control-plane/controllers/exportedservices_controller_ent_test.go rename to control-plane/controller/exportedservices_controller_ent_test.go index 94a605eab4..29b4e006f1 100644 --- a/control-plane/controllers/exportedservices_controller_ent_test.go +++ b/control-plane/controller/exportedservices_controller_ent_test.go @@ -1,9 +1,6 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise -package controllers_test +package controller_test import ( "context" @@ -11,10 +8,10 @@ import ( "testing" "time" - logrtest "github.com/go-logr/logr/testing" + logrtest "github.com/go-logr/logr/testr" "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/controllers" + "github.com/hashicorp/consul-k8s/control-plane/controller" "github.com/hashicorp/consul-k8s/control-plane/helper/test" capi "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" @@ -103,11 +100,11 @@ func TestExportedServicesController_createsExportedServices(tt *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controllers.ExportedServicesController{ + controller := &controller.ExportedServicesController{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), Scheme: s, - ConfigEntryController: &controllers.ConfigEntryController{ + ConfigEntryController: &controller.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -195,7 +192,7 @@ func TestExportedServicesController_updatesExportedServices(tt *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{controller.FinalizerName}, }, Spec: v1alpha1.ExportedServicesSpec{ Services: []v1alpha1.ExportedService{ @@ -218,11 +215,11 @@ func TestExportedServicesController_updatesExportedServices(tt *testing.T) { consulClient := testClient.APIClient fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controllers.ExportedServicesController{ + controller := &controller.ExportedServicesController{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), Scheme: s, - ConfigEntryController: &controllers.ConfigEntryController{ + ConfigEntryController: &controller.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -332,7 +329,7 @@ func TestExportedServicesController_deletesExportedServices(tt *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{controller.FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ExportedServicesSpec{ @@ -356,11 +353,11 @@ func TestExportedServicesController_deletesExportedServices(tt *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controllers.ExportedServicesController{ + controller := &controller.ExportedServicesController{ Client: fakeClient, - Log: logrtest.NewTestLogger(t), + Log: logrtest.New(t), Scheme: s, - ConfigEntryController: &controllers.ConfigEntryController{ + ConfigEntryController: &controller.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, diff --git a/control-plane/controllers/ingressgateway_controller.go b/control-plane/controller/ingressgateway_controller.go similarity index 94% rename from control-plane/controllers/ingressgateway_controller.go rename to control-plane/controller/ingressgateway_controller.go index 5bcb39bc2a..5a6a07776b 100644 --- a/control-plane/controllers/ingressgateway_controller.go +++ b/control-plane/controller/ingressgateway_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/mesh_controller.go b/control-plane/controller/mesh_controller.go similarity index 93% rename from control-plane/controllers/mesh_controller.go rename to control-plane/controller/mesh_controller.go index ba78f0c144..94b0df6a5e 100644 --- a/control-plane/controllers/mesh_controller.go +++ b/control-plane/controller/mesh_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/proxydefaults_controller.go b/control-plane/controller/proxydefaults_controller.go similarity index 93% rename from control-plane/controllers/proxydefaults_controller.go rename to control-plane/controller/proxydefaults_controller.go index 882843bf9e..fe929c1bf1 100644 --- a/control-plane/controllers/proxydefaults_controller.go +++ b/control-plane/controller/proxydefaults_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/servicedefaults_controller.go b/control-plane/controller/servicedefaults_controller.go similarity index 94% rename from control-plane/controllers/servicedefaults_controller.go rename to control-plane/controller/servicedefaults_controller.go index 0496788bb3..e58e186234 100644 --- a/control-plane/controllers/servicedefaults_controller.go +++ b/control-plane/controller/servicedefaults_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/serviceintentions_controller.go b/control-plane/controller/serviceintentions_controller.go similarity index 94% rename from control-plane/controllers/serviceintentions_controller.go rename to control-plane/controller/serviceintentions_controller.go index 4461a82dd6..e5bfab959e 100644 --- a/control-plane/controllers/serviceintentions_controller.go +++ b/control-plane/controller/serviceintentions_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/serviceresolver_controller.go b/control-plane/controller/serviceresolver_controller.go similarity index 94% rename from control-plane/controllers/serviceresolver_controller.go rename to control-plane/controller/serviceresolver_controller.go index cfc5c31ca3..3019369dc6 100644 --- a/control-plane/controllers/serviceresolver_controller.go +++ b/control-plane/controller/serviceresolver_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/servicerouter_controller.go b/control-plane/controller/servicerouter_controller.go similarity index 94% rename from control-plane/controllers/servicerouter_controller.go rename to control-plane/controller/servicerouter_controller.go index a0b3bc0581..9c435169f4 100644 --- a/control-plane/controllers/servicerouter_controller.go +++ b/control-plane/controller/servicerouter_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/servicesplitter_controller.go b/control-plane/controller/servicesplitter_controller.go similarity index 94% rename from control-plane/controllers/servicesplitter_controller.go rename to control-plane/controller/servicesplitter_controller.go index b733fb9cb5..f977301afe 100644 --- a/control-plane/controllers/servicesplitter_controller.go +++ b/control-plane/controller/servicesplitter_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/terminatinggateway_controller.go b/control-plane/controller/terminatinggateway_controller.go similarity index 94% rename from control-plane/controllers/terminatinggateway_controller.go rename to control-plane/controller/terminatinggateway_controller.go index d73d4e043c..159f8ff8c1 100644 --- a/control-plane/controllers/terminatinggateway_controller.go +++ b/control-plane/controller/terminatinggateway_controller.go @@ -1,7 +1,4 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers +package controller import ( "context" diff --git a/control-plane/controllers/configentry_controller_ent_test.go b/control-plane/controllers/configentry_controller_ent_test.go deleted file mode 100644 index 14ae477a56..0000000000 --- a/control-plane/controllers/configentry_controller_ent_test.go +++ /dev/null @@ -1,1387 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -//go:build enterprise - -package controllers - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/go-logr/logr" - logrtest "github.com/go-logr/logr/testing" - "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/consul" - "github.com/hashicorp/consul-k8s/control-plane/helper/test" - capi "github.com/hashicorp/consul/api" - "github.com/stretchr/testify/require" - corev1 "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" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -// NOTE: We're not testing each controller type here because that's mostly done in -// the OSS tests and it would result in too many permutations. Instead -// we're only testing with the ServiceDefaults and ProxyDefaults controllers which -// will exercise all the namespaces code for config entries that are namespaced and those that -// exist in the global namespace. -// We also test Enterprise only features like SamenessGroups. - -func TestConfigEntryController_createsEntConfigEntry(t *testing.T) { - t.Parallel() - kubeNS := "default" - - cases := []struct { - kubeKind string - consulKind string - consulPrereqs []capi.ConfigEntry - configEntryResource common.ConfigEntryResource - reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) testReconciler - compare func(t *testing.T, consul capi.ConfigEntry) - }{ - { - kubeKind: "SamenessGroup", - consulKind: capi.SamenessGroup, - configEntryResource: &v1alpha1.SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []v1alpha1.SamenessGroupMember{ - { - Peer: "dc1", - Partition: "", - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, true, resource.DefaultForFailover) - require.Equal(t, true, resource.IncludeLocal) - require.Equal(t, "dc1", resource.Members[0].Peer) - require.Equal(t, "", resource.Members[0].Partition) - }, - }, - { - kubeKind: "ControlPlaneRequestLimit", - consulKind: capi.RateLimitIPConfig, - configEntryResource: &v1alpha1.ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ACL: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Catalog: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConfigEntry: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConnectCA: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Coordinate: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - DiscoveryChain: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Health: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Intention: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - KV: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Tenancy: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - PreparedQuery: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Session: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Txn: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &ControlPlaneRequestLimitController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - resource, ok := consulEntry.(*capi.RateLimitIPConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, "permissive", resource.Mode) - require.Equal(t, 100.0, resource.ReadRate) - require.Equal(t, 100.0, resource.WriteRate) - require.Equal(t, 100.0, resource.ACL.ReadRate) - require.Equal(t, 100.0, resource.ACL.WriteRate) - require.Equal(t, 100.0, resource.Catalog.ReadRate) - require.Equal(t, 100.0, resource.Catalog.WriteRate) - require.Equal(t, 100.0, resource.ConfigEntry.ReadRate) - require.Equal(t, 100.0, resource.ConfigEntry.WriteRate) - require.Equal(t, 100.0, resource.ConnectCA.ReadRate) - require.Equal(t, 100.0, resource.ConnectCA.WriteRate) - require.Equal(t, 100.0, resource.Coordinate.ReadRate) - require.Equal(t, 100.0, resource.Coordinate.WriteRate) - require.Equal(t, 100.0, resource.DiscoveryChain.ReadRate) - require.Equal(t, 100.0, resource.DiscoveryChain.WriteRate) - require.Equal(t, 100.0, resource.Health.ReadRate) - require.Equal(t, 100.0, resource.Health.WriteRate) - require.Equal(t, 100.0, resource.Intention.ReadRate) - require.Equal(t, 100.0, resource.Intention.WriteRate) - require.Equal(t, 100.0, resource.KV.ReadRate) - require.Equal(t, 100.0, resource.KV.WriteRate) - require.Equal(t, 100.0, resource.Tenancy.ReadRate) - require.Equal(t, 100.0, resource.Tenancy.WriteRate) - require.Equal(t, 100.0, resource.PreparedQuery.ReadRate) - require.Equal(t, 100.0, resource.PreparedQuery.WriteRate) - require.Equal(t, 100.0, resource.Session.ReadRate) - require.Equal(t, 100.0, resource.Session.WriteRate) - require.Equal(t, 100.0, resource.Txn.ReadRate) - require.Equal(t, 100.0, resource.Txn.WriteRate, 100.0) - }, - }, - } - - for _, c := range cases { - t.Run(c.kubeKind, func(t *testing.T) { - req := require.New(t) - ctx := context.Background() - - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, c.configEntryResource) - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.configEntryResource).Build() - - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - testClient.TestServer.WaitForServiceIntentions(t) - consulClient := testClient.APIClient - - for _, configEntry := range c.consulPrereqs { - written, _, err := consulClient.ConfigEntries().Set(configEntry, nil) - req.NoError(err) - req.True(written) - } - - r := c.reconciler(fakeClient, testClient.Cfg, testClient.Watcher, logrtest.NewTestLogger(t)) - namespacedName := types.NamespacedName{ - Namespace: kubeNS, - Name: c.configEntryResource.KubernetesName(), - } - resp, err := r.Reconcile(ctx, ctrl.Request{ - NamespacedName: namespacedName, - }) - req.NoError(err) - req.False(resp.Requeue) - - cfg, _, err := consulClient.ConfigEntries().Get(c.consulKind, c.configEntryResource.ConsulName(), nil) - req.NoError(err) - req.Equal(c.configEntryResource.ConsulName(), cfg.GetName()) - c.compare(t, cfg) - - // Check that the status is "synced". - err = fakeClient.Get(ctx, namespacedName, c.configEntryResource) - req.NoError(err) - req.Equal(corev1.ConditionTrue, c.configEntryResource.SyncedConditionStatus()) - - // Check that the finalizer is added. - req.Contains(c.configEntryResource.Finalizers(), FinalizerName) - }) - } -} - -func TestConfigEntryController_updatesEntConfigEntry(t *testing.T) { - t.Parallel() - kubeNS := "default" - - cases := []struct { - kubeKind string - consulKind string - consulPrereqs []capi.ConfigEntry - configEntryResource common.ConfigEntryResource - reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) testReconciler - updateF func(common.ConfigEntryResource) - compare func(t *testing.T, consul capi.ConfigEntry) - }{ - { - kubeKind: "SamenessGroup", - consulKind: capi.SamenessGroup, - configEntryResource: &v1alpha1.SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []v1alpha1.SamenessGroupMember{ - { - Peer: "dc1", - Partition: "", - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - updateF: func(resource common.ConfigEntryResource) { - sg := resource.(*v1alpha1.SamenessGroup) - sg.Spec.IncludeLocal = false - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, true, resource.DefaultForFailover) - require.Equal(t, false, resource.IncludeLocal) - require.Equal(t, "dc1", resource.Members[0].Peer) - require.Equal(t, "", resource.Members[0].Partition) - }, - }, - { - kubeKind: "ControlPlaneRequestLimit", - consulKind: capi.RateLimitIPConfig, - configEntryResource: &v1alpha1.ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ACL: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Catalog: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConfigEntry: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConnectCA: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Coordinate: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - DiscoveryChain: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Health: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Intention: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - KV: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Tenancy: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - PreparedQuery: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Session: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Txn: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &ControlPlaneRequestLimitController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - updateF: func(resource common.ConfigEntryResource) { - ipRateLimit := resource.(*v1alpha1.ControlPlaneRequestLimit) - ipRateLimit.Spec.Mode = "enforcing" - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - resource, ok := consulEntry.(*capi.RateLimitIPConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, "enforcing", resource.Mode) - require.Equal(t, 100.0, resource.ReadRate) - require.Equal(t, 100.0, resource.WriteRate) - require.Equal(t, 100.0, resource.ACL.ReadRate) - require.Equal(t, 100.0, resource.ACL.WriteRate) - require.Equal(t, 100.0, resource.Catalog.ReadRate) - require.Equal(t, 100.0, resource.Catalog.WriteRate) - require.Equal(t, 100.0, resource.ConfigEntry.ReadRate) - require.Equal(t, 100.0, resource.ConfigEntry.WriteRate) - require.Equal(t, 100.0, resource.ConnectCA.ReadRate) - require.Equal(t, 100.0, resource.ConnectCA.WriteRate) - require.Equal(t, 100.0, resource.Coordinate.ReadRate) - require.Equal(t, 100.0, resource.Coordinate.WriteRate) - require.Equal(t, 100.0, resource.DiscoveryChain.ReadRate) - require.Equal(t, 100.0, resource.DiscoveryChain.WriteRate) - require.Equal(t, 100.0, resource.Health.ReadRate) - require.Equal(t, 100.0, resource.Health.WriteRate) - require.Equal(t, 100.0, resource.Intention.ReadRate) - require.Equal(t, 100.0, resource.Intention.WriteRate) - require.Equal(t, 100.0, resource.KV.ReadRate) - require.Equal(t, 100.0, resource.KV.WriteRate) - require.Equal(t, 100.0, resource.Tenancy.ReadRate) - require.Equal(t, 100.0, resource.Tenancy.WriteRate) - require.Equal(t, 100.0, resource.PreparedQuery.ReadRate) - require.Equal(t, 100.0, resource.PreparedQuery.WriteRate) - require.Equal(t, 100.0, resource.Session.ReadRate) - require.Equal(t, 100.0, resource.Session.WriteRate) - require.Equal(t, 100.0, resource.Txn.ReadRate) - require.Equal(t, 100.0, resource.Txn.WriteRate) - }, - }, - } - - for _, c := range cases { - t.Run(c.kubeKind, func(t *testing.T) { - req := require.New(t) - ctx := context.Background() - - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, c.configEntryResource) - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.configEntryResource).Build() - - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - testClient.TestServer.WaitForServiceIntentions(t) - consulClient := testClient.APIClient - - // Create any prereqs. - for _, configEntry := range c.consulPrereqs { - written, _, err := consulClient.ConfigEntries().Set(configEntry, nil) - req.NoError(err) - req.True(written) - } - - // We haven't run reconcile yet so we must create the config entry - // in Consul ourselves. - { - written, _, err := consulClient.ConfigEntries().Set(c.configEntryResource.ToConsul(datacenterName), nil) - req.NoError(err) - req.True(written) - } - - // Now run reconcile which should update the entry in Consul. - { - namespacedName := types.NamespacedName{ - Namespace: kubeNS, - Name: c.configEntryResource.KubernetesName(), - } - // First get it so we have the latest revision number. - err := fakeClient.Get(ctx, namespacedName, c.configEntryResource) - req.NoError(err) - - // Update the entry in Kube and run reconcile. - c.updateF(c.configEntryResource) - err = fakeClient.Update(ctx, c.configEntryResource) - req.NoError(err) - r := c.reconciler(fakeClient, testClient.Cfg, testClient.Watcher, logrtest.NewTestLogger(t)) - resp, err := r.Reconcile(ctx, ctrl.Request{ - NamespacedName: namespacedName, - }) - req.NoError(err) - req.False(resp.Requeue) - - // Now check that the object in Consul is as expected. - cfg, _, err := consulClient.ConfigEntries().Get(c.consulKind, c.configEntryResource.ConsulName(), nil) - req.NoError(err) - req.Equal(c.configEntryResource.ConsulName(), cfg.GetName()) - c.compare(t, cfg) - } - }) - } -} - -func TestConfigEntryController_deletesEntConfigEntry(t *testing.T) { - t.Parallel() - kubeNS := "default" - - cases := []struct { - kubeKind string - consulKind string - consulPrereq []capi.ConfigEntry - configEntryResourceWithDeletion common.ConfigEntryResource - reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) testReconciler - }{ - { - kubeKind: "SamenessGroup", - consulKind: capi.SamenessGroup, - configEntryResourceWithDeletion: &v1alpha1.SamenessGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - DeletionTimestamp: &metav1.Time{Time: time.Now()}, - Finalizers: []string{FinalizerName}, - }, - Spec: v1alpha1.SamenessGroupSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []v1alpha1.SamenessGroupMember{ - { - Peer: "dc1", - Partition: "", - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - }, - { - - kubeKind: "ControlPlaneRequestLimit", - consulKind: capi.RateLimitIPConfig, - configEntryResourceWithDeletion: &v1alpha1.ControlPlaneRequestLimit{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - DeletionTimestamp: &metav1.Time{Time: time.Now()}, - Finalizers: []string{FinalizerName}, - }, - Spec: v1alpha1.ControlPlaneRequestLimitSpec{ - Mode: "permissive", - ReadWriteRatesConfig: v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ACL: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Catalog: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConfigEntry: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - ConnectCA: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Coordinate: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - DiscoveryChain: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Health: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Intention: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - KV: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Tenancy: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - PreparedQuery: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Session: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - Txn: &v1alpha1.ReadWriteRatesConfig{ - ReadRate: 100.0, - WriteRate: 100.0, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &ControlPlaneRequestLimitController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - }, - } - - for _, c := range cases { - t.Run(c.kubeKind, func(t *testing.T) { - req := require.New(t) - - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, c.configEntryResourceWithDeletion) - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.configEntryResourceWithDeletion).Build() - - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - testClient.TestServer.WaitForServiceIntentions(t) - consulClient := testClient.APIClient - - // Create any prereqs. - for _, configEntry := range c.consulPrereq { - written, _, err := consulClient.ConfigEntries().Set(configEntry, nil) - req.NoError(err) - req.True(written) - } - - // We haven't run reconcile yet so we must create the config entry - // in Consul ourselves. - { - written, _, err := consulClient.ConfigEntries().Set(c.configEntryResourceWithDeletion.ToConsul(datacenterName), nil) - req.NoError(err) - req.True(written) - } - - // Now run reconcile. It's marked for deletion so this should delete it. - { - namespacedName := types.NamespacedName{ - Namespace: kubeNS, - Name: c.configEntryResourceWithDeletion.KubernetesName(), - } - r := c.reconciler(fakeClient, testClient.Cfg, testClient.Watcher, logrtest.NewTestLogger(t)) - resp, err := r.Reconcile(context.Background(), ctrl.Request{ - NamespacedName: namespacedName, - }) - req.NoError(err) - req.False(resp.Requeue) - - _, _, err = consulClient.ConfigEntries().Get(c.consulKind, c.configEntryResourceWithDeletion.ConsulName(), nil) - req.EqualError(err, - fmt.Sprintf("Unexpected response code: 404 (Config entry not found for %q / %q)", - c.consulKind, c.configEntryResourceWithDeletion.ConsulName())) - } - }) - } -} - -func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T) { - tt.Parallel() - - cases := map[string]struct { - Mirror bool - MirrorPrefix string - SourceKubeNS string - DestConsulNS string - ExpConsulNS string - }{ - "SourceKubeNS=default, DestConsulNS=default": { - SourceKubeNS: "default", - DestConsulNS: "default", - ExpConsulNS: "default", - }, - "SourceKubeNS=kube, DestConsulNS=default": { - SourceKubeNS: "kube", - DestConsulNS: "default", - ExpConsulNS: "default", - }, - "SourceKubeNS=default, DestConsulNS=other": { - SourceKubeNS: "default", - DestConsulNS: "other", - ExpConsulNS: "other", - }, - "SourceKubeNS=kube, DestConsulNS=other": { - SourceKubeNS: "kube", - DestConsulNS: "other", - ExpConsulNS: "other", - }, - "SourceKubeNS=default, Mirror=true": { - SourceKubeNS: "default", - Mirror: true, - ExpConsulNS: "default", - }, - "SourceKubeNS=kube, Mirror=true": { - SourceKubeNS: "kube", - Mirror: true, - ExpConsulNS: "kube", - }, - "SourceKubeNS=default, Mirror=true, Prefix=prefix": { - SourceKubeNS: "default", - Mirror: true, - MirrorPrefix: "prefix-", - ExpConsulNS: "prefix-default", - }, - } - - for name, c := range cases { - configEntryKinds := map[string]struct { - ConsulKind string - ConsulNamespace string - KubeResource common.ConfigEntryResource - GetController func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler - AssertValidConfig func(entry capi.ConfigEntry) bool - }{ - "namespaced": { - ConsulKind: capi.ServiceDefaults, - KubeResource: &v1alpha1.ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: c.SourceKubeNS, - }, - Spec: v1alpha1.ServiceDefaultsSpec{ - Protocol: "http", - }, - }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ServiceDefaultsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - AssertValidConfig: func(cfg capi.ConfigEntry) bool { - configEntry, ok := cfg.(*capi.ServiceConfigEntry) - if !ok { - return false - } - return configEntry.Protocol == "http" - }, - ConsulNamespace: c.ExpConsulNS, - }, - "global": { - ConsulKind: capi.ProxyDefaults, - KubeResource: &v1alpha1.ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.Global, - Namespace: c.SourceKubeNS, - }, - Spec: v1alpha1.ProxyDefaultsSpec{ - MeshGateway: v1alpha1.MeshGateway{ - Mode: "remote", - }, - }, - }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ProxyDefaultsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - AssertValidConfig: func(cfg capi.ConfigEntry) bool { - configEntry, ok := cfg.(*capi.ProxyConfigEntry) - if !ok { - return false - } - return configEntry.MeshGateway.Mode == capi.MeshGatewayModeRemote - }, - ConsulNamespace: common.DefaultConsulNamespace, - }, - "intentions": { - ConsulKind: capi.ServiceIntentions, - KubeResource: &v1alpha1.ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: c.SourceKubeNS, - }, - Spec: v1alpha1.ServiceIntentionsSpec{ - Destination: v1alpha1.IntentionDestination{ - Name: "test", - Namespace: c.ExpConsulNS, - }, - Sources: v1alpha1.SourceIntentions{ - &v1alpha1.SourceIntention{ - Name: "baz", - Namespace: "bar", - Action: "allow", - }, - }, - }, - }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ServiceIntentionsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - AssertValidConfig: func(cfg capi.ConfigEntry) bool { - configEntry, ok := cfg.(*capi.ServiceIntentionsConfigEntry) - if !ok { - return false - } - return configEntry.Sources[0].Action == capi.IntentionActionAllow - }, - ConsulNamespace: c.ExpConsulNS, - }, - } - - for kind, in := range configEntryKinds { - tt.Run(fmt.Sprintf("%s : %s", name, kind), func(t *testing.T) { - req := require.New(t) - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, in.KubeResource) - ctx := context.Background() - - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - testClient.TestServer.WaitForServiceIntentions(t) - consulClient := testClient.APIClient - - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(in.KubeResource).Build() - - r := in.GetController( - fakeClient, - logrtest.NewTestLogger(t), - s, - &ConfigEntryController{ - ConsulClientConfig: testClient.Cfg, - ConsulServerConnMgr: testClient.Watcher, - EnableConsulNamespaces: true, - EnableNSMirroring: c.Mirror, - NSMirroringPrefix: c.MirrorPrefix, - ConsulDestinationNamespace: c.DestConsulNS, - }, - ) - - resp, err := r.Reconcile(ctx, ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: c.SourceKubeNS, - Name: in.KubeResource.KubernetesName(), - }, - }) - req.NoError(err) - req.False(resp.Requeue) - - cfg, _, err := consulClient.ConfigEntries().Get(in.ConsulKind, in.KubeResource.ConsulName(), &capi.QueryOptions{ - Namespace: in.ConsulNamespace, - }) - req.NoError(err) - - result := in.AssertValidConfig(cfg) - req.True(result) - - // Check that the status is "synced". - err = fakeClient.Get(ctx, types.NamespacedName{ - Namespace: c.SourceKubeNS, - Name: in.KubeResource.KubernetesName(), - }, in.KubeResource) - req.NoError(err) - conditionSynced := in.KubeResource.SyncedConditionStatus() - req.Equal(conditionSynced, corev1.ConditionTrue) - }) - } - } -} - -func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T) { - tt.Parallel() - - cases := map[string]struct { - Mirror bool - MirrorPrefix string - SourceKubeNS string - DestConsulNS string - ExpConsulNS string - }{ - "SourceKubeNS=default, DestConsulNS=default": { - SourceKubeNS: "default", - DestConsulNS: "default", - ExpConsulNS: "default", - }, - "SourceKubeNS=kube, DestConsulNS=default": { - SourceKubeNS: "kube", - DestConsulNS: "default", - ExpConsulNS: "default", - }, - "SourceKubeNS=default, DestConsulNS=other": { - SourceKubeNS: "default", - DestConsulNS: "other", - ExpConsulNS: "other", - }, - "SourceKubeNS=kube, DestConsulNS=other": { - SourceKubeNS: "kube", - DestConsulNS: "other", - ExpConsulNS: "other", - }, - "SourceKubeNS=default, Mirror=true": { - SourceKubeNS: "default", - Mirror: true, - ExpConsulNS: "default", - }, - "SourceKubeNS=kube, Mirror=true": { - SourceKubeNS: "kube", - Mirror: true, - ExpConsulNS: "kube", - }, - "SourceKubeNS=default, Mirror=true, Prefix=prefix": { - SourceKubeNS: "default", - Mirror: true, - MirrorPrefix: "prefix-", - ExpConsulNS: "prefix-default", - }, - } - - for name, c := range cases { - configEntryKinds := map[string]struct { - ConsulKind string - ConsulNamespace string - KubeResource common.ConfigEntryResource - GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler - AssertValidConfigFunc func(entry capi.ConfigEntry) bool - WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error - UpdateResourceFunc func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error - }{ - "namespaced": { - ConsulKind: capi.ServiceDefaults, - KubeResource: &v1alpha1.ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: c.SourceKubeNS, - Finalizers: []string{FinalizerName}, - }, - Spec: v1alpha1.ServiceDefaultsSpec{ - Protocol: "http", - }, - }, - ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ServiceDefaultsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { - _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceConfigEntry{ - Kind: capi.ServiceDefaults, - Name: "foo", - Protocol: "http", - }, &capi.WriteOptions{Namespace: namespace}) - return err - }, - UpdateResourceFunc: func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error { - svcDefault := in.(*v1alpha1.ServiceDefaults) - svcDefault.Spec.Protocol = "tcp" - return client.Update(ctx, svcDefault) - }, - AssertValidConfigFunc: func(cfg capi.ConfigEntry) bool { - configEntry, ok := cfg.(*capi.ServiceConfigEntry) - if !ok { - return false - } - return configEntry.Protocol == "tcp" - }, - }, - "global": { - ConsulKind: capi.ProxyDefaults, - KubeResource: &v1alpha1.ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.Global, - Namespace: c.SourceKubeNS, - Finalizers: []string{FinalizerName}, - }, - Spec: v1alpha1.ProxyDefaultsSpec{ - MeshGateway: v1alpha1.MeshGateway{ - Mode: "remote", - }, - }, - }, - ConsulNamespace: common.DefaultConsulNamespace, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ProxyDefaultsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { - _, _, err := consulClient.ConfigEntries().Set(&capi.ProxyConfigEntry{ - Kind: capi.ProxyDefaults, - Name: common.Global, - MeshGateway: capi.MeshGatewayConfig{ - Mode: capi.MeshGatewayModeRemote, - }, - }, &capi.WriteOptions{Namespace: namespace}) - return err - }, - UpdateResourceFunc: func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error { - proxyDefaults := in.(*v1alpha1.ProxyDefaults) - proxyDefaults.Spec.MeshGateway.Mode = "local" - return client.Update(ctx, proxyDefaults) - }, - AssertValidConfigFunc: func(cfg capi.ConfigEntry) bool { - configEntry, ok := cfg.(*capi.ProxyConfigEntry) - if !ok { - return false - } - return configEntry.MeshGateway.Mode == capi.MeshGatewayModeLocal - }, - }, - "intentions": { - ConsulKind: capi.ServiceIntentions, - KubeResource: &v1alpha1.ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: c.SourceKubeNS, - Finalizers: []string{FinalizerName}, - }, - Spec: v1alpha1.ServiceIntentionsSpec{ - Destination: v1alpha1.IntentionDestination{ - Name: "foo", - Namespace: c.ExpConsulNS, - }, - Sources: v1alpha1.SourceIntentions{ - &v1alpha1.SourceIntention{ - Name: "bar", - Namespace: "baz", - Action: "deny", - }, - }, - }, - }, - ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ServiceIntentionsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { - _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceIntentionsConfigEntry{ - Kind: capi.ServiceIntentions, - Name: "foo", - Sources: []*capi.SourceIntention{ - { - Name: "bar", - Namespace: "baz", - Action: capi.IntentionActionDeny, - }, - }, - }, &capi.WriteOptions{Namespace: namespace}) - return err - }, - UpdateResourceFunc: func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error { - svcIntention := in.(*v1alpha1.ServiceIntentions) - svcIntention.Spec.Sources[0].Action = "allow" - return client.Update(ctx, svcIntention) - }, - AssertValidConfigFunc: func(cfg capi.ConfigEntry) bool { - configEntry, ok := cfg.(*capi.ServiceIntentionsConfigEntry) - if !ok { - return false - } - return configEntry.Sources[0].Action == capi.IntentionActionAllow - }, - }, - } - for kind, in := range configEntryKinds { - tt.Run(fmt.Sprintf("%s : %s", name, kind), func(t *testing.T) { - req := require.New(t) - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, in.KubeResource) - ctx := context.Background() - - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - testClient.TestServer.WaitForServiceIntentions(t) - consulClient := testClient.APIClient - - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(in.KubeResource).Build() - - r := in.GetControllerFunc( - fakeClient, - logrtest.NewTestLogger(t), - s, - &ConfigEntryController{ - ConsulClientConfig: testClient.Cfg, - ConsulServerConnMgr: testClient.Watcher, - EnableConsulNamespaces: true, - EnableNSMirroring: c.Mirror, - NSMirroringPrefix: c.MirrorPrefix, - ConsulDestinationNamespace: c.DestConsulNS, - }, - ) - - // We haven't run reconcile yet so ensure it's created in Consul. - { - if in.ConsulNamespace != "default" { - _, _, err := consulClient.Namespaces().Create(&capi.Namespace{ - Name: in.ConsulNamespace, - }, nil) - req.NoError(err) - } - - err := in.WriteConfigEntryFunc(consulClient, in.ConsulNamespace) - req.NoError(err) - } - - // Now update it. - { - // First get it so we have the latest revision number. - err := fakeClient.Get(ctx, types.NamespacedName{ - Namespace: c.SourceKubeNS, - Name: in.KubeResource.KubernetesName(), - }, in.KubeResource) - req.NoError(err) - - // Update the resource. - err = in.UpdateResourceFunc(fakeClient, ctx, in.KubeResource) - req.NoError(err) - - resp, err := r.Reconcile(ctx, ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: c.SourceKubeNS, - Name: in.KubeResource.KubernetesName(), - }, - }) - req.NoError(err) - req.False(resp.Requeue) - - cfg, _, err := consulClient.ConfigEntries().Get(in.ConsulKind, in.KubeResource.ConsulName(), &capi.QueryOptions{ - Namespace: in.ConsulNamespace, - }) - req.NoError(err) - req.True(in.AssertValidConfigFunc(cfg)) - } - }) - } - } -} - -func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T) { - tt.Parallel() - - cases := map[string]struct { - Mirror bool - MirrorPrefix string - SourceKubeNS string - DestConsulNS string - ExpConsulNS string - }{ - "SourceKubeNS=default, DestConsulNS=default": { - SourceKubeNS: "default", - DestConsulNS: "default", - ExpConsulNS: "default", - }, - "SourceKubeNS=kube, DestConsulNS=default": { - SourceKubeNS: "kube", - DestConsulNS: "default", - ExpConsulNS: "default", - }, - "SourceKubeNS=default, DestConsulNS=other": { - SourceKubeNS: "default", - DestConsulNS: "other", - ExpConsulNS: "other", - }, - "SourceKubeNS=kube, DestConsulNS=other": { - SourceKubeNS: "kube", - DestConsulNS: "other", - ExpConsulNS: "other", - }, - "SourceKubeNS=default, Mirror=true": { - SourceKubeNS: "default", - Mirror: true, - ExpConsulNS: "default", - }, - "SourceKubeNS=kube, Mirror=true": { - SourceKubeNS: "kube", - Mirror: true, - ExpConsulNS: "kube", - }, - "SourceKubeNS=default, Mirror=true, Prefix=prefix": { - SourceKubeNS: "default", - Mirror: true, - MirrorPrefix: "prefix-", - ExpConsulNS: "prefix-default", - }, - } - - for name, c := range cases { - configEntryKinds := map[string]struct { - ConsulKind string - ConsulNamespace string - KubeResource common.ConfigEntryResource - GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler - WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error - }{ - "namespaced": { - ConsulKind: capi.ServiceDefaults, - // Create it with the deletion timestamp set to mimic that it's already - // been marked for deletion. - KubeResource: &v1alpha1.ServiceDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: c.SourceKubeNS, - Finalizers: []string{FinalizerName}, - DeletionTimestamp: &metav1.Time{Time: time.Now()}, - }, - Spec: v1alpha1.ServiceDefaultsSpec{ - Protocol: "http", - }, - }, - ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ServiceDefaultsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { - _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceConfigEntry{ - Kind: capi.ServiceDefaults, - Name: "foo", - Protocol: "http", - }, &capi.WriteOptions{Namespace: namespace}) - return err - }, - }, - "global": { - ConsulKind: capi.ProxyDefaults, - // Create it with the deletion timestamp set to mimic that it's already - // been marked for deletion. - KubeResource: &v1alpha1.ProxyDefaults{ - ObjectMeta: metav1.ObjectMeta{ - Name: common.Global, - Namespace: c.SourceKubeNS, - Finalizers: []string{FinalizerName}, - DeletionTimestamp: &metav1.Time{Time: time.Now()}, - }, - Spec: v1alpha1.ProxyDefaultsSpec{ - MeshGateway: v1alpha1.MeshGateway{ - Mode: "remote", - }, - }, - }, - ConsulNamespace: common.DefaultConsulNamespace, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ProxyDefaultsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { - _, _, err := consulClient.ConfigEntries().Set(&capi.ProxyConfigEntry{ - Kind: capi.ProxyDefaults, - Name: common.Global, - MeshGateway: capi.MeshGatewayConfig{ - Mode: capi.MeshGatewayModeRemote, - }, - }, &capi.WriteOptions{Namespace: namespace}) - return err - }, - }, - "intentions": { - ConsulKind: capi.ServiceIntentions, - // Create it with the deletion timestamp set to mimic that it's already - // been marked for deletion. - KubeResource: &v1alpha1.ServiceIntentions{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: c.SourceKubeNS, - Finalizers: []string{FinalizerName}, - DeletionTimestamp: &metav1.Time{Time: time.Now()}, - }, - Spec: v1alpha1.ServiceIntentionsSpec{ - Destination: v1alpha1.IntentionDestination{ - Name: "test", - Namespace: c.ExpConsulNS, - }, - Sources: v1alpha1.SourceIntentions{ - &v1alpha1.SourceIntention{ - Name: "bar", - Namespace: "baz", - Action: "deny", - }, - }, - }, - }, - ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { - return &ServiceIntentionsController{ - Client: client, - Log: logger, - Scheme: scheme, - ConfigEntryController: cont, - } - }, - WriteConfigEntryFunc: func(consulClient *capi.Client, namespace string) error { - _, _, err := consulClient.ConfigEntries().Set(&capi.ServiceIntentionsConfigEntry{ - Kind: capi.ServiceIntentions, - Name: "test", - Sources: []*capi.SourceIntention{ - { - Name: "bar", - Namespace: "baz", - Action: capi.IntentionActionDeny, - }, - }, - }, &capi.WriteOptions{Namespace: namespace}) - return err - }, - }, - } - for kind, in := range configEntryKinds { - tt.Run(fmt.Sprintf("%s : %s", name, kind), func(t *testing.T) { - req := require.New(t) - - s := runtime.NewScheme() - s.AddKnownTypes(v1alpha1.GroupVersion, in.KubeResource) - - testClient := test.TestServerWithMockConnMgrWatcher(t, nil) - testClient.TestServer.WaitForServiceIntentions(t) - consulClient := testClient.APIClient - - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(in.KubeResource).Build() - - r := in.GetControllerFunc( - fakeClient, - logrtest.NewTestLogger(t), - s, - &ConfigEntryController{ - ConsulClientConfig: testClient.Cfg, - ConsulServerConnMgr: testClient.Watcher, - EnableConsulNamespaces: true, - EnableNSMirroring: c.Mirror, - NSMirroringPrefix: c.MirrorPrefix, - ConsulDestinationNamespace: c.DestConsulNS, - }, - ) - - // We haven't run reconcile yet so ensure it's created in Consul. - { - if in.ConsulNamespace != "default" { - _, _, err := consulClient.Namespaces().Create(&capi.Namespace{ - Name: in.ConsulNamespace, - }, nil) - req.NoError(err) - } - - err := in.WriteConfigEntryFunc(consulClient, in.ConsulNamespace) - req.NoError(err) - } - - // Now run reconcile. It's marked for deletion so this should delete it. - { - resp, err := r.Reconcile(context.Background(), ctrl.Request{ - NamespacedName: types.NamespacedName{ - Namespace: c.SourceKubeNS, - Name: in.KubeResource.KubernetesName(), - }, - }) - req.NoError(err) - req.False(resp.Requeue) - - _, _, err = consulClient.ConfigEntries().Get(in.ConsulKind, in.KubeResource.ConsulName(), &capi.QueryOptions{ - Namespace: in.ConsulNamespace, - }) - req.EqualError(err, fmt.Sprintf(`Unexpected response code: 404 (Config entry not found for "%s" / "%s")`, in.ConsulKind, in.KubeResource.ConsulName())) - } - }) - } - } -} diff --git a/control-plane/controllers/controlplanerequestlimit_controller.go b/control-plane/controllers/controlplanerequestlimit_controller.go deleted file mode 100644 index f5afbdcc48..0000000000 --- a/control-plane/controllers/controlplanerequestlimit_controller.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" -) - -// ControlPlaneRequestLimitController reconciles a ControlPlaneRequestLimit object. -type ControlPlaneRequestLimitController struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme - ConfigEntryController *ConfigEntryController -} - -//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=controlplanerequestlimits,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=controlplanerequestlimits/status,verbs=get;update;patch - -func (r *ControlPlaneRequestLimitController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.ControlPlaneRequestLimit{}) -} - -func (r *ControlPlaneRequestLimitController) Logger(name types.NamespacedName) logr.Logger { - return r.Log.WithValues("request", name) -} - -func (r *ControlPlaneRequestLimitController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { - return r.Status().Update(ctx, obj, opts...) -} - -func (r *ControlPlaneRequestLimitController) SetupWithManager(mgr ctrl.Manager) error { - return setupWithManager(mgr, &consulv1alpha1.ControlPlaneRequestLimit{}, r) -} diff --git a/control-plane/controllers/jwtprovider_controller.go b/control-plane/controllers/jwtprovider_controller.go deleted file mode 100644 index 157f4bc855..0000000000 --- a/control-plane/controllers/jwtprovider_controller.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" -) - -// JWTProviderController reconciles a JWTProvider object. -type JWTProviderController struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme - ConfigEntryController *ConfigEntryController -} - -//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=jwtproviders,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=jwtproviders/status,verbs=get;update;patch - -func (r *JWTProviderController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.JWTProvider{}) -} - -func (r *JWTProviderController) Logger(name types.NamespacedName) logr.Logger { - return r.Log.WithValues("request", name) -} - -func (r *JWTProviderController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { - return r.Status().Update(ctx, obj, opts...) -} - -func (r *JWTProviderController) SetupWithManager(mgr ctrl.Manager) error { - return setupWithManager(mgr, &consulv1alpha1.JWTProvider{}, r) -} diff --git a/control-plane/controllers/samenessgroups_controller.go b/control-plane/controllers/samenessgroups_controller.go deleted file mode 100644 index 815b7e8ab8..0000000000 --- a/control-plane/controllers/samenessgroups_controller.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package controllers - -import ( - "context" - - "k8s.io/apimachinery/pkg/types" - - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" -) - -// SamenessGroupController reconciles a SamenessGroups object. -type SamenessGroupController struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme - ConfigEntryController *ConfigEntryController -} - -//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=samenessgroups,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=samenessgroups/status,verbs=get;update;patch - -func (r *SamenessGroupController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.SamenessGroup{}) -} - -func (r *SamenessGroupController) Logger(name types.NamespacedName) logr.Logger { - return r.Log.WithValues("request", name) -} - -func (r *SamenessGroupController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { - return r.Status().Update(ctx, obj, opts...) -} - -// SetupWithManager sets up the controller with the Manager. -func (r *SamenessGroupController) SetupWithManager(mgr ctrl.Manager) error { - return setupWithManager(mgr, &consulv1alpha1.SamenessGroup{}, r) -} diff --git a/control-plane/go.mod b/control-plane/go.mod index 55918dceb4..d70b04542d 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -1,9 +1,5 @@ module github.com/hashicorp/consul-k8s/control-plane -// TODO: remove when the SDK is released for Consul 1.17 -// The replace directive is needed be because `api` requires 0.14.1 of SDK and is both a direct and indirect dependency -replace github.com/hashicorp/consul/sdk v0.14.1 => github.com/hashicorp/consul/sdk v0.4.1-0.20230825164720-ecdcde430924 - require ( github.com/cenkalti/backoff v2.2.1+incompatible github.com/containernetworking/cni v1.1.1 @@ -12,48 +8,37 @@ require ( github.com/go-logr/logr v1.2.3 github.com/google/go-cmp v0.5.9 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20230821180813-217d305b38d5 - github.com/hashicorp/consul/proto-public v0.1.2-0.20230821180813-217d305b38d5 // this points to a commit on Consul main - github.com/hashicorp/consul/sdk v0.14.1 - github.com/hashicorp/go-bexpr v0.1.11 + github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20230511143918-bd16ab83383d + github.com/hashicorp/consul-server-connection-manager v0.1.3 + github.com/hashicorp/consul/api v1.10.1-0.20230512003852-bd0eb07ed3ca + github.com/hashicorp/consul/sdk v0.13.1 github.com/hashicorp/go-discover v0.0.0-20230519164032-214571b6a530 - github.com/hashicorp/go-hclog v1.5.0 + github.com/hashicorp/go-hclog v1.2.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-netaddrs v0.1.0 github.com/hashicorp/go-rootcerts v1.0.2 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/serf v0.10.1 - github.com/hashicorp/vault/api v1.8.3 github.com/kr/text v0.2.0 github.com/miekg/dns v1.1.50 github.com/mitchellh/cli v1.1.0 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/stretchr/testify v1.8.3 + github.com/stretchr/testify v1.8.1 go.uber.org/zap v1.24.0 - golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 golang.org/x/text v0.11.0 golang.org/x/time v0.3.0 gomodules.xyz/jsonpatch/v2 v2.3.0 - gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.26.3 - k8s.io/apimachinery v0.26.3 - k8s.io/client-go v0.26.3 - k8s.io/klog/v2 v2.100.1 + k8s.io/api v0.26.1 + k8s.io/apimachinery v0.26.1 + k8s.io/client-go v0.26.1 + k8s.io/klog/v2 v2.90.1 k8s.io/utils v0.0.0-20230209194617-a36077c30491 sigs.k8s.io/controller-runtime v0.14.6 - sigs.k8s.io/gateway-api v0.7.1 ) require ( - github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20230825213844-4ea04860c5ed - github.com/hashicorp/consul-server-connection-manager v0.1.4 - google.golang.org/protobuf v1.30.0 -) - -require ( - cloud.google.com/go/compute v1.19.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go v0.81.0 // indirect github.com/Azure/azure-sdk-for-go v44.0.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.18 // indirect @@ -70,111 +55,97 @@ require ( github.com/aws/aws-sdk-go v1.44.262 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661 // indirect - github.com/digitalocean/godo v1.7.5 // indirect + github.com/digitalocean/godo v1.10.0 // indirect github.com/dimchansky/utfbom v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fatih/color v1.14.1 // indirect + github.com/fatih/color v1.13.0 // indirect github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/go-logr/zapr v1.2.3 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect + github.com/google/go-querystring v1.0.0 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.7.1 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gax-go/v2 v2.0.5 // indirect github.com/gophercloud/gophercloud v0.1.0 // indirect + github.com/hashicorp/consul/proto-public v0.1.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 - github.com/hashicorp/go-plugin v1.4.5 // indirect - github.com/hashicorp/go-retryablehttp v0.6.6 // indirect - github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect - github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/mdns v1.0.4 // indirect - github.com/hashicorp/vault/sdk v0.7.0 // indirect github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 // indirect - github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62 // indirect + github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/linode/linodego v0.7.1 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect - github.com/mitchellh/copystructure v1.0.0 // indirect - github.com/mitchellh/go-testing-interface v1.0.0 // indirect - github.com/mitchellh/pointerstructure v1.2.1 // indirect - github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect - github.com/oklog/run v1.0.0 // indirect github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect - github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/posener/complete v1.2.3 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect - github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.480 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.480 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.658 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.658 // indirect github.com/vmware/govmomi v0.18.0 // indirect - go.opencensus.io v0.24.0 // indirect + go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.11.0 // indirect - golang.org/x/mod v0.9.0 // indirect + golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect + golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.13.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/sync v0.2.0 // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect + golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/term v0.10.0 // indirect - golang.org/x/tools v0.7.0 // indirect - google.golang.org/api v0.114.0 // indirect + golang.org/x/tools v0.6.0 // indirect + google.golang.org/api v0.43.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.55.0 // indirect + google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect + google.golang.org/grpc v1.49.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/resty.v1 v1.12.0 // indirect - gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.26.3 // indirect - k8s.io/component-base v0.26.3 // indirect - k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + k8s.io/apiextensions-apiserver v0.26.1 // indirect + k8s.io/component-base v0.26.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) -go 1.20 +replace github.com/hashicorp/consul/sdk => github.com/hashicorp/consul/sdk v0.4.1-0.20221021205723-cc843c4be892 + +go 1.19 diff --git a/control-plane/go.sum b/control-plane/go.sum index 7868dc727b..cd604e02a3 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -13,20 +13,20 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -68,13 +68,17 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14= +github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= @@ -93,15 +97,13 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -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.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/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= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -109,29 +111,47 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/containernetworking/cni v1.1.1 h1:ky20T7c0MvKvbMOwS/FrlbNwjEoqJEUUYfsL4b0mc4k= github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -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/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= -github.com/digitalocean/godo v1.7.5 h1:JOQbAO6QT1GGjor0doT0mXefX2FgUDPOpYh2RaXA+ko= -github.com/digitalocean/godo v1.7.5/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/digitalocean/godo v1.10.0 h1:uW1/FcvZE/hoixnJcnlmIUvTVNdZCLjRLzmDtRi1xXY= +github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.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.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -139,18 +159,16 @@ github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -168,19 +186,22 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -193,6 +214,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -208,11 +230,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= @@ -225,18 +245,21 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= -github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -244,85 +267,75 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -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/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20230825213844-4ea04860c5ed h1:eM9tGgSqAZbm4Ndkp35Dg8YROT0dNH3ghTYu5pcUIAc= -github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20230825213844-4ea04860c5ed/go.mod h1:mwODEC+VTCA1LY/m2RUG4S2c5lNRvBcsvqaMJtMLLos= -github.com/hashicorp/consul-server-connection-manager v0.1.4 h1:wrcSRV6WGXFBNpNbN6XsdoGgBOyso7ZbN5VaWPEX1jY= -github.com/hashicorp/consul-server-connection-manager v0.1.4/go.mod h1:LMqHkALoLP0HUQKOG21xXYr0YPUayIQIHNTlmxG100E= -github.com/hashicorp/consul/api v1.10.1-0.20230821180813-217d305b38d5 h1:TTTgXv9YeaRnODyFP1k2b2Nq5RIGrUUgI5SkDhuSNwM= -github.com/hashicorp/consul/api v1.10.1-0.20230821180813-217d305b38d5/go.mod h1:NZJGRFYruc/80wYowkPFCp1LbGmJC9L8izrwfyVx/Wg= -github.com/hashicorp/consul/proto-public v0.1.2-0.20230821180813-217d305b38d5 h1:mN5hKOn+G5fQBuXjdne/HluE4FhesUxscZEblqP4OSQ= -github.com/hashicorp/consul/proto-public v0.1.2-0.20230821180813-217d305b38d5/go.mod h1:ENwzmloQTUPAYPu7nC1mli3VY0Ny9QNi/FSzJ+KlZD0= -github.com/hashicorp/consul/sdk v0.4.1-0.20230825164720-ecdcde430924 h1:gkb6/ix0Tg1Th5FTjyq4QklLgrtIVQ/TUB0kbhIcPsY= -github.com/hashicorp/consul/sdk v0.4.1-0.20230825164720-ecdcde430924/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20230511143918-bd16ab83383d h1:RJ1MZ8JKnfgKQ1kR3IBQAMpOpzXrdseZAYN/QR//MFM= +github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20230511143918-bd16ab83383d/go.mod h1:IHIHMzkoMwlv6rLsgwcoFBVYupR7/1pKEOHBMjD4L0k= +github.com/hashicorp/consul-server-connection-manager v0.1.3 h1:fxsZ15XBNNWhV26yBVdCcnxHwSRgf9wqHGS2ZVCQIhc= +github.com/hashicorp/consul-server-connection-manager v0.1.3/go.mod h1:Md2IGKaFJ4ek9GUA0pW1S2R60wpquMOUs27GiD9kZd0= +github.com/hashicorp/consul/api v1.10.1-0.20230512003852-bd0eb07ed3ca h1:5UPVYOlJg/HBEJ2q82rkkQ3ZLzeMnF5MOpGcw2kh+XU= +github.com/hashicorp/consul/api v1.10.1-0.20230512003852-bd0eb07ed3ca/go.mod h1:tXfrC6o0yFTgAW46xd5Ic8STHc9oIBcRVBcwhX5KNCQ= +github.com/hashicorp/consul/proto-public v0.1.0 h1:O0LSmCqydZi363hsqc6n2v5sMz3usQMXZF6ziK3SzXU= +github.com/hashicorp/consul/proto-public v0.1.0/go.mod h1:vs2KkuWwtjkIgA5ezp4YKPzQp4GitV+q/+PvksrA92k= +github.com/hashicorp/consul/sdk v0.4.1-0.20221021205723-cc843c4be892 h1:jw0NwPmNPr5CxAU04hACdj61JSaJBKZ0FdBo+kwfNp4= +github.com/hashicorp/consul/sdk v0.4.1-0.20221021205723-cc843c4be892/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= 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= -github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubCI7dY= -github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U+N8T+6Kz1AE= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-discover v0.0.0-20230519164032-214571b6a530 h1:WUwSDou+memX/pb6xnjA0PfAqEEJtdWSrK00kl8ySK8= github.com/hashicorp/go-discover v0.0.0-20230519164032-214571b6a530/go.mod h1:RH2Jr1/cCsZ1nRLmAOC65hp/gRehf55SsUIYV2+NAxI= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -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/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.2 h1:ihRI7YFwcZdiSD7SIenIhHfQH3OuDvWerAUBZbeQS3M= +github.com/hashicorp/go-hclog v1.2.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 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-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= -github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= 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= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= @@ -331,30 +344,28 @@ github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hashicorp/vault/api v1.8.3 h1:cHQOLcMhBR+aVI0HzhPxO62w2+gJhIrKguQNONPzu6o= -github.com/hashicorp/vault/api v1.8.3/go.mod h1:4g/9lj9lmuJQMtT6CmVMHC5FW1yENaVv+Nv4ZfG8fAg= -github.com/hashicorp/vault/sdk v0.7.0 h1:2pQRO40R1etpKkia5fb4kjrdYMx3BHklPxl1pxpxDHg= -github.com/hashicorp/vault/sdk v0.7.0/go.mod h1:KyfArJkhooyba7gYCKSq8v66QdqJmnbAxtV/OX1+JTs= github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 h1:O/pT5C1Q3mVXMyuqg7yuAWUg/jMZR1/0QTzTRdNR6Uw= github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62 h1:JHCT6xuyPUrbbgAPE/3dqlvUKzRHMNuTBKKUb6OeR/k= -github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= +github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f h1:ENpDacvnr8faw5ugQmEF1QYk+f/Y9lXFvuYmRxykago= +github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -366,6 +377,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -373,16 +385,18 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/linode/linodego v0.7.1 h1:4WZmMpSA2NRwlPZcc0+4Gyn7rr99Evk9bnr0B3gXRKE= github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -392,12 +406,13 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -405,24 +420,14 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= -github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -436,10 +441,12 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= @@ -455,19 +462,18 @@ github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otz github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= -github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -481,6 +487,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= @@ -489,6 +497,7 @@ github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+ github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -496,16 +505,21 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627/go.mod h1:7zjs06qF79/FKAJpBvFx3P8Ww4UTIMAe+lpNXDHziac= +github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5/go.mod h1:BeybITEsBEg6qbIiqJ6/Bqeq25bCLbL7YFmpaFfJDuM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -513,8 +527,18 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d h1:bVQRCxQvfjNUeRqaY/uT0tFuvuFY0ulgnczuR684Xic= github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -525,48 +549,61 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.480 h1:Dwnfdrk3KXpYRH9Kwrk9sHpZSOmrE7P9LBoNsYUJKR4= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.480/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.480 h1:YEDZmv2ABU8QvwXEVTOQgVEQzDOByhz73vdjL6sERkE= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.480/go.mod h1:zaBIuDDs+rC74X8Aog+LSu91GFtHYRYDC196RGTm2jk= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.658 h1:q208plt7F8Pj3b1w8D3XDb/vTgHsn/JlEwDCSe+lvyo= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.658/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.658 h1:wF/3PTojsx9/J8CaeiTy0zXxvwrcuu282R4g7fDlgCQ= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.658/go.mod h1:LLex9maWMIQzOFF/mYz5rEsTUwKKcmAbGRehSNRWqgQ= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -598,6 +635,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -606,10 +644,12 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -621,6 +661,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -643,8 +684,12 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= @@ -661,10 +706,15 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -677,13 +727,15 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -692,6 +744,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -700,6 +753,7 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -721,11 +775,19 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -735,6 +797,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -754,6 +817,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -764,6 +829,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -807,12 +873,18 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -835,8 +907,12 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0 h1:4sAyIHT6ZohtAQDoxws+ez7bROYmUlOVvsUscYCDTqA= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -868,17 +944,29 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 h1:hrbNEivu7Zn1pxvHk6MBrq9iE22woVILTHqexqBxe6I= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -889,9 +977,16 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -904,25 +999,27 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -941,20 +1038,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU= -k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE= -k8s.io/apiextensions-apiserver v0.26.3 h1:5PGMm3oEzdB1W/FTMgGIDmm100vn7IaUP5er36dB+YE= -k8s.io/apiextensions-apiserver v0.26.3/go.mod h1:jdA5MdjNWGP+njw1EKMZc64xAT5fIhN6VJrElV3sfpQ= -k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= -k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= -k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= -k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= -k8s.io/component-base v0.26.3 h1:oC0WMK/ggcbGDTkdcqefI4wIZRYdK3JySx9/HADpV0g= -k8s.io/component-base v0.26.3/go.mod h1:5kj1kZYwSC6ZstHJN7oHBqcJC6yyn41eR+Sqa/mQc8E= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/api v0.26.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ= +k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg= +k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI= +k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU= +k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE= +k8s.io/component-base v0.26.1 h1:4ahudpeQXHZL5kko+iDHqLj/FSGAEUnSVO0EBbgDd+4= +k8s.io/component-base v0.26.1/go.mod h1:VHrLR0b58oC035w6YQiBSbtsf0ThuSwXP+p5dD/kAWU= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= @@ -962,10 +1059,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA= sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= -sigs.k8s.io/gateway-api v0.7.1 h1:Tts2jeepVkPA5rVG/iO+S43s9n7Vp7jCDhZDQYtPigQ= -sigs.k8s.io/gateway-api v0.7.1/go.mod h1:Xv0+ZMxX0lu1nSSDIIPEfbVztgNZ+3cfiYrJsa2Ooso= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/control-plane/hack/lint-api-new-client/main.go b/control-plane/hack/lint-api-new-client/main.go index 6297f0abb1..c4c6d896b1 100644 --- a/control-plane/hack/lint-api-new-client/main.go +++ b/control-plane/hack/lint-api-new-client/main.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Parses golang code looking for github.com/hashicorp/consul/api.NewClient() // being used in non-test code. If it finds this, it will error. // The purpose of this lint is that we actually want to use our internal diff --git a/control-plane/helper/cert/notify.go b/control-plane/helper/cert/notify.go index 076c923119..201ca34dd5 100644 --- a/control-plane/helper/cert/notify.go +++ b/control-plane/helper/cert/notify.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cert import ( diff --git a/control-plane/helper/cert/notify_test.go b/control-plane/helper/cert/notify_test.go index 7e7cbf6d68..8813816f86 100644 --- a/control-plane/helper/cert/notify_test.go +++ b/control-plane/helper/cert/notify_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cert import ( diff --git a/control-plane/helper/cert/source.go b/control-plane/helper/cert/source.go index 5a85cb271d..dcc4e3640c 100644 --- a/control-plane/helper/cert/source.go +++ b/control-plane/helper/cert/source.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cert import ( diff --git a/control-plane/helper/cert/source_gen.go b/control-plane/helper/cert/source_gen.go index 9d54f2836c..e9c79ed390 100644 --- a/control-plane/helper/cert/source_gen.go +++ b/control-plane/helper/cert/source_gen.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cert import ( diff --git a/control-plane/helper/cert/source_gen_test.go b/control-plane/helper/cert/source_gen_test.go index fd31de654e..b68ffc7e13 100644 --- a/control-plane/helper/cert/source_gen_test.go +++ b/control-plane/helper/cert/source_gen_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cert import ( diff --git a/control-plane/helper/cert/tls_util.go b/control-plane/helper/cert/tls_util.go index d5552d60f3..37e2f4ea97 100644 --- a/control-plane/helper/cert/tls_util.go +++ b/control-plane/helper/cert/tls_util.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package cert import ( diff --git a/control-plane/helper/coalesce/coalesce.go b/control-plane/helper/coalesce/coalesce.go index bfe341d1d6..d3e96e6be8 100644 --- a/control-plane/helper/coalesce/coalesce.go +++ b/control-plane/helper/coalesce/coalesce.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package coalesce import ( diff --git a/control-plane/helper/coalesce/coalesce_test.go b/control-plane/helper/coalesce/coalesce_test.go index d2c37135c7..8489fed8b4 100644 --- a/control-plane/helper/coalesce/coalesce_test.go +++ b/control-plane/helper/coalesce/coalesce_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package coalesce import ( diff --git a/control-plane/helper/controller/controller.go b/control-plane/helper/controller/controller.go index db6de05b07..12b84b567d 100644 --- a/control-plane/helper/controller/controller.go +++ b/control-plane/helper/controller/controller.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package controller contains a reusable abstraction for efficiently // watching for changes in resources in a Kubernetes cluster. package controller diff --git a/control-plane/helper/controller/controller_test.go b/control-plane/helper/controller/controller_test.go index a7e960a6aa..43fe677280 100644 --- a/control-plane/helper/controller/controller_test.go +++ b/control-plane/helper/controller/controller_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package controller import ( diff --git a/control-plane/helper/controller/resource.go b/control-plane/helper/controller/resource.go index 9634db51ae..959d101488 100644 --- a/control-plane/helper/controller/resource.go +++ b/control-plane/helper/controller/resource.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package controller import ( diff --git a/control-plane/helper/controller/testing.go b/control-plane/helper/controller/testing.go index e4809c70bd..7575276bf5 100644 --- a/control-plane/helper/controller/testing.go +++ b/control-plane/helper/controller/testing.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package controller import ( diff --git a/control-plane/helper/go-discover/discover.go b/control-plane/helper/go-discover/discover.go index 140586634a..845a7b144b 100644 --- a/control-plane/helper/go-discover/discover.go +++ b/control-plane/helper/go-discover/discover.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package godiscover import ( diff --git a/control-plane/helper/go-discover/discover_test.go b/control-plane/helper/go-discover/discover_test.go index 5c25261516..b655dc388e 100644 --- a/control-plane/helper/go-discover/discover_test.go +++ b/control-plane/helper/go-discover/discover_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package godiscover import ( diff --git a/control-plane/helper/go-discover/mocks/mock_provider.go b/control-plane/helper/go-discover/mocks/mock_provider.go index dfdab445da..51afb86a84 100644 --- a/control-plane/helper/go-discover/mocks/mock_provider.go +++ b/control-plane/helper/go-discover/mocks/mock_provider.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package mocks import ( diff --git a/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration.go b/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration.go index 093b1ef908..c3c93b5204 100644 --- a/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration.go +++ b/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package mutatingwebhookconfiguration import ( diff --git a/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration_test.go b/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration_test.go index be1a3b5c64..e247c71d14 100644 --- a/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration_test.go +++ b/control-plane/helper/mutating-webhook-configuration/mutating_webhook_configuration_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package mutatingwebhookconfiguration import ( diff --git a/control-plane/helper/parsetags/parsetags.go b/control-plane/helper/parsetags/parsetags.go index caec75bb1d..e9d9625338 100644 --- a/control-plane/helper/parsetags/parsetags.go +++ b/control-plane/helper/parsetags/parsetags.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package parsetags import ( diff --git a/control-plane/helper/parsetags/parsetags_test.go b/control-plane/helper/parsetags/parsetags_test.go index 2a6b9ad47f..f403a2f711 100644 --- a/control-plane/helper/parsetags/parsetags_test.go +++ b/control-plane/helper/parsetags/parsetags_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package parsetags import ( diff --git a/control-plane/helper/test/test_util.go b/control-plane/helper/test/test_util.go index e29e44de59..0ad4601fde 100644 --- a/control-plane/helper/test/test_util.go +++ b/control-plane/helper/test/test_util.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package test import ( diff --git a/control-plane/main.go b/control-plane/main.go index 64ccd5d43a..7ec1340290 100644 --- a/control-plane/main.go +++ b/control-plane/main.go @@ -1,15 +1,11 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( "log" "os" - "github.com/mitchellh/cli" - "github.com/hashicorp/consul-k8s/control-plane/version" + "github.com/mitchellh/cli" ) func main() { diff --git a/control-plane/namespaces/namespaces.go b/control-plane/namespaces/namespaces.go index 84b8c15ee4..c17aa1f788 100644 --- a/control-plane/namespaces/namespaces.go +++ b/control-plane/namespaces/namespaces.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package namespaces handles interaction with Consul namespaces needed across // commands. package namespaces diff --git a/control-plane/namespaces/namespaces_test.go b/control-plane/namespaces/namespaces_test.go index a2c9989ae8..7b6a061a65 100644 --- a/control-plane/namespaces/namespaces_test.go +++ b/control-plane/namespaces/namespaces_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package namespaces diff --git a/control-plane/subcommand/acl-init/command.go b/control-plane/subcommand/acl-init/command.go index 77e8f87d87..af85128ea8 100644 --- a/control-plane/subcommand/acl-init/command.go +++ b/control-plane/subcommand/acl-init/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package aclinit import ( diff --git a/control-plane/subcommand/acl-init/command_test.go b/control-plane/subcommand/acl-init/command_test.go index acdafc939f..c9f5703459 100644 --- a/control-plane/subcommand/acl-init/command_test.go +++ b/control-plane/subcommand/acl-init/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package aclinit import ( diff --git a/control-plane/subcommand/auth.go b/control-plane/subcommand/auth.go index 6389e7d6f7..58a9b801e8 100644 --- a/control-plane/subcommand/auth.go +++ b/control-plane/subcommand/auth.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package subcommand import ( diff --git a/control-plane/subcommand/common/common.go b/control-plane/subcommand/common/common.go index 1636c0b10e..00535cb6fe 100644 --- a/control-plane/subcommand/common/common.go +++ b/control-plane/subcommand/common/common.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package common holds code needed by multiple commands. package common diff --git a/control-plane/subcommand/common/common_test.go b/control-plane/subcommand/common/common_test.go index 9e50302b17..bce90d6b76 100644 --- a/control-plane/subcommand/common/common_test.go +++ b/control-plane/subcommand/common/common_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( @@ -11,6 +8,7 @@ import ( "net/url" "os" "testing" + "time" "github.com/hashicorp/consul-k8s/control-plane/helper/go-discover/mocks" "github.com/hashicorp/consul/api" @@ -165,33 +163,36 @@ func TestConsulLogin_TokenNotReplicated(t *testing.T) { func TestConsulLogin_EmptyBearerTokenFile(t *testing.T) { t.Parallel() + require := require.New(t) bearerTokenFile := WriteTempFile(t, "") params := LoginParams{ BearerTokenFile: bearerTokenFile, } _, err := ConsulLogin(nil, params, hclog.NewNullLogger()) - require.EqualError(t, err, fmt.Sprintf("no bearer token found in %q", bearerTokenFile)) + require.EqualError(err, fmt.Sprintf("no bearer token found in %q", bearerTokenFile)) } func TestConsulLogin_BearerTokenFileDoesNotExist(t *testing.T) { t.Parallel() + require := require.New(t) randFileName := fmt.Sprintf("/foo/%d/%d", rand.Int(), rand.Int()) params := LoginParams{ BearerTokenFile: randFileName, } _, err := ConsulLogin(nil, params, hclog.NewNullLogger()) - require.Error(t, err) - require.Contains(t, err.Error(), "unable to read bearer token file") + require.Error(err) + require.Contains(err.Error(), "unable to read bearer token file") } func TestConsulLogin_TokenFileUnwritable(t *testing.T) { t.Parallel() + require := require.New(t) bearerTokenFile := WriteTempFile(t, "foo") client := startMockServer(t) // This is a common.Logger. log, err := Logger("INFO", false) - require.NoError(t, err) + require.NoError(err) randFileName := fmt.Sprintf("/foo/%d/%d", rand.Int(), rand.Int()) params := LoginParams{ AuthMethod: testAuthMethod, @@ -200,12 +201,13 @@ func TestConsulLogin_TokenFileUnwritable(t *testing.T) { NumRetries: 2, } _, err = ConsulLogin(client, params, log) - require.Error(t, err) - require.Contains(t, err.Error(), "error writing token to file sink") + require.Error(err) + require.Contains(err.Error(), "error writing token to file sink") } func TestWriteFileWithPerms_InvalidOutputFile(t *testing.T) { t.Parallel() + rand.New(rand.NewSource(time.Now().UnixNano())) randFileName := fmt.Sprintf("/tmp/tmp/tmp/%d", rand.Int()) t.Cleanup(func() { os.RemoveAll(randFileName) @@ -216,6 +218,7 @@ func TestWriteFileWithPerms_InvalidOutputFile(t *testing.T) { func TestWriteFileWithPerms_OutputFileExists(t *testing.T) { t.Parallel() + rand.New(rand.NewSource(time.Now().UnixNano())) randFileName := fmt.Sprintf("/tmp/%d", rand.Int()) err := os.WriteFile(randFileName, []byte("foo"), os.FileMode(0444)) require.NoError(t, err) @@ -233,6 +236,7 @@ func TestWriteFileWithPerms_OutputFileExists(t *testing.T) { func TestWriteFileWithPerms(t *testing.T) { t.Parallel() payload := "foo-foo-foo-foo" + rand.New(rand.NewSource(time.Now().UnixNano())) randFileName := fmt.Sprintf("/tmp/%d", rand.Int()) t.Cleanup(func() { os.RemoveAll(randFileName) diff --git a/control-plane/subcommand/common/test_util.go b/control-plane/subcommand/common/test_util.go index 3399b40e2b..13d9017fe4 100644 --- a/control-plane/subcommand/common/test_util.go +++ b/control-plane/subcommand/common/test_util.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package common import ( diff --git a/control-plane/subcommand/connect-init/command.go b/control-plane/subcommand/connect-init/command.go index 4f83ea98f1..4750e9455c 100644 --- a/control-plane/subcommand/connect-init/command.go +++ b/control-plane/subcommand/connect-init/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connectinit import ( @@ -17,19 +14,17 @@ import ( "time" "github.com/cenkalti/backoff" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/namespaces" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" "github.com/hashicorp/consul-server-connection-manager/discovery" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/iptables" "github.com/hashicorp/go-hclog" "github.com/mitchellh/cli" "github.com/mitchellh/mapstructure" - - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" - "github.com/hashicorp/consul-k8s/control-plane/version" ) const ( @@ -163,17 +158,6 @@ func (c *Command) Run(args []string) int { c.logger.Error("Unable to get client connection", "error", err) return 1 } - if version.IsFIPS() { - // make sure we are also using FIPS Consul - var versionInfo map[string]interface{} - _, err := consulClient.Raw().Query("/v1/agent/version", versionInfo, nil) - if err != nil { - c.logger.Warn("This is a FIPS build of consul-k8s, which should be used with FIPS Consul. Unable to verify FIPS Consul while setting up Consul API client.") - } - if val, ok := versionInfo["FIPS"]; !ok || val == "" { - c.logger.Warn("This is a FIPS build of consul-k8s, which should be used with FIPS Consul. A non-FIPS version of Consul was detected.") - } - } proxyService := &api.AgentService{} if c.flagGatewayKind != "" { err = backoff.Retry(c.getGatewayRegistration(consulClient), backoff.WithMaxRetries(backoff.NewConstantBackOff(1*time.Second), c.serviceRegistrationPollingAttempts)) @@ -329,7 +313,7 @@ func (c *Command) getGatewayRegistration(client *api.Client) backoff.Operation { } for _, gateway := range gatewayList.Services { switch gateway.Kind { - case api.ServiceKindAPIGateway, api.ServiceKindMeshGateway, api.ServiceKindIngressGateway, api.ServiceKindTerminatingGateway: + case api.ServiceKindMeshGateway, api.ServiceKindIngressGateway, api.ServiceKindTerminatingGateway: proxyID = gateway.ID } } diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index b3ef7109e0..ecdc34122e 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package connectinit diff --git a/control-plane/subcommand/connect-init/command_test.go b/control-plane/subcommand/connect-init/command_test.go index cb1d32d03b..14bdc5280c 100644 --- a/control-plane/subcommand/connect-init/command_test.go +++ b/control-plane/subcommand/connect-init/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connectinit import ( @@ -615,7 +612,7 @@ func TestRun_Gateways_Errors(t *testing.T) { "-pod-name", testPodName, "-pod-namespace", testPodNamespace, "-proxy-id-file", proxyFile, - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", "-consul-node-name", nodeName, } @@ -729,7 +726,7 @@ func TestRun_InvalidProxyFile(t *testing.T) { "-http-port", strconv.Itoa(serverCfg.Ports.HTTP), "-grpc-port", strconv.Itoa(serverCfg.Ports.GRPC), "-proxy-id-file", randFileName, - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", } code := cmd.Run(flags) require.Equal(t, 1, code) diff --git a/control-plane/subcommand/consul-logout/command.go b/control-plane/subcommand/consul-logout/command.go index a6b599dccd..b0836b71f0 100644 --- a/control-plane/subcommand/consul-logout/command.go +++ b/control-plane/subcommand/consul-logout/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consullogout import ( diff --git a/control-plane/subcommand/consul-logout/command_test.go b/control-plane/subcommand/consul-logout/command_test.go index 1a0744996a..22412ea752 100644 --- a/control-plane/subcommand/consul-logout/command_test.go +++ b/control-plane/subcommand/consul-logout/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package consullogout import ( @@ -54,7 +51,7 @@ func TestRun_InvalidSinkFile(t *testing.T) { } code := cmd.Run([]string{ "-token-file", randFileName, - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, code) } @@ -107,7 +104,7 @@ func Test_UnableToLogoutDueToInvalidToken(t *testing.T) { code := cmd.Run([]string{ "-http-addr", fmt.Sprintf("%s://%s", cfg.Scheme, cfg.Address), "-token-file", tokenFile, - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, code, ui.ErrorWriter.String()) require.Contains(t, "Unexpected response code: 403 (ACL not found)", ui.ErrorWriter.String()) @@ -172,7 +169,7 @@ func Test_RunUsingLogin(t *testing.T) { code := cmd.Run([]string{ "-http-addr", fmt.Sprintf("%s://%s", cfg.Scheme, cfg.Address), "-token-file", tokenFile, - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 0, code, ui.ErrorWriter.String()) diff --git a/control-plane/subcommand/create-federation-secret/command.go b/control-plane/subcommand/create-federation-secret/command.go index 52600aedda..3a96e18134 100644 --- a/control-plane/subcommand/create-federation-secret/command.go +++ b/control-plane/subcommand/create-federation-secret/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package createfederationsecret import ( diff --git a/control-plane/subcommand/create-federation-secret/command_test.go b/control-plane/subcommand/create-federation-secret/command_test.go index 15f12b132c..86ff8aec18 100644 --- a/control-plane/subcommand/create-federation-secret/command_test.go +++ b/control-plane/subcommand/create-federation-secret/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package createfederationsecret import ( @@ -80,7 +77,7 @@ func TestRun_FlagValidation(t *testing.T) { "-server-ca-key-file=file", "-ca-file", f.Name(), "-mesh-gateway-service-name=name", - "-consul-api-timeout=10s", + "-consul-api-timeout=5s", "-log-level=invalid", }, expErr: "unknown log level: invalid", @@ -117,7 +114,7 @@ func TestRun_CAFileMissing(t *testing.T) { "-server-ca-cert-file", f.Name(), "-server-ca-key-file", f.Name(), "-ca-file=/this/does/not/exist", - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, exitCode, ui.ErrorWriter.String()) require.Contains(t, ui.ErrorWriter.String(), "error reading CA file") @@ -140,7 +137,7 @@ func TestRun_ServerCACertFileMissing(t *testing.T) { "-ca-file", f.Name(), "-server-ca-cert-file=/this/does/not/exist", "-server-ca-key-file", f.Name(), - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, exitCode, ui.ErrorWriter.String()) require.Contains(t, ui.ErrorWriter.String(), "Error reading server CA cert file") @@ -163,7 +160,7 @@ func TestRun_ServerCAKeyFileMissing(t *testing.T) { "-ca-file", f.Name(), "-server-ca-cert-file", f.Name(), "-server-ca-key-file=/this/does/not/exist", - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, exitCode, ui.ErrorWriter.String()) require.Contains(t, ui.ErrorWriter.String(), "Error reading server CA key file") @@ -187,7 +184,7 @@ func TestRun_GossipEncryptionKeyFileMissing(t *testing.T) { "-server-ca-cert-file", f.Name(), "-server-ca-key-file", f.Name(), "-gossip-key-file=/this/does/not/exist", - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, exitCode, ui.ErrorWriter.String()) require.Contains(t, ui.ErrorWriter.String(), "Error reading gossip encryption key file") @@ -211,7 +208,7 @@ func TestRun_GossipEncryptionKeyFileEmpty(t *testing.T) { "-server-ca-cert-file", f.Name(), "-server-ca-key-file", f.Name(), "-gossip-key-file", f.Name(), - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, exitCode, ui.ErrorWriter.String()) require.Contains(t, ui.ErrorWriter.String(), fmt.Sprintf("gossip key file %q was empty", f.Name())) @@ -249,7 +246,7 @@ func TestRun_ReplicationTokenMissingExpectedKey(t *testing.T) { "-server-ca-cert-file", f.Name(), "-server-ca-key-file", f.Name(), "-export-replication-token", - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 1, exitCode, ui.ErrorWriter.String()) } @@ -844,7 +841,7 @@ func TestRun_ReplicationSecretDelay(t *testing.T) { "-server-ca-key-file", keyFile, "-http-addr", fmt.Sprintf("https://%s", testserver.HTTPSAddr), "-export-replication-token", - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", } exitCode := cmd.Run(flags) require.Equal(t, 0, exitCode, ui.ErrorWriter.String()) @@ -1052,7 +1049,7 @@ func TestRun_ConsulClientDelay(t *testing.T) { "-server-ca-cert-file", caFile, "-server-ca-key-file", keyFile, "-http-addr", fmt.Sprintf("https://127.0.0.1:%d", randomPorts[2]), - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", } exitCode := cmd.Run(flags) require.Equal(t, 0, exitCode, ui.ErrorWriter.String()) diff --git a/control-plane/subcommand/delete-completed-job/command.go b/control-plane/subcommand/delete-completed-job/command.go index f6f594393d..273e621a2a 100644 --- a/control-plane/subcommand/delete-completed-job/command.go +++ b/control-plane/subcommand/delete-completed-job/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package deletecompletedjob import ( diff --git a/control-plane/subcommand/delete-completed-job/command_test.go b/control-plane/subcommand/delete-completed-job/command_test.go index abfbb0e788..0da056fc88 100644 --- a/control-plane/subcommand/delete-completed-job/command_test.go +++ b/control-plane/subcommand/delete-completed-job/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package deletecompletedjob import ( diff --git a/control-plane/subcommand/fetch-server-region/command.go b/control-plane/subcommand/fetch-server-region/command.go deleted file mode 100644 index 248ce971e7..0000000000 --- a/control-plane/subcommand/fetch-server-region/command.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package fetchserverregion - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "os" - "sync" - - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" - "github.com/hashicorp/go-hclog" - "github.com/mitchellh/cli" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -// The consul-logout command issues a Consul logout API request to delete an ACL token. -type Command struct { - UI cli.Ui - - flagLogLevel string - flagLogJSON bool - flagNodeName string - flagOutputFile string - - flagSet *flag.FlagSet - k8s *flags.K8SFlags - - once sync.Once - help string - logger hclog.Logger - - // for testing - clientset kubernetes.Interface -} - -type Locality struct { - Region string `json:"region"` -} - -type Config struct { - Locality Locality `json:"locality"` -} - -func (c *Command) init() { - c.flagSet = flag.NewFlagSet("", flag.ContinueOnError) - c.flagSet.StringVar(&c.flagLogLevel, "log-level", "info", - "Log verbosity level. Supported values (in order of detail) are \"trace\", "+ - "\"debug\", \"info\", \"warn\", and \"error\".") - c.flagSet.BoolVar(&c.flagLogJSON, "log-json", false, - "Enable or disable JSON output format for logging.") - c.flagSet.StringVar(&c.flagNodeName, "node-name", "", - "Specifies the node name that will be used.") - c.flagSet.StringVar(&c.flagOutputFile, "output-file", "", - "The file path for writing the locality portion of a Consul agent configuration to.") - - c.k8s = &flags.K8SFlags{} - flags.Merge(c.flagSet, c.k8s.Flags()) - - c.help = flags.Usage(help, c.flagSet) - -} - -func (c *Command) Run(args []string) int { - var err error - c.once.Do(c.init) - - if err := c.flagSet.Parse(args); err != nil { - return 1 - } - - if c.logger == nil { - c.logger, err = common.Logger(c.flagLogLevel, c.flagLogJSON) - if err != nil { - c.UI.Error(err.Error()) - return 1 - } - } - - if c.flagNodeName == "" { - c.UI.Error("-node-name is required") - return 1 - } - - if c.flagOutputFile == "" { - c.UI.Error("-output-file is required") - return 1 - } - - if c.clientset == nil { - config, err := rest.InClusterConfig() - if err != nil { - // This just allows us to test it locally. - kubeconfig := clientcmd.RecommendedHomeFile - config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - c.UI.Error(err.Error()) - return 1 - } - } - - c.clientset, err = kubernetes.NewForConfig(config) - if err != nil { - c.UI.Error(err.Error()) - return 1 - } - } - - config := c.fetchLocalityConfig() - - jsonData, err := json.Marshal(config) - if err != nil { - c.UI.Error(err.Error()) - return 1 - } - - err = os.WriteFile(c.flagOutputFile, jsonData, 0644) - if err != nil { - c.UI.Error(fmt.Sprintf("Error writing locality file: %s", err)) - return 1 - } - - return 0 -} - -func (c *Command) fetchLocalityConfig() Config { - var cfg Config - node, err := c.clientset.CoreV1().Nodes().Get(context.Background(), c.flagNodeName, metav1.GetOptions{}) - if err != nil { - return cfg - } - - cfg.Locality.Region = node.Labels[corev1.LabelTopologyRegion] - - return cfg -} - -func (c *Command) Synopsis() string { return synopsis } -func (c *Command) Help() string { - c.once.Do(c.init) - return c.help -} - -const synopsis = "Fetch the cloud region for a Consul server from the Kubernetes node's region label." -const help = ` -Usage: consul-k8s-control-plane fetch-server-region [options] - - Fetch the region for a Consul server. - Not intended for stand-alone use. -` diff --git a/control-plane/subcommand/fetch-server-region/command_test.go b/control-plane/subcommand/fetch-server-region/command_test.go deleted file mode 100644 index a64dc9be95..0000000000 --- a/control-plane/subcommand/fetch-server-region/command_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package fetchserverregion - -import ( - "os" - "testing" - - "github.com/mitchellh/cli" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/fake" -) - -func TestRun_FlagValidation(t *testing.T) { - t.Parallel() - - ui := cli.NewMockUi() - cmd := Command{ - UI: ui, - } - - cases := map[string]struct { - args []string - err string - }{ - "missing node name": { - args: []string{}, - err: "-node-name is required", - }, - "missing output-file": { - args: []string{"-node-name", "n1"}, - err: "-output-file is required", - }, - } - - for n, c := range cases { - c := c - t.Run(n, func(t *testing.T) { - responseCode := cmd.Run(c.args) - require.Equal(t, 1, responseCode, ui.ErrorWriter.String()) - require.Contains(t, ui.ErrorWriter.String(), c.err) - }) - } -} - -func TestRun(t *testing.T) { - t.Parallel() - - cases := map[string]struct { - region string - expected string - missingNode bool - }{ - "no region": { - expected: `{"locality":{"region":""}}`, - }, - "region": { - region: "us-east-1", - expected: `{"locality":{"region":"us-east-1"}}`, - }, - "missing node": { - region: "us-east-1", - missingNode: true, - expected: `{"locality":{"region":""}}`, - }, - } - - for n, c := range cases { - c := c - t.Run(n, func(t *testing.T) { - outputFile, err := os.CreateTemp("", "ca") - require.NoError(t, err) - t.Cleanup(func() { - os.RemoveAll(outputFile.Name()) - }) - - var objs []runtime.Object - if !c.missingNode { - objs = append(objs, &v1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node", - Labels: map[string]string{ - corev1.LabelTopologyRegion: c.region, - }, - }, - }) - } - - k8s := fake.NewSimpleClientset(objs...) - ui := cli.NewMockUi() - cmd := Command{ - UI: ui, - clientset: k8s, - } - - responseCode := cmd.Run([]string{ - "-node-name", - "my-node", - "-output-file", - outputFile.Name(), - }) - require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) - require.NoError(t, err) - cfg, err := os.ReadFile(outputFile.Name()) - require.NoError(t, err) - require.Equal(t, c.expected, string(cfg)) - }) - } -} diff --git a/control-plane/subcommand/flags/consul.go b/control-plane/subcommand/flags/consul.go index 9368b95b3d..1294729a6b 100644 --- a/control-plane/subcommand/flags/consul.go +++ b/control-plane/subcommand/flags/consul.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/consul_test.go b/control-plane/subcommand/flags/consul_test.go index 7f35dc8575..b53025daa6 100644 --- a/control-plane/subcommand/flags/consul_test.go +++ b/control-plane/subcommand/flags/consul_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/flag_map_value.go b/control-plane/subcommand/flags/flag_map_value.go index c647f57bf5..9ddb4dad08 100644 --- a/control-plane/subcommand/flags/flag_map_value.go +++ b/control-plane/subcommand/flags/flag_map_value.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/flag_map_value_test.go b/control-plane/subcommand/flags/flag_map_value_test.go index ea68b6b312..a3b7659cc4 100644 --- a/control-plane/subcommand/flags/flag_map_value_test.go +++ b/control-plane/subcommand/flags/flag_map_value_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/flag_slice_value.go b/control-plane/subcommand/flags/flag_slice_value.go index 42c45562b2..11e838e683 100644 --- a/control-plane/subcommand/flags/flag_slice_value.go +++ b/control-plane/subcommand/flags/flag_slice_value.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import "strings" diff --git a/control-plane/subcommand/flags/flag_slice_value_test.go b/control-plane/subcommand/flags/flag_slice_value_test.go index 24cf4df695..e361c12b10 100644 --- a/control-plane/subcommand/flags/flag_slice_value_test.go +++ b/control-plane/subcommand/flags/flag_slice_value_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/flags.go b/control-plane/subcommand/flags/flags.go index 6739684bf0..e290e876d7 100644 --- a/control-plane/subcommand/flags/flags.go +++ b/control-plane/subcommand/flags/flags.go @@ -1,5 +1,2 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Package flags holds common flags that are shared between our commands. package flags diff --git a/control-plane/subcommand/flags/http.go b/control-plane/subcommand/flags/http.go index 21ccb45df1..74db3c26dc 100644 --- a/control-plane/subcommand/flags/http.go +++ b/control-plane/subcommand/flags/http.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/http_test.go b/control-plane/subcommand/flags/http_test.go index 3292661933..a44f79931c 100644 --- a/control-plane/subcommand/flags/http_test.go +++ b/control-plane/subcommand/flags/http_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/k8s.go b/control-plane/subcommand/flags/k8s.go index 15f1a996b9..31a2284f65 100644 --- a/control-plane/subcommand/flags/k8s.go +++ b/control-plane/subcommand/flags/k8s.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/mapset.go b/control-plane/subcommand/flags/mapset.go index d97419a827..c58cc9a3a2 100644 --- a/control-plane/subcommand/flags/mapset.go +++ b/control-plane/subcommand/flags/mapset.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import "github.com/deckarep/golang-set" diff --git a/control-plane/subcommand/flags/usage.go b/control-plane/subcommand/flags/usage.go index df63d9c8a6..960ce85926 100644 --- a/control-plane/subcommand/flags/usage.go +++ b/control-plane/subcommand/flags/usage.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/flags/usage_test.go b/control-plane/subcommand/flags/usage_test.go index 7e27ad77fb..801888e549 100644 --- a/control-plane/subcommand/flags/usage_test.go +++ b/control-plane/subcommand/flags/usage_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package flags import ( diff --git a/control-plane/subcommand/gateway-cleanup/command.go b/control-plane/subcommand/gateway-cleanup/command.go deleted file mode 100644 index 04aa8f60a9..0000000000 --- a/control-plane/subcommand/gateway-cleanup/command.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatewaycleanup - -import ( - "context" - "errors" - "flag" - "fmt" - "sync" - "time" - - "github.com/cenkalti/backoff" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/subcommand" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" - "github.com/mitchellh/cli" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -type Command struct { - UI cli.Ui - - flags *flag.FlagSet - k8s *flags.K8SFlags - - flagGatewayClassName string - flagGatewayClassConfigName string - - k8sClient client.Client - - once sync.Once - help string - - ctx context.Context -} - -func (c *Command) init() { - c.flags = flag.NewFlagSet("", flag.ContinueOnError) - - c.flags.StringVar(&c.flagGatewayClassName, "gateway-class-name", "", - "Name of Kubernetes GatewayClass to delete.") - c.flags.StringVar(&c.flagGatewayClassConfigName, "gateway-class-config-name", "", - "Name of Kubernetes GatewayClassConfig to delete.") - - c.k8s = &flags.K8SFlags{} - flags.Merge(c.flags, c.k8s.Flags()) - c.help = flags.Usage(help, c.flags) -} - -func (c *Command) Run(args []string) int { - var err error - c.once.Do(c.init) - if err = c.flags.Parse(args); err != nil { - return 1 - } - // Validate flags - if err := c.validateFlags(); err != nil { - c.UI.Error(err.Error()) - return 1 - } - - if c.ctx == nil { - c.ctx = context.Background() - } - - // Create the Kubernetes clientset - if c.k8sClient == nil { - config, err := subcommand.K8SConfig(c.k8s.KubeConfig()) - if err != nil { - c.UI.Error(fmt.Sprintf("Error retrieving Kubernetes auth: %s", err)) - return 1 - } - - s := runtime.NewScheme() - if err := clientgoscheme.AddToScheme(s); err != nil { - c.UI.Error(fmt.Sprintf("Could not add client-go schema: %s", err)) - return 1 - } - if err := gwv1beta1.Install(s); err != nil { - c.UI.Error(fmt.Sprintf("Could not add api-gateway schema: %s", err)) - return 1 - } - if err := v1alpha1.AddToScheme(s); err != nil { - c.UI.Error(fmt.Sprintf("Could not add consul-k8s schema: %s", err)) - return 1 - } - - c.k8sClient, err = client.New(config, client.Options{Scheme: s}) - if err != nil { - c.UI.Error(fmt.Sprintf("Error initializing Kubernetes client: %s", err)) - return 1 - } - } - - // do the cleanup - - // find the class config and mark it for deletion first so that we - // can do an early return if the gateway class isn't found - config := &v1alpha1.GatewayClassConfig{} - err = c.k8sClient.Get(context.Background(), types.NamespacedName{Name: c.flagGatewayClassConfigName}, config) - if err != nil { - if k8serrors.IsNotFound(err) { - // no gateway class config, just ignore and return - return 0 - } - c.UI.Error(err.Error()) - return 1 - } - - // ignore any returned errors - _ = c.k8sClient.Delete(context.Background(), config) - - // find the gateway class - gatewayClass := &gwv1beta1.GatewayClass{} - err = c.k8sClient.Get(context.Background(), types.NamespacedName{Name: c.flagGatewayClassName}, gatewayClass) - if err != nil { - if k8serrors.IsNotFound(err) { - // no gateway class, just ignore and return - return 0 - } - c.UI.Error(err.Error()) - return 1 - } - - // ignore any returned errors - _ = c.k8sClient.Delete(context.Background(), gatewayClass) - - // make sure they're gone - if err := backoff.Retry(func() error { - err = c.k8sClient.Get(context.Background(), types.NamespacedName{Name: c.flagGatewayClassConfigName}, config) - if err == nil || !k8serrors.IsNotFound(err) { - return errors.New("gateway class config still exists") - } - - err = c.k8sClient.Get(context.Background(), types.NamespacedName{Name: c.flagGatewayClassName}, gatewayClass) - if err == nil || !k8serrors.IsNotFound(err) { - return errors.New("gateway class still exists") - } - - return nil - }, exponentialBackoffWithMaxIntervalAndTime()); err != nil { - c.UI.Error(err.Error()) - // if we failed, return 0 anyway after logging the error - // since we don't want to block someone from uninstallation - } - - return 0 -} - -func (c *Command) validateFlags() error { - if c.flagGatewayClassConfigName == "" { - return errors.New("-gateway-class-config-name must be set") - } - if c.flagGatewayClassName == "" { - return errors.New("-gateway-class-name must be set") - } - - return nil -} - -func (c *Command) Synopsis() string { return synopsis } -func (c *Command) Help() string { - c.once.Do(c.init) - return c.help -} - -const synopsis = "Clean up global gateway resources prior to uninstall." -const help = ` -Usage: consul-k8s-control-plane gateway-cleanup [options] - - Deletes installed gateway class and gateway class config objects - prior to helm uninstallation. This is required due to finalizers - existing on the GatewayClassConfig that will leave around a dangling - object without deleting these prior to their controllers being deleted. - The job is best effort, so if it fails to successfully delete the - objects, it will allow the uninstallation to continue. - -` - -func exponentialBackoffWithMaxIntervalAndTime() *backoff.ExponentialBackOff { - backoff := backoff.NewExponentialBackOff() - backoff.MaxElapsedTime = 10 * time.Second - backoff.MaxInterval = 1 * time.Second - backoff.Reset() - return backoff -} diff --git a/control-plane/subcommand/gateway-cleanup/command_test.go b/control-plane/subcommand/gateway-cleanup/command_test.go deleted file mode 100644 index 56b7651270..0000000000 --- a/control-plane/subcommand/gateway-cleanup/command_test.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatewaycleanup - -import ( - "testing" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/mitchellh/cli" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestRun(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - gatewayClassConfig *v1alpha1.GatewayClassConfig - gatewayClass *gwv1beta1.GatewayClass - }{ - "both exist": { - gatewayClassConfig: &v1alpha1.GatewayClassConfig{}, - gatewayClass: &gwv1beta1.GatewayClass{}, - }, - "gateway class config doesn't exist": { - gatewayClass: &gwv1beta1.GatewayClass{}, - }, - "gateway class doesn't exist": { - gatewayClassConfig: &v1alpha1.GatewayClassConfig{}, - }, - "neither exist": {}, - "finalizers on gatewayclass blocking deletion": { - gatewayClassConfig: &v1alpha1.GatewayClassConfig{}, - gatewayClass: &gwv1beta1.GatewayClass{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"finalizer"}}}, - }, - "finalizers on gatewayclassconfig blocking deletion": { - gatewayClassConfig: &v1alpha1.GatewayClassConfig{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"finalizer"}}}, - gatewayClass: &gwv1beta1.GatewayClass{}, - }, - } { - t.Run(name, func(t *testing.T) { - tt := tt - - t.Parallel() - - s := runtime.NewScheme() - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - objs := []client.Object{} - if tt.gatewayClass != nil { - tt.gatewayClass.Name = "gateway-class" - objs = append(objs, tt.gatewayClass) - } - if tt.gatewayClassConfig != nil { - tt.gatewayClassConfig.Name = "gateway-class-config" - objs = append(objs, tt.gatewayClassConfig) - } - - client := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).Build() - - ui := cli.NewMockUi() - cmd := Command{ - UI: ui, - k8sClient: client, - flagGatewayClassName: "gateway-class", - flagGatewayClassConfigName: "gateway-class-config", - } - - code := cmd.Run([]string{ - "-gateway-class-config-name", "gateway-class-config", - "-gateway-class-name", "gateway-class", - }) - - require.Equal(t, 0, code) - }) - } -} diff --git a/control-plane/subcommand/gateway-resources/command.go b/control-plane/subcommand/gateway-resources/command.go deleted file mode 100644 index 19c7b28742..0000000000 --- a/control-plane/subcommand/gateway-resources/command.go +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatewayresources - -import ( - "context" - "encoding/json" - "errors" - "flag" - "fmt" - "io" - "os" - "sync" - "time" - - "github.com/cenkalti/backoff" - "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/subcommand" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" - "github.com/mitchellh/cli" - yaml "gopkg.in/yaml.v2" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -// this dupes the Kubernetes tolerations -// struct with yaml tags for validation. -type toleration struct { - Key string `yaml:"key"` - Operator string `yaml:"operator"` - Value string `yaml:"value"` - Effect string `yaml:"effect"` - TolerationSeconds *int64 `yaml:"tolerationSeconds"` -} - -func tolerationToKubernetes(t toleration) corev1.Toleration { - return corev1.Toleration{ - Key: t.Key, - Operator: corev1.TolerationOperator(t.Operator), - Value: t.Value, - Effect: corev1.TaintEffect(t.Effect), - TolerationSeconds: t.TolerationSeconds, - } -} - -type Command struct { - UI cli.Ui - - flags *flag.FlagSet - k8s *flags.K8SFlags - - flagHeritage string - flagChart string - flagApp string - flagRelease string - flagComponent string - flagControllerName string - flagGatewayClassName string - flagGatewayClassConfigName string - - flagServiceType string - flagDeploymentDefaultInstances int - flagDeploymentMaxInstances int - flagDeploymentMinInstances int - - flagNodeSelector string // this is a yaml multiline string map - flagTolerations string // this is a multiline yaml string matching the tolerations array - flagServiceAnnotations string // this is a multiline yaml string array of annotations to allow - - flagOpenshiftSCCName string - - flagMapPrivilegedContainerPorts int - - k8sClient client.Client - - once sync.Once - help string - - nodeSelector map[string]string - tolerations []corev1.Toleration - serviceAnnotations []string - resources corev1.ResourceRequirements - - ctx context.Context -} - -func (c *Command) init() { - c.flags = flag.NewFlagSet("", flag.ContinueOnError) - - c.flags.StringVar(&c.flagGatewayClassName, "gateway-class-name", "", - "Name of Kubernetes GatewayClass to ensure is created.") - c.flags.StringVar(&c.flagGatewayClassConfigName, "gateway-class-config-name", "", - "Name of Kubernetes GatewayClassConfig to ensure is created.") - c.flags.StringVar(&c.flagHeritage, "heritage", "", - "Helm chart heritage for created objects.") - c.flags.StringVar(&c.flagChart, "chart", "", - "Helm chart name for created objects.") - c.flags.StringVar(&c.flagApp, "app", "", - "Helm chart app for created objects.") - c.flags.StringVar(&c.flagRelease, "release-name", "", - "Helm chart release for created objects.") - c.flags.StringVar(&c.flagComponent, "component", "", - "Helm chart component for created objects.") - c.flags.StringVar(&c.flagControllerName, "controller-name", "", - "The controller name value to use in the GatewayClass.") - c.flags.StringVar(&c.flagServiceType, "service-type", "", - "The service type to use for a gateway deployment.", - ) - c.flags.IntVar(&c.flagDeploymentDefaultInstances, "deployment-default-instances", 0, - "The number of instances to deploy for each gateway by default.", - ) - c.flags.IntVar(&c.flagDeploymentMaxInstances, "deployment-max-instances", 0, - "The maximum number of instances to deploy for each gateway.", - ) - c.flags.IntVar(&c.flagDeploymentMinInstances, "deployment-min-instances", 0, - "The minimum number of instances to deploy for each gateway.", - ) - c.flags.StringVar(&c.flagNodeSelector, "node-selector", "", - "The node selector to use in scheduling a gateway.", - ) - c.flags.StringVar(&c.flagTolerations, "tolerations", "", - "The tolerations to use in a deployed gateway.", - ) - c.flags.StringVar(&c.flagServiceAnnotations, "service-annotations", "", - "The annotations to copy over from a gateway to its service.", - ) - c.flags.StringVar(&c.flagOpenshiftSCCName, "openshift-scc-name", "", - "Name of security context constraint to use for gateways on Openshift.", - ) - c.flags.IntVar(&c.flagMapPrivilegedContainerPorts, "map-privileged-container-ports", 0, - "The value to add to privileged container ports (< 1024) to avoid requiring addition privileges for the "+ - "gateway container.", - ) - - c.k8s = &flags.K8SFlags{} - flags.Merge(c.flags, c.k8s.Flags()) - c.help = flags.Usage(help, c.flags) -} - -func (c *Command) Run(args []string) int { - var err error - c.once.Do(c.init) - if err = c.flags.Parse(args); err != nil { - return 1 - } - // Validate flags - if err := c.validateFlags(); err != nil { - c.UI.Error(err.Error()) - return 1 - } - - // Load config from the configmap. - if err := c.loadConfig(); err != nil { - c.UI.Error(fmt.Sprintf("Error loading config: %s", err)) - return 1 - } - - if c.ctx == nil { - c.ctx = context.Background() - } - - // Create the Kubernetes client - if c.k8sClient == nil { - config, err := subcommand.K8SConfig(c.k8s.KubeConfig()) - if err != nil { - c.UI.Error(fmt.Sprintf("Error retrieving Kubernetes auth: %s", err)) - return 1 - } - - s := runtime.NewScheme() - if err := clientgoscheme.AddToScheme(s); err != nil { - c.UI.Error(fmt.Sprintf("Could not add client-go schema: %s", err)) - return 1 - } - if err := gwv1beta1.Install(s); err != nil { - c.UI.Error(fmt.Sprintf("Could not add api-gateway schema: %s", err)) - return 1 - } - if err := v1alpha1.AddToScheme(s); err != nil { - c.UI.Error(fmt.Sprintf("Could not add consul-k8s schema: %s", err)) - return 1 - } - - c.k8sClient, err = client.New(config, client.Options{Scheme: s}) - if err != nil { - c.UI.Error(fmt.Sprintf("Error initializing Kubernetes client: %s", err)) - return 1 - } - } - - // do the creation - - labels := map[string]string{ - "app": c.flagApp, - "chart": c.flagChart, - "heritage": c.flagHeritage, - "release": c.flagRelease, - "component": c.flagComponent, - } - classConfig := &v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{Name: c.flagGatewayClassConfigName, Labels: labels}, - Spec: v1alpha1.GatewayClassConfigSpec{ - ServiceType: serviceTypeIfSet(c.flagServiceType), - NodeSelector: c.nodeSelector, - CopyAnnotations: v1alpha1.CopyAnnotationsSpec{ - Service: c.serviceAnnotations, - }, - Tolerations: c.tolerations, - DeploymentSpec: v1alpha1.DeploymentSpec{ - DefaultInstances: nonZeroOrNil(c.flagDeploymentDefaultInstances), - MaxInstances: nonZeroOrNil(c.flagDeploymentMaxInstances), - MinInstances: nonZeroOrNil(c.flagDeploymentMinInstances), - Resources: &c.resources, - }, - OpenshiftSCCName: c.flagOpenshiftSCCName, - MapPrivilegedContainerPorts: int32(c.flagMapPrivilegedContainerPorts), - }, - } - - class := &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{Name: c.flagGatewayClassName, Labels: labels}, - Spec: gwv1beta1.GatewayClassSpec{ - ControllerName: gwv1beta1.GatewayController(c.flagControllerName), - ParametersRef: &gwv1beta1.ParametersReference{ - Group: gwv1beta1.Group(v1alpha1.ConsulHashicorpGroup), - Kind: gwv1beta1.Kind(v1alpha1.GatewayClassConfigKind), - Name: c.flagGatewayClassConfigName, - }, - }, - } - - if err := forceClassConfig(context.Background(), c.k8sClient, classConfig); err != nil { - c.UI.Error(err.Error()) - return 1 - } - if err := forceClass(context.Background(), c.k8sClient, class); err != nil { - c.UI.Error(err.Error()) - return 1 - } - - return 0 -} - -func (c *Command) validateFlags() error { - if c.flagGatewayClassConfigName == "" { - return errors.New("-gateway-class-config-name must be set") - } - if c.flagGatewayClassName == "" { - return errors.New("-gateway-class-name must be set") - } - if c.flagHeritage == "" { - return errors.New("-heritage must be set") - } - if c.flagChart == "" { - return errors.New("-chart must be set") - } - if c.flagApp == "" { - return errors.New("-app must be set") - } - if c.flagRelease == "" { - return errors.New("-release-name must be set") - } - if c.flagComponent == "" { - return errors.New("-component must be set") - } - if c.flagControllerName == "" { - return errors.New("-controller-name must be set") - } - if c.flagTolerations != "" { - var tolerations []toleration - if err := yaml.Unmarshal([]byte(c.flagTolerations), &tolerations); err != nil { - return fmt.Errorf("error decoding tolerations: %w", err) - } - c.tolerations = common.ConvertSliceFunc(tolerations, tolerationToKubernetes) - } - if c.flagNodeSelector != "" { - if err := yaml.Unmarshal([]byte(c.flagNodeSelector), &c.nodeSelector); err != nil { - return fmt.Errorf("error decoding node selector: %w", err) - } - } - if c.flagNodeSelector != "" { - if err := yaml.Unmarshal([]byte(c.flagNodeSelector), &c.nodeSelector); err != nil { - return fmt.Errorf("error decoding node selector: %w", err) - } - } - if c.flagServiceAnnotations != "" { - if err := yaml.Unmarshal([]byte(c.flagServiceAnnotations), &c.serviceAnnotations); err != nil { - return fmt.Errorf("error decoding service annotations: %w", err) - } - } - - return nil -} - -func (c *Command) loadConfig() error { - // Load resources.json - file, err := os.Open("/consul/config/resources.json") - if err != nil { - if !os.IsNotExist(err) { - return err - } - c.UI.Info("No resources.json found, using defaults") - c.resources = defaultResourceRequirements() - return nil - } - - resources, err := io.ReadAll(file) - if err != nil { - c.UI.Error(fmt.Sprintf("Unable to read resources.json, using defaults: %s", err)) - c.resources = defaultResourceRequirements() - return err - } - - if err := json.Unmarshal(resources, &c.resources); err != nil { - return err - } - - if err := file.Close(); err != nil { - return err - } - return nil -} - -func (c *Command) Synopsis() string { return synopsis } -func (c *Command) Help() string { - c.once.Do(c.init) - return c.help -} - -const synopsis = "Create managed gateway resources after installation/upgrade." -const help = ` -Usage: consul-k8s-control-plane gateway-resources [options] - - Installs managed gateway class and configuration resources - after a helm installation or upgrade in order to avoid the - dependencies of CRDs being in-place prior to resource creation. - -` - -func defaultResourceRequirements() v1.ResourceRequirements { - // This is a fallback. The resource.json file should be present unless explicitly removed. - return v1.ResourceRequirements{ - Requests: v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("100Mi"), - v1.ResourceCPU: resource.MustParse("100m"), - }, - Limits: v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("100Mi"), - v1.ResourceCPU: resource.MustParse("100m"), - }, - } -} - -func forceClassConfig(ctx context.Context, k8sClient client.Client, o *v1alpha1.GatewayClassConfig) error { - return backoff.Retry(func() error { - var existing v1alpha1.GatewayClassConfig - err := k8sClient.Get(ctx, client.ObjectKeyFromObject(o), &existing) - if err != nil && !k8serrors.IsNotFound(err) { - return err - } - - if k8serrors.IsNotFound(err) { - return k8sClient.Create(ctx, o) - } - - existing.Spec = o.Spec - existing.Labels = o.Labels - - return k8sClient.Update(ctx, &existing) - }, exponentialBackoffWithMaxIntervalAndTime()) -} - -func forceClass(ctx context.Context, k8sClient client.Client, o *gwv1beta1.GatewayClass) error { - return backoff.Retry(func() error { - var existing gwv1beta1.GatewayClass - err := k8sClient.Get(ctx, client.ObjectKeyFromObject(o), &existing) - if err != nil && !k8serrors.IsNotFound(err) { - return err - } - - if k8serrors.IsNotFound(err) { - return k8sClient.Create(ctx, o) - } - - existing.Spec = o.Spec - existing.Labels = o.Labels - - return k8sClient.Update(ctx, &existing) - }, exponentialBackoffWithMaxIntervalAndTime()) -} - -func exponentialBackoffWithMaxIntervalAndTime() *backoff.ExponentialBackOff { - backoff := backoff.NewExponentialBackOff() - backoff.MaxElapsedTime = 10 * time.Second - backoff.MaxInterval = 1 * time.Second - backoff.Reset() - return backoff -} - -func nonZeroOrNil(v int) *int32 { - if v == 0 { - return nil - } - return common.PointerTo(int32(v)) -} - -func serviceTypeIfSet(v string) *corev1.ServiceType { - if v == "" { - return nil - } - return common.PointerTo(corev1.ServiceType(v)) -} diff --git a/control-plane/subcommand/gateway-resources/command_test.go b/control-plane/subcommand/gateway-resources/command_test.go deleted file mode 100644 index f60e376042..0000000000 --- a/control-plane/subcommand/gateway-resources/command_test.go +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package gatewayresources - -import ( - "testing" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/mitchellh/cli" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" -) - -func TestRun_flagValidation(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - cmd *Command - expectedErr string - }{ - "required gateway class config name": { - cmd: &Command{}, - expectedErr: "-gateway-class-config-name must be set", - }, - "required gateway class name": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - }, - expectedErr: "-gateway-class-name must be set", - }, - "required heritage": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - }, - expectedErr: "-heritage must be set", - }, - "required chart": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - }, - expectedErr: "-chart must be set", - }, - "required app": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - }, - expectedErr: "-app must be set", - }, - "required release": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - }, - expectedErr: "-release-name must be set", - }, - "required component": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - flagRelease: "test", - }, - expectedErr: "-component must be set", - }, - "required controller name": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - flagRelease: "test", - flagComponent: "test", - }, - expectedErr: "-controller-name must be set", - }, - "required valid tolerations": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - flagRelease: "test", - flagComponent: "test", - flagControllerName: "test", - flagTolerations: "foo", - }, - expectedErr: "error decoding tolerations: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `foo` into []gatewayresources.toleration", - }, - "required valid nodeSelector": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - flagRelease: "test", - flagComponent: "test", - flagControllerName: "test", - flagNodeSelector: "foo", - }, - expectedErr: "error decoding node selector: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `foo` into map[string]string", - }, - "required valid service annotations": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - flagRelease: "test", - flagComponent: "test", - flagControllerName: "test", - flagServiceAnnotations: "foo", - }, - expectedErr: "error decoding service annotations: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `foo` into []string", - }, - "valid without optional flags": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - flagRelease: "test", - flagComponent: "test", - flagControllerName: "test", - }, - }, - "valid with optional flags": { - cmd: &Command{ - flagGatewayClassConfigName: "test", - flagGatewayClassName: "test", - flagHeritage: "test", - flagChart: "test", - flagApp: "test", - flagRelease: "test", - flagComponent: "test", - flagControllerName: "test", - flagNodeSelector: ` -foo: 1 -bar: 2`, - flagTolerations: ` -- value: foo -- value: bar`, - flagServiceAnnotations: ` -- foo -- bar`, - flagOpenshiftSCCName: "restricted-v2", - }, - }, - } { - t.Run(name, func(t *testing.T) { - tt := tt - - t.Parallel() - - err := tt.cmd.validateFlags() - if tt.expectedErr == "" && err != nil { - t.Errorf("unexpected error occured: %v", err) - } - if tt.expectedErr != "" && err == nil { - t.Error("expected error but got none") - } - if tt.expectedErr != "" { - require.EqualError(t, err, tt.expectedErr) - } - }) - } -} - -func TestRun(t *testing.T) { - t.Parallel() - - for name, tt := range map[string]struct { - existingGatewayClass bool - existingGatewayClassConfig bool - }{ - "both exist": { - existingGatewayClass: true, - existingGatewayClassConfig: true, - }, - "gateway class config doesn't exist": { - existingGatewayClass: true, - }, - "gateway class doesn't exist": { - existingGatewayClassConfig: true, - }, - "neither exist": {}, - } { - t.Run(name, func(t *testing.T) { - tt := tt - - t.Parallel() - - existingGatewayClassConfig := &v1alpha1.GatewayClassConfig{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - } - existingGatewayClass := &gwv1beta1.GatewayClass{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - } - - s := runtime.NewScheme() - require.NoError(t, gwv1beta1.Install(s)) - require.NoError(t, v1alpha1.AddToScheme(s)) - - objs := []client.Object{} - if tt.existingGatewayClass { - objs = append(objs, existingGatewayClass) - } - if tt.existingGatewayClassConfig { - objs = append(objs, existingGatewayClassConfig) - } - - client := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).Build() - - ui := cli.NewMockUi() - cmd := Command{ - UI: ui, - k8sClient: client, - } - - code := cmd.Run([]string{ - "-gateway-class-config-name", "test", - "-gateway-class-name", "test", - "-heritage", "test", - "-chart", "test", - "-app", "test", - "-release-name", "test", - "-component", "test", - "-controller-name", "test", - "-openshift-scc-name", "restricted-v2", - }) - - require.Equal(t, 0, code) - }) - } -} diff --git a/control-plane/subcommand/get-consul-client-ca/command.go b/control-plane/subcommand/get-consul-client-ca/command.go index 619f08625d..a154d778e9 100644 --- a/control-plane/subcommand/get-consul-client-ca/command.go +++ b/control-plane/subcommand/get-consul-client-ca/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package getconsulclientca import ( diff --git a/control-plane/subcommand/get-consul-client-ca/command_test.go b/control-plane/subcommand/get-consul-client-ca/command_test.go index 68bdd918b1..1446018922 100644 --- a/control-plane/subcommand/get-consul-client-ca/command_test.go +++ b/control-plane/subcommand/get-consul-client-ca/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package getconsulclientca import ( @@ -51,7 +48,7 @@ func TestRun_FlagsValidation(t *testing.T) { flags: []string{ "-output-file=output.pem", "-server-addr=foo.com", - "-consul-api-timeout=10s", + "-consul-api-timeout=5s", "-log-level=invalid-log-level", }, expErr: "unknown log level: invalid-log-level", @@ -106,7 +103,7 @@ func TestRun(t *testing.T) { "-server-port", strings.Split(a.HTTPSAddr, ":")[1], "-ca-file", caFile, "-output-file", outputFile.Name(), - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 0, exitCode, ui.ErrorWriter.String()) @@ -138,7 +135,8 @@ func TestRun(t *testing.T) { // Test that if the Consul server is not available at first, // we continue to poll it until it comes up. func TestRun_ConsulServerAvailableLater(t *testing.T) { - t.Parallel() + // Skipping this test because it is flaky on release/1.0.x. It is much better in newer versions of Consul. + t.Skip() outputFile, err := os.CreateTemp("", "ca") require.NoError(t, err) defer os.RemoveAll(outputFile.Name()) @@ -281,7 +279,7 @@ func TestRun_GetsOnlyActiveRoot(t *testing.T) { "-server-port", strings.Split(a.HTTPSAddr, ":")[1], "-ca-file", caFile, "-output-file", outputFile.Name(), - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 0, exitCode) @@ -349,7 +347,7 @@ func TestRun_WithProvider(t *testing.T) { "-server-port", strings.Split(a.HTTPSAddr, ":")[1], "-output-file", outputFile.Name(), "-ca-file", caFile, - "-consul-api-timeout", "10s", + "-consul-api-timeout", "5s", }) require.Equal(t, 0, exitCode, ui.ErrorWriter.String()) diff --git a/control-plane/subcommand/gossip-encryption-autogenerate/command.go b/control-plane/subcommand/gossip-encryption-autogenerate/command.go index cf871eca69..3668a20c35 100644 --- a/control-plane/subcommand/gossip-encryption-autogenerate/command.go +++ b/control-plane/subcommand/gossip-encryption-autogenerate/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package gossipencryptionautogenerate import ( diff --git a/control-plane/subcommand/gossip-encryption-autogenerate/command_test.go b/control-plane/subcommand/gossip-encryption-autogenerate/command_test.go index 55b32bdb06..91d7101232 100644 --- a/control-plane/subcommand/gossip-encryption-autogenerate/command_test.go +++ b/control-plane/subcommand/gossip-encryption-autogenerate/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package gossipencryptionautogenerate import ( diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index 4434d52d98..f3559e2679 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connectinject import ( @@ -15,6 +12,18 @@ import ( "sync" "syscall" + 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/connect-inject/constants" + "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" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" + "github.com/hashicorp/consul-k8s/control-plane/connect-inject/webhook" + "github.com/hashicorp/consul-k8s/control-plane/controller" + mutatingwebhookconfiguration "github.com/hashicorp/consul-k8s/control-plane/helper/mutating-webhook-configuration" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" "github.com/hashicorp/consul-server-connection-manager/discovery" "github.com/mitchellh/cli" "go.uber.org/zap/zapcore" @@ -27,18 +36,11 @@ import ( "k8s.io/client-go/rest" "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" - gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - - "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" + ctrlRuntimeWebhook "sigs.k8s.io/controller-runtime/pkg/webhook" + ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook" ) -const ( - WebhookCAFilename = "ca.crt" -) +const WebhookCAFilename = "ca.crt" type Command struct { UI cli.Ui @@ -54,7 +56,6 @@ type Command struct { flagEnableWebhookCAUpdate bool flagLogLevel string flagLogJSON bool - flagResourceAPIs bool // Use V2 APIs flagAllowK8sNamespacesList []string // K8s namespaces to explicitly inject flagDenyK8sNamespacesList []string // K8s namespaces to deny injection (has precedence) @@ -118,9 +119,6 @@ type Command struct { flagEnableAutoEncrypt bool - // Consul telemetry collector - flagEnableTelemetryCollector bool - // Consul DNS flags. flagEnableConsulDNS bool flagResourcePrefix string @@ -132,18 +130,6 @@ type Command struct { clientset kubernetes.Interface - // sidecarProxy* are resource limits that are parsed and validated from other flags - // these are individual members because there are override annotations - sidecarProxyCPULimit resource.Quantity - sidecarProxyCPURequest resource.Quantity - sidecarProxyMemoryLimit resource.Quantity - sidecarProxyMemoryRequest resource.Quantity - - // static resources requirements for connect-init - initContainerResources corev1.ResourceRequirements - - caCertPem []byte - once sync.Once help string } @@ -157,8 +143,6 @@ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) // We need v1alpha1 here to add the peering api to the scheme utilruntime.Must(v1alpha1.AddToScheme(scheme)) - utilruntime.Must(gwv1beta1.AddToScheme(scheme)) - utilruntime.Must(gwv1alpha2.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } @@ -218,15 +202,11 @@ func (c *Command) init() { "Enables updating the CABundle on the webhook within this controller rather than using the web cert manager.") c.flagSet.BoolVar(&c.flagEnableAutoEncrypt, "enable-auto-encrypt", false, "Indicates whether TLS with auto-encrypt should be used when talking to Consul clients.") - c.flagSet.BoolVar(&c.flagEnableTelemetryCollector, "enable-telemetry-collector", false, - "Indicates whether proxies should be registered with configuration to enable forwarding metrics to consul-telemetry-collector") c.flagSet.StringVar(&c.flagLogLevel, "log-level", zapcore.InfoLevel.String(), fmt.Sprintf("Log verbosity level. Supported values (in order of detail) are "+ "%q, %q, %q, and %q.", zapcore.DebugLevel.String(), zapcore.InfoLevel.String(), zapcore.WarnLevel.String(), zapcore.ErrorLevel.String())) c.flagSet.BoolVar(&c.flagLogJSON, "log-json", false, "Enable or disable JSON output format for logging.") - c.flagSet.BoolVar(&c.flagResourceAPIs, "enable-resource-apis", false, - "Enable of disable Consul V2 Resource APIs.") // Proxy sidecar resource setting flags. c.flagSet.StringVar(&c.flagDefaultSidecarProxyCPURequest, "default-sidecar-proxy-cpu-request", "", "Default sidecar proxy CPU request.") @@ -279,13 +259,67 @@ func (c *Command) Run(args []string) int { return 1 } - if err := c.parseAndValidateSidecarProxyFlags(); err != nil { + // Proxy resources. + var sidecarProxyCPULimit, sidecarProxyCPURequest, sidecarProxyMemoryLimit, sidecarProxyMemoryRequest resource.Quantity + var err error + if c.flagDefaultSidecarProxyCPURequest != "" { + sidecarProxyCPURequest, err = resource.ParseQuantity(c.flagDefaultSidecarProxyCPURequest) + if err != nil { + c.UI.Error(fmt.Sprintf("-default-sidecar-proxy-cpu-request is invalid: %s", err)) + return 1 + } + } + + if c.flagDefaultSidecarProxyCPULimit != "" { + sidecarProxyCPULimit, err = resource.ParseQuantity(c.flagDefaultSidecarProxyCPULimit) + if err != nil { + c.UI.Error(fmt.Sprintf("-default-sidecar-proxy-cpu-limit is invalid: %s", err)) + return 1 + } + } + if sidecarProxyCPULimit.Value() != 0 && sidecarProxyCPURequest.Cmp(sidecarProxyCPULimit) > 0 { + c.UI.Error(fmt.Sprintf( + "request must be <= limit: -default-sidecar-proxy-cpu-request value of %q is greater than the -default-sidecar-proxy-cpu-limit value of %q", + c.flagDefaultSidecarProxyCPURequest, c.flagDefaultSidecarProxyCPULimit)) + return 1 + } + + if c.flagDefaultSidecarProxyMemoryRequest != "" { + sidecarProxyMemoryRequest, err = resource.ParseQuantity(c.flagDefaultSidecarProxyMemoryRequest) + if err != nil { + c.UI.Error(fmt.Sprintf("-default-sidecar-proxy-memory-request is invalid: %s", err)) + return 1 + } + } + if c.flagDefaultSidecarProxyMemoryLimit != "" { + sidecarProxyMemoryLimit, err = resource.ParseQuantity(c.flagDefaultSidecarProxyMemoryLimit) + if err != nil { + c.UI.Error(fmt.Sprintf("-default-sidecar-proxy-memory-limit is invalid: %s", err)) + return 1 + } + } + if sidecarProxyMemoryLimit.Value() != 0 && sidecarProxyMemoryRequest.Cmp(sidecarProxyMemoryLimit) > 0 { + c.UI.Error(fmt.Sprintf( + "request must be <= limit: -default-sidecar-proxy-memory-request value of %q is greater than the -default-sidecar-proxy-memory-limit value of %q", + c.flagDefaultSidecarProxyMemoryRequest, c.flagDefaultSidecarProxyMemoryLimit)) + return 1 + } + + // Validate ports in metrics flags. + err = common.ValidateUnprivilegedPort("-default-merged-metrics-port", c.flagDefaultMergedMetricsPort) + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + err = common.ValidateUnprivilegedPort("-default-prometheus-scrape-port", c.flagDefaultPrometheusScrapePort) + if err != nil { c.UI.Error(err.Error()) return 1 } // Validate resource request/limit flags and parse into corev1.ResourceRequirements - if err := c.parseAndValidateResourceFlags(); err != nil { + initResources, err := c.parseAndValidateResourceFlags() + if err != nil { c.UI.Error(err.Error()) return 1 } @@ -304,6 +338,10 @@ func (c *Command) Run(args []string) int { } } + // Convert allow/deny lists to sets. + allowK8sNamespaces := flags.ToSet(c.flagAllowK8sNamespacesList) + denyK8sNamespaces := flags.ToSet(c.flagDenyK8sNamespacesList) + zapLogger, err := common.ZapLogger(c.flagLogLevel, c.flagLogJSON) if err != nil { c.UI.Error(fmt.Sprintf("Error setting up logging: %s", err.Error())) @@ -330,9 +368,13 @@ func (c *Command) Run(args []string) int { return 1 } + // Create Consul API config object. + consulConfig := c.consul.ConsulClientConfig() + + var caCertPem []byte if c.consul.CACertFile != "" { var err error - c.caCertPem, err = os.ReadFile(c.consul.CACertFile) + caCertPem, err = os.ReadFile(c.consul.CACertFile) if err != nil { c.UI.Error(fmt.Sprintf("error reading Consul's CA cert file %q", c.consul.CACertFile)) return 1 @@ -349,14 +391,14 @@ func (c *Command) Run(args []string) int { c.UI.Error(fmt.Sprintf("unable to create config for consul-server-connection-manager: %s", err)) return 1 } - - watcher, err := discovery.NewWatcher(ctx, serverConnMgrCfg, hcLog.Named("consul-server-connection-manager")) + watcher, err := discovery.NewWatcher(ctx, serverConnMgrCfg, hcLog) if err != nil { c.UI.Error(fmt.Sprintf("unable to create Consul server watcher: %s", err)) return 1 } - defer watcher.Stop() + go watcher.Run() + defer watcher.Stop() // This is a blocking command that is run in order to ensure we only start the // connect-inject controllers only after we have access to the Consul server. @@ -381,17 +423,320 @@ func (c *Command) Run(args []string) int { return 1 } - //Right now we exclusively start controllers for V1 or V2. - //In the future we might add a flag to pick and choose from both. - if c.flagResourceAPIs { - err = c.configureV2Controllers(ctx, mgr, watcher) - } else { - err = c.configureV1Controllers(ctx, mgr, watcher) + lifecycleConfig := lifecycle.Config{ + DefaultEnableProxyLifecycle: c.flagDefaultEnableSidecarProxyLifecycle, + DefaultEnableShutdownDrainListeners: c.flagDefaultEnableSidecarProxyLifecycleShutdownDrainListeners, + DefaultShutdownGracePeriodSeconds: c.flagDefaultSidecarProxyLifecycleShutdownGracePeriodSeconds, + DefaultGracefulPort: c.flagDefaultSidecarProxyLifecycleGracefulPort, + DefaultGracefulShutdownPath: c.flagDefaultSidecarProxyLifecycleGracefulShutdownPath, + } + + metricsConfig := metrics.Config{ + DefaultEnableMetrics: c.flagDefaultEnableMetrics, + EnableGatewayMetrics: c.flagEnableGatewayMetrics, + DefaultEnableMetricsMerging: c.flagDefaultEnableMetricsMerging, + DefaultMergedMetricsPort: c.flagDefaultMergedMetricsPort, + DefaultPrometheusScrapePort: c.flagDefaultPrometheusScrapePort, + DefaultPrometheusScrapePath: c.flagDefaultPrometheusScrapePath, + } + + if err = (&endpoints.Controller{ + Client: mgr.GetClient(), + ConsulClientConfig: consulConfig, + ConsulServerConnMgr: watcher, + AllowK8sNamespacesSet: allowK8sNamespaces, + DenyK8sNamespacesSet: denyK8sNamespaces, + MetricsConfig: metricsConfig, + EnableConsulPartitions: c.flagEnablePartitions, + EnableConsulNamespaces: c.flagEnableNamespaces, + ConsulDestinationNamespace: c.flagConsulDestinationNamespace, + EnableNSMirroring: c.flagEnableK8SNSMirroring, + NSMirroringPrefix: c.flagK8SNSMirroringPrefix, + CrossNSACLPolicy: c.flagCrossNamespaceACLPolicy, + EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, + EnableWANFederation: c.flagEnableFederation, + TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, + AuthMethod: c.flagACLAuthMethod, + NodeMeta: c.flagNodeMeta, + Log: ctrl.Log.WithName("controller").WithName("endpoints"), + Scheme: mgr.GetScheme(), + ReleaseName: c.flagReleaseName, + ReleaseNamespace: c.flagReleaseNamespace, + EnableAutoEncrypt: c.flagEnableAutoEncrypt, + Context: ctx, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", endpoints.Controller{}) + return 1 } - if err != nil { - setupLog.Error(err, fmt.Sprintf("could not configure controllers: %s", err.Error())) + + consulMeta := apicommon.ConsulMeta{ + PartitionsEnabled: c.flagEnablePartitions, + Partition: c.consul.Partition, + NamespacesEnabled: c.flagEnableNamespaces, + DestinationNamespace: c.flagConsulDestinationNamespace, + Mirroring: c.flagEnableK8SNSMirroring, + Prefix: c.flagK8SNSMirroringPrefix, + } + + configEntryReconciler := &controller.ConfigEntryController{ + ConsulClientConfig: c.consul.ConsulClientConfig(), + ConsulServerConnMgr: watcher, + DatacenterName: c.consul.Datacenter, + EnableConsulNamespaces: c.flagEnableNamespaces, + ConsulDestinationNamespace: c.flagConsulDestinationNamespace, + EnableNSMirroring: c.flagEnableK8SNSMirroring, + NSMirroringPrefix: c.flagK8SNSMirroringPrefix, + CrossNSACLPolicy: c.flagCrossNamespaceACLPolicy, + } + if err = (&controller.ServiceDefaultsController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceDefaults), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceDefaults) + return 1 + } + if err = (&controller.ServiceResolverController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceResolver), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceResolver) + return 1 + } + if err = (&controller.ProxyDefaultsController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.ProxyDefaults), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.ProxyDefaults) + return 1 + } + if err = (&controller.MeshController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.Mesh), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.Mesh) + return 1 + } + if err = (&controller.ExportedServicesController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.ExportedServices), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.ExportedServices) return 1 } + if err = (&controller.ServiceRouterController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceRouter), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceRouter) + return 1 + } + if err = (&controller.ServiceSplitterController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceSplitter), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceSplitter) + return 1 + } + if err = (&controller.ServiceIntentionsController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceIntentions), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceIntentions) + return 1 + } + if err = (&controller.IngressGatewayController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.IngressGateway), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.IngressGateway) + return 1 + } + if err = (&controller.TerminatingGatewayController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.TerminatingGateway), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.TerminatingGateway) + return 1 + } + + 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 1 + } + + if c.flagEnablePeering { + if err = (&peering.AcceptorController{ + Client: mgr.GetClient(), + ConsulClientConfig: consulConfig, + ConsulServerConnMgr: watcher, + ExposeServersServiceName: c.flagResourcePrefix + "-expose-servers", + ReleaseNamespace: c.flagReleaseNamespace, + Log: ctrl.Log.WithName("controller").WithName("peering-acceptor"), + Scheme: mgr.GetScheme(), + Context: ctx, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "peering-acceptor") + return 1 + } + if err = (&peering.PeeringDialerController{ + Client: mgr.GetClient(), + ConsulClientConfig: consulConfig, + ConsulServerConnMgr: watcher, + Log: ctrl.Log.WithName("controller").WithName("peering-dialer"), + Scheme: mgr.GetScheme(), + Context: ctx, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "peering-dialer") + return 1 + } + + mgr.GetWebhookServer().Register("/mutate-v1alpha1-peeringacceptors", + &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.PeeringAcceptorWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName("peering-acceptor"), + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-peeringdialers", + &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.PeeringDialerWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName("peering-dialer"), + }}) + } + + mgr.GetWebhookServer().CertDir = c.flagCertDir + + mgr.GetWebhookServer().Register("/mutate", + &ctrlRuntimeWebhook.Admission{Handler: &webhook.MeshWebhook{ + 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(caCertPem), + TLSEnabled: c.consul.UseTLS, + ConsulAddress: c.consul.Addresses, + SkipServerWatch: c.consul.SkipServerWatch, + ConsulTLSServerName: c.consul.TLSServerName, + DefaultProxyCPURequest: sidecarProxyCPURequest, + DefaultProxyCPULimit: sidecarProxyCPULimit, + DefaultProxyMemoryRequest: sidecarProxyMemoryRequest, + DefaultProxyMemoryLimit: sidecarProxyMemoryLimit, + DefaultEnvoyProxyConcurrency: c.flagDefaultEnvoyProxyConcurrency, + LifecycleConfig: lifecycleConfig, + MetricsConfig: metricsConfig, + InitContainerResources: initResources, + 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, + }}) + + // Note: The path here should be identical to the one on the kubebuilder + // annotation in each webhook file. + mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicedefaults", + &ctrlwebhook.Admission{Handler: &v1alpha1.ServiceDefaultsWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceDefaults), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-serviceresolver", + &ctrlwebhook.Admission{Handler: &v1alpha1.ServiceResolverWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceResolver), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-proxydefaults", + &ctrlwebhook.Admission{Handler: &v1alpha1.ProxyDefaultsWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ProxyDefaults), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-mesh", + &ctrlwebhook.Admission{Handler: &v1alpha1.MeshWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.Mesh), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-exportedservices", + &ctrlwebhook.Admission{Handler: &v1alpha1.ExportedServicesWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ExportedServices), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicerouter", + &ctrlwebhook.Admission{Handler: &v1alpha1.ServiceRouterWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceRouter), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicesplitter", + &ctrlwebhook.Admission{Handler: &v1alpha1.ServiceSplitterWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceSplitter), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-serviceintentions", + &ctrlwebhook.Admission{Handler: &v1alpha1.ServiceIntentionsWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceIntentions), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-ingressgateway", + &ctrlwebhook.Admission{Handler: &v1alpha1.IngressGatewayWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.IngressGateway), + ConsulMeta: consulMeta, + }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-terminatinggateway", + &ctrlwebhook.Admission{Handler: &v1alpha1.TerminatingGatewayWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.TerminatingGateway), + ConsulMeta: consulMeta, + }}) + + if c.flagEnableWebhookCAUpdate { + err = c.updateWebhookCABundle(ctx) + if err != nil { + setupLog.Error(err, "problem getting CA Cert") + return 1 + } + } if err = mgr.Start(ctx); err != nil { setupLog.Error(err, "problem running manager") @@ -401,6 +746,20 @@ func (c *Command) Run(args []string) int { return 0 } +func (c *Command) updateWebhookCABundle(ctx context.Context) error { + webhookConfigName := fmt.Sprintf("%s-connect-injector", c.flagResourcePrefix) + caPath := fmt.Sprintf("%s/%s", c.flagCertDir, WebhookCAFilename) + caCert, err := os.ReadFile(caPath) + if err != nil { + return err + } + err = mutatingwebhookconfiguration.UpdateWithCABundle(ctx, c.clientset, webhookConfigName, caCert) + if err != nil { + return err + } + return nil +} + func (c *Command) validateFlags() error { if c.flagConsulK8sImage == "" { return errors.New("-consul-k8s-image must be set") @@ -424,95 +783,48 @@ func (c *Command) validateFlags() error { return errors.New("-default-envoy-proxy-concurrency must be >= 0 if set") } - // Validate ports in metrics flags. - err := common.ValidateUnprivilegedPort("-default-merged-metrics-port", c.flagDefaultMergedMetricsPort) - if err != nil { - return err - } - err = common.ValidateUnprivilegedPort("-default-prometheus-scrape-port", c.flagDefaultPrometheusScrapePort) - if err != nil { - return err - } - - return nil -} - -func (c *Command) parseAndValidateSidecarProxyFlags() error { - var err error - - if c.flagDefaultSidecarProxyCPURequest != "" { - c.sidecarProxyCPURequest, err = resource.ParseQuantity(c.flagDefaultSidecarProxyCPURequest) - if err != nil { - return fmt.Errorf("-default-sidecar-proxy-cpu-request is invalid: %w", err) - } - } - - if c.flagDefaultSidecarProxyCPULimit != "" { - c.sidecarProxyCPULimit, err = resource.ParseQuantity(c.flagDefaultSidecarProxyCPULimit) - if err != nil { - return fmt.Errorf("-default-sidecar-proxy-cpu-limit is invalid: %w", err) - } - } - if c.sidecarProxyCPULimit.Value() != 0 && c.sidecarProxyCPURequest.Cmp(c.sidecarProxyMemoryLimit) > 0 { - return fmt.Errorf("request must be <= limit: -default-sidecar-proxy-cpu-request value of %q is greater than the -default-sidecar-proxy-cpu-limit value of %q", - c.flagDefaultSidecarProxyCPURequest, c.flagDefaultSidecarProxyCPULimit) - } - - if c.flagDefaultSidecarProxyMemoryRequest != "" { - c.sidecarProxyMemoryRequest, err = resource.ParseQuantity(c.flagDefaultSidecarProxyMemoryRequest) - if err != nil { - return fmt.Errorf("-default-sidecar-proxy-memory-request is invalid: %w", err) - } - } - if c.flagDefaultSidecarProxyMemoryLimit != "" { - c.sidecarProxyMemoryLimit, err = resource.ParseQuantity(c.flagDefaultSidecarProxyMemoryLimit) - if err != nil { - return fmt.Errorf("-default-sidecar-proxy-memory-limit is invalid: %w", err) - } - } - if c.sidecarProxyMemoryLimit.Value() != 0 && c.sidecarProxyMemoryRequest.Cmp(c.sidecarProxyMemoryLimit) > 0 { - return fmt.Errorf("request must be <= limit: -default-sidecar-proxy-memory-request value of %q is greater than the -default-sidecar-proxy-memory-limit value of %q", - c.flagDefaultSidecarProxyMemoryRequest, c.flagDefaultSidecarProxyMemoryLimit) - } - return nil } -func (c *Command) parseAndValidateResourceFlags() error { +func (c *Command) parseAndValidateResourceFlags() (corev1.ResourceRequirements, error) { // Init container var initContainerCPULimit, initContainerCPURequest, initContainerMemoryLimit, initContainerMemoryRequest resource.Quantity // Parse and validate the initContainer resources. initContainerCPURequest, err := resource.ParseQuantity(c.flagInitContainerCPURequest) if err != nil { - return fmt.Errorf("-init-container-cpu-request '%s' is invalid: %s", c.flagInitContainerCPURequest, err) + return corev1.ResourceRequirements{}, + fmt.Errorf("-init-container-cpu-request '%s' is invalid: %s", c.flagInitContainerCPURequest, err) } initContainerCPULimit, err = resource.ParseQuantity(c.flagInitContainerCPULimit) if err != nil { - return fmt.Errorf("-init-container-cpu-limit '%s' is invalid: %s", c.flagInitContainerCPULimit, err) + return corev1.ResourceRequirements{}, + fmt.Errorf("-init-container-cpu-limit '%s' is invalid: %s", c.flagInitContainerCPULimit, err) } if initContainerCPULimit.Value() != 0 && initContainerCPURequest.Cmp(initContainerCPULimit) > 0 { - return fmt.Errorf( + return corev1.ResourceRequirements{}, fmt.Errorf( "request must be <= limit: -init-container-cpu-request value of %q is greater than the -init-container-cpu-limit value of %q", c.flagInitContainerCPURequest, c.flagInitContainerCPULimit) } initContainerMemoryRequest, err = resource.ParseQuantity(c.flagInitContainerMemoryRequest) if err != nil { - return fmt.Errorf("-init-container-memory-request '%s' is invalid: %s", c.flagInitContainerMemoryRequest, err) + return corev1.ResourceRequirements{}, + fmt.Errorf("-init-container-memory-request '%s' is invalid: %s", c.flagInitContainerMemoryRequest, err) } initContainerMemoryLimit, err = resource.ParseQuantity(c.flagInitContainerMemoryLimit) if err != nil { - return fmt.Errorf("-init-container-memory-limit '%s' is invalid: %s", c.flagInitContainerMemoryLimit, err) + return corev1.ResourceRequirements{}, + fmt.Errorf("-init-container-memory-limit '%s' is invalid: %s", c.flagInitContainerMemoryLimit, err) } if initContainerMemoryLimit.Value() != 0 && initContainerMemoryRequest.Cmp(initContainerMemoryLimit) > 0 { - return fmt.Errorf( + return corev1.ResourceRequirements{}, fmt.Errorf( "request must be <= limit: -init-container-memory-request value of %q is greater than the -init-container-memory-limit value of %q", c.flagInitContainerMemoryRequest, c.flagInitContainerMemoryLimit) } // Put into corev1.ResourceRequirements form - c.initContainerResources = corev1.ResourceRequirements{ + initResources := corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: initContainerCPURequest, corev1.ResourceMemory: initContainerMemoryRequest, @@ -523,7 +835,7 @@ func (c *Command) parseAndValidateResourceFlags() error { }, } - return nil + return initResources, nil } func (c *Command) Synopsis() string { return synopsis } diff --git a/control-plane/subcommand/inject-connect/command_test.go b/control-plane/subcommand/inject-connect/command_test.go index 9c64020376..5f067cf7c2 100644 --- a/control-plane/subcommand/inject-connect/command_test.go +++ b/control-plane/subcommand/inject-connect/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package connectinject import ( diff --git a/control-plane/subcommand/inject-connect/v1controllers.go b/control-plane/subcommand/inject-connect/v1controllers.go deleted file mode 100644 index 57ac1691c3..0000000000 --- a/control-plane/subcommand/inject-connect/v1controllers.go +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package connectinject - -import ( - "context" - "fmt" - "os" - - "github.com/hashicorp/consul-server-connection-manager/discovery" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/manager" - ctrlRuntimeWebhook "sigs.k8s.io/controller-runtime/pkg/webhook" - - gatewaycommon "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" - 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/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" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/webhook" - "github.com/hashicorp/consul-k8s/control-plane/controllers" - mutatingwebhookconfiguration "github.com/hashicorp/consul-k8s/control-plane/helper/mutating-webhook-configuration" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" -) - -func (c *Command) configureV1Controllers(ctx context.Context, mgr manager.Manager, watcher *discovery.Watcher) error { - - // Create Consul API config object. - consulConfig := c.consul.ConsulClientConfig() - - // Convert allow/deny lists to sets. - allowK8sNamespaces := flags.ToSet(c.flagAllowK8sNamespacesList) - denyK8sNamespaces := flags.ToSet(c.flagDenyK8sNamespacesList) - - lifecycleConfig := lifecycle.Config{ - DefaultEnableProxyLifecycle: c.flagDefaultEnableSidecarProxyLifecycle, - DefaultEnableShutdownDrainListeners: c.flagDefaultEnableSidecarProxyLifecycleShutdownDrainListeners, - DefaultShutdownGracePeriodSeconds: c.flagDefaultSidecarProxyLifecycleShutdownGracePeriodSeconds, - DefaultGracefulPort: c.flagDefaultSidecarProxyLifecycleGracefulPort, - DefaultGracefulShutdownPath: c.flagDefaultSidecarProxyLifecycleGracefulShutdownPath, - } - - metricsConfig := metrics.Config{ - DefaultEnableMetrics: c.flagDefaultEnableMetrics, - EnableGatewayMetrics: c.flagEnableGatewayMetrics, - DefaultEnableMetricsMerging: c.flagDefaultEnableMetricsMerging, - DefaultMergedMetricsPort: c.flagDefaultMergedMetricsPort, - DefaultPrometheusScrapePort: c.flagDefaultPrometheusScrapePort, - DefaultPrometheusScrapePath: c.flagDefaultPrometheusScrapePath, - } - - if err := (&endpoints.Controller{ - Client: mgr.GetClient(), - ConsulClientConfig: consulConfig, - ConsulServerConnMgr: watcher, - AllowK8sNamespacesSet: allowK8sNamespaces, - DenyK8sNamespacesSet: denyK8sNamespaces, - MetricsConfig: metricsConfig, - EnableConsulPartitions: c.flagEnablePartitions, - EnableConsulNamespaces: c.flagEnableNamespaces, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - EnableNSMirroring: c.flagEnableK8SNSMirroring, - NSMirroringPrefix: c.flagK8SNSMirroringPrefix, - CrossNSACLPolicy: c.flagCrossNamespaceACLPolicy, - EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, - EnableWANFederation: c.flagEnableFederation, - TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, - AuthMethod: c.flagACLAuthMethod, - NodeMeta: c.flagNodeMeta, - Log: ctrl.Log.WithName("controller").WithName("endpoints"), - Scheme: mgr.GetScheme(), - ReleaseName: c.flagReleaseName, - ReleaseNamespace: c.flagReleaseNamespace, - EnableAutoEncrypt: c.flagEnableAutoEncrypt, - EnableTelemetryCollector: c.flagEnableTelemetryCollector, - Context: ctx, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", endpoints.Controller{}) - return err - } - - // API Gateway Controllers - if err := gatewaycontrollers.RegisterFieldIndexes(ctx, mgr); err != nil { - setupLog.Error(err, "unable to register field indexes") - return err - } - - if err := (&gatewaycontrollers.GatewayClassConfigController{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName("gateways"), - }).SetupWithManager(ctx, mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", gatewaycontrollers.GatewayClassConfigController{}) - return err - } - - if err := (&gatewaycontrollers.GatewayClassController{ - ControllerName: gatewaycommon.GatewayClassControllerName, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("GatewayClass"), - }).SetupWithManager(ctx, mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "GatewayClass") - return err - } - - cache, err := gatewaycontrollers.SetupGatewayControllerWithManager(ctx, mgr, gatewaycontrollers.GatewayControllerConfig{ - HelmConfig: gatewaycommon.HelmConfig{ - ConsulConfig: gatewaycommon.ConsulConfig{ - Address: c.consul.Addresses, - GRPCPort: consulConfig.GRPCPort, - HTTPPort: consulConfig.HTTPPort, - APITimeout: consulConfig.APITimeout, - }, - ImageDataplane: c.flagConsulDataplaneImage, - ImageConsulK8S: c.flagConsulK8sImage, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NamespaceMirroringPrefix: c.flagK8SNSMirroringPrefix, - EnableNamespaces: c.flagEnableNamespaces, - PeeringEnabled: c.flagEnablePeering, - EnableOpenShift: c.flagEnableOpenShift, - EnableNamespaceMirroring: c.flagEnableK8SNSMirroring, - AuthMethod: c.consul.ConsulLogin.AuthMethod, - LogLevel: c.flagLogLevel, - LogJSON: c.flagLogJSON, - TLSEnabled: c.consul.UseTLS, - ConsulTLSServerName: c.consul.TLSServerName, - ConsulPartition: c.consul.Partition, - ConsulCACert: string(c.caCertPem), - }, - AllowK8sNamespacesSet: allowK8sNamespaces, - DenyK8sNamespacesSet: denyK8sNamespaces, - ConsulClientConfig: consulConfig, - ConsulServerConnMgr: watcher, - NamespacesEnabled: c.flagEnableNamespaces, - CrossNamespaceACLPolicy: c.flagCrossNamespaceACLPolicy, - Partition: c.consul.Partition, - Datacenter: c.consul.Datacenter, - }) - - if err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Gateway") - return err - } - - go cache.Run(ctx) - - // wait for the cache to fill - setupLog.Info("waiting for Consul cache sync") - cache.WaitSynced(ctx) - setupLog.Info("Consul cache synced") - - configEntryReconciler := &controllers.ConfigEntryController{ - ConsulClientConfig: consulConfig, - ConsulServerConnMgr: watcher, - DatacenterName: c.consul.Datacenter, - EnableConsulNamespaces: c.flagEnableNamespaces, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - EnableNSMirroring: c.flagEnableK8SNSMirroring, - NSMirroringPrefix: c.flagK8SNSMirroringPrefix, - CrossNSACLPolicy: c.flagCrossNamespaceACLPolicy, - } - if err := (&controllers.ServiceDefaultsController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceDefaults), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceDefaults) - return err - } - if err := (&controllers.ServiceResolverController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceResolver), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceResolver) - return err - } - if err := (&controllers.ProxyDefaultsController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ProxyDefaults), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ProxyDefaults) - return err - } - if err := (&controllers.MeshController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.Mesh), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.Mesh) - return err - } - if err := (&controllers.ExportedServicesController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ExportedServices), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ExportedServices) - return err - } - if err := (&controllers.ServiceRouterController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceRouter), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceRouter) - return err - } - if err := (&controllers.ServiceSplitterController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceSplitter), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceSplitter) - return err - } - if err := (&controllers.ServiceIntentionsController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceIntentions), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceIntentions) - return err - } - if err := (&controllers.IngressGatewayController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.IngressGateway), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.IngressGateway) - return err - } - if err := (&controllers.TerminatingGatewayController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.TerminatingGateway), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.TerminatingGateway) - return err - } - if err := (&controllers.SamenessGroupController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.SamenessGroup), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.SamenessGroup) - return err - } - if err := (&controllers.JWTProviderController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.JWTProvider), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.JWTProvider) - return err - } - if err := (&controllers.ControlPlaneRequestLimitController{ - ConfigEntryController: configEntryReconciler, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ControlPlaneRequestLimit), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ControlPlaneRequestLimit) - 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 - } - - if c.flagEnablePeering { - if err := (&peering.AcceptorController{ - Client: mgr.GetClient(), - ConsulClientConfig: consulConfig, - ConsulServerConnMgr: watcher, - ExposeServersServiceName: c.flagResourcePrefix + "-expose-servers", - ReleaseNamespace: c.flagReleaseNamespace, - Log: ctrl.Log.WithName("controller").WithName("peering-acceptor"), - Scheme: mgr.GetScheme(), - Context: ctx, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "peering-acceptor") - return err - } - if err := (&peering.PeeringDialerController{ - Client: mgr.GetClient(), - ConsulClientConfig: consulConfig, - ConsulServerConnMgr: watcher, - Log: ctrl.Log.WithName("controller").WithName("peering-dialer"), - Scheme: mgr.GetScheme(), - Context: ctx, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "peering-dialer") - return err - } - - mgr.GetWebhookServer().Register("/mutate-v1alpha1-peeringacceptors", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.PeeringAcceptorWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName("peering-acceptor"), - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-peeringdialers", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.PeeringDialerWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName("peering-dialer"), - }}) - } - - mgr.GetWebhookServer().CertDir = c.flagCertDir - - mgr.GetWebhookServer().Register("/mutate", - &ctrlRuntimeWebhook.Admission{Handler: &webhook.MeshWebhook{ - 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, - 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, - }}) - - consulMeta := apicommon.ConsulMeta{ - PartitionsEnabled: c.flagEnablePartitions, - Partition: c.consul.Partition, - NamespacesEnabled: c.flagEnableNamespaces, - DestinationNamespace: c.flagConsulDestinationNamespace, - Mirroring: c.flagEnableK8SNSMirroring, - Prefix: c.flagK8SNSMirroringPrefix, - } - - // Note: The path here should be identical to the one on the kubebuilder - // annotation in each webhook file. - mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicedefaults", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ServiceDefaultsWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceDefaults), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-serviceresolver", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ServiceResolverWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceResolver), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-proxydefaults", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ProxyDefaultsWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ProxyDefaults), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-mesh", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.MeshWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.Mesh), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-exportedservices", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ExportedServicesWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ExportedServices), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicerouter", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ServiceRouterWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceRouter), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicesplitter", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ServiceSplitterWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceSplitter), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-serviceintentions", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ServiceIntentionsWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ServiceIntentions), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-ingressgateway", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.IngressGatewayWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.IngressGateway), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-terminatinggateway", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.TerminatingGatewayWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.TerminatingGateway), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-samenessgroup", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.SamenessGroupWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.SamenessGroup), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-jwtprovider", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.JWTProviderWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.JWTProvider), - ConsulMeta: consulMeta, - }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-controlplanerequestlimits", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.ControlPlaneRequestLimitWebhook{ - Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.ControlPlaneRequestLimit), - ConsulMeta: consulMeta, - }}) - - if c.flagEnableWebhookCAUpdate { - err = c.updateWebhookCABundle(ctx) - if err != nil { - setupLog.Error(err, "problem getting CA Cert") - return err - } - } - - return nil -} - -func (c *Command) updateWebhookCABundle(ctx context.Context) error { - webhookConfigName := fmt.Sprintf("%s-connect-injector", c.flagResourcePrefix) - caPath := fmt.Sprintf("%s/%s", c.flagCertDir, WebhookCAFilename) - caCert, err := os.ReadFile(caPath) - if err != nil { - return err - } - err = mutatingwebhookconfiguration.UpdateWithCABundle(ctx, c.clientset, webhookConfigName, caCert) - if err != nil { - return err - } - return nil -} diff --git a/control-plane/subcommand/inject-connect/v2controllers.go b/control-plane/subcommand/inject-connect/v2controllers.go deleted file mode 100644 index d851f71cb8..0000000000 --- a/control-plane/subcommand/inject-connect/v2controllers.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package connectinject - -import ( - "context" - - "github.com/hashicorp/consul-server-connection-manager/discovery" - "sigs.k8s.io/controller-runtime/pkg/manager" -) - -func (c *Command) configureV2Controllers(ctx context.Context, mgr manager.Manager, watcher *discovery.Watcher) error { - - //resourceClient, err := consul.NewResourceServiceClient(watcher) - //if err != nil { - // return fmt.Errorf("unable to create Consul resource service client: %w", err) - //} - - //// Create Consul API config object. - //consulConfig := c.consul.ConsulClientConfig() - // - ////Convert allow/deny lists to sets. - //allowK8sNamespaces := flags.ToSet(c.flagAllowK8sNamespacesList) - //denyK8sNamespaces := flags.ToSet(c.flagDenyK8sNamespacesList) - - //lifecycleConfig := lifecycle.Config{ - // DefaultEnableProxyLifecycle: c.flagDefaultEnableSidecarProxyLifecycle, - // DefaultEnableShutdownDrainListeners: c.flagDefaultEnableSidecarProxyLifecycleShutdownDrainListeners, - // DefaultShutdownGracePeriodSeconds: c.flagDefaultSidecarProxyLifecycleShutdownGracePeriodSeconds, - // DefaultGracefulPort: c.flagDefaultSidecarProxyLifecycleGracefulPort, - // DefaultGracefulShutdownPath: c.flagDefaultSidecarProxyLifecycleGracefulShutdownPath, - //} - - //metricsConfig := metrics.Config{ - // DefaultEnableMetrics: c.flagDefaultEnableMetrics, - // EnableGatewayMetrics: c.flagEnableGatewayMetrics, - // DefaultEnableMetricsMerging: c.flagDefaultEnableMetricsMerging, - // DefaultMergedMetricsPort: c.flagDefaultMergedMetricsPort, - // DefaultPrometheusScrapePort: c.flagDefaultPrometheusScrapePort, - // DefaultPrometheusScrapePath: c.flagDefaultPrometheusScrapePath, - //} - - // TODO(dans): Pods Controller - //if err := (&pod.Controller{ - // Client: mgr.GetClient(), - // ConsulClientConfig: consulConfig, - // ConsulServerConnMgr: watcher, - // ConsulResourceServiceClient: client, - // AllowK8sNamespacesSet: allowK8sNamespaces, - // DenyK8sNamespacesSet: denyK8sNamespaces, - // MetricsConfig: metricsConfig, - // EnableConsulPartitions: c.flagEnablePartitions, - // EnableConsulNamespaces: c.flagEnableNamespaces, - // ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - // EnableNSMirroring: c.flagEnableK8SNSMirroring, - // NSMirroringPrefix: c.flagK8SNSMirroringPrefix, - // EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, - // TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, - // AuthMethod: c.flagACLAuthMethod, - // NodeMeta: c.flagNodeMeta, - // Log: ctrl.Log.WithName("controller").WithName("pods"), - // Scheme: mgr.GetScheme(), - // EnableTelemetryCollector: c.flagEnableTelemetryCollector, - // Context: ctx, - //}).SetupWithManager(mgr); err != nil { - // setupLog.Error(err, "unable to create controller", "controller", pod.Controller{}) - // return err - //} - - // TODO: V2 Endpoints Controller - - // TODO: Nodes Controller - - // TODO: Serviceaccounts Controller - - // TODO: V2 Config Controller(s) - - // // Metadata for webhooks - //consulMeta := apicommon.ConsulMeta{ - // PartitionsEnabled: c.flagEnablePartitions, - // Partition: c.consul.Partition, - // NamespacesEnabled: c.flagEnableNamespaces, - // DestinationNamespace: c.flagConsulDestinationNamespace, - // Mirroring: c.flagEnableK8SNSMirroring, - // Prefix: c.flagK8SNSMirroringPrefix, - //} - - // TODO: register webhooks - - // TODO: Update Webhook CA Bundle - - return nil -} diff --git a/control-plane/subcommand/install-cni/binary.go b/control-plane/subcommand/install-cni/binary.go index 5bf25ab607..2429770109 100644 --- a/control-plane/subcommand/install-cni/binary.go +++ b/control-plane/subcommand/install-cni/binary.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/install-cni/binary_test.go b/control-plane/subcommand/install-cni/binary_test.go index 397751d42c..e65f61c63b 100644 --- a/control-plane/subcommand/install-cni/binary_test.go +++ b/control-plane/subcommand/install-cni/binary_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/install-cni/cniconfig.go b/control-plane/subcommand/install-cni/cniconfig.go index 448c9efa92..922d7283dd 100644 --- a/control-plane/subcommand/install-cni/cniconfig.go +++ b/control-plane/subcommand/install-cni/cniconfig.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/install-cni/cniconfig_test.go b/control-plane/subcommand/install-cni/cniconfig_test.go index 06fa848074..b6e2154adb 100644 --- a/control-plane/subcommand/install-cni/cniconfig_test.go +++ b/control-plane/subcommand/install-cni/cniconfig_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/install-cni/command.go b/control-plane/subcommand/install-cni/command.go index 53abe7cda1..7c481a0800 100644 --- a/control-plane/subcommand/install-cni/command.go +++ b/control-plane/subcommand/install-cni/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/install-cni/command_test.go b/control-plane/subcommand/install-cni/command_test.go index d5ee65f928..5cb9bea91e 100644 --- a/control-plane/subcommand/install-cni/command_test.go +++ b/control-plane/subcommand/install-cni/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/install-cni/kubeconfig.go b/control-plane/subcommand/install-cni/kubeconfig.go index 467130dea9..ca93759578 100644 --- a/control-plane/subcommand/install-cni/kubeconfig.go +++ b/control-plane/subcommand/install-cni/kubeconfig.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/install-cni/kubeconfig_test.go b/control-plane/subcommand/install-cni/kubeconfig_test.go index 8197115db3..899ad3f600 100644 --- a/control-plane/subcommand/install-cni/kubeconfig_test.go +++ b/control-plane/subcommand/install-cni/kubeconfig_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package installcni import ( diff --git a/control-plane/subcommand/partition-init/command.go b/control-plane/subcommand/partition-init/command.go index 0684f8b1bb..7ca70b50a7 100644 --- a/control-plane/subcommand/partition-init/command.go +++ b/control-plane/subcommand/partition-init/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package partition_init import ( @@ -11,14 +8,13 @@ import ( "sync" "time" + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" "github.com/hashicorp/consul-server-connection-manager/discovery" "github.com/hashicorp/consul/api" "github.com/hashicorp/go-hclog" "github.com/mitchellh/cli" - - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" ) type Command struct { @@ -31,8 +27,6 @@ type Command struct { flagLogJSON bool flagTimeout time.Duration - flagResourceAPIs bool // Use V2 APIs - // ctx is cancelled when the command timeout is reached. ctx context.Context retryDuration time.Duration @@ -54,8 +48,6 @@ func (c *Command) init() { "\"debug\", \"info\", \"warn\", and \"error\".") c.flags.BoolVar(&c.flagLogJSON, "log-json", false, "Enable or disable JSON output format for logging.") - c.flags.BoolVar(&c.flagResourceAPIs, "enable-resource-apis", false, - "Enable of disable V2 Resource APIs.") c.consul = &flags.ConsulFlags{} flags.Merge(c.flags, c.consul.Flags()) @@ -176,12 +168,6 @@ func (c *Command) validateFlags() error { if c.consul.APITimeout <= 0 { return errors.New("-api-timeout must be set to a value greater than 0") } - - // TODO(dans) this needs to be replaced when the partition workflow is available. - if c.flagResourceAPIs { - return errors.New("partition-init is not implemented when the -enable-resource-apis flag is set for V2 Resource APIs") - } - return nil } diff --git a/control-plane/subcommand/partition-init/command_ent_test.go b/control-plane/subcommand/partition-init/command_ent_test.go index 182412c8aa..5bb1868b39 100644 --- a/control-plane/subcommand/partition-init/command_ent_test.go +++ b/control-plane/subcommand/partition-init/command_ent_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package partition_init diff --git a/control-plane/subcommand/server-acl-init/anonymous_token.go b/control-plane/subcommand/server-acl-init/anonymous_token.go index 32c19ec208..3423ee78da 100644 --- a/control-plane/subcommand/server-acl-init/anonymous_token.go +++ b/control-plane/subcommand/server-acl-init/anonymous_token.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index 7ff0ae2268..698da2a25c 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( @@ -25,11 +22,12 @@ import ( "github.com/hashicorp/consul/api" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-netaddrs" - vaultApi "github.com/hashicorp/vault/api" "github.com/mitchellh/cli" "github.com/mitchellh/mapstructure" "golang.org/x/text/cases" "golang.org/x/text/language" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) @@ -88,10 +86,8 @@ type Command struct { flagEnableInjectK8SNSMirroring bool // Enables mirroring of k8s namespaces into Consul for Connect inject flagInjectK8SNSMirroringPrefix string // Prefix added to Consul namespaces created when mirroring injected services - // Flags for the secrets backend. - flagSecretsBackend SecretsBackendType - flagBootstrapTokenSecretName string - flagBootstrapTokenSecretKey string + // Flag to support a custom bootstrap token. + flagBootstrapTokenFile string flagLogLevel string flagLogJSON bool @@ -102,9 +98,7 @@ type Command struct { // flagFederation indicates if federation has been enabled in the cluster. flagFederation bool - backend SecretsBackend // for unit testing. - clientset kubernetes.Interface - vaultClient *vaultApi.Client + clientset kubernetes.Interface watcher consul.ServerConnectionManager @@ -200,14 +194,9 @@ func (c *Command) init() { c.flags.BoolVar(&c.flagFederation, "federation", false, "Toggle for when federation has been enabled.") - c.flags.StringVar((*string)(&c.flagSecretsBackend), "secrets-backend", "kubernetes", - `The secrets backend to use. Either "vault" or "kubernetes". Defaults to "kubernetes"`) - c.flags.StringVar(&c.flagBootstrapTokenSecretName, "bootstrap-token-secret-name", "", - "The name of the Vault or Kuberenetes secret for the bootstrap token. This token must have `ac::write` permission "+ - "in order to create policies and tokens. If not provided or if the secret is empty, then this command will "+ - "bootstrap ACLs and write the bootstrap token to this secret.") - c.flags.StringVar(&c.flagBootstrapTokenSecretKey, "bootstrap-token-secret-key", "", - "The key within the Vault or Kuberenetes secret containing the bootstrap token.") + c.flags.StringVar(&c.flagBootstrapTokenFile, "bootstrap-token-file", "", + "Path to file containing ACL token for creating policies and tokens. This token must have 'acl:write' permissions."+ + "When provided, servers will not be bootstrapped and their policies and tokens will not be updated.") c.flags.DurationVar(&c.flagTimeout, "timeout", 10*time.Minute, "How long we'll try to bootstrap ACLs for before timing out, e.g. 1ms, 2s, 3m") @@ -242,7 +231,6 @@ func (c *Command) Help() string { // The function will retry its tasks indefinitely until they are complete. func (c *Command) Run(args []string) int { c.once.Do(c.init) - defer c.quitVaultAgent() if err := c.flags.Parse(args); err != nil { return 1 } @@ -276,6 +264,16 @@ func (c *Command) Run(args []string) int { } } + var providedBootstrapToken string + if c.flagBootstrapTokenFile != "" { + var err error + providedBootstrapToken, err = loadTokenFromFile(c.flagBootstrapTokenFile) + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + } + var cancel context.CancelFunc c.ctx, cancel = context.WithTimeout(context.Background(), c.flagTimeout) // The context will only ever be intentionally ended by the timeout. @@ -308,12 +306,8 @@ func (c *Command) Run(args []string) int { c.UI.Error(err.Error()) } - if err := c.configureSecretsBackend(); err != nil { - c.log.Error(err.Error()) - return 1 - } - var bootstrapToken string + if c.flagACLReplicationTokenFile != "" && !c.flagCreateACLReplicationToken { // If ACL replication is enabled, we don't need to ACL bootstrap the servers // since they will be performing replication. @@ -322,7 +316,21 @@ func (c *Command) Run(args []string) int { c.log.Info("ACL replication is enabled so skipping Consul server ACL bootstrapping") bootstrapToken = aclReplicationToken } else { - bootstrapToken, err = c.bootstrapServers(ipAddrs, c.backend) + // Check if we've already been bootstrapped. + var bootTokenSecretName string + if providedBootstrapToken != "" { + c.log.Info("Using provided bootstrap token") + bootstrapToken = providedBootstrapToken + } else { + bootTokenSecretName = c.withPrefix("bootstrap-acl-token") + bootstrapToken, err = c.getBootstrapToken(bootTokenSecretName) + if err != nil { + c.log.Error(fmt.Sprintf("Unexpected error looking for preexisting bootstrap Secret: %s", err)) + return 1 + } + } + + bootstrapToken, err = c.bootstrapServers(ipAddrs, bootstrapToken, bootTokenSecretName) if err != nil { c.log.Error(err.Error()) return 1 @@ -798,6 +806,24 @@ func (c *Command) configureGateway(gatewayParams ConfigureGatewayParams, consulC return nil } +// getBootstrapToken returns the existing bootstrap token if there is one by +// reading the Kubernetes Secret with name secretName. +// If there is no bootstrap token yet, then it returns an empty string (not an error). +func (c *Command) getBootstrapToken(secretName string) (string, error) { + secret, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(c.ctx, secretName, metav1.GetOptions{}) + if err != nil { + if k8serrors.IsNotFound(err) { + return "", nil + } + return "", err + } + token, ok := secret.Data[common.ACLTokenSecretKey] + if !ok { + return "", fmt.Errorf("secret %q does not have data key 'token'", secretName) + } + return string(token), nil +} + func (c *Command) configureKubeClient() error { config, err := subcommand.K8SConfig(c.k8s.KubeConfig()) if err != nil { @@ -810,55 +836,6 @@ func (c *Command) configureKubeClient() error { return nil } -// configureSecretsBackend configures either the Kubernetes or Vault -// secrets backend based on flags. -func (c *Command) configureSecretsBackend() error { - if c.backend != nil { - // support a fake backend in unit tests - return nil - } - secretName := c.flagBootstrapTokenSecretName - if secretName == "" { - secretName = c.withPrefix("bootstrap-acl-token") - } - - secretKey := c.flagBootstrapTokenSecretKey - if secretKey == "" { - secretKey = common.ACLTokenSecretKey - } - - switch c.flagSecretsBackend { - case SecretsBackendTypeKubernetes: - c.backend = &KubernetesSecretsBackend{ - ctx: c.ctx, - clientset: c.clientset, - k8sNamespace: c.flagK8sNamespace, - secretName: secretName, - secretKey: secretKey, - } - return nil - case SecretsBackendTypeVault: - cfg := vaultApi.DefaultConfig() - cfg.Address = "" - cfg.AgentAddress = "http://127.0.0.1:8200" - vaultClient, err := vaultApi.NewClient(cfg) - if err != nil { - return fmt.Errorf("Error initializing Vault client: %w", err) - } - - c.vaultClient = vaultClient // must set this for c.quitVaultAgent. - c.backend = &VaultSecretsBackend{ - vaultClient: c.vaultClient, - secretName: secretName, - secretKey: secretKey, - } - return nil - default: - validValues := []SecretsBackendType{SecretsBackendTypeKubernetes, SecretsBackendTypeVault} - return fmt.Errorf("Invalid value for -secrets-backend: %q. Valid values are %v.", c.flagSecretsBackend, validValues) - } -} - // untilSucceeds runs op until it returns a nil error. // If c.cmdTimeout is cancelled it will exit. func (c *Command) untilSucceeds(opName string, op func() error) error { @@ -985,10 +962,6 @@ func (c *Command) validateFlags() error { return errors.New("-consul-api-timeout must be set to a value greater than 0") } - //if c.flagVaultNamespace != "" && c.flagSecretsBackend != SecretsBackendTypeVault { - // return fmt.Errorf("-vault-namespace not supported for -secrets-backend=%q", c.flagSecretsBackend) - //} - return nil } @@ -1004,28 +977,6 @@ func loadTokenFromFile(tokenFile string) (string, error) { return strings.TrimSpace(string(tokenBytes)), nil } -func (c *Command) quitVaultAgent() { - if c.vaultClient == nil { - return - } - - // Tell the Vault agent sidecar to quit. Without this, the Job does not - // complete because the Vault agent does not stop. This retries because it - // does not know exactly when the Vault agent sidecar will start. - err := c.untilSucceeds("tell Vault agent to quit", func() error { - // TODO: RawRequest is deprecated, but there is also not a high level - // method for this in the Vault client. - // nolint:staticcheck // SA1004 ignore - _, err := c.vaultClient.RawRequest( - c.vaultClient.NewRequest("POST", "/agent/v1/quit"), - ) - return err - }) - if err != nil { - c.log.Error("Error telling Vault agent to quit", "error", err) - } -} - const ( consulDefaultNamespace = "default" consulDefaultPartition = "default" diff --git a/control-plane/subcommand/server-acl-init/command_ent_test.go b/control-plane/subcommand/server-acl-init/command_ent_test.go index a67a2d0e41..e31b787e4b 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package serveraclinit @@ -225,6 +222,7 @@ func TestRun_ConnectInject_NamespaceMirroring(t *testing.T) { // a non-default partition. func TestRun_AnonymousToken_CreatedFromNonDefaultPartition(t *testing.T) { bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + tokenFile := common.WriteTempFile(t, bootToken) server := partitionedSetup(t, bootToken, "test") k8s := fake.NewSimpleClientset() setUpK8sServiceAccount(t, k8s, ns) @@ -233,7 +231,6 @@ func TestRun_AnonymousToken_CreatedFromNonDefaultPartition(t *testing.T) { cmd := Command{ UI: ui, clientset: k8s, - backend: &FakeSecretsBackend{bootstrapToken: bootToken}, } cmd.init() args := []string{ @@ -242,6 +239,7 @@ func TestRun_AnonymousToken_CreatedFromNonDefaultPartition(t *testing.T) { "-grpc-port=" + strings.Split(server.GRPCAddr, ":")[1], "-resource-prefix=" + resourcePrefix, "-k8s-namespace=" + ns, + "-bootstrap-token-file", tokenFile, "-allow-dns", "-partition=test", "-enable-namespaces", diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index 68ce4c1e02..3111f58820 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( @@ -63,6 +60,13 @@ func TestRun_FlagValidation(t *testing.T) { "-resource-prefix=prefix"}, ExpErr: "unable to read token from file \"/notexist\": open /notexist: no such file or directory", }, + { + Flags: []string{ + "-bootstrap-token-file=/notexist", + "-addresses=localhost", + "-resource-prefix=prefix"}, + ExpErr: "unable to read token from file \"/notexist\": open /notexist: no such file or directory", + }, { Flags: []string{ "-addresses=localhost", @@ -403,6 +407,7 @@ func TestRun_TokensWithProvidedBootstrapToken(t *testing.T) { for _, c := range cases { t.Run(c.TestName, func(t *testing.T) { bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + tokenFile := common.WriteTempFile(t, bootToken) k8s, testAgent := completeBootstrappedSetup(t, bootToken) setUpK8sServiceAccount(t, k8s, ns) @@ -412,11 +417,11 @@ func TestRun_TokensWithProvidedBootstrapToken(t *testing.T) { cmd := Command{ UI: ui, clientset: k8s, - backend: &FakeSecretsBackend{bootstrapToken: bootToken}, } cmdArgs := append([]string{ "-timeout=1m", "-k8s-namespace", ns, + "-bootstrap-token-file", tokenFile, "-addresses", strings.Split(testAgent.TestServer.HTTPAddr, ":")[0], "-http-port", strings.Split(testAgent.TestServer.HTTPAddr, ":")[1], "-grpc-port", strings.Split(testAgent.TestServer.GRPCAddr, ":")[1], @@ -910,6 +915,7 @@ func TestRun_ErrorsOnDuplicateACLPolicy(t *testing.T) { // Create Consul with ACLs already bootstrapped so that we can // then seed it with our manually created policy. bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + tokenFile := common.WriteTempFile(t, bootToken) k8s, testAgent := completeBootstrappedSetup(t, bootToken) setUpK8sServiceAccount(t, k8s, ns) @@ -932,11 +938,11 @@ func TestRun_ErrorsOnDuplicateACLPolicy(t *testing.T) { cmd := Command{ UI: ui, clientset: k8s, - backend: &FakeSecretsBackend{bootstrapToken: bootToken}, } cmdArgs := []string{ "-timeout=1s", "-k8s-namespace", ns, + "-bootstrap-token-file", tokenFile, "-resource-prefix=" + resourcePrefix, "-k8s-namespace=" + ns, "-addresses", strings.Split(testAgent.TestServer.HTTPAddr, ":")[0], @@ -1447,223 +1453,272 @@ func TestRun_ClientPolicyAndBindingRuleRetry(t *testing.T) { // Test if there is an old bootstrap Secret we still try to create and set // server tokens. func TestRun_AlreadyBootstrapped(t *testing.T) { - k8s := fake.NewSimpleClientset() - - type APICall struct { - Method string - Path string + t.Parallel() + cases := map[string]bool{ + "token saved in k8s secret": true, + "token provided via file": false, } - var consulAPICalls []APICall - // Start the Consul server. - consulServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Record all the API calls made. - consulAPICalls = append(consulAPICalls, APICall{ - Method: r.Method, - Path: r.URL.Path, - }) - switch r.URL.Path { - case "/v1/agent/self": - fmt.Fprintln(w, `{"Config": {"Datacenter": "dc1", "PrimaryDatacenter": "dc1"}}`) - case "/v1/acl/tokens": - fmt.Fprintln(w, `[]`) - case "/v1/acl/token": - fmt.Fprintln(w, `{}`) - case "/v1/acl/policy": - fmt.Fprintln(w, `{}`) - case "/v1/agent/token/acl_agent_token": - fmt.Fprintln(w, `{}`) - case "/v1/acl/auth-method": - fmt.Fprintln(w, `{}`) - case "/v1/acl/role/name/release-name-consul-client-acl-role": - w.WriteHeader(404) - case "/v1/acl/role": - fmt.Fprintln(w, `{}`) - case "/v1/acl/binding-rules": - fmt.Fprintln(w, `[]`) - case "/v1/acl/binding-rule": - fmt.Fprintln(w, `{}`) - default: - w.WriteHeader(500) - fmt.Fprintln(w, "Mock Server not configured for this route: "+r.URL.Path) - } - })) - defer consulServer.Close() + for name, tokenFromK8sSecret := range cases { + t.Run(name, func(t *testing.T) { + k8s := fake.NewSimpleClientset() - serverURL, err := url.Parse(consulServer.URL) - require.NoError(t, err) - port, err := strconv.Atoi(serverURL.Port()) - require.NoError(t, err) - setUpK8sServiceAccount(t, k8s, ns) + type APICall struct { + Method string + Path string + } + var consulAPICalls []APICall - cmdArgs := []string{ - "-timeout=500ms", - "-resource-prefix=" + resourcePrefix, - "-k8s-namespace=" + ns, - "-addresses=" + serverURL.Hostname(), - "-http-port=" + serverURL.Port(), - } + // Start the Consul server. + consulServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Record all the API calls made. + consulAPICalls = append(consulAPICalls, APICall{ + Method: r.Method, + Path: r.URL.Path, + }) + switch r.URL.Path { + case "/v1/agent/self": + fmt.Fprintln(w, `{"Config": {"Datacenter": "dc1", "PrimaryDatacenter": "dc1"}}`) + case "/v1/acl/tokens": + fmt.Fprintln(w, `[]`) + case "/v1/acl/token": + fmt.Fprintln(w, `{}`) + case "/v1/acl/policy": + fmt.Fprintln(w, `{}`) + case "/v1/agent/token/acl_agent_token": + fmt.Fprintln(w, `{}`) + case "/v1/acl/auth-method": + fmt.Fprintln(w, `{}`) + case "/v1/acl/role/name/release-name-consul-client-acl-role": + w.WriteHeader(404) + case "/v1/acl/role": + fmt.Fprintln(w, `{}`) + case "/v1/acl/binding-rules": + fmt.Fprintln(w, `[]`) + case "/v1/acl/binding-rule": + fmt.Fprintln(w, `{}`) + default: + w.WriteHeader(500) + fmt.Fprintln(w, "Mock Server not configured for this route: "+r.URL.Path) + } + })) + defer consulServer.Close() - // Create the bootstrap secret. - _, err = k8s.CoreV1().Secrets(ns).Create( - context.Background(), - &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: resourcePrefix + "-bootstrap-acl-token", - Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, - }, - Data: map[string][]byte{ - "token": []byte("old-token"), - }, - }, - metav1.CreateOptions{}) - require.NoError(t, err) + serverURL, err := url.Parse(consulServer.URL) + require.NoError(t, err) + port, err := strconv.Atoi(serverURL.Port()) + require.NoError(t, err) + setUpK8sServiceAccount(t, k8s, ns) - // Run the command. - ui := cli.NewMockUi() - cmd := Command{ - UI: ui, - clientset: k8s, - watcher: test.MockConnMgrForIPAndPort(serverURL.Hostname(), port), - } + cmdArgs := []string{ + "-timeout=500ms", + "-resource-prefix=" + resourcePrefix, + "-k8s-namespace=" + ns, + "-addresses=" + serverURL.Hostname(), + "-http-port=" + serverURL.Port(), + } - responseCode := cmd.Run(cmdArgs) - require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) + // Create the bootstrap secret. + if tokenFromK8sSecret { + _, err = k8s.CoreV1().Secrets(ns).Create( + context.Background(), + &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourcePrefix + "-bootstrap-acl-token", + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, + }, + Data: map[string][]byte{ + "token": []byte("old-token"), + }, + }, + metav1.CreateOptions{}) + require.NoError(t, err) + } else { + // Write token to a file. + bootTokenFile, err := os.CreateTemp("", "") + require.NoError(t, err) + defer os.RemoveAll(bootTokenFile.Name()) - // Test that the Secret is the same. - secret, err := k8s.CoreV1().Secrets(ns).Get(context.Background(), resourcePrefix+"-bootstrap-acl-token", metav1.GetOptions{}) - require.NoError(t, err) - require.Contains(t, secret.Data, "token") - require.Equal(t, "old-token", string(secret.Data["token"])) + _, err = bootTokenFile.WriteString("old-token") + require.NoError(t, err) - // Test that the expected API calls were made. - require.Equal(t, []APICall{ - // We expect calls for updating the server policy, setting server tokens, - // and updating client policy. - { - "PUT", - "/v1/acl/policy", - }, - { - "GET", - "/v1/acl/tokens", - }, - { - "PUT", - "/v1/acl/token", - }, - { - "PUT", - "/v1/agent/token/agent", - }, - { - "PUT", - "/v1/agent/token/acl_agent_token", - }, - { - "GET", - "/v1/agent/self", - }, - { - "PUT", - "/v1/acl/auth-method", - }, - { - "PUT", - "/v1/acl/policy", - }, - { - "GET", - "/v1/acl/role/name/release-name-consul-client-acl-role", - }, - { - "PUT", - "/v1/acl/role", - }, - { - "GET", - "/v1/acl/binding-rules", - }, - { - "PUT", - "/v1/acl/binding-rule", - }, - }, consulAPICalls) + require.NoError(t, err) + cmdArgs = append(cmdArgs, "-bootstrap-token-file", bootTokenFile.Name()) + } + + // Run the command. + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + clientset: k8s, + watcher: test.MockConnMgrForIPAndPort(serverURL.Hostname(), port), + } + + responseCode := cmd.Run(cmdArgs) + require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) + + // Test that the Secret is the same. + if tokenFromK8sSecret { + secret, err := k8s.CoreV1().Secrets(ns).Get(context.Background(), resourcePrefix+"-bootstrap-acl-token", metav1.GetOptions{}) + require.NoError(t, err) + require.Contains(t, secret.Data, "token") + require.Equal(t, "old-token", string(secret.Data["token"])) + } + + // Test that the expected API calls were made. + require.Equal(t, []APICall{ + // We expect calls for updating the server policy, setting server tokens, + // and updating client policy. + { + "PUT", + "/v1/acl/policy", + }, + { + "GET", + "/v1/acl/tokens", + }, + { + "PUT", + "/v1/acl/token", + }, + { + "PUT", + "/v1/agent/token/agent", + }, + { + "PUT", + "/v1/agent/token/acl_agent_token", + }, + { + "GET", + "/v1/agent/self", + }, + { + "PUT", + "/v1/acl/auth-method", + }, + { + "PUT", + "/v1/acl/policy", + }, + { + "GET", + "/v1/acl/role/name/release-name-consul-client-acl-role", + }, + { + "PUT", + "/v1/acl/role", + }, + { + "GET", + "/v1/acl/binding-rules", + }, + { + "PUT", + "/v1/acl/binding-rule", + }, + }, consulAPICalls) + }) + } } // Test if there is an old bootstrap Secret and the server token exists // that we don't try and recreate the token. func TestRun_AlreadyBootstrapped_ServerTokenExists(t *testing.T) { - // First set everything up with ACLs bootstrapped. - bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" - k8s, testAgent := completeBootstrappedSetup(t, bootToken) - setUpK8sServiceAccount(t, k8s, ns) - - cmdArgs := []string{ - "-timeout=1m", - "-k8s-namespace", ns, - "-addresses", strings.Split(testAgent.TestServer.HTTPAddr, ":")[0], - "-http-port", strings.Split(testAgent.TestServer.HTTPAddr, ":")[1], - "-grpc-port", strings.Split(testAgent.TestServer.GRPCAddr, ":")[1], - "-resource-prefix", resourcePrefix, + t.Parallel() + cases := map[string]bool{ + "token saved in k8s secret": true, + "token provided via file": false, } - _, err := k8s.CoreV1().Secrets(ns).Create(context.Background(), &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: resourcePrefix + "-bootstrap-acl-token", - }, - Data: map[string][]byte{ - "token": []byte(bootToken), - }, - }, metav1.CreateOptions{}) - require.NoError(t, err) + for name, tokenInK8sSecret := range cases { + t.Run(name, func(t *testing.T) { - consulClient, err := api.NewClient(&api.Config{ - Address: testAgent.TestServer.HTTPAddr, - Token: bootToken, - }) - require.NoError(t, err) - ui := cli.NewMockUi() - cmd := Command{ - UI: ui, - clientset: k8s, - } + // First set everything up with ACLs bootstrapped. + bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + k8s, testAgent := completeBootstrappedSetup(t, bootToken) + setUpK8sServiceAccount(t, k8s, ns) - cmd.init() - // Create the server policy and token _before_ we run the command. - agentPolicyRules, err := cmd.agentRules() - require.NoError(t, err) - policy, _, err := consulClient.ACL().PolicyCreate(&api.ACLPolicy{ - Name: "agent-token", - Description: "Agent Token Policy", - Rules: agentPolicyRules, - }, nil) - require.NoError(t, err) - _, _, err = consulClient.ACL().TokenCreate(&api.ACLToken{ - Description: fmt.Sprintf("Server Token for %s", strings.Split(testAgent.TestServer.HTTPAddr, ":")[0]), - Policies: []*api.ACLTokenPolicyLink{ - { - Name: policy.Name, - }, - }, - }, nil) - require.NoError(t, err) + cmdArgs := []string{ + "-timeout=1m", + "-k8s-namespace", ns, + "-addresses", strings.Split(testAgent.TestServer.HTTPAddr, ":")[0], + "-http-port", strings.Split(testAgent.TestServer.HTTPAddr, ":")[1], + "-grpc-port", strings.Split(testAgent.TestServer.GRPCAddr, ":")[1], + "-resource-prefix", resourcePrefix, + } - // Run the command. - responseCode := cmd.Run(cmdArgs) - require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) + if tokenInK8sSecret { + _, err := k8s.CoreV1().Secrets(ns).Create(context.Background(), &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourcePrefix + "-bootstrap-acl-token", + }, + Data: map[string][]byte{ + "token": []byte(bootToken), + }, + }, metav1.CreateOptions{}) + require.NoError(t, err) + } else { + // Write token to a file. + bootTokenFile, err := os.CreateTemp("", "") + require.NoError(t, err) + defer os.RemoveAll(bootTokenFile.Name()) - // Check that only one server token exists, i.e. it didn't create an - // extra token. - tokens, _, err := consulClient.ACL().TokenList(nil) - require.NoError(t, err) - count := 0 - for _, token := range tokens { - if len(token.Policies) == 1 && token.Policies[0].Name == policy.Name { - count++ - } + _, err = bootTokenFile.WriteString(bootToken) + require.NoError(t, err) + + require.NoError(t, err) + cmdArgs = append(cmdArgs, "-bootstrap-token-file", bootTokenFile.Name()) + } + + consulClient, err := api.NewClient(&api.Config{ + Address: testAgent.TestServer.HTTPAddr, + Token: bootToken, + }) + require.NoError(t, err) + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + clientset: k8s, + } + + cmd.init() + // Create the server policy and token _before_ we run the command. + agentPolicyRules, err := cmd.agentRules() + require.NoError(t, err) + policy, _, err := consulClient.ACL().PolicyCreate(&api.ACLPolicy{ + Name: "agent-token", + Description: "Agent Token Policy", + Rules: agentPolicyRules, + }, nil) + require.NoError(t, err) + _, _, err = consulClient.ACL().TokenCreate(&api.ACLToken{ + Description: fmt.Sprintf("Server Token for %s", strings.Split(testAgent.TestServer.HTTPAddr, ":")[0]), + Policies: []*api.ACLTokenPolicyLink{ + { + Name: policy.Name, + }, + }, + }, nil) + require.NoError(t, err) + + // Run the command. + responseCode := cmd.Run(cmdArgs) + require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) + + // Check that only one server token exists, i.e. it didn't create an + // extra token. + tokens, _, err := consulClient.ACL().TokenList(nil) + require.NoError(t, err) + count := 0 + for _, token := range tokens { + if len(token.Policies) == 1 && token.Policies[0].Name == policy.Name { + count++ + } + } + require.Equal(t, 1, count) + }) } - require.Equal(t, 1, count) } // Test if -set-server-tokens is false (i.e. servers are disabled), we skip bootstrapping of the servers @@ -1673,6 +1728,7 @@ func TestRun_SkipBootstrapping_WhenServersAreDisabled(t *testing.T) { k8s := fake.NewSimpleClientset() bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + tokenFile := common.WriteTempFile(t, bootToken) type APICall struct { Method string @@ -1710,7 +1766,6 @@ func TestRun_SkipBootstrapping_WhenServersAreDisabled(t *testing.T) { UI: ui, clientset: k8s, watcher: test.MockConnMgrForIPAndPort(serverURL.Hostname(), port), - backend: &FakeSecretsBackend{bootstrapToken: bootToken}, } responseCode := cmd.Run([]string{ "-timeout=500ms", @@ -1718,6 +1773,7 @@ func TestRun_SkipBootstrapping_WhenServersAreDisabled(t *testing.T) { "-k8s-namespace=" + ns, "-addresses=" + serverURL.Hostname(), "-http-port=" + serverURL.Port(), + "-bootstrap-token-file=" + tokenFile, "-set-server-tokens=false", "-client=false", // disable client token, so there are fewer calls }) diff --git a/control-plane/subcommand/server-acl-init/connect_inject.go b/control-plane/subcommand/server-acl-init/connect_inject.go index 58a36b988f..e732dae452 100644 --- a/control-plane/subcommand/server-acl-init/connect_inject.go +++ b/control-plane/subcommand/server-acl-init/connect_inject.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( diff --git a/control-plane/subcommand/server-acl-init/connect_inject_test.go b/control-plane/subcommand/server-acl-init/connect_inject_test.go index 03e47c8ba6..e7144146b7 100644 --- a/control-plane/subcommand/server-acl-init/connect_inject_test.go +++ b/control-plane/subcommand/server-acl-init/connect_inject_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( diff --git a/control-plane/subcommand/server-acl-init/create_or_update.go b/control-plane/subcommand/server-acl-init/create_or_update.go index 50f215eacb..af67842445 100644 --- a/control-plane/subcommand/server-acl-init/create_or_update.go +++ b/control-plane/subcommand/server-acl-init/create_or_update.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( diff --git a/control-plane/subcommand/server-acl-init/create_or_update_test.go b/control-plane/subcommand/server-acl-init/create_or_update_test.go index 84ccdc1635..23ab46347f 100644 --- a/control-plane/subcommand/server-acl-init/create_or_update_test.go +++ b/control-plane/subcommand/server-acl-init/create_or_update_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( diff --git a/control-plane/subcommand/server-acl-init/k8s_secrets_backend.go b/control-plane/subcommand/server-acl-init/k8s_secrets_backend.go deleted file mode 100644 index 93d9d0d2d8..0000000000 --- a/control-plane/subcommand/server-acl-init/k8s_secrets_backend.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package serveraclinit - -import ( - "context" - "fmt" - - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" - apiv1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -const SecretsBackendTypeKubernetes SecretsBackendType = "kubernetes" - -type KubernetesSecretsBackend struct { - ctx context.Context - clientset kubernetes.Interface - k8sNamespace string - secretName string - secretKey string -} - -var _ SecretsBackend = (*KubernetesSecretsBackend)(nil) - -// BootstrapToken returns the existing bootstrap token if there is one by -// reading the Kubernetes Secret. If there is no bootstrap token yet, then -// it returns an empty string (not an error). -func (b *KubernetesSecretsBackend) BootstrapToken() (string, error) { - secret, err := b.clientset.CoreV1().Secrets(b.k8sNamespace).Get(b.ctx, b.secretName, metav1.GetOptions{}) - if err != nil { - if k8serrors.IsNotFound(err) { - return "", nil - } - return "", err - } - token, ok := secret.Data[b.secretKey] - if !ok { - return "", fmt.Errorf("secret %q does not have data key %q", b.secretName, b.secretKey) - } - return string(token), nil - -} - -// WriteBootstrapToken writes the given bootstrap token to the Kubernetes Secret. -func (b *KubernetesSecretsBackend) WriteBootstrapToken(bootstrapToken string) error { - secret := &apiv1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: b.secretName, - Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, - }, - Data: map[string][]byte{ - b.secretKey: []byte(bootstrapToken), - }, - } - _, err := b.clientset.CoreV1().Secrets(b.k8sNamespace).Create(b.ctx, secret, metav1.CreateOptions{}) - return err -} - -func (b *KubernetesSecretsBackend) BootstrapTokenSecretName() string { - return b.secretName -} diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 5f65b6c75c..ee6ae41e40 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( @@ -154,10 +151,8 @@ partition "{{ .PartitionName }}" { operator = "write" acl = "write" {{- end }} - {{- if .EnableNamespaces }} namespace_prefix "" { - policy = "write" {{- end }} service_prefix "" { policy = "write" @@ -172,7 +167,7 @@ namespace_prefix "" { {{- if .EnablePartitions }} } {{- end }} -` + ` return c.renderRules(apiGatewayRulesTpl) } @@ -330,7 +325,6 @@ partition "{{ .PartitionName }}" { mesh = "write" acl = "write" {{- else }} - mesh = "write" operator = "write" acl = "write" {{- end }} diff --git a/control-plane/subcommand/server-acl-init/rules_test.go b/control-plane/subcommand/server-acl-init/rules_test.go index a45af33c11..22e63ed0ce 100644 --- a/control-plane/subcommand/server-acl-init/rules_test.go +++ b/control-plane/subcommand/server-acl-init/rules_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( @@ -146,7 +143,6 @@ func TestAPIGatewayControllerRules(t *testing.T) { cases := []struct { Name string EnableNamespaces bool - Partition string Expected string }{ { @@ -169,26 +165,6 @@ acl = "write" 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" @@ -196,7 +172,6 @@ namespace_prefix "" { node_prefix "" { policy = "read" } -} }`, }, } @@ -205,9 +180,7 @@ namespace_prefix "" { t.Run(tt.Name, func(t *testing.T) { cmd := Command{ flagEnableNamespaces: tt.EnableNamespaces, - consulFlags: &flags.ConsulFlags{ - Partition: tt.Partition, - }, + consulFlags: &flags.ConsulFlags{}, } meshGatewayRules, err := cmd.apiGatewayControllerRules() @@ -953,7 +926,6 @@ func TestInjectRules(t *testing.T) { EnablePartitions: false, EnablePeering: false, Expected: ` - mesh = "write" operator = "write" acl = "write" node_prefix "" { @@ -970,7 +942,6 @@ func TestInjectRules(t *testing.T) { EnablePartitions: false, EnablePeering: false, Expected: ` - mesh = "write" operator = "write" acl = "write" node_prefix "" { @@ -989,7 +960,6 @@ func TestInjectRules(t *testing.T) { EnablePartitions: false, EnablePeering: true, Expected: ` - mesh = "write" operator = "write" acl = "write" peering = "write" diff --git a/control-plane/subcommand/server-acl-init/secrets_backend.go b/control-plane/subcommand/server-acl-init/secrets_backend.go deleted file mode 100644 index e0d74462cf..0000000000 --- a/control-plane/subcommand/server-acl-init/secrets_backend.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package serveraclinit - -type SecretsBackendType string - -type SecretsBackend interface { - // BootstrapToken fetches the bootstrap token from the backend. If the - // token is not found or empty, implementations should return an empty - // string (not an error). - BootstrapToken() (string, error) - - // WriteBootstrapToken writes the given bootstrap token to the backend. - // Implementations of this method do not need to retry the write until - // successful. - WriteBootstrapToken(string) error - - // BootstrapTokenSecretName returns the name of the bootstrap token secret. - BootstrapTokenSecretName() string -} diff --git a/control-plane/subcommand/server-acl-init/servers.go b/control-plane/subcommand/server-acl-init/servers.go index c530f648e5..2dc8f8ab67 100644 --- a/control-plane/subcommand/server-acl-init/servers.go +++ b/control-plane/subcommand/server-acl-init/servers.go @@ -1,9 +1,7 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package serveraclinit import ( + "errors" "fmt" "net" "net/http" @@ -11,30 +9,29 @@ import ( "time" "github.com/hashicorp/consul/api" + apiv1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" ) // bootstrapServers bootstraps ACLs and ensures each server has an ACL token. -// If a bootstrap is found in the secrets backend, then skip ACL bootstrapping. -// Otherwise, bootstrap ACLs and write the bootstrap token to the secrets backend. -func (c *Command) bootstrapServers(serverAddresses []net.IPAddr, backend SecretsBackend) (string, error) { +// If bootstrapToken is not empty then ACLs are already bootstrapped. +func (c *Command) bootstrapServers(serverAddresses []net.IPAddr, bootstrapToken, bootTokenSecretName string) (string, error) { // Pick the first server address to connect to for bootstrapping and set up connection. firstServerAddr := fmt.Sprintf("%s:%d", serverAddresses[0].IP.String(), c.consulFlags.HTTPPort) - bootstrapToken, err := backend.BootstrapToken() - if err != nil { - return "", fmt.Errorf("Unexpected error fetching bootstrap token secret: %w", err) - } + if bootstrapToken == "" { + c.log.Info("No bootstrap token from previous installation found, continuing on to bootstrapping") - if bootstrapToken != "" { - c.log.Info("Found bootstrap token in secrets backend", "secret", backend.BootstrapTokenSecretName()) - } else { - c.log.Info("No bootstrap token found in secrets backend, continuing to ACL bootstrapping", "secret", backend.BootstrapTokenSecretName()) - bootstrapToken, err = c.bootstrapACLs(firstServerAddr, backend) + var err error + bootstrapToken, err = c.bootstrapACLs(firstServerAddr, bootTokenSecretName) if err != nil { return "", err } + } else { + c.log.Info(fmt.Sprintf("ACLs already bootstrapped - retrieved bootstrap token from Secret %q", bootTokenSecretName)) } // We should only create and set server tokens when servers are running within this cluster. @@ -50,7 +47,7 @@ func (c *Command) bootstrapServers(serverAddresses []net.IPAddr, backend Secrets // bootstrapACLs makes the ACL bootstrap API call and writes the bootstrap token // to a kube secret. -func (c *Command) bootstrapACLs(firstServerAddr string, backend SecretsBackend) (string, error) { +func (c *Command) bootstrapACLs(firstServerAddr, bootTokenSecretName string) (string, error) { config := c.consulFlags.ConsulClientConfig().APIClientConfig config.Address = firstServerAddr // Exempting this particular use of the http client from using global.consulAPITimeout @@ -81,12 +78,9 @@ func (c *Command) bootstrapACLs(firstServerAddr string, backend SecretsBackend) // Check if already bootstrapped. if strings.Contains(err.Error(), "Unexpected response code: 403") { - unrecoverableErr = fmt.Errorf( - "ACLs already bootstrapped but unable to find the bootstrap token in the secrets backend."+ - " We can't proceed without a bootstrap token."+ - " Store a token with `acl:write` permission in the secret %q.", - backend.BootstrapTokenSecretName(), - ) + unrecoverableErr = errors.New("ACLs already bootstrapped but the ACL token was not written to a Kubernetes secret." + + " We can't proceed because the bootstrap token is lost." + + " You must reset ACLs.") return nil } @@ -104,12 +98,21 @@ func (c *Command) bootstrapACLs(firstServerAddr string, backend SecretsBackend) return "", err } - // Write bootstrap token to the secrets backend. - err = c.untilSucceeds(fmt.Sprintf("writing bootstrap Secret %q", backend.BootstrapTokenSecretName()), + // Write bootstrap token to a Kubernetes secret. + err = c.untilSucceeds(fmt.Sprintf("writing bootstrap Secret %q", bootTokenSecretName), func() error { - return backend.WriteBootstrapToken(bootstrapToken) - }, - ) + secret := &apiv1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: bootTokenSecretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, + }, + Data: map[string][]byte{ + common.ACLTokenSecretKey: []byte(bootstrapToken), + }, + } + _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(c.ctx, secret, metav1.CreateOptions{}) + return err + }) return bootstrapToken, err } diff --git a/control-plane/subcommand/server-acl-init/test_fake_secrets_backend.go b/control-plane/subcommand/server-acl-init/test_fake_secrets_backend.go deleted file mode 100644 index 87826f6c60..0000000000 --- a/control-plane/subcommand/server-acl-init/test_fake_secrets_backend.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package serveraclinit - -type FakeSecretsBackend struct { - bootstrapToken string -} - -func (b *FakeSecretsBackend) BootstrapToken() (string, error) { - return b.bootstrapToken, nil -} - -func (*FakeSecretsBackend) BootstrapTokenSecretName() string { - return "fake-bootstrap-token" -} - -func (b *FakeSecretsBackend) WriteBootstrapToken(token string) error { - b.bootstrapToken = token - return nil -} - -var _ SecretsBackend = (*FakeSecretsBackend)(nil) diff --git a/control-plane/subcommand/server-acl-init/vault_secrets_backend.go b/control-plane/subcommand/server-acl-init/vault_secrets_backend.go deleted file mode 100644 index 5a9097cca3..0000000000 --- a/control-plane/subcommand/server-acl-init/vault_secrets_backend.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package serveraclinit - -import ( - "fmt" - - "github.com/hashicorp/vault/api" -) - -const SecretsBackendTypeVault SecretsBackendType = "vault" - -type VaultSecretsBackend struct { - vaultClient *api.Client - secretName string - secretKey string -} - -var _ SecretsBackend = (*VaultSecretsBackend)(nil) - -// BootstrapToken returns the bootstrap token stored in Vault. -// If not found this returns an empty string (not an error). -func (b *VaultSecretsBackend) BootstrapToken() (string, error) { - secret, err := b.vaultClient.Logical().Read(b.secretName) - if err != nil { - return "", err - } - if secret == nil || secret.Data == nil { - // secret not found or empty. - return "", nil - } - // Grab secret.Data["data"][secretKey]. - dataRaw, found := secret.Data["data"] - if !found { - return "", nil - } - data, ok := dataRaw.(map[string]interface{}) - if !ok { - return "", nil - } - tokRaw, found := data[b.secretKey] - if !found { - return "", nil - } - if tok, ok := tokRaw.(string); ok { - return tok, nil - } - return "", fmt.Errorf("Unexpected data. To resolve this, "+ - "`vault kv put %[1]s=` if Consul is already ACL bootstrapped. "+ - "If not ACL bootstrapped, `vault kv put %[1]s=\"\"`", b.secretKey, b.secretKey) -} - -// BootstrapTokenSecretName returns the name of the bootstrap token secret. -func (b *VaultSecretsBackend) BootstrapTokenSecretName() string { - return b.secretName -} - -// WriteBootstrapToken writes the bootstrap token to Vault. -func (b *VaultSecretsBackend) WriteBootstrapToken(bootstrapToken string) error { - _, err := b.vaultClient.Logical().Write(b.secretName, - map[string]interface{}{ - "data": map[string]interface{}{ - b.secretKey: bootstrapToken, - }, - }, - ) - return err -} diff --git a/control-plane/subcommand/sync-catalog/command.go b/control-plane/subcommand/sync-catalog/command.go index 2dadf6e039..e146a76667 100644 --- a/control-plane/subcommand/sync-catalog/command.go +++ b/control-plane/subcommand/sync-catalog/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package synccatalog import ( diff --git a/control-plane/subcommand/sync-catalog/command_ent_test.go b/control-plane/subcommand/sync-catalog/command_ent_test.go index fb6c6c4347..fac330c557 100644 --- a/control-plane/subcommand/sync-catalog/command_ent_test.go +++ b/control-plane/subcommand/sync-catalog/command_ent_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - //go:build enterprise package synccatalog diff --git a/control-plane/subcommand/sync-catalog/command_test.go b/control-plane/subcommand/sync-catalog/command_test.go index 0223931cc1..8228986d00 100644 --- a/control-plane/subcommand/sync-catalog/command_test.go +++ b/control-plane/subcommand/sync-catalog/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package synccatalog import ( diff --git a/control-plane/subcommand/tls-init/command.go b/control-plane/subcommand/tls-init/command.go index c2498a3125..354a26fdc5 100644 --- a/control-plane/subcommand/tls-init/command.go +++ b/control-plane/subcommand/tls-init/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package tls_init import ( diff --git a/control-plane/subcommand/tls-init/command_test.go b/control-plane/subcommand/tls-init/command_test.go index 81f5893543..ae3cbd8982 100644 --- a/control-plane/subcommand/tls-init/command_test.go +++ b/control-plane/subcommand/tls-init/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package tls_init import ( diff --git a/control-plane/subcommand/version/command.go b/control-plane/subcommand/version/command.go index 1f6b2aed01..58768a1f92 100644 --- a/control-plane/subcommand/version/command.go +++ b/control-plane/subcommand/version/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package version import ( diff --git a/control-plane/subcommand/webhook-cert-manager/command.go b/control-plane/subcommand/webhook-cert-manager/command.go index 4d85565b62..214a1d41e2 100644 --- a/control-plane/subcommand/webhook-cert-manager/command.go +++ b/control-plane/subcommand/webhook-cert-manager/command.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhookcertmanager import ( diff --git a/control-plane/subcommand/webhook-cert-manager/command_test.go b/control-plane/subcommand/webhook-cert-manager/command_test.go index 31c98b0ebe..7e302d5261 100644 --- a/control-plane/subcommand/webhook-cert-manager/command_test.go +++ b/control-plane/subcommand/webhook-cert-manager/command_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package webhookcertmanager import ( diff --git a/control-plane/subcommand/webhook-cert-manager/mocks/mocks.go b/control-plane/subcommand/webhook-cert-manager/mocks/mocks.go index 5efa09eb29..d700b192ac 100644 --- a/control-plane/subcommand/webhook-cert-manager/mocks/mocks.go +++ b/control-plane/subcommand/webhook-cert-manager/mocks/mocks.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package mocks import ( diff --git a/control-plane/version/fips_build.go b/control-plane/version/fips_build.go deleted file mode 100644 index 63e0e68883..0000000000 --- a/control-plane/version/fips_build.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -//go:build fips - -package version - -// This validates during compilation that we are being built with a FIPS enabled go toolchain -import ( - _ "crypto/tls/fipsonly" - "runtime" - "strings" -) - -// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode. -func IsFIPS() bool { - return true -} - -func GetFIPSInfo() string { - str := "Enabled" - // Try to get the crypto module name - gover := strings.Split(runtime.Version(), "X:") - if len(gover) >= 2 { - gover_last := gover[len(gover)-1] - // Able to find crypto module name; add that to status string. - str = "FIPS 140-2 Enabled, crypto module " + gover_last - } - return str -} diff --git a/control-plane/version/non_fips_build.go b/control-plane/version/non_fips_build.go deleted file mode 100644 index ce99575d2c..0000000000 --- a/control-plane/version/non_fips_build.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -//go:build !fips - -package version - -// IsFIPS returns true if consul-k8s is operating in FIPS-140-2 mode. -func IsFIPS() bool { - return false -} - -func GetFIPSInfo() string { - return "" -} diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 952cd9ca81..c17eb5d89e 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package version import ( @@ -17,7 +14,7 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "1.3.0" + Version = "1.0.10" // 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 @@ -39,12 +36,8 @@ func GetHumanVersion() string { release = "dev" } - if IsFIPS() { - version += "+fips1402" - } - if release != "" { - if !strings.Contains(version, "-"+release) { + if !strings.HasSuffix(version, "-"+release) { // if we tagged a prerelease version then the release is in the version already version += fmt.Sprintf("-%s", release) } diff --git a/docs/admin-partitions-with-acls.md b/docs/admin-partitions-with-acls.md new file mode 100644 index 0000000000..fb282fa38d --- /dev/null +++ b/docs/admin-partitions-with-acls.md @@ -0,0 +1,98 @@ +## Installing Admin Partitions with ACLs enabled + +To enable ACLs on the server cluster use the following config: +```yaml +global: + enableConsulNamespaces: true + tls: + enabled: true + image: hashicorp/consul-enterprise:1.11.1 + adminPartitions: + enabled: true + acls: + manageSystemACLs: true +server: + exposeGossipAndRPCPorts: true + enterpriseLicense: + secretName: license + secretKey: key + replicas: 1 +connectInject: + enabled: true + transparentProxy: + defaultEnabled: false + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +meshGateway: + enabled: true +``` + +Identify the LoadBalancer External IP of the `partition-service` +```bash +kubectl get svc consul-consul-partition-service -o json | jq -r '.status.loadBalancer.ingress[0].ip' +``` + +Migrate the TLS CA credentials from the server cluster to the workload clusters +```bash +kubectl get secret consul-consul-ca-key --context "server-context" -o json | kubectl apply --context "workload-context" -f - +kubectl get secret consul-consul-ca-cert --context "server-context" -o json | kubectl apply --context "workload-context" -f - +``` + +Migrate the Partition token from the server cluster to the workload clusters +```bash +kubectl get secret consul-consul-partitions-acl-token --context "server-context" -o json | kubectl apply --context "workload-context" -f - +``` + +Identify the Kubernetes AuthMethod URL of the workload cluster to use as the `k8sAuthMethodHost`: +```bash +kubectl config view -o "jsonpath={.clusters[?(@.name=='workload-cluster-name')].cluster.server}" +``` + +Configure the workload cluster using the following: + +```yaml +global: + enabled: false + enableConsulNamespaces: true + image: hashicorp/consul-enterprise:1.11.1 + adminPartitions: + enabled: true + name: "partition-name" + tls: + enabled: true + caCert: + secretName: consul-consul-ca-cert + secretKey: tls.crt + caKey: + secretName: consul-consul-ca-key + secretKey: tls.key + acls: + manageSystemACLs: true + bootstrapToken: + secretName: consul-consul-partitions-acl-token + secretKey: token +server: + enterpriseLicense: + secretName: license + secretKey: key +externalServers: + enabled: true + hosts: [ "loadbalancer IP" ] + tlsServerName: server.dc1.consul + k8sAuthMethodHost: "authmethod-host IP" +client: + enabled: true + exposeGossipPorts: true + join: [ "loadbalancer IP" ] +connectInject: + enabled: true + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +meshGateway: + enabled: true +``` +This should create clusters that have Admin Partitions deployed on them with ACLs enabled. diff --git a/hack/aws-acceptance-test-cleanup/go.mod b/hack/aws-acceptance-test-cleanup/go.mod index ac4f7b0d1a..13e8f48909 100644 --- a/hack/aws-acceptance-test-cleanup/go.mod +++ b/hack/aws-acceptance-test-cleanup/go.mod @@ -1,6 +1,6 @@ module github.com/hashicorp/consul-helm/hack/aws-acceptance-test-cleanup -go 1.20 +go 1.19 require ( github.com/aws/aws-sdk-go v1.38.63 diff --git a/hack/aws-acceptance-test-cleanup/main.go b/hack/aws-acceptance-test-cleanup/main.go index e4094ec47e..b72b88c12f 100644 --- a/hack/aws-acceptance-test-cleanup/main.go +++ b/hack/aws-acceptance-test-cleanup/main.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main // This script deletes AWS resources created for acceptance tests that have @@ -25,7 +22,6 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/eks" "github.com/aws/aws-sdk-go/service/elb" - "github.com/aws/aws-sdk-go/service/iam" "github.com/cenkalti/backoff/v4" ) @@ -39,11 +35,6 @@ var ( errNotDestroyed = errors.New("not yet destroyed") ) -type oidc struct { - arn string - buildUrl string -} - func main() { flag.BoolVar(&flagAutoApprove, "auto-approve", false, "Skip interactive approval before destroying.") flag.Parse() @@ -74,106 +65,6 @@ func realMain(ctx context.Context) error { eksClient := eks.New(clientSession, awsCfg) ec2Client := ec2.New(clientSession, awsCfg) elbClient := elb.New(clientSession, awsCfg) - iamClient := iam.New(clientSession, awsCfg) - - // Find OIDC providers to delete. - oidcProvidersOutput, err := iamClient.ListOpenIDConnectProvidersWithContext(ctx, &iam.ListOpenIDConnectProvidersInput{}) - if err != nil { - return err - } else if oidcProvidersOutput == nil { - return fmt.Errorf("nil output for OIDC Providers") - } - - toDeleteOidcArns := []*oidc{} - for _, providerEntry := range oidcProvidersOutput.OpenIDConnectProviderList { - arnString := "" - if providerEntry.Arn != nil { - arnString = *providerEntry.Arn - } - // Check if it's older than 8 hours. - older, err := oidcOlderThanEightHours(ctx, iamClient, providerEntry.Arn) - if err != nil { - return err - } - // Only add to delete list if it's older than 8 hours and has a buildURL tag. - if older { - output, err := iamClient.ListOpenIDConnectProviderTags(&iam.ListOpenIDConnectProviderTagsInput{OpenIDConnectProviderArn: providerEntry.Arn}) - if err != nil { - return err - } - for _, tag := range output.Tags { - if tag.Key != nil && *tag.Key == buildURLTag { - var buildUrl string - if tag.Value != nil { - buildUrl = *tag.Value - } - toDeleteOidcArns = append(toDeleteOidcArns, &oidc{arn: arnString, buildUrl: buildUrl}) - } - } - } else { - fmt.Printf("Skipping OIDC provider: %s because it's not over 8 hours old\n", arnString) - } - } - - oidcProvidersExist := true - if len(toDeleteOidcArns) == 0 { - fmt.Println("Found no OIDC Providers to clean up") - oidcProvidersExist = false - } else { - // Print out the OIDC Provider arns and the build tags. - var oidcPrint string - for _, oidcProvider := range toDeleteOidcArns { - oidcPrint += fmt.Sprintf("- %s (%s)\n", oidcProvider.arn, oidcProvider.buildUrl) - } - - fmt.Printf("Found OIDC Providers:\n%s", oidcPrint) - } - - // Check for approval. - if !flagAutoApprove && oidcProvidersExist { - type input struct { - text string - err error - } - inputCh := make(chan input) - - // Read input in a goroutine so we can also exit if we get a Ctrl-C - // (see select{} below). - go func() { - reader := bufio.NewReader(os.Stdin) - fmt.Println("\nDo you want to delete these OIDC Providers (y/n)?") - inputStr, err := reader.ReadString('\n') - if err != nil { - inputCh <- input{err: err} - return - } - inputCh <- input{text: inputStr} - }() - - select { - case in := <-inputCh: - if in.err != nil { - return in.err - } - inputTrimmed := strings.TrimSpace(in.text) - if inputTrimmed != "y" && inputTrimmed != "yes" { - return errors.New("exiting after negative") - } - case <-ctx.Done(): - return errors.New("context cancelled") - } - } - - // Actually delete the OIDC providers. - for _, oidcArn := range toDeleteOidcArns { - fmt.Printf("Deleting OIDC provider: %s\n", oidcArn.arn) - _, err := iamClient.DeleteOpenIDConnectProviderWithContext(ctx, &iam.DeleteOpenIDConnectProviderInput{ - OpenIDConnectProviderArn: &oidcArn.arn, - }) - if err != nil { - return err - } - } // Find VPCs to delete. Most resources we create belong to a VPC, except // for IAM resources, and so if there are no VPCs, that means all leftover resources have been deleted. @@ -643,25 +534,6 @@ func realMain(ctx context.Context) error { return nil } -// oidcOlderThanEightHours checks if the oidc provider is older than 8 hours. -func oidcOlderThanEightHours(ctx context.Context, iamClient *iam.IAM, oidcArn *string) (bool, error) { - fullOidc, err := iamClient.GetOpenIDConnectProviderWithContext(ctx, &iam.GetOpenIDConnectProviderInput{ - OpenIDConnectProviderArn: oidcArn, - }) - if err != nil { - return false, err - } - if fullOidc != nil { - if fullOidc.CreateDate != nil { - d := time.Since(*fullOidc.CreateDate) - if d.Hours() > 8 { - return true, nil - } - } - } - return false, nil -} - func vpcNameAndBuildURL(vpc *ec2.Vpc) (string, string) { var vpcName string var buildURL string diff --git a/hack/copy-crds-to-chart/go.mod b/hack/copy-crds-to-chart/go.mod index c224f8f244..73b1f10306 100644 --- a/hack/copy-crds-to-chart/go.mod +++ b/hack/copy-crds-to-chart/go.mod @@ -1,3 +1,3 @@ module github.com/hashicorp/consul-k8s/hack/copy-crds-to-chart -go 1.20 +go 1.19 diff --git a/hack/copy-crds-to-chart/main.go b/hack/copy-crds-to-chart/main.go index 149126b392..7276c468f8 100644 --- a/hack/copy-crds-to-chart/main.go +++ b/hack/copy-crds-to-chart/main.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - // Script to copy generated CRD yaml into chart directory and modify it to match // the expected chart format (e.g. formatted YAML). package main @@ -12,14 +9,6 @@ import ( "strings" ) -var ( - // HACK IT! - requiresPeering = map[string]struct{}{ - "consul.hashicorp.com_peeringacceptors.yaml": {}, - "consul.hashicorp.com_peeringdialers.yaml": {}, - } -) - func main() { if len(os.Args) != 1 { fmt.Println("Usage: go run ./...") @@ -34,82 +23,54 @@ func main() { } func realMain(helmPath string) error { - root := "../../control-plane/config/crd/" - dirs := []string{"bases", "external"} - - for _, dir := range dirs { - err := filepath.Walk(root+dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if info.IsDir() || filepath.Ext(path) != ".yaml" || filepath.Base(path) == "kustomization.yaml" { - return nil - } - - printf("processing %s", filepath.Base(path)) - - contentBytes, err := os.ReadFile(path) - if err != nil { - return err - } - contents := string(contentBytes) - - // Strip leading newline. - contents = strings.TrimPrefix(contents, "\n") - - if _, ok := requiresPeering[info.Name()]; ok { - // Add {{- if and .Values.connectInject.enabled .Values.global.peering.enabled }} {{- end }} wrapper. - contents = fmt.Sprintf("{{- if and .Values.connectInject.enabled .Values.global.peering.enabled }}\n%s{{- end }}\n", contents) - } else if dir == "external" { - contents = fmt.Sprintf("{{- if and .Values.connectInject.enabled .Values.connectInject.apiGateway.manageExternalCRDs }}\n%s{{- end }}\n", contents) - } else { - // Add {{- if .Values.connectInject.enabled }} {{- end }} wrapper. - contents = fmt.Sprintf("{{- if .Values.connectInject.enabled }}\n%s{{- end }}\n", contents) - } + return filepath.Walk("../../control-plane/config/crd/bases", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } - // Add labels, this is hacky because we're relying on the line number - // but it means we don't need to regex or yaml parse. - splitOnNewlines := strings.Split(contents, "\n") - labelLines := []string{ - ` labels:`, - ` app: {{ template "consul.name" . }}`, - ` chart: {{ template "consul.chart" . }}`, - ` heritage: {{ .Release.Service }}`, - ` release: {{ .Release.Name }}`, - ` component: crd`, - } - withLabels := append(splitOnNewlines[0:9], append(labelLines, splitOnNewlines[9:]...)...) - contents = strings.Join(withLabels, "\n") + if info.IsDir() || filepath.Ext(path) != ".yaml" { + return nil + } - var crdName string - if dir == "bases" { - // Construct the destination filename. - filenameSplit := strings.Split(info.Name(), "_") - crdName = filenameSplit[1] - } else if dir == "external" { - filenameSplit := strings.Split(info.Name(), ".") - crdName = filenameSplit[0] + ".yaml" - } + printf("processing %s", filepath.Base(path)) - destinationPath := filepath.Join(helmPath, "templates", fmt.Sprintf("crd-%s", crdName)) - // Write it. - printf("writing to %s", destinationPath) - return os.WriteFile(destinationPath, []byte(contents), 0644) - }) + contentBytes, err := os.ReadFile(path) if err != nil { return err } - } - return nil + contents := string(contentBytes) + + // Strip leading newline. + contents = strings.TrimPrefix(contents, "\n") + + // Add {{- if .Values.connectInject.enabled }} {{- end }} wrapper. + contents = fmt.Sprintf("{{- if .Values.connectInject.enabled }}\n%s{{- end }}\n", contents) + + // Add labels, this is hacky because we're relying on the line number + // but it means we don't need to regex or yaml parse. + splitOnNewlines := strings.Split(contents, "\n") + labelLines := []string{ + ` labels:`, + ` app: {{ template "consul.name" . }}`, + ` chart: {{ template "consul.chart" . }}`, + ` heritage: {{ .Release.Service }}`, + ` release: {{ .Release.Name }}`, + ` component: crd`, + } + withLabels := append(splitOnNewlines[0:9], append(labelLines, splitOnNewlines[9:]...)...) + contents = strings.Join(withLabels, "\n") + + // Construct the destination filename. + filenameSplit := strings.Split(info.Name(), "_") + crdName := filenameSplit[1] + destinationPath := filepath.Join(helmPath, "templates", fmt.Sprintf("crd-%s", crdName)) + + // Write it. + printf("writing to %s", destinationPath) + return os.WriteFile(destinationPath, []byte(contents), 0644) + }) } func printf(format string, args ...interface{}) { fmt.Println(fmt.Sprintf(format, args...)) } - -func formatCRDName(name string) string { - name = strings.TrimSuffix(name, ".yaml") - segments := strings.Split(name, "_") - return fmt.Sprintf("%s.%s.yaml", segments[1], segments[0]) -} diff --git a/hack/helm-reference-gen/doc_node.go b/hack/helm-reference-gen/doc_node.go index cf28cf9374..a183ead969 100644 --- a/hack/helm-reference-gen/doc_node.go +++ b/hack/helm-reference-gen/doc_node.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( diff --git a/hack/helm-reference-gen/fixtures/full-values.yaml b/hack/helm-reference-gen/fixtures/full-values.yaml index a79fbc6944..b0eec07666 100644 --- a/hack/helm-reference-gen/fixtures/full-values.yaml +++ b/hack/helm-reference-gen/fixtures/full-values.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - # Available parameters and their default values for the Consul chart. # Holds values that affect multiple components of the chart. diff --git a/hack/helm-reference-gen/go.mod b/hack/helm-reference-gen/go.mod index 36e1ff3a8d..7e41675f18 100644 --- a/hack/helm-reference-gen/go.mod +++ b/hack/helm-reference-gen/go.mod @@ -1,6 +1,6 @@ module github.com/hashicorp/consul-k8s/hack/helm-reference-gen -go 1.20 +go 1.19 require ( github.com/stretchr/testify v1.6.1 diff --git a/hack/helm-reference-gen/main.go b/hack/helm-reference-gen/main.go index 0bc623cff0..5f23143caa 100644 --- a/hack/helm-reference-gen/main.go +++ b/hack/helm-reference-gen/main.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main // This script generates markdown documentation out of the values.yaml file @@ -162,14 +159,11 @@ func GenerateDocs(yamlStr string) (string, error) { return "", err } - docsStr := strings.Join(children, "\n\n") - docsStr = strings.ReplaceAll(docsStr, "[Enterprise Only]", "") - // Remove https://developer.hashicorp.com prefix from links because docs linting requires it. - docsStr = strings.ReplaceAll(docsStr, "https://developer.hashicorp.com/", "/") + enterpriseSubst := strings.ReplaceAll(strings.Join(children, "\n\n"), "[Enterprise Only]", "") // Add table of contents. toc := generateTOC(node) - return toc + "\n\n" + docsStr + "\n", nil + return toc + "\n\n" + enterpriseSubst + "\n", nil } // Parse parses yamlStr into a tree of DocNode's. diff --git a/hack/helm-reference-gen/main_test.go b/hack/helm-reference-gen/main_test.go index fc91032203..03e8648218 100644 --- a/hack/helm-reference-gen/main_test.go +++ b/hack/helm-reference-gen/main_test.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import ( diff --git a/hack/helm-reference-gen/parse_error.go b/hack/helm-reference-gen/parse_error.go index 914737db5f..f474664f1f 100644 --- a/hack/helm-reference-gen/parse_error.go +++ b/hack/helm-reference-gen/parse_error.go @@ -1,6 +1,3 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - package main import "fmt"