diff --git a/.changelog/21758.txt b/.changelog/21758.txt deleted file mode 100644 index 05f97e2c4bef8..0000000000000 --- a/.changelog/21758.txt +++ /dev/null @@ -1,7 +0,0 @@ -```release-note:enhancement -raft: update raft library to 1.7.0 which include pre-vote extension -``` - -```release-note:enhancement -raft: add a configuration `raft_prevote_disabled` to allow disabling raft prevote -``` diff --git a/.changelog/21883.txt b/.changelog/21883.txt deleted file mode 100644 index 44eb78fc43373..0000000000000 --- a/.changelog/21883.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:feature -v2: remove HCP Link integration -``` diff --git a/.changelog/22001.txt b/.changelog/22001.txt deleted file mode 100644 index 04b211c9ed26f..0000000000000 --- a/.changelog/22001.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:security -Update `golang.org/x/crypto` to v0.31.0 to address [GO-2024-3321](https://pkg.go.dev/vuln/GO-2024-3321). -``` \ No newline at end of file diff --git a/.changelog/22011.txt b/.changelog/22011.txt deleted file mode 100644 index 572eb2f42bd89..0000000000000 --- a/.changelog/22011.txt +++ /dev/null @@ -1,4 +0,0 @@ -```release-note:security -Update `registry.access.redhat.com/ubi9-minimal` image to 9.5 to address [CVE-2019-12900](https://nvd.nist.gov/vuln/detail/cve-2019-12900),[CVE-2024-3596](https://nvd.nist.gov/vuln/detail/CVE-2024-3596),[CVE-2024-2511](https://nvd.nist.gov/vuln/detail/CVE-2024-2511),[CVE-2024-26458](https://nvd.nist.gov/vuln/detail/CVE-2024-26458),[CVE-2024-4067](https://nvd.nist.gov/vuln/detail/CVE-2024-4067). -``` - diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index da52ae11b755d..d9af3f042a7e6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,3 @@ -* @hashicorp/consul-selfmanage-maintainers - # Techical Writer Review /website/content/docs/ @hashicorp/consul-docs @@ -8,8 +6,8 @@ # release configuration -/.release/ @hashicorp/team-selfmanaged-releng @hashicorp/consul-selfmanage-maintainers -/.github/workflows/build.yml @hashicorp/team-selfmanaged-releng @hashicorp/consul-selfmanage-maintainers +/.release/ @hashicorp/release-engineering @hashicorp/github-consul-core +/.github/workflows/build.yml @hashicorp/release-engineering @hashicorp/github-consul-core # Staff Engineer Review (protocol buffer definitions) diff --git a/.github/workflows/nightly-test-integrations.yml b/.github/workflows/nightly-test-integrations.yml index 184937c093966..cfaa25303062a 100644 --- a/.github/workflows/nightly-test-integrations.yml +++ b/.github/workflows/nightly-test-integrations.yml @@ -217,7 +217,7 @@ jobs: # matrix.consul-version (i.e. whenever the highest common Envoy version across active # Consul versions changes). The minor Envoy version does not necessarily need to be # kept current for the purpose of these tests, but the major (1.N) version should be. - ENVOY_VERSION: 1.28.7 + ENVOY_VERSION: 1.27.6 steps: - name: Checkout code uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 diff --git a/.github/workflows/test-integrations.yml b/.github/workflows/test-integrations.yml index ba4eecdf4210b..820080f38678c 100644 --- a/.github/workflows/test-integrations.yml +++ b/.github/workflows/test-integrations.yml @@ -83,7 +83,7 @@ jobs: contents: read strategy: matrix: - nomad-version: ['v1.8.3', 'v1.7.7', 'v1.6.10'] + nomad-version: ['v1.7.7', 'v1.6.10', 'v1.5.17'] steps: - name: Checkout Nomad uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 @@ -166,7 +166,7 @@ jobs: contents: read strategy: matrix: - vault-version: ["1.17.5", "1.16.3", "1.15.6"] + vault-version: ["1.16.2", "1.15.6", "1.14.10"] env: VAULT_BINARY_VERSION: ${{ matrix.vault-version }} steps: diff --git a/.gitignore b/.gitignore index fcd852606c5e1..9649c4a8cb988 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,3 @@ terraform.rc /go.work /go.work.sum .docker - -# Avoid accidental commits of consul-k8s submodule used by some dev environments -consul-k8s/ diff --git a/.release/security-scan.hcl b/.release/security-scan.hcl index d18ea456070e2..c807d606c00bd 100644 --- a/.release/security-scan.hcl +++ b/.release/security-scan.hcl @@ -77,7 +77,6 @@ binary { triage { suppress { vulnerabilities = [ - "GO-2022-0635", // github.com/aws/aws-sdk-go@v1.55.5 ] paths = [ "internal/tools/proto-gen-rpc-glue/e2e/consul/*", diff --git a/CHANGELOG.md b/CHANGELOG.md index 69978221dea0b..8b06bb25615c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,11 +52,11 @@ SECURITY: * Explicitly set 'Content-Type' header to mitigate XSS vulnerability. [[GH-21704](https://github.com/hashicorp/consul/issues/21704)] * Implement HTML sanitization for user-generated content to prevent XSS attacks in the UI. [[GH-21711](https://github.com/hashicorp/consul/issues/21711)] * UI: Remove codemirror linting due to package dependency [[GH-21726](https://github.com/hashicorp/consul/issues/21726)] -* Upgrade Go to use 1.22.7. This addresses CVE - [CVE-2024-34155](https://nvd.nist.gov/vuln/detail/CVE-2024-34155) [[GH-21705](https://github.com/hashicorp/consul/issues/21705)] +* Upgrade Go to use 1.22.7. This addresses CVE +[CVE-2024-34155](https://nvd.nist.gov/vuln/detail/CVE-2024-34155) [[GH-21705](https://github.com/hashicorp/consul/issues/21705)] * Upgrade to support aws/aws-sdk-go `v1.55.5 or higher`. This resolves CVEs - [CVE-2020-8911](https://nvd.nist.gov/vuln/detail/cve-2020-8911) and - [CVE-2020-8912](https://nvd.nist.gov/vuln/detail/cve-2020-8912). [[GH-21684](https://github.com/hashicorp/consul/issues/21684)] +[CVE-2020-8911](https://nvd.nist.gov/vuln/detail/cve-2020-8911) and +[CVE-2020-8912](https://nvd.nist.gov/vuln/detail/cve-2020-8912). [[GH-21684](https://github.com/hashicorp/consul/issues/21684)] * ui: Pin a newer resolution of Braces [[GH-21710](https://github.com/hashicorp/consul/issues/21710)] * ui: Pin a newer resolution of Codemirror [[GH-21715](https://github.com/hashicorp/consul/issues/21715)] * ui: Pin a newer resolution of Markdown-it [[GH-21717](https://github.com/hashicorp/consul/issues/21717)] @@ -75,38 +75,6 @@ BUG FIXES: * jwt-provider: change dns lookup family from the default of AUTO which would prefer ipv6 to ALL if LOGICAL_DNS is used or PREFER_IPV4 if STRICT_DNS is used to gracefully handle transitions to ipv6. [[GH-21703](https://github.com/hashicorp/consul/issues/21703)] -## 1.19.3 Enterprise (October 29, 2024) -BREAKING CHANGES: - -* mesh: **(Enterprise Only)** Enable Envoy `HttpConnectionManager.normalize_path` by default on inbound traffic to mesh proxies. This resolves [CVE-2024-10005](https://nvd.nist.gov/vuln/detail/CVE-2024-10005). - -SECURITY: - -* Explicitly set 'Content-Type' header to mitigate XSS vulnerability. [[GH-21704](https://github.com/hashicorp/consul/issues/21704)] -* Implement HTML sanitization for user-generated content to prevent XSS attacks in the UI. [[GH-21711](https://github.com/hashicorp/consul/issues/21711)] -* UI: Remove codemirror linting due to package dependency [[GH-21726](https://github.com/hashicorp/consul/issues/21726)] -* Upgrade Go to use 1.22.7. This addresses CVE -[CVE-2024-34155](https://nvd.nist.gov/vuln/detail/CVE-2024-34155) [[GH-21705](https://github.com/hashicorp/consul/issues/21705)] -* Upgrade to support aws/aws-sdk-go `v1.55.5 or higher`. This resolves CVEs -[CVE-2020-8911](https://nvd.nist.gov/vuln/detail/cve-2020-8911) and -[CVE-2020-8912](https://nvd.nist.gov/vuln/detail/cve-2020-8912). [[GH-21684](https://github.com/hashicorp/consul/issues/21684)] -* mesh: **(Enterprise Only)** Add `contains` and `ignoreCase` to L7 Intentions HTTP header matching criteria to support configuration resilient to variable casing and multiple values. This resolves [CVE-2024-10006](https://nvd.nist.gov/vuln/detail/CVE-2024-10006). -* mesh: **(Enterprise Only)** Add `http.incoming.requestNormalization` to Mesh configuration entry to support inbound service traffic request normalization. This resolves [CVE-2024-10005](https://nvd.nist.gov/vuln/detail/CVE-2024-10005) and [CVE-2024-10006](https://nvd.nist.gov/vuln/detail/CVE-2024-10006). -* ui: Pin a newer resolution of Braces [[GH-21710](https://github.com/hashicorp/consul/issues/21710)] -* ui: Pin a newer resolution of Codemirror [[GH-21715](https://github.com/hashicorp/consul/issues/21715)] -* ui: Pin a newer resolution of Markdown-it [[GH-21717](https://github.com/hashicorp/consul/issues/21717)] -* ui: Pin a newer resolution of ansi-html [[GH-21735](https://github.com/hashicorp/consul/issues/21735)] - -IMPROVEMENTS: - -* security: upgrade ubi base image to 9.4 [[GH-21750](https://github.com/hashicorp/consul/issues/21750)] -* api: remove dependency on proto-public, protobuf, and grpc [[GH-21780](https://github.com/hashicorp/consul/issues/21780)] -* xds: configures Envoy to load balance over all instances of an external service configured with hostnames when "envoy_dns_discovery_type" is set to "STRICT_DNS" [[GH-21655](https://github.com/hashicorp/consul/issues/21655)] - -BUG FIXES: - -* jwt-provider: change dns lookup family from the default of AUTO which would prefer ipv6 to ALL if LOGICAL_DNS is used or PREFER_IPV4 if STRICT_DNS is used to gracefully handle transitions to ipv6. [[GH-21703](https://github.com/hashicorp/consul/issues/21703)] - ## 1.19.2 (August 26, 2024) SECURITY: @@ -121,39 +89,6 @@ BUG FIXES: * api-gateway: **(Enterprise only)** ensure clusters are properly created for JWT providers with a remote URI for the JWKS endpoint [[GH-21604](https://github.com/hashicorp/consul/issues/21604)] -## 1.18.5 Enterprise (October 29, 2024) - -Enterprise LTS: Consul Enterprise 1.18 is a Long-Term Support (LTS) release. -BREAKING CHANGES: - -* mesh: **(Enterprise Only)** Enable Envoy `HttpConnectionManager.normalize_path` by default on inbound traffic to mesh proxies. This resolves [CVE-2024-10005](https://nvd.nist.gov/vuln/detail/CVE-2024-10005). - -SECURITY: - -* Explicitly set 'Content-Type' header to mitigate XSS vulnerability. [[GH-21704](https://github.com/hashicorp/consul/issues/21704)] -* Implement HTML sanitization for user-generated content to prevent XSS attacks in the UI. [[GH-21711](https://github.com/hashicorp/consul/issues/21711)] -* Upgrade Go to use 1.22.7. This addresses CVE -[CVE-2024-34155](https://nvd.nist.gov/vuln/detail/CVE-2024-34155) [[GH-21705](https://github.com/hashicorp/consul/issues/21705)] -* Upgrade to support aws/aws-sdk-go `v1.55.5 or higher`. This resolves CVEs -[CVE-2020-8911](https://nvd.nist.gov/vuln/detail/cve-2020-8911) and -[CVE-2020-8912](https://nvd.nist.gov/vuln/detail/cve-2020-8912). [[GH-21684](https://github.com/hashicorp/consul/issues/21684)] -* mesh: **(Enterprise Only)** Add `contains` and `ignoreCase` to L7 Intentions HTTP header matching criteria to support configuration resilient to variable casing and multiple values. This resolves [CVE-2024-10006](https://nvd.nist.gov/vuln/detail/CVE-2024-10006). -* mesh: **(Enterprise Only)** Add `http.incoming.requestNormalization` to Mesh configuration entry to support inbound service traffic request normalization. This resolves [CVE-2024-10005](https://nvd.nist.gov/vuln/detail/CVE-2024-10005) and [CVE-2024-10006](https://nvd.nist.gov/vuln/detail/CVE-2024-10006). -* ui: Pin a newer resolution of Braces [[GH-21710](https://github.com/hashicorp/consul/issues/21710)] -* ui: Pin a newer resolution of Codemirror [[GH-21715](https://github.com/hashicorp/consul/issues/21715)] -* ui: Pin a newer resolution of Markdown-it [[GH-21717](https://github.com/hashicorp/consul/issues/21717)] -* ui: Pin a newer resolution of ansi-html [[GH-21735](https://github.com/hashicorp/consul/issues/21735)] - -IMPROVEMENTS: - -* security: upgrade ubi base image to 9.4 [[GH-21750](https://github.com/hashicorp/consul/issues/21750)] -* api: remove dependency on proto-public, protobuf, and grpc [[GH-21780](https://github.com/hashicorp/consul/issues/21780)] -* xds: configures Envoy to load balance over all instances of an external service configured with hostnames when "envoy_dns_discovery_type" is set to "STRICT_DNS" [[GH-21655](https://github.com/hashicorp/consul/issues/21655)] - -BUG FIXES: - -* jwt-provider: change dns lookup family from the default of AUTO which would prefer ipv6 to ALL if LOGICAL_DNS is used or PREFER_IPV4 if STRICT_DNS is used to gracefully handle transitions to ipv6. [[GH-21703](https://github.com/hashicorp/consul/issues/21703)] - ## 1.18.4 Enterprise (August 26, 2024) Enterprise LTS: Consul Enterprise 1.18 is a Long-Term Support (LTS) release. @@ -174,35 +109,6 @@ IMPROVEMENTS: * Use Envoy's default for a route's validate_clusters option, which is false. This fixes a case where non-existent clusters could cause a route to no longer route to any of its backends, including existing ones. [[GH-21587](https://github.com/hashicorp/consul/issues/21587)] -## 1.15.15 Enterprise (October 29, 2024) - -Enterprise LTS: Consul Enterprise 1.15 is a Long-Term Support (LTS) release. -BREAKING CHANGES: - -* mesh: **(Enterprise Only)** Enable Envoy `HttpConnectionManager.normalize_path` by default on inbound traffic to mesh proxies. This resolves [CVE-2024-10005](https://nvd.nist.gov/vuln/detail/CVE-2024-10005). - -SECURITY: - -* Explicitly set 'Content-Type' header to mitigate XSS vulnerability. [[GH-21704](https://github.com/hashicorp/consul/issues/21704)] -* Implement HTML sanitization for user-generated content to prevent XSS attacks in the UI. [[GH-21711](https://github.com/hashicorp/consul/issues/21711)] -* UI: Remove codemirror linting due to package dependency [[GH-21726](https://github.com/hashicorp/consul/issues/21726)] -* Upgrade Go to use 1.22.7. This addresses CVE -[CVE-2024-34155](https://nvd.nist.gov/vuln/detail/CVE-2024-34155) [[GH-21705](https://github.com/hashicorp/consul/issues/21705)] -* Upgrade to support aws/aws-sdk-go `v1.55.5 or higher`. This resolves CVEs -[CVE-2020-8911](https://nvd.nist.gov/vuln/detail/cve-2020-8911) and -[CVE-2020-8912](https://nvd.nist.gov/vuln/detail/cve-2020-8912). [[GH-21684](https://github.com/hashicorp/consul/issues/21684)] -* mesh: **(Enterprise Only)** Add `contains` and `ignoreCase` to L7 Intentions HTTP header matching criteria to support configuration resilient to variable casing and multiple values. This resolves [CVE-2024-10006](https://nvd.nist.gov/vuln/detail/CVE-2024-10006). -* mesh: **(Enterprise Only)** Add `http.incoming.requestNormalization` to Mesh configuration entry to support inbound service traffic request normalization. This resolves [CVE-2024-10005](https://nvd.nist.gov/vuln/detail/CVE-2024-10005) and [CVE-2024-10006](https://nvd.nist.gov/vuln/detail/CVE-2024-10006). -* ui: Pin a newer resolution of Braces [[GH-21710](https://github.com/hashicorp/consul/issues/21710)] -* ui: Pin a newer resolution of Codemirror [[GH-21715](https://github.com/hashicorp/consul/issues/21715)] -* ui: Pin a newer resolution of Markdown-it [[GH-21717](https://github.com/hashicorp/consul/issues/21717)] -* ui: Pin a newer resolution of ansi-html [[GH-21735](https://github.com/hashicorp/consul/issues/21735)] - -IMPROVEMENTS: - -* security: upgrade ubi base image to 9.4 [[GH-21750](https://github.com/hashicorp/consul/issues/21750)] -* xds: configures Envoy to load balance over all instances of an external service configured with hostnames when "envoy_dns_discovery_type" is set to "STRICT_DNS" [[GH-21655](https://github.com/hashicorp/consul/issues/21655)] - ## 1.15.14 Enterprise (August 26, 2024) Enterprise LTS: Consul Enterprise 1.15 is a Long-Term Support (LTS) release. diff --git a/Dockerfile b/Dockerfile index 0440878788fff..e520db57ad586 100644 --- a/Dockerfile +++ b/Dockerfile @@ -203,7 +203,7 @@ CMD ["agent", "-dev", "-client", "0.0.0.0"] # Red Hat UBI-based image # This target is used to build a Consul image for use on OpenShift. -FROM registry.access.redhat.com/ubi9-minimal:9.5 as ubi +FROM registry.access.redhat.com/ubi9-minimal:9.4 as ubi ARG PRODUCT_VERSION ARG PRODUCT_REVISION diff --git a/agent/agent.go b/agent/agent.go index c5fb3cc886c01..a509ea2b34459 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -1434,9 +1434,6 @@ func newConsulConfig(runtimeCfg *config.RuntimeConfig, logger hclog.Logger) (*co cfg.GRPCTLSPort = runtimeCfg.GRPCTLSPort cfg.Segment = runtimeCfg.SegmentName - - cfg.RaftConfig.PreVoteDisabled = runtimeCfg.RaftPreVoteDisabled - if len(runtimeCfg.Segments) > 0 { segments, err := segmentConfig(runtimeCfg) if err != nil { diff --git a/agent/config/builder.go b/agent/config/builder.go index 5e8b5c215f6d7..f8d0df7b5c93f 100644 --- a/agent/config/builder.go +++ b/agent/config/builder.go @@ -1073,7 +1073,6 @@ func (b *builder) build() (rt RuntimeConfig, err error) { RaftSnapshotThreshold: intVal(c.RaftSnapshotThreshold), RaftSnapshotInterval: b.durationVal("raft_snapshot_interval", c.RaftSnapshotInterval), RaftTrailingLogs: intVal(c.RaftTrailingLogs), - RaftPreVoteDisabled: boolVal(c.RaftPreVoteDisabled), RaftLogStoreConfig: b.raftLogStoreConfigVal(&c.RaftLogStore), ReconnectTimeoutLAN: b.durationVal("reconnect_timeout", c.ReconnectTimeoutLAN), ReconnectTimeoutWAN: b.durationVal("reconnect_timeout_wan", c.ReconnectTimeoutWAN), diff --git a/agent/config/config.go b/agent/config/config.go index 4a93c27020210..3201f790a7521 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -8,9 +8,8 @@ import ( "fmt" "time" - "github.com/mitchellh/mapstructure" - "github.com/hashicorp/hcl" + "github.com/mitchellh/mapstructure" "github.com/hashicorp/consul/lib/decode" ) @@ -215,7 +214,6 @@ type Config struct { RaftSnapshotThreshold *int `mapstructure:"raft_snapshot_threshold" json:"raft_snapshot_threshold,omitempty"` RaftSnapshotInterval *string `mapstructure:"raft_snapshot_interval" json:"raft_snapshot_interval,omitempty"` RaftTrailingLogs *int `mapstructure:"raft_trailing_logs" json:"raft_trailing_logs,omitempty"` - RaftPreVoteDisabled *bool `mapstructure:"raft_prevote_disabled" json:"raft_prevote_disabled,omitempty"` ReconnectTimeoutLAN *string `mapstructure:"reconnect_timeout" json:"reconnect_timeout,omitempty"` ReconnectTimeoutWAN *string `mapstructure:"reconnect_timeout_wan" json:"reconnect_timeout_wan,omitempty"` RejoinAfterLeave *bool `mapstructure:"rejoin_after_leave" json:"rejoin_after_leave,omitempty"` diff --git a/agent/config/default.go b/agent/config/default.go index 1b98056aa1102..f07a8bdf46dcf 100644 --- a/agent/config/default.go +++ b/agent/config/default.go @@ -146,7 +146,6 @@ func DefaultSource() Source { raft_snapshot_threshold = ` + strconv.Itoa(int(cfg.RaftConfig.SnapshotThreshold)) + ` raft_snapshot_interval = "` + cfg.RaftConfig.SnapshotInterval.String() + `" raft_trailing_logs = ` + strconv.Itoa(int(cfg.RaftConfig.TrailingLogs)) + ` - raft_prevote_disabled = false raft_logstore { wal { segment_size_mb = 64 diff --git a/agent/config/runtime.go b/agent/config/runtime.go index e31047354ddaf..2ac7ea19d9f12 100644 --- a/agent/config/runtime.go +++ b/agent/config/runtime.go @@ -10,9 +10,8 @@ import ( "strings" "time" - "golang.org/x/time/rate" - "github.com/hashicorp/go-uuid" + "golang.org/x/time/rate" "github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/consul" @@ -1005,9 +1004,6 @@ type RuntimeConfig struct { // hcl: raft_trailing_logs = int RaftTrailingLogs int - // hcl: raft_prevote_disabled = bool - RaftPreVoteDisabled bool - RaftLogStoreConfig consul.RaftLogStoreConfig // ReconnectTimeoutLAN specifies the amount of time to wait to reconnect with diff --git a/agent/config/runtime_test.go b/agent/config/runtime_test.go index 549429bf8682d..a36d5f67dad93 100644 --- a/agent/config/runtime_test.go +++ b/agent/config/runtime_test.go @@ -6594,7 +6594,6 @@ func TestLoad_FullConfig(t *testing.T) { RaftSnapshotThreshold: 16384, RaftSnapshotInterval: 30 * time.Second, RaftTrailingLogs: 83749, - RaftPreVoteDisabled: false, ReconnectTimeoutLAN: 23739 * time.Second, ReconnectTimeoutWAN: 26694 * time.Second, RequestLimitsMode: consulrate.ModePermissive, diff --git a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden index 53e533b246209..5ead1e2f764c9 100644 --- a/agent/config/testdata/TestRuntimeConfig_Sanitize.golden +++ b/agent/config/testdata/TestRuntimeConfig_Sanitize.golden @@ -71,7 +71,6 @@ "AutopilotDisableUpgradeMigration": false, "AutopilotLastContactThreshold": "0s", "AutopilotMaxTrailingLogs": 0, - "AutopilotMinQuorum": 0, "AutopilotRedundancyZoneTag": "", "AutopilotServerStabilizationTime": "0s", @@ -300,7 +299,6 @@ "RaftSnapshotInterval": "0s", "RaftSnapshotThreshold": 0, "RaftTrailingLogs": 0, - "RaftPreVoteDisabled": false, "ReadReplica": false, "ReconnectTimeoutLAN": "0s", "ReconnectTimeoutWAN": "0s", diff --git a/agent/consul/internal_endpoint_test.go b/agent/consul/internal_endpoint_test.go index 2a46c85e25771..3c73f31c17c1b 100644 --- a/agent/consul/internal_endpoint_test.go +++ b/agent/consul/internal_endpoint_test.go @@ -3899,15 +3899,12 @@ func TestInternal_AssignManualServiceVIPs(t *testing.T) { } var resp structs.AssignServiceManualVIPsResponse - idx1 := s1.raft.CommitIndex() err := msgpackrpc.CallWithCodec(codec, "Internal.AssignManualServiceVIPs", tc.req, &resp) - idx2 := s1.raft.CommitIndex() if tc.expectErr != "" { testutil.RequireErrorContains(t, err, tc.expectErr) } else { if again { require.Equal(t, tc.expectAgain, resp) - require.Equal(t, idx1, idx2, "no raft operations occurred") } else { require.Equal(t, tc.expect, resp) } diff --git a/agent/consul/server.go b/agent/consul/server.go index e33fd493ae453..979d9e3cd4341 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -53,6 +53,7 @@ import ( "github.com/hashicorp/consul/agent/consul/xdscapacity" "github.com/hashicorp/consul/agent/grpc-external/services/peerstream" "github.com/hashicorp/consul/agent/hcp" + "github.com/hashicorp/consul/agent/hcp/bootstrap" hcpclient "github.com/hashicorp/consul/agent/hcp/client" logdrop "github.com/hashicorp/consul/agent/log-drop" "github.com/hashicorp/consul/agent/metadata" @@ -64,6 +65,7 @@ import ( "github.com/hashicorp/consul/agent/token" "github.com/hashicorp/consul/internal/controller" "github.com/hashicorp/consul/internal/gossip/librtt" + hcpctl "github.com/hashicorp/consul/internal/hcp" "github.com/hashicorp/consul/internal/multicluster" "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource/demo" @@ -836,6 +838,25 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server, // to enable RPC forwarding. s.grpcLeaderForwarder = flat.LeaderForwarder + if s.config.Cloud.IsConfigured() { + // Start watching HCP Link resource. This needs to be created after + // the GRPC services are set up in order for the resource service client to + // function. This uses the insecure grpc channel so that it doesn't need to + // present a valid ACL token. + go hcp.RunHCPLinkWatcher( + &lib.StopChannelContext{StopCh: shutdownCh}, + logger.Named("hcp-link-watcher"), + pbresource.NewResourceServiceClient(s.insecureSafeGRPCChan), + hcp.HCPManagerLifecycleFn( + s.hcpManager, + hcpclient.NewClient, + bootstrap.LoadManagementToken, + flat.HCP.Config, + flat.HCP.DataDir, + ), + ) + } + s.controllerManager = controller.NewManager( // Usage of the insecure + unsafe grpc chan is required for the controller // manager. It must be unauthorized so that controllers do not need to @@ -907,7 +928,15 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server, return s, nil } -func (s *Server) registerControllers(_ Deps) error { +func (s *Server) registerControllers(deps Deps) error { + if s.config.Cloud.IsConfigured() { + hcpctl.RegisterControllers( + s.controllerManager, hcpctl.ControllerDependencies{ + CloudConfig: deps.HCP.Config, + }, + ) + } + shim := NewExportedServicesShim(s) multicluster.RegisterCompatControllers(s.controllerManager, multicluster.DefaultCompatControllerDependencies(shim)) diff --git a/agent/consul/testdata/v2-resource-dependencies.md b/agent/consul/testdata/v2-resource-dependencies.md index b69cb967f95d6..7bcb0d55c4f47 100644 --- a/agent/consul/testdata/v2-resource-dependencies.md +++ b/agent/consul/testdata/v2-resource-dependencies.md @@ -7,6 +7,8 @@ flowchart TD demo/v1/recordlabel demo/v2/album demo/v2/artist + hcp/v2/link + hcp/v2/telemetrystate internal/v1/tombstone multicluster/v2/computedexportedservices --> multicluster/v2/exportedservices multicluster/v2/computedexportedservices --> multicluster/v2/namespaceexportedservices @@ -14,4 +16,4 @@ flowchart TD multicluster/v2/exportedservices multicluster/v2/namespaceexportedservices multicluster/v2/partitionexportedservices -``` +``` \ No newline at end of file diff --git a/agent/consul/type_registry.go b/agent/consul/type_registry.go index 8ab91f79466ac..cd2087e48f12e 100644 --- a/agent/consul/type_registry.go +++ b/agent/consul/type_registry.go @@ -4,6 +4,7 @@ package consul import ( + "github.com/hashicorp/consul/internal/hcp" "github.com/hashicorp/consul/internal/multicluster" "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource/demo" @@ -21,6 +22,7 @@ func NewTypeRegistry() resource.Registry { demo.RegisterTypes(registry) multicluster.RegisterTypes(registry) + hcp.RegisterTypes(registry) return registry } diff --git a/agent/hcp/link_watch.go b/agent/hcp/link_watch.go new file mode 100644 index 0000000000000..b89ba942e4655 --- /dev/null +++ b/agent/hcp/link_watch.go @@ -0,0 +1,68 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package hcp + +import ( + "context" + "time" + + "github.com/hashicorp/go-hclog" + + hcpctl "github.com/hashicorp/consul/internal/hcp" + "github.com/hashicorp/consul/lib/retry" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +type LinkEventHandler = func(context.Context, hclog.Logger, *pbresource.WatchEvent) + +func handleLinkEvents(ctx context.Context, logger hclog.Logger, watchClient pbresource.ResourceService_WatchListClient, linkEventHandler LinkEventHandler) { + for { + select { + case <-ctx.Done(): + logger.Debug("context canceled, exiting") + return + default: + watchEvent, err := watchClient.Recv() + + if err != nil { + logger.Error("error receiving link watch event", "error", err) + return + } + + linkEventHandler(ctx, logger, watchEvent) + } + } +} + +func RunHCPLinkWatcher( + ctx context.Context, logger hclog.Logger, client pbresource.ResourceServiceClient, linkEventHandler LinkEventHandler, +) { + errorBackoff := &retry.Waiter{ + MinFailures: 10, + MinWait: 0, + MaxWait: 1 * time.Minute, + } + for { + select { + case <-ctx.Done(): + logger.Debug("context canceled, exiting") + return + default: + watchClient, err := client.WatchList( + ctx, &pbresource.WatchListRequest{ + Type: pbhcp.LinkType, + NamePrefix: hcpctl.LinkName, + }, + ) + if err != nil { + logger.Error("failed to create watch on Link", "error", err) + errorBackoff.Wait(ctx) + continue + } + errorBackoff.Reset() + handleLinkEvents(ctx, logger, watchClient, linkEventHandler) + } + } +} diff --git a/agent/hcp/link_watch_test.go b/agent/hcp/link_watch_test.go new file mode 100644 index 0000000000000..22d2204a817d1 --- /dev/null +++ b/agent/hcp/link_watch_test.go @@ -0,0 +1,101 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package hcp + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + + "github.com/hashicorp/go-hclog" + + mockpbresource "github.com/hashicorp/consul/grpcmocks/proto-public/pbresource" + hcpctl "github.com/hashicorp/consul/internal/hcp" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +// This tests that when we get a watch event from the Recv call, we get that same event on the +// output channel, then we +func TestLinkWatcher_Ok(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + testWatchEvent := &pbresource.WatchEvent{} + mockWatchListClient := mockpbresource.NewResourceService_WatchListClient(t) + mockWatchListClient.EXPECT().Recv().Return(testWatchEvent, nil) + + eventCh := make(chan *pbresource.WatchEvent) + mockLinkHandler := func(_ context.Context, _ hclog.Logger, event *pbresource.WatchEvent) { + eventCh <- event + } + + client := mockpbresource.NewResourceServiceClient(t) + client.EXPECT().WatchList(mock.Anything, &pbresource.WatchListRequest{ + Type: pbhcp.LinkType, + NamePrefix: hcpctl.LinkName, + }).Return(mockWatchListClient, nil) + + go RunHCPLinkWatcher(ctx, hclog.Default(), client, mockLinkHandler) + + // Assert that the link handler is called with the testWatchEvent + receivedWatchEvent := <-eventCh + require.Equal(t, testWatchEvent, receivedWatchEvent) +} + +func TestLinkWatcher_RecvError(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + // Our mock WatchListClient will simulate 5 errors, then will cancel the context. + // We expect RunHCPLinkWatcher to attempt to create the WatchListClient 6 times (initial attempt plus 5 retries) + // before exiting due to context cancellation. + mockWatchListClient := mockpbresource.NewResourceService_WatchListClient(t) + numFailures := 5 + failures := 0 + mockWatchListClient.EXPECT().Recv().RunAndReturn(func() (*pbresource.WatchEvent, error) { + if failures < numFailures { + failures++ + return nil, errors.New("unexpectedError") + } + defer cancel() + return &pbresource.WatchEvent{}, nil + }) + + client := mockpbresource.NewResourceServiceClient(t) + client.EXPECT().WatchList(mock.Anything, &pbresource.WatchListRequest{ + Type: pbhcp.LinkType, + NamePrefix: hcpctl.LinkName, + }).Return(mockWatchListClient, nil).Times(numFailures + 1) + + RunHCPLinkWatcher(ctx, hclog.Default(), client, func(_ context.Context, _ hclog.Logger, _ *pbresource.WatchEvent) {}) +} + +func TestLinkWatcher_WatchListError(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + // Our mock WatchList will simulate 5 errors, then will cancel the context. + // We expect RunHCPLinkWatcher to attempt to create the WatchListClient 6 times (initial attempt plus 5 retries) + // before exiting due to context cancellation. + numFailures := 5 + failures := 0 + + client := mockpbresource.NewResourceServiceClient(t) + client.EXPECT().WatchList(mock.Anything, &pbresource.WatchListRequest{ + Type: pbhcp.LinkType, + NamePrefix: hcpctl.LinkName, + }).RunAndReturn(func(_ context.Context, _ *pbresource.WatchListRequest, _ ...grpc.CallOption) (pbresource.ResourceService_WatchListClient, error) { + if failures < numFailures { + failures++ + return nil, errors.New("unexpectedError") + } + defer cancel() + return mockpbresource.NewResourceService_WatchListClient(t), nil + }).Times(numFailures + 1) + + RunHCPLinkWatcher(ctx, hclog.Default(), client, func(_ context.Context, _ hclog.Logger, _ *pbresource.WatchEvent) {}) +} diff --git a/agent/hcp/manager_lifecycle.go b/agent/hcp/manager_lifecycle.go new file mode 100644 index 0000000000000..6b7b6a46dc712 --- /dev/null +++ b/agent/hcp/manager_lifecycle.go @@ -0,0 +1,107 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package hcp + +import ( + "context" + "os" + "path/filepath" + + "github.com/hashicorp/go-hclog" + + "github.com/hashicorp/consul/agent/hcp/bootstrap/constants" + hcpclient "github.com/hashicorp/consul/agent/hcp/client" + "github.com/hashicorp/consul/agent/hcp/config" + hcpctl "github.com/hashicorp/consul/internal/hcp" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +// HCPManagerLifecycleFn returns a LinkEventHandler function which will appropriately +// Start and Stop the HCP Manager based on the Link event received. If a link is upserted, +// the HCP Manager is started, and if a link is deleted, the HCP manager is stopped. +func HCPManagerLifecycleFn( + m Manager, + hcpClientFn func(cfg config.CloudConfig) (hcpclient.Client, error), + loadMgmtTokenFn func( + ctx context.Context, logger hclog.Logger, hcpClient hcpclient.Client, dataDir string, + ) (string, error), + cloudConfig config.CloudConfig, + dataDir string, +) LinkEventHandler { + return func(ctx context.Context, logger hclog.Logger, watchEvent *pbresource.WatchEvent) { + // This indicates that a Link was deleted + if watchEvent.GetDelete() != nil { + logger.Debug("HCP Link deleted, stopping HCP manager") + + if dataDir != "" { + hcpConfigDir := filepath.Join(dataDir, constants.SubDir) + logger.Debug("deleting hcp-config dir", "dir", hcpConfigDir) + err := os.RemoveAll(hcpConfigDir) + if err != nil { + logger.Error("failed to delete hcp-config dir", "dir", hcpConfigDir, "err", err) + } + } + + err := m.Stop() + if err != nil { + logger.Error("error stopping HCP manager", "error", err) + } + return + } + + // This indicates that a Link was either created or updated + if watchEvent.GetUpsert() != nil { + logger.Debug("HCP Link upserted, starting manager if not already started") + + res := watchEvent.GetUpsert().GetResource() + var link pbhcp.Link + if err := res.GetData().UnmarshalTo(&link); err != nil { + logger.Error("error unmarshalling link data", "error", err) + return + } + + if validated, reason := hcpctl.IsValidated(res); !validated { + logger.Debug("HCP Link not validated, not starting manager", "reason", reason) + return + } + + // Update the HCP manager configuration with the link values + // Merge the link data with the existing cloud config so that we only overwrite the + // fields that are provided by the link. This ensures that: + // 1. The HCP configuration (i.e., how to connect to HCP) is preserved + // 2. The Consul agent's node ID and node name are preserved + newCfg := config.CloudConfig{ + ResourceID: link.ResourceId, + ClientID: link.ClientId, + ClientSecret: link.ClientSecret, + } + mergedCfg := config.Merge(cloudConfig, newCfg) + hcpClient, err := hcpClientFn(mergedCfg) + if err != nil { + logger.Error("error creating HCP client", "error", err) + return + } + + // Load the management token if access is set to read-write. Read-only clusters + // will not have a management token provided by HCP. + var token string + if link.GetAccessLevel() == pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_WRITE { + token, err = loadMgmtTokenFn(ctx, logger, hcpClient, dataDir) + if err != nil { + logger.Error("error loading management token", "error", err) + return + } + } + + mergedCfg.ManagementToken = token + m.UpdateConfig(hcpClient, mergedCfg) + + err = m.Start(ctx) + if err != nil { + logger.Error("error starting HCP manager", "error", err) + } + } + } +} diff --git a/agent/hcp/manager_lifecycle_test.go b/agent/hcp/manager_lifecycle_test.go new file mode 100644 index 0000000000000..b40a772ab4c8e --- /dev/null +++ b/agent/hcp/manager_lifecycle_test.go @@ -0,0 +1,236 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package hcp + +import ( + "context" + "errors" + "io" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/hashicorp/go-hclog" + + "github.com/hashicorp/consul/agent/hcp/bootstrap/constants" + hcpclient "github.com/hashicorp/consul/agent/hcp/client" + "github.com/hashicorp/consul/agent/hcp/config" + hcpctl "github.com/hashicorp/consul/internal/hcp" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/sdk/testutil" +) + +func TestHCPManagerLifecycleFn(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + logger := hclog.New(&hclog.LoggerOptions{Output: io.Discard}) + + mockHCPClient := hcpclient.NewMockClient(t) + mockHcpClientFn := func(_ config.CloudConfig) (hcpclient.Client, error) { + return mockHCPClient, nil + } + + mockLoadMgmtTokenFn := func(ctx context.Context, logger hclog.Logger, hcpClient hcpclient.Client, dataDir string) (string, error) { + return "test-mgmt-token", nil + } + + dataDir := testutil.TempDir(t, "test-link-controller") + err := os.Mkdir(filepath.Join(dataDir, constants.SubDir), os.ModeDir) + require.NoError(t, err) + existingCfg := config.CloudConfig{ + AuthURL: "test.com", + } + + type testCase struct { + mutateLink func(*pbhcp.Link) + mutateUpsertEvent func(*pbresource.WatchEvent_Upsert) + applyMocksAndAssertions func(*testing.T, *MockManager, *pbhcp.Link) + hcpClientFn func(config.CloudConfig) (hcpclient.Client, error) + loadMgmtTokenFn func(context.Context, hclog.Logger, hcpclient.Client, string) (string, error) + } + + testCases := map[string]testCase{ + // HCP manager should be started when link is created and stopped when link is deleted + "Ok": { + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.EXPECT().Start(mock.Anything).Return(nil).Once() + + expectedCfg := config.CloudConfig{ + ResourceID: link.ResourceId, + ClientID: link.ClientId, + ClientSecret: link.ClientSecret, + AuthURL: "test.com", + ManagementToken: "test-mgmt-token", + } + mgr.EXPECT().UpdateConfig(mockHCPClient, expectedCfg).Once() + + mgr.EXPECT().Stop().Return(nil).Once() + }, + }, + // HCP manager should not be updated with management token + "ReadOnly": { + mutateLink: func(link *pbhcp.Link) { + link.AccessLevel = pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_ONLY + }, + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.EXPECT().Start(mock.Anything).Return(nil).Once() + + expectedCfg := config.CloudConfig{ + ResourceID: link.ResourceId, + ClientID: link.ClientId, + ClientSecret: link.ClientSecret, + AuthURL: "test.com", + ManagementToken: "", + } + mgr.EXPECT().UpdateConfig(mockHCPClient, expectedCfg).Once() + + mgr.EXPECT().Stop().Return(nil).Once() + }, + }, + // HCP manager should not be started or updated if link is not validated + "ValidationError": { + mutateUpsertEvent: func(upsert *pbresource.WatchEvent_Upsert) { + upsert.Resource.Status = map[string]*pbresource.Status{ + hcpctl.StatusKey: { + Conditions: []*pbresource.Condition{hcpctl.ConditionValidatedFailed}, + }, + } + }, + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.AssertNotCalled(t, "Start", mock.Anything) + mgr.AssertNotCalled(t, "UpdateConfig", mock.Anything, mock.Anything) + mgr.EXPECT().Stop().Return(nil).Once() + }, + }, + "Error_InvalidLink": { + mutateUpsertEvent: func(upsert *pbresource.WatchEvent_Upsert) { + upsert.Resource = nil + }, + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.AssertNotCalled(t, "Start", mock.Anything) + mgr.AssertNotCalled(t, "UpdateConfig", mock.Anything, mock.Anything) + mgr.EXPECT().Stop().Return(nil).Once() + }, + }, + "Error_HCPManagerStop": { + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.EXPECT().Start(mock.Anything).Return(nil).Once() + mgr.EXPECT().UpdateConfig(mock.Anything, mock.Anything).Return().Once() + mgr.EXPECT().Stop().Return(errors.New("could not stop HCP manager")).Once() + }, + }, + "Error_CreatingHCPClient": { + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.AssertNotCalled(t, "Start", mock.Anything) + mgr.AssertNotCalled(t, "UpdateConfig", mock.Anything, mock.Anything) + mgr.EXPECT().Stop().Return(nil).Once() + }, + hcpClientFn: func(_ config.CloudConfig) (hcpclient.Client, error) { + return nil, errors.New("could not create HCP client") + }, + }, + // This should result in the HCP manager not being started + "Error_LoadMgmtToken": { + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.AssertNotCalled(t, "Start", mock.Anything) + mgr.AssertNotCalled(t, "UpdateConfig", mock.Anything, mock.Anything) + mgr.EXPECT().Stop().Return(nil).Once() + }, + loadMgmtTokenFn: func(ctx context.Context, logger hclog.Logger, hcpClient hcpclient.Client, dataDir string) (string, error) { + return "", errors.New("could not load management token") + }, + }, + "Error_HCPManagerStart": { + applyMocksAndAssertions: func(t *testing.T, mgr *MockManager, link *pbhcp.Link) { + mgr.EXPECT().Start(mock.Anything).Return(errors.New("could not start HCP manager")).Once() + mgr.EXPECT().UpdateConfig(mock.Anything, mock.Anything).Return().Once() + mgr.EXPECT().Stop().Return(nil).Once() + }, + }, + } + + for name, test := range testCases { + t.Run(name, func(t2 *testing.T) { + mgr := NewMockManager(t2) + + // Set up a link + link := pbhcp.Link{ + ResourceId: "abc", + ClientId: "def", + ClientSecret: "ghi", + AccessLevel: pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_WRITE, + } + + if test.mutateLink != nil { + test.mutateLink(&link) + } + + linkResource, err := anypb.New(&link) + require.NoError(t2, err) + + if test.applyMocksAndAssertions != nil { + test.applyMocksAndAssertions(t2, mgr, &link) + } + + testHcpClientFn := mockHcpClientFn + if test.hcpClientFn != nil { + testHcpClientFn = test.hcpClientFn + } + + testLoadMgmtToken := mockLoadMgmtTokenFn + if test.loadMgmtTokenFn != nil { + testLoadMgmtToken = test.loadMgmtTokenFn + } + + updateManagerLifecycle := HCPManagerLifecycleFn( + mgr, testHcpClientFn, + testLoadMgmtToken, existingCfg, dataDir, + ) + + upsertEvent := &pbresource.WatchEvent_Upsert{ + Resource: &pbresource.Resource{ + Id: &pbresource.ID{ + Name: "global", + Type: pbhcp.LinkType, + }, + Status: map[string]*pbresource.Status{ + hcpctl.StatusKey: { + Conditions: []*pbresource.Condition{hcpctl.ConditionValidatedSuccess}, + }, + }, + Data: linkResource, + }, + } + if test.mutateUpsertEvent != nil { + test.mutateUpsertEvent(upsertEvent) + } + + // Handle upsert event + updateManagerLifecycle(ctx, logger, &pbresource.WatchEvent{ + Event: &pbresource.WatchEvent_Upsert_{ + Upsert: upsertEvent, + }, + }) + + // Handle delete event. This should stop HCP manager + updateManagerLifecycle(ctx, logger, &pbresource.WatchEvent{ + Event: &pbresource.WatchEvent_Delete_{ + Delete: &pbresource.WatchEvent_Delete{}, + }, + }) + + // Ensure hcp-config directory is removed + file := filepath.Join(dataDir, constants.SubDir) + if _, err := os.Stat(file); err == nil || !os.IsNotExist(err) { + require.Fail(t2, "should have removed hcp-config directory") + } + }) + } +} diff --git a/agent/hcp/manager_test.go b/agent/hcp/manager_test.go index 75e1e3d2849d5..83773791727d5 100644 --- a/agent/hcp/manager_test.go +++ b/agent/hcp/manager_test.go @@ -12,15 +12,75 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "golang.org/x/net/context" + "google.golang.org/protobuf/types/known/anypb" "github.com/hashicorp/go-hclog" hcpclient "github.com/hashicorp/consul/agent/hcp/client" "github.com/hashicorp/consul/agent/hcp/config" "github.com/hashicorp/consul/agent/hcp/scada" + hcpctl "github.com/hashicorp/consul/internal/hcp" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/sdk/testutil" ) +func TestManager_MonitorHCPLink(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + logger := hclog.New(&hclog.LoggerOptions{Output: io.Discard}) + + mgr := NewManager( + ManagerConfig{ + Logger: hclog.New(&hclog.LoggerOptions{Output: io.Discard}), + }, + ) + mockHCPClient := hcpclient.NewMockClient(t) + mockHcpClientFn := func(_ config.CloudConfig) (hcpclient.Client, error) { + return mockHCPClient, nil + } + loadMgmtTokenFn := func(ctx context.Context, logger hclog.Logger, hcpClient hcpclient.Client, dataDir string) (string, error) { + return "test-mgmt-token", nil + } + + require.False(t, mgr.isRunning()) + updateManagerLifecycle := HCPManagerLifecycleFn( + mgr, mockHcpClientFn, + loadMgmtTokenFn, config.CloudConfig{}, "", + ) + + // Set up a link + link := pbhcp.Link{ + ResourceId: "abc", + ClientId: "def", + ClientSecret: "ghi", + AccessLevel: pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_WRITE, + } + linkResource, err := anypb.New(&link) + require.NoError(t, err) + updateManagerLifecycle(ctx, logger, &pbresource.WatchEvent{ + Event: &pbresource.WatchEvent_Upsert_{ + Upsert: &pbresource.WatchEvent_Upsert{ + Resource: &pbresource.Resource{ + Id: &pbresource.ID{ + Name: "global", + Type: pbhcp.LinkType, + }, + Status: map[string]*pbresource.Status{ + hcpctl.StatusKey: { + Conditions: []*pbresource.Condition{hcpctl.ConditionValidatedSuccess}, + }, + }, + Data: linkResource, + }, + }, + }, + }) + + // Validate that the HCP manager is started + require.True(t, mgr.isRunning()) +} + func TestManager_Start(t *testing.T) { client := hcpclient.NewMockClient(t) statusF := func(ctx context.Context) (hcpclient.ServerStatus, error) { diff --git a/go.mod b/go.mod index 1e436fb00cea0..28b77533c9c3e 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/go-jose/go-jose/v3 v3.0.3 github.com/go-openapi/runtime v0.26.2 github.com/go-openapi/strfmt v0.21.10 - github.com/google/go-cmp v0.6.0 + github.com/google/go-cmp v0.5.9 github.com/google/gofuzz v1.2.0 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 @@ -114,12 +114,12 @@ require ( go.opentelemetry.io/otel/sdk/metric v0.39.0 go.opentelemetry.io/proto/otlp v1.0.0 go.uber.org/goleak v1.1.10 - golang.org/x/crypto v0.31.0 + golang.org/x/crypto v0.22.0 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 - golang.org/x/net v0.25.0 + golang.org/x/net v0.24.0 golang.org/x/oauth2 v0.15.0 - golang.org/x/sync v0.10.0 - golang.org/x/sys v0.28.0 + golang.org/x/sync v0.4.0 + golang.org/x/sys v0.20.0 golang.org/x/time v0.3.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 google.golang.org/grpc v1.58.3 @@ -263,10 +263,10 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/trace v1.17.0 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/term v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.14.0 // indirect google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect diff --git a/go.sum b/go.sum index 26849a802d2a2..d8e67fa6af70e 100644 --- a/go.sum +++ b/go.sum @@ -348,9 +348,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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= @@ -921,8 +920,8 @@ golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -963,8 +962,8 @@ 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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1015,8 +1014,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1047,8 +1046,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ 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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -1128,15 +1127,15 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1149,9 +1148,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 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= @@ -1217,8 +1215,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= diff --git a/internal/hcp/exports.go b/internal/hcp/exports.go new file mode 100644 index 0000000000000..18ede30d27970 --- /dev/null +++ b/internal/hcp/exports.go @@ -0,0 +1,34 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package hcp + +import ( + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/controllers" + "github.com/hashicorp/consul/internal/hcp/internal/controllers/link" + "github.com/hashicorp/consul/internal/hcp/internal/types" + "github.com/hashicorp/consul/internal/resource" +) + +// RegisterTypes adds all resource types within the "hcp" API group +// to the given type registry +func RegisterTypes(r resource.Registry) { + types.Register(r) +} + +type ControllerDependencies = controllers.Dependencies + +var IsValidated = link.IsValidated +var LinkName = types.LinkName + +// RegisterControllers registers controllers for the catalog types with +// the given controller Manager. +func RegisterControllers(mgr *controller.Manager, deps ControllerDependencies) { + controllers.Register(mgr, deps) +} + +// Needed for testing +var StatusKey = link.StatusKey +var ConditionValidatedSuccess = link.ConditionValidatedSuccess +var ConditionValidatedFailed = link.ConditionValidatedFailed diff --git a/internal/hcp/internal/controllers/link/controller.go b/internal/hcp/internal/controllers/link/controller.go new file mode 100644 index 0000000000000..77c439f5cb4de --- /dev/null +++ b/internal/hcp/internal/controllers/link/controller.go @@ -0,0 +1,234 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package link + +import ( + "context" + "crypto/tls" + "strings" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/anypb" + + gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models" + + hcpclient "github.com/hashicorp/consul/agent/hcp/client" + "github.com/hashicorp/consul/agent/hcp/config" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/types" + "github.com/hashicorp/consul/internal/storage" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +// HCPClientFn is a function that can be used to create an HCP client from a Link object. +// This function type should be passed to a LinkController in order to tell it how to make a client from +// a Link. For normal use, DefaultHCPClientFn should be used, but tests can substitute in a function that creates a +// mock client. +type HCPClientFn func(config.CloudConfig) (hcpclient.Client, error) + +var DefaultHCPClientFn HCPClientFn = func(cfg config.CloudConfig) (hcpclient.Client, error) { + hcpClient, err := hcpclient.NewClient(cfg) + if err != nil { + return nil, err + } + return hcpClient, nil +} + +func LinkController( + hcpClientFn HCPClientFn, + cfg config.CloudConfig, +) *controller.Controller { + return controller.NewController("link", pbhcp.LinkType). + WithInitializer( + &linkInitializer{ + cloudConfig: cfg, + }, + ). + WithReconciler( + &linkReconciler{ + hcpClientFn: hcpClientFn, + cloudConfig: cfg, + }, + ) +} + +type linkReconciler struct { + hcpClientFn HCPClientFn + cloudConfig config.CloudConfig +} + +func hcpAccessLevelToConsul(level *gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevel) pbhcp.AccessLevel { + if level == nil { + return pbhcp.AccessLevel_ACCESS_LEVEL_UNSPECIFIED + } + + switch *level { + case gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELUNSPECIFIED: + return pbhcp.AccessLevel_ACCESS_LEVEL_UNSPECIFIED + case gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELGLOBALREADWRITE: + return pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_WRITE + case gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELGLOBALREADONLY: + return pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_ONLY + default: + return pbhcp.AccessLevel_ACCESS_LEVEL_UNSPECIFIED + } +} + +func (r *linkReconciler) Reconcile(ctx context.Context, rt controller.Runtime, req controller.Request) error { + // The runtime is passed by value so replacing it here for the remainder of this + // reconciliation request processing will not affect future invocations. + rt.Logger = rt.Logger.With("resource-id", req.ID, "controller", StatusKey) + + rt.Logger.Trace("reconciling link") + + rsp, err := rt.Client.Read(ctx, &pbresource.ReadRequest{Id: req.ID}) + switch { + case status.Code(err) == codes.NotFound: + rt.Logger.Trace("link has been deleted") + return nil + case err != nil: + rt.Logger.Error("the resource service has returned an unexpected error", "error", err) + return err + } + + res := rsp.Resource + var link pbhcp.Link + if err := res.Data.UnmarshalTo(&link); err != nil { + rt.Logger.Error("error unmarshalling link data", "error", err) + return err + } + + newStatus := &pbresource.Status{ + ObservedGeneration: res.Generation, + Conditions: []*pbresource.Condition{}, + } + defer writeStatusIfNotEqual(ctx, rt, res, newStatus) + newStatus.Conditions = append(newStatus.Conditions, ConditionValidatedSuccess) + + // Merge the link data with the existing cloud config so that we only overwrite the + // fields that are provided by the link. This ensures that: + // 1. The HCP configuration (i.e., how to connect to HCP) is preserved + // 2. The Consul agent's node ID and node name are preserved + newCfg := CloudConfigFromLink(&link) + cfg := config.Merge(r.cloudConfig, newCfg) + hcpClient, err := r.hcpClientFn(cfg) + if err != nil { + rt.Logger.Error("error creating HCP client", "error", err) + return err + } + + // Sync cluster data from HCP + cluster, err := hcpClient.GetCluster(ctx) + if err != nil { + rt.Logger.Error("error querying HCP for cluster", "error", err) + condition := linkingFailedCondition(err) + newStatus.Conditions = append(newStatus.Conditions, condition) + return err + } + accessLevel := hcpAccessLevelToConsul(cluster.AccessLevel) + + if link.HcpClusterUrl != cluster.HCPPortalURL || + link.AccessLevel != accessLevel { + + link.HcpClusterUrl = cluster.HCPPortalURL + link.AccessLevel = accessLevel + + updatedData, err := anypb.New(&link) + if err != nil { + rt.Logger.Error("error marshalling link data", "error", err) + return err + } + _, err = rt.Client.Write( + ctx, &pbresource.WriteRequest{Resource: &pbresource.Resource{ + Id: &pbresource.ID{ + Name: types.LinkName, + Type: pbhcp.LinkType, + }, + Metadata: res.Metadata, + Data: updatedData, + }}, + ) + if err != nil { + rt.Logger.Error("error updating link", "error", err) + return err + } + } + + newStatus.Conditions = append(newStatus.Conditions, ConditionLinked(link.ResourceId)) + + return writeStatusIfNotEqual(ctx, rt, res, newStatus) +} + +type linkInitializer struct { + cloudConfig config.CloudConfig +} + +func (i *linkInitializer) Initialize(ctx context.Context, rt controller.Runtime) error { + if !i.cloudConfig.IsConfigured() { + return nil + } + + // Construct a link resource to reflect the configuration + data, err := anypb.New( + &pbhcp.Link{ + ResourceId: i.cloudConfig.ResourceID, + ClientId: i.cloudConfig.ClientID, + ClientSecret: i.cloudConfig.ClientSecret, + }, + ) + if err != nil { + return err + } + + // Create the link resource for a configuration-based link + _, err = rt.Client.Write( + ctx, + &pbresource.WriteRequest{ + Resource: &pbresource.Resource{ + Id: &pbresource.ID{ + Name: types.LinkName, + Type: pbhcp.LinkType, + }, + Metadata: map[string]string{ + types.MetadataSourceKey: types.MetadataSourceConfig, + }, + Data: data, + }, + }, + ) + if err != nil { + if strings.Contains(err.Error(), storage.ErrWrongUid.Error()) || + strings.Contains(err.Error(), "leader unknown") { + // If the error is likely ignorable and could eventually resolve itself, + // log it as TRACE rather than ERROR. + rt.Logger.Trace("error initializing controller", "error", err) + } else { + rt.Logger.Error("error initializing controller", "error", err) + } + return err + } + + return nil +} + +func CloudConfigFromLink(link *pbhcp.Link) config.CloudConfig { + var cfg config.CloudConfig + if link == nil { + return cfg + } + cfg = config.CloudConfig{ + ResourceID: link.GetResourceId(), + ClientID: link.GetClientId(), + ClientSecret: link.GetClientSecret(), + } + if link.GetHcpConfig() != nil { + cfg.AuthURL = link.GetHcpConfig().GetAuthUrl() + cfg.ScadaAddress = link.GetHcpConfig().GetScadaAddress() + cfg.Hostname = link.GetHcpConfig().GetApiAddress() + cfg.TLSConfig = &tls.Config{InsecureSkipVerify: link.GetHcpConfig().GetTlsInsecureSkipVerify()} + } + return cfg +} diff --git a/internal/hcp/internal/controllers/link/controller_test.go b/internal/hcp/internal/controllers/link/controller_test.go new file mode 100644 index 0000000000000..fc23c3c627bac --- /dev/null +++ b/internal/hcp/internal/controllers/link/controller_test.go @@ -0,0 +1,248 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package link + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + gnmmod "github.com/hashicorp/hcp-sdk-go/clients/cloud-global-network-manager-service/preview/2022-02-15/models" + + svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" + hcpclient "github.com/hashicorp/consul/agent/hcp/client" + "github.com/hashicorp/consul/agent/hcp/config" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/types" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/sdk/testutil" +) + +type controllerSuite struct { + suite.Suite + + ctx context.Context + client *rtest.Client + rt controller.Runtime + + tenancies []*pbresource.Tenancy +} + +func mockHcpClientFn(t *testing.T) (*hcpclient.MockClient, HCPClientFn) { + mockClient := hcpclient.NewMockClient(t) + + mockClientFunc := func(config config.CloudConfig) (hcpclient.Client, error) { + return mockClient, nil + } + + return mockClient, mockClientFunc +} + +func (suite *controllerSuite) SetupTest() { + suite.ctx = testutil.TestContext(suite.T()) + suite.tenancies = rtest.TestTenancies() + client := svctest.NewResourceServiceBuilder(). + WithRegisterFns(types.Register). + WithTenancies(suite.tenancies...). + Run(suite.T()) + + suite.rt = controller.Runtime{ + Client: client, + Logger: testutil.Logger(suite.T()), + } + suite.client = rtest.NewClient(client) +} + +func TestLinkController(t *testing.T) { + suite.Run(t, new(controllerSuite)) +} + +func (suite *controllerSuite) deleteResourceFunc(id *pbresource.ID) func() { + return func() { + suite.client.MustDelete(suite.T(), id) + suite.client.WaitForDeletion(suite.T(), id) + } +} + +func (suite *controllerSuite) TestController_Ok() { + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mockClient, mockClientFn := mockHcpClientFn(suite.T()) + readWrite := gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELGLOBALREADWRITE + mockClient.EXPECT().GetCluster(mock.Anything).Return(&hcpclient.Cluster{ + HCPPortalURL: "http://test.com", + AccessLevel: &readWrite, + }, nil) + + mgr.Register(LinkController( + mockClientFn, + config.CloudConfig{}, + )) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + linkData := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: types.GenerateTestResourceID(suite.T()), + } + + link := rtest.Resource(pbhcp.LinkType, "global"). + WithData(suite.T(), linkData). + Write(suite.T(), suite.client) + + suite.T().Cleanup(suite.deleteResourceFunc(link.Id)) + + suite.client.WaitForStatusCondition(suite.T(), link.Id, StatusKey, ConditionLinked(linkData.ResourceId)) + var updatedLink pbhcp.Link + updatedLinkResource := suite.client.WaitForNewVersion(suite.T(), link.Id, link.Version) + require.NoError(suite.T(), updatedLinkResource.Data.UnmarshalTo(&updatedLink)) + require.Equal(suite.T(), "http://test.com", updatedLink.HcpClusterUrl) + require.Equal(suite.T(), pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_WRITE, updatedLink.AccessLevel) +} + +func (suite *controllerSuite) TestController_Initialize() { + // Run the controller manager with a configured link + mgr := controller.NewManager(suite.client, suite.rt.Logger) + + mockClient, mockClientFn := mockHcpClientFn(suite.T()) + readOnly := gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELGLOBALREADONLY + mockClient.EXPECT().GetCluster(mock.Anything).Return(&hcpclient.Cluster{ + HCPPortalURL: "http://test.com", + AccessLevel: &readOnly, + }, nil) + + cloudCfg := config.CloudConfig{ + ClientID: "client-id-abc", + ClientSecret: "client-secret-abc", + ResourceID: types.GenerateTestResourceID(suite.T()), + } + + mgr.Register(LinkController( + mockClientFn, + cloudCfg, + )) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + // Wait for link to be created by initializer + id := &pbresource.ID{ + Type: pbhcp.LinkType, + Name: types.LinkName, + } + suite.T().Cleanup(suite.deleteResourceFunc(id)) + r := suite.client.WaitForResourceExists(suite.T(), id) + + // Check that created link has expected values + var link pbhcp.Link + err := r.Data.UnmarshalTo(&link) + require.NoError(suite.T(), err) + + require.Equal(suite.T(), cloudCfg.ResourceID, link.ResourceId) + require.Equal(suite.T(), cloudCfg.ClientID, link.ClientId) + require.Equal(suite.T(), cloudCfg.ClientSecret, link.ClientSecret) + require.Equal(suite.T(), types.MetadataSourceConfig, r.Metadata[types.MetadataSourceKey]) + + // Wait for link to be connected successfully + suite.client.WaitForStatusCondition(suite.T(), id, StatusKey, ConditionLinked(link.ResourceId)) +} + +func (suite *controllerSuite) TestController_GetClusterError() { + type testCase struct { + expectErr error + expectCondition *pbresource.Condition + } + tt := map[string]testCase{ + "unexpected": { + expectErr: fmt.Errorf("error"), + expectCondition: ConditionFailed, + }, + "unauthorized": { + expectErr: hcpclient.ErrUnauthorized, + expectCondition: ConditionUnauthorized, + }, + "forbidden": { + expectErr: hcpclient.ErrForbidden, + expectCondition: ConditionForbidden, + }, + } + + for name, tc := range tt { + suite.T().Run(name, func(t *testing.T) { + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mockClient, mockClientFunc := mockHcpClientFn(t) + mockClient.EXPECT().GetCluster(mock.Anything).Return(nil, tc.expectErr) + + mgr.Register(LinkController( + mockClientFunc, + config.CloudConfig{}, + )) + + mgr.SetRaftLeader(true) + ctx, cancel := context.WithCancel(suite.ctx) + t.Cleanup(cancel) + go mgr.Run(ctx) + + linkData := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: types.GenerateTestResourceID(t), + } + link := rtest.Resource(pbhcp.LinkType, "global"). + WithData(t, linkData). + Write(t, suite.client) + + t.Cleanup(suite.deleteResourceFunc(link.Id)) + + suite.client.WaitForStatusCondition(t, link.Id, StatusKey, tc.expectCondition) + }) + } +} + +func Test_hcpAccessModeToConsul(t *testing.T) { + type testCase struct { + hcpAccessLevel *gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevel + consulAccessLevel pbhcp.AccessLevel + } + tt := map[string]testCase{ + "unspecified": { + hcpAccessLevel: func() *gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevel { + t := gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELUNSPECIFIED + return &t + }(), + consulAccessLevel: pbhcp.AccessLevel_ACCESS_LEVEL_UNSPECIFIED, + }, + "invalid": { + hcpAccessLevel: nil, + consulAccessLevel: pbhcp.AccessLevel_ACCESS_LEVEL_UNSPECIFIED, + }, + "read_only": { + hcpAccessLevel: func() *gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevel { + t := gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELGLOBALREADONLY + return &t + }(), + consulAccessLevel: pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_ONLY, + }, + "read_write": { + hcpAccessLevel: func() *gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevel { + t := gnmmod.HashicorpCloudGlobalNetworkManager20220215ClusterConsulAccessLevelCONSULACCESSLEVELGLOBALREADWRITE + return &t + }(), + consulAccessLevel: pbhcp.AccessLevel_ACCESS_LEVEL_GLOBAL_READ_WRITE, + }, + } + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + accessLevel := hcpAccessLevelToConsul(tc.hcpAccessLevel) + require.Equal(t, tc.consulAccessLevel, accessLevel) + }) + } +} diff --git a/internal/hcp/internal/controllers/link/status.go b/internal/hcp/internal/controllers/link/status.go new file mode 100644 index 0000000000000..88210c4a4997b --- /dev/null +++ b/internal/hcp/internal/controllers/link/status.go @@ -0,0 +1,142 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package link + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/consul/agent/hcp/client" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/resource" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +const ( + StatusKey = "consul.io/hcp/link" + + // Statuses + StatusLinked = "linked" + StatusValidated = "validated" + + LinkedSuccessReason = "SUCCESS" + LinkedFailedReason = "FAILED" + LinkedDisabledReasonV2ResourcesUnsupportedReason = "DISABLED_V2_RESOURCES_UNSUPPORTED" + LinkedUnauthorizedReason = "UNAUTHORIZED" + LinkedForbiddenReason = "FORBIDDEN" + ValidatedSuccessReason = "SUCCESS" + ValidatedFailedV2ResourcesReason = "V2_RESOURCES_UNSUPPORTED" + + LinkedMessageFormat = "Successfully linked to cluster '%s'" + FailedMessage = "Failed to link to HCP due to unexpected error" + DisabledResourceAPIsEnabledMessage = "Link is disabled because resource-apis are enabled" + UnauthorizedMessage = "Access denied, check client_id and client_secret" + ForbiddenMessage = "Access denied, check the resource_id" + ValidatedSuccessMessage = "Successfully validated link" + ValidatedFailedV2ResourcesMessage = "Link is disabled because resource-apis are enabled" +) + +var ( + ConditionDisabled = &pbresource.Condition{ + Type: StatusLinked, + State: pbresource.Condition_STATE_FALSE, + Reason: LinkedDisabledReasonV2ResourcesUnsupportedReason, + Message: DisabledResourceAPIsEnabledMessage, + } + ConditionFailed = &pbresource.Condition{ + Type: StatusLinked, + State: pbresource.Condition_STATE_FALSE, + Reason: LinkedFailedReason, + Message: FailedMessage, + } + ConditionUnauthorized = &pbresource.Condition{ + Type: StatusLinked, + State: pbresource.Condition_STATE_FALSE, + Reason: LinkedUnauthorizedReason, + Message: UnauthorizedMessage, + } + ConditionForbidden = &pbresource.Condition{ + Type: StatusLinked, + State: pbresource.Condition_STATE_FALSE, + Reason: LinkedForbiddenReason, + Message: ForbiddenMessage, + } + ConditionValidatedSuccess = &pbresource.Condition{ + Type: StatusValidated, + State: pbresource.Condition_STATE_TRUE, + Reason: ValidatedSuccessReason, + Message: ValidatedSuccessMessage, + } + ConditionValidatedFailed = &pbresource.Condition{ + Type: StatusValidated, + State: pbresource.Condition_STATE_FALSE, + Reason: ValidatedFailedV2ResourcesReason, + Message: ValidatedFailedV2ResourcesMessage, + } +) + +func ConditionLinked(resourceId string) *pbresource.Condition { + return &pbresource.Condition{ + Type: StatusLinked, + State: pbresource.Condition_STATE_TRUE, + Reason: LinkedSuccessReason, + Message: fmt.Sprintf(LinkedMessageFormat, resourceId), + } +} + +func writeStatusIfNotEqual(ctx context.Context, rt controller.Runtime, res *pbresource.Resource, status *pbresource.Status) error { + if resource.EqualStatus(res.Status[StatusKey], status, false) { + return nil + } + _, err := rt.Client.WriteStatus( + ctx, &pbresource.WriteStatusRequest{ + Id: res.Id, + Key: StatusKey, + Status: status, + }, + ) + if err != nil { + rt.Logger.Error("error writing link status", "error", err) + } + return err +} + +func linkingFailedCondition(err error) *pbresource.Condition { + switch { + case errors.Is(err, client.ErrUnauthorized): + return ConditionUnauthorized + case errors.Is(err, client.ErrForbidden): + return ConditionForbidden + default: + return ConditionFailed + } +} + +func IsLinked(res *pbresource.Resource) (linked bool, reason string) { + return isConditionTrue(res, StatusLinked) +} + +func IsValidated(res *pbresource.Resource) (linked bool, reason string) { + return isConditionTrue(res, StatusValidated) +} + +func isConditionTrue(res *pbresource.Resource, statusType string) (bool, string) { + if !resource.EqualType(res.GetId().GetType(), pbhcp.LinkType) { + return false, "resource is not hcp.Link type" + } + + linkStatus, ok := res.GetStatus()[StatusKey] + if !ok { + return false, "link status not set" + } + + for _, cond := range linkStatus.GetConditions() { + if cond.Type == statusType && cond.GetState() == pbresource.Condition_STATE_TRUE { + return true, "" + } + } + return false, fmt.Sprintf("link status does not include positive %s condition", statusType) +} diff --git a/internal/hcp/internal/controllers/register.go b/internal/hcp/internal/controllers/register.go new file mode 100644 index 0000000000000..05203f525cb62 --- /dev/null +++ b/internal/hcp/internal/controllers/register.go @@ -0,0 +1,26 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package controllers + +import ( + "github.com/hashicorp/consul/agent/hcp/config" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/controllers/link" + "github.com/hashicorp/consul/internal/hcp/internal/controllers/telemetrystate" +) + +type Dependencies struct { + CloudConfig config.CloudConfig +} + +func Register(mgr *controller.Manager, deps Dependencies) { + mgr.Register( + link.LinkController( + link.DefaultHCPClientFn, + deps.CloudConfig, + ), + ) + + mgr.Register(telemetrystate.TelemetryStateController(link.DefaultHCPClientFn)) +} diff --git a/internal/hcp/internal/controllers/telemetrystate/controller.go b/internal/hcp/internal/controllers/telemetrystate/controller.go new file mode 100644 index 0000000000000..e21c85685ed86 --- /dev/null +++ b/internal/hcp/internal/controllers/telemetrystate/controller.go @@ -0,0 +1,203 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package telemetrystate + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/controller/dependency" + "github.com/hashicorp/consul/internal/hcp/internal/controllers/link" + "github.com/hashicorp/consul/internal/hcp/internal/types" + "github.com/hashicorp/consul/internal/resource" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +var ( + globalID = &pbresource.ID{ + Name: "global", + Type: pbhcp.TelemetryStateType, + Tenancy: &pbresource.Tenancy{}, + } +) + +const MetaKeyDebugSkipDeletion = StatusKey + "/debug/skip-deletion" + +func TelemetryStateController(hcpClientFn link.HCPClientFn) *controller.Controller { + return controller.NewController(StatusKey, pbhcp.TelemetryStateType). + WithWatch(pbhcp.LinkType, dependency.ReplaceType(pbhcp.TelemetryStateType)). + WithReconciler(&telemetryStateReconciler{ + hcpClientFn: hcpClientFn, + }) +} + +type telemetryStateReconciler struct { + hcpClientFn link.HCPClientFn +} + +func (r *telemetryStateReconciler) Reconcile(ctx context.Context, rt controller.Runtime, req controller.Request) error { + // The runtime is passed by value so replacing it here for the remainder of this + // reconciliation request processing will not affect future invocations. + rt.Logger = rt.Logger.With("resource-id", req.ID, "controller", StatusKey) + + rt.Logger.Trace("reconciling telemetry-state") + + // First get the link resource in order to build a hcp client. If the link resource + // doesn't exist then the telemetry-state should not exist either. + res, err := getLinkResource(ctx, rt) + if err != nil { + rt.Logger.Error("failed to lookup Link resource", "error", err) + return err + } + if res == nil { + return ensureTelemetryStateDeleted(ctx, rt) + } + + // Check that the link resource indicates the cluster is linked + // If the cluster is not linked, the telemetry-state resource should not exist + if linked, reason := link.IsLinked(res.GetResource()); !linked { + rt.Logger.Trace("cluster is not linked", "reason", reason) + return ensureTelemetryStateDeleted(ctx, rt) + } + + hcpClient, err := r.hcpClientFn(link.CloudConfigFromLink(res.GetData())) + if err != nil { + rt.Logger.Error("error creating HCP Client", "error", err) + return err + } + + // Get the telemetry configuration and observability scoped credentials from hcp + tCfg, err := hcpClient.FetchTelemetryConfig(ctx) + if err != nil { + rt.Logger.Error("error requesting telemetry config", "error", err) + return err + } + clientID, clientSecret, err := hcpClient.GetObservabilitySecret(ctx) + if err != nil { + rt.Logger.Error("error requesting telemetry credentials", "error", err) + return nil + } + + // TODO allow hcp client config override from hcp TelemetryConfig + hcpCfg := res.GetData().GetHcpConfig() + + // TODO implement proxy options from hcp + proxyCfg := &pbhcp.ProxyConfig{} + + state := &pbhcp.TelemetryState{ + ResourceId: res.GetData().ResourceId, + ClientId: clientID, + ClientSecret: clientSecret, + HcpConfig: hcpCfg, + Proxy: proxyCfg, + Metrics: &pbhcp.MetricsConfig{ + Labels: tCfg.MetricsConfig.Labels, + Disabled: tCfg.MetricsConfig.Disabled, + }, + } + + if tCfg.MetricsConfig.Endpoint != nil { + state.Metrics.Endpoint = tCfg.MetricsConfig.Endpoint.String() + } + if tCfg.MetricsConfig.Filters != nil { + state.Metrics.IncludeList = []string{tCfg.MetricsConfig.Filters.String()} + } + + if err := writeTelemetryStateIfUpdated(ctx, rt, state); err != nil { + rt.Logger.Error("error updating telemetry-state", "error", err) + return err + } + + return nil +} + +func ensureTelemetryStateDeleted(ctx context.Context, rt controller.Runtime) error { + resp, err := rt.Client.Read(ctx, &pbresource.ReadRequest{Id: &pbresource.ID{Name: "global", Type: pbhcp.TelemetryStateType}}) + switch { + case status.Code(err) == codes.NotFound: + return nil + case err != nil: + rt.Logger.Error("the resource service has returned an unexpected error", "error", err) + return err + } + + rt.Logger.Trace("deleting telemetry-state") + if _, ok := resp.GetResource().Metadata[MetaKeyDebugSkipDeletion]; ok { + rt.Logger.Debug("skip-deletion metadata key found, skipping deletion of telemetry-state resource") + return nil + } + + if _, err := rt.Client.Delete(ctx, &pbresource.DeleteRequest{Id: resp.GetResource().GetId()}); err != nil { + rt.Logger.Error("error deleting telemetry-state resource", "error", err) + return err + } + return nil +} + +func writeTelemetryStateIfUpdated(ctx context.Context, rt controller.Runtime, state *pbhcp.TelemetryState) error { + currentState, err := getTelemetryStateResource(ctx, rt) + if err != nil { + return err + } + + if currentState != nil && proto.Equal(currentState.GetData(), state) { + return nil + } + + stateData, err := anypb.New(state) + if err != nil { + return err + } + + _, err = rt.Client.Write(ctx, &pbresource.WriteRequest{Resource: &pbresource.Resource{ + Id: &pbresource.ID{ + Name: "global", + Type: pbhcp.TelemetryStateType, + }, + Data: stateData, + }}) + return err +} + +func getGlobalResource(ctx context.Context, rt controller.Runtime, t *pbresource.Type) (*pbresource.Resource, error) { + resp, err := rt.Client.Read(ctx, &pbresource.ReadRequest{Id: &pbresource.ID{Name: "global", Type: t}}) + switch { + case status.Code(err) == codes.NotFound: + return nil, nil + case err != nil: + return nil, err + } + + return resp.GetResource(), nil +} + +// getLinkResource returns the cluster scoped pbhcp.Link resource. If the resource is not found a nil +// pointer and no error will be returned. +func getLinkResource(ctx context.Context, rt controller.Runtime) (*types.DecodedLink, error) { + res, err := getGlobalResource(ctx, rt, pbhcp.LinkType) + if err != nil { + return nil, err + } + if res == nil { + return nil, nil + } + return resource.Decode[*pbhcp.Link](res) +} + +func getTelemetryStateResource(ctx context.Context, rt controller.Runtime) (*types.DecodedTelemetryState, error) { + res, err := getGlobalResource(ctx, rt, pbhcp.TelemetryStateType) + if err != nil { + return nil, err + } + if res == nil { + return nil, nil + } + return resource.Decode[*pbhcp.TelemetryState](res) +} diff --git a/internal/hcp/internal/controllers/telemetrystate/controller_test.go b/internal/hcp/internal/controllers/telemetrystate/controller_test.go new file mode 100644 index 0000000000000..e11c1e30638fb --- /dev/null +++ b/internal/hcp/internal/controllers/telemetrystate/controller_test.go @@ -0,0 +1,174 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package telemetrystate + +import ( + "context" + "net/url" + "regexp" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" + hcpclient "github.com/hashicorp/consul/agent/hcp/client" + "github.com/hashicorp/consul/agent/hcp/config" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/controllers/link" + "github.com/hashicorp/consul/internal/hcp/internal/types" + "github.com/hashicorp/consul/internal/resource" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/sdk/testutil" +) + +type controllerSuite struct { + suite.Suite + + ctx context.Context + client *rtest.Client + rt controller.Runtime + + ctl *controller.TestController + tenancies []*pbresource.Tenancy + + hcpMock *hcpclient.MockClient +} + +func mockHcpClientFn(t *testing.T) (*hcpclient.MockClient, link.HCPClientFn) { + mockClient := hcpclient.NewMockClient(t) + + mockClientFunc := func(link config.CloudConfig) (hcpclient.Client, error) { + return mockClient, nil + } + + return mockClient, mockClientFunc +} + +func (suite *controllerSuite) SetupTest() { + suite.ctx = testutil.TestContext(suite.T()) + suite.tenancies = rtest.TestTenancies() + client := svctest.NewResourceServiceBuilder(). + WithRegisterFns(types.Register). + WithTenancies(suite.tenancies...). + Run(suite.T()) + + hcpMock, hcpClientFn := mockHcpClientFn(suite.T()) + suite.hcpMock = hcpMock + suite.ctl = controller.NewTestController(TelemetryStateController(hcpClientFn), client). + WithLogger(testutil.Logger(suite.T())) + + suite.rt = suite.ctl.Runtime() + suite.client = rtest.NewClient(client) +} + +func TestTelemetryStateController(t *testing.T) { + suite.Run(t, new(controllerSuite)) +} + +func (suite *controllerSuite) deleteResourceFunc(id *pbresource.ID) func() { + return func() { + suite.client.MustDelete(suite.T(), id) + } +} + +func (suite *controllerSuite) TestController_Ok() { + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mockClient, mockClientFn := mockHcpClientFn(suite.T()) + mockClient.EXPECT().FetchTelemetryConfig(mock.Anything).Return(&hcpclient.TelemetryConfig{ + MetricsConfig: &hcpclient.MetricsConfig{ + Endpoint: &url.URL{ + Scheme: "http", + Host: "localhost", + Path: "/test", + }, + Labels: map[string]string{"foo": "bar"}, + Filters: regexp.MustCompile(".*"), + }, + RefreshConfig: &hcpclient.RefreshConfig{}, + }, nil) + mockClient.EXPECT().GetObservabilitySecret(mock.Anything).Return("xxx", "yyy", nil) + mgr.Register(TelemetryStateController(mockClientFn)) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + link := suite.writeLinkResource() + + tsRes := suite.client.WaitForResourceExists(suite.T(), &pbresource.ID{Name: "global", Type: pbhcp.TelemetryStateType}) + decodedState, err := resource.Decode[*pbhcp.TelemetryState](tsRes) + require.NoError(suite.T(), err) + require.Equal(suite.T(), link.GetData().GetResourceId(), decodedState.GetData().ResourceId) + require.Equal(suite.T(), "xxx", decodedState.GetData().ClientId) + require.Equal(suite.T(), "http://localhost/test", decodedState.GetData().Metrics.Endpoint) + + suite.client.MustDelete(suite.T(), link.Id) + suite.client.WaitForDeletion(suite.T(), tsRes.Id) +} + +func (suite *controllerSuite) TestReconcile_AvoidReconciliationWriteLoop() { + suite.hcpMock.EXPECT().FetchTelemetryConfig(mock.Anything).Return(&hcpclient.TelemetryConfig{ + MetricsConfig: &hcpclient.MetricsConfig{ + Endpoint: &url.URL{ + Scheme: "http", + Host: "localhost", + Path: "/test", + }, + Labels: map[string]string{"foo": "bar"}, + Filters: regexp.MustCompile(".*"), + }, + RefreshConfig: &hcpclient.RefreshConfig{}, + }, nil) + link := suite.writeLinkResource() + suite.hcpMock.EXPECT().GetObservabilitySecret(mock.Anything).Return("xxx", "yyy", nil) + suite.NoError(suite.ctl.Reconcile(context.Background(), controller.Request{ID: link.Id})) + tsRes := suite.client.WaitForResourceExists(suite.T(), &pbresource.ID{Name: "global", Type: pbhcp.TelemetryStateType}) + suite.NoError(suite.ctl.Reconcile(context.Background(), controller.Request{ID: tsRes.Id})) + suite.client.RequireVersionUnchanged(suite.T(), tsRes.Id, tsRes.Version) +} + +func (suite *controllerSuite) TestController_LinkingDisabled() { + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + _, mockClientFn := mockHcpClientFn(suite.T()) + mgr.Register(TelemetryStateController(mockClientFn)) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + linkData := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: types.GenerateTestResourceID(suite.T()), + } + + rtest.Resource(pbhcp.LinkType, "global"). + WithData(suite.T(), linkData). + WithStatus(link.StatusKey, &pbresource.Status{Conditions: []*pbresource.Condition{link.ConditionDisabled}}). + Write(suite.T(), suite.client) + + suite.client.WaitForDeletion(suite.T(), &pbresource.ID{Name: "global", Type: pbhcp.TelemetryStateType}) +} + +func (suite *controllerSuite) writeLinkResource() *types.DecodedLink { + suite.T().Helper() + + linkData := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: types.GenerateTestResourceID(suite.T()), + } + + res := rtest.Resource(pbhcp.LinkType, "global"). + WithData(suite.T(), linkData). + WithStatus(link.StatusKey, &pbresource.Status{Conditions: []*pbresource.Condition{link.ConditionLinked(linkData.ResourceId)}}). + Write(suite.T(), suite.client) + + suite.T().Cleanup(suite.deleteResourceFunc(res.Id)) + link, err := resource.Decode[*pbhcp.Link](res) + require.NoError(suite.T(), err) + return link +} diff --git a/internal/hcp/internal/controllers/telemetrystate/status.go b/internal/hcp/internal/controllers/telemetrystate/status.go new file mode 100644 index 0000000000000..d68873b6d91b5 --- /dev/null +++ b/internal/hcp/internal/controllers/telemetrystate/status.go @@ -0,0 +1,8 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package telemetrystate + +const ( + StatusKey = "consul.io/hcp/telemetry-state" +) diff --git a/internal/hcp/internal/types/link.go b/internal/hcp/internal/types/link.go new file mode 100644 index 0000000000000..111f58a85899f --- /dev/null +++ b/internal/hcp/internal/types/link.go @@ -0,0 +1,117 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import ( + "errors" + + "github.com/hashicorp/go-multierror" + hcpresource "github.com/hashicorp/hcp-sdk-go/resource" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/internal/resource" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +type DecodedLink = resource.DecodedResource[*pbhcp.Link] + +const ( + LinkName = "global" + MetadataSourceKey = "source" + MetadataSourceConfig = "config" +) + +var ( + errLinkConfigurationName = errors.New("only a single Link resource is allowed and it must be named global") + errInvalidHCPResourceID = errors.New("could not parse, invalid format") +) + +func RegisterLink(r resource.Registry) { + r.Register(resource.Registration{ + Type: pbhcp.LinkType, + Proto: &pbhcp.Link{}, + Scope: resource.ScopeCluster, + Validate: ValidateLink, + ACLs: &resource.ACLHooks{ + Read: aclReadHookLink, + Write: aclWriteHookLink, + List: aclListHookLink, + }, + }) +} + +func aclReadHookLink(authorizer acl.Authorizer, authzContext *acl.AuthorizerContext, _ *pbresource.ID, _ *pbresource.Resource) error { + err := authorizer.ToAllowAuthorizer().OperatorReadAllowed(authzContext) + if err != nil { + return err + } + return nil +} + +func aclWriteHookLink(authorizer acl.Authorizer, authzContext *acl.AuthorizerContext, _ *pbresource.Resource) error { + err := authorizer.ToAllowAuthorizer().OperatorWriteAllowed(authzContext) + if err != nil { + return err + } + + err = authorizer.ToAllowAuthorizer().ACLWriteAllowed(authzContext) + if err != nil { + return err + } + + return nil +} + +func aclListHookLink(authorizer acl.Authorizer, authzContext *acl.AuthorizerContext) error { + err := authorizer.ToAllowAuthorizer().OperatorReadAllowed(authzContext) + if err != nil { + return err + } + return nil +} + +var ValidateLink = resource.DecodeAndValidate(validateLink) + +func validateLink(res *DecodedLink) error { + var err error + + if res.Id.Name != LinkName { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "name", + Wrapped: errLinkConfigurationName, + }) + } + + if res.Data.ClientId == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "client_id", + Wrapped: resource.ErrMissing, + }) + } + + if res.Data.ClientSecret == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "client_secret", + Wrapped: resource.ErrMissing, + }) + } + + if res.Data.ResourceId == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "resource_id", + Wrapped: resource.ErrMissing, + }) + } else { + _, parseErr := hcpresource.FromString(res.Data.ResourceId) + if parseErr != nil { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "resource_id", + Wrapped: errInvalidHCPResourceID, + }) + } + } + + return err +} diff --git a/internal/hcp/internal/types/link_test.go b/internal/hcp/internal/types/link_test.go new file mode 100644 index 0000000000000..2de25091d276c --- /dev/null +++ b/internal/hcp/internal/types/link_test.go @@ -0,0 +1,205 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/hashicorp/consul/internal/resource" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +func createCloudLinkResource(t *testing.T, data protoreflect.ProtoMessage) *pbresource.Resource { + res := &pbresource.Resource{ + Id: &pbresource.ID{ + Type: pbhcp.LinkType, + Name: "global", + }, + } + + var err error + res.Data, err = anypb.New(data) + require.NoError(t, err) + return res +} + +func TestValidateLink_Ok(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: GenerateTestResourceID(t), + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + require.NoError(t, err) +} + +func TestValidateLink_ParseError(t *testing.T) { + // Any type other than the Link type would work + // to cause the error we are expecting + data := &pbresource.Type{Group: "a", GroupVersion: "b", Kind: "c"} + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + require.Error(t, err) + require.ErrorAs(t, err, &resource.ErrDataParse{}) +} + +func TestValidateLink_InvalidName(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: GenerateTestResourceID(t), + } + + res := createCloudLinkResource(t, data) + res.Id.Name = "default" + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "name", + Wrapped: errLinkConfigurationName, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +func TestValidateLink_MissingClientId(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "", + ClientSecret: "abc", + ResourceId: GenerateTestResourceID(t), + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "client_id", + Wrapped: resource.ErrMissing, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +func TestValidateLink_MissingClientSecret(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "", + ResourceId: GenerateTestResourceID(t), + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "client_secret", + Wrapped: resource.ErrMissing, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +func TestValidateLink_MissingResourceId(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "", + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "resource_id", + Wrapped: resource.ErrMissing, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +func TestValidateLink_InvalidResourceId(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "abc", + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "resource_id", + Wrapped: errInvalidHCPResourceID, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +// Currently, we have no specific ACLs configured so the default `operator` permissions are required +func TestLinkACLs(t *testing.T) { + registry := resource.NewRegistry() + RegisterLink(registry) + + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: GenerateTestResourceID(t), + } + link := createCloudLinkResource(t, data) + + cases := map[string]rtest.ACLTestCase{ + "no rules": { + Rules: ``, + Res: link, + ReadOK: rtest.DENY, + WriteOK: rtest.DENY, + ListOK: rtest.DENY, + }, + "link test read and list": { + Rules: `{"operator": "read"}`, + Res: link, + ReadOK: rtest.ALLOW, + WriteOK: rtest.DENY, + ListOK: rtest.ALLOW, + }, + "link test write": { + Rules: `{"operator": "write", "acl": "write"}`, + Res: link, + ReadOK: rtest.ALLOW, + WriteOK: rtest.ALLOW, + ListOK: rtest.ALLOW, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + rtest.RunACLTestCase(t, tc, registry) + }) + } +} diff --git a/internal/hcp/internal/types/telemetry_state.go b/internal/hcp/internal/types/telemetry_state.go new file mode 100644 index 0000000000000..7c6b3971cf1ec --- /dev/null +++ b/internal/hcp/internal/types/telemetry_state.go @@ -0,0 +1,85 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import ( + "errors" + + "github.com/hashicorp/go-multierror" + + "github.com/hashicorp/consul/internal/resource" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" +) + +type DecodedTelemetryState = resource.DecodedResource[*pbhcp.TelemetryState] + +var ( + telemetryStateConfigurationNameError = errors.New("only a single Telemetry resource is allowed and it must be named global") +) + +func RegisterTelemetryState(r resource.Registry) { + r.Register(resource.Registration{ + Type: pbhcp.TelemetryStateType, + Proto: &pbhcp.TelemetryState{}, + Scope: resource.ScopeCluster, + Validate: ValidateTelemetryState, + }) +} + +var ValidateTelemetryState = resource.DecodeAndValidate(validateTelemetryState) + +func validateTelemetryState(res *DecodedTelemetryState) error { + var err error + + if res.GetId().GetName() != "global" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "name", + Wrapped: telemetryStateConfigurationNameError, + }) + } + + if res.GetData().GetClientId() == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "client_id", + Wrapped: resource.ErrMissing, + }) + } + + if res.GetData().GetClientSecret() == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "client_secret", + Wrapped: resource.ErrMissing, + }) + } + + if res.GetData().GetResourceId() == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "resource_id", + Wrapped: resource.ErrMissing, + }) + } + + if res.GetData().GetMetrics().GetEndpoint() == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "metrics.endpoint", + Wrapped: resource.ErrMissing, + }) + } + + if res.GetData().GetMetrics().GetIncludeList() == nil { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "metrics.include_list", + Wrapped: resource.ErrMissing, + }) + } + + if res.GetData().GetMetrics().GetLabels() == nil { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "metrics.labels", + Wrapped: resource.ErrMissing, + }) + } + + return err +} diff --git a/internal/hcp/internal/types/testing.go b/internal/hcp/internal/types/testing.go new file mode 100644 index 0000000000000..420f79e920efd --- /dev/null +++ b/internal/hcp/internal/types/testing.go @@ -0,0 +1,23 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import ( + "fmt" + "testing" + + "github.com/hashicorp/go-uuid" + "github.com/stretchr/testify/require" +) + +func GenerateTestResourceID(t *testing.T) string { + orgID, err := uuid.GenerateUUID() + require.NoError(t, err) + + projectID, err := uuid.GenerateUUID() + require.NoError(t, err) + + template := "organization/%s/project/%s/hashicorp.consul.global-network-manager.cluster/test-cluster" + return fmt.Sprintf(template, orgID, projectID) +} diff --git a/internal/hcp/internal/types/types.go b/internal/hcp/internal/types/types.go new file mode 100644 index 0000000000000..17b495fabf6f6 --- /dev/null +++ b/internal/hcp/internal/types/types.go @@ -0,0 +1,11 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import "github.com/hashicorp/consul/internal/resource" + +func Register(r resource.Registry) { + RegisterLink(r) + RegisterTelemetryState(r) +} diff --git a/internal/storage/raft/backend.go b/internal/storage/raft/backend.go index 3db72f25462cf..8a7a973c3e7cf 100644 --- a/internal/storage/raft/backend.go +++ b/internal/storage/raft/backend.go @@ -14,10 +14,10 @@ import ( "github.com/hashicorp/go-hclog" - "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/storage" "github.com/hashicorp/consul/internal/storage/inmem" "github.com/hashicorp/consul/proto-public/pbresource" + pbstorage "github.com/hashicorp/consul/proto/private/pbstorage" ) @@ -53,7 +53,7 @@ func NewBackend(h Handle, l hclog.Logger) (*Backend, error) { if err != nil { return nil, err } - b := &Backend{handle: h, store: s, logger: l} + b := &Backend{handle: h, store: s} b.forwardingServer = newForwardingServer(b) b.forwardingClient = newForwardingClient(h, l) return b, nil @@ -80,7 +80,6 @@ type Handle interface { type Backend struct { handle Handle store *inmem.Store - logger hclog.Logger forwardingServer *forwardingServer forwardingClient *forwardingClient @@ -226,24 +225,6 @@ func (b *Backend) ListByOwner(_ context.Context, id *pbresource.ID) ([]*pbresour return b.store.ListByOwner(id) } -// isRetiredType ensures that types that have been formally retired (deprecated -// and deleted) do not sneak back in during a snapshot restore. -func isRetiredType(typ *pbresource.Type) bool { - switch typ.GetGroupVersion() { - case "v2": - switch typ.GetGroup() { - case "hcp": - return true - } - case "v2beta1": - switch typ.GetGroup() { - case "auth", "catalog", "mesh", "multicluster", "tenancy": - return true - } - } - return false -} - // Apply is called by the FSM with the bytes of a Raft log entry, with Consul's // envelope (i.e. type prefix and msgpack wrapper) stripped off. func (b *Backend) Apply(buf []byte, idx uint64) any { @@ -258,18 +239,8 @@ func (b *Backend) Apply(buf []byte, idx uint64) any { oldVsn := res.Version res.Version = strconv.Itoa(int(idx)) - if isRetiredType(res.GetId().GetType()) { - // When a type is retired, the caller should think that the write - // was applied, but we should simply skip loading it. This means - // that retired types will not linger in the database indefinitely. - b.logger.Warn("ignoring operation for retired type", - "operation", "apply", - "type", resource.ToGVK(res.GetId().GetType()), - ) - } else { - if err := b.store.WriteCAS(res, oldVsn); err != nil { - return err - } + if err := b.store.WriteCAS(res, oldVsn); err != nil { + return err } return &pbstorage.LogResponse{ @@ -279,19 +250,8 @@ func (b *Backend) Apply(buf []byte, idx uint64) any { } case pbstorage.LogType_LOG_TYPE_DELETE: req := req.GetDelete() - - if isRetiredType(req.GetId().GetType()) { - // When a type is retired, the caller should think that the write - // was applied, but we should simply skip loading it. This means - // that retired types will not linger in the database indefinitely. - b.logger.Warn("ignoring operation for retired type", - "operation", "delete", - "type", resource.ToGVK(req.GetId().GetType()), - ) - } else { - if err := b.store.DeleteCAS(req.Id, req.Version); err != nil { - return err - } + if err := b.store.DeleteCAS(req.Id, req.Version); err != nil { + return err } return &pbstorage.LogResponse{ Response: &pbstorage.LogResponse_Delete{}, diff --git a/internal/storage/raft/backend_test.go b/internal/storage/raft/backend_test.go deleted file mode 100644 index fb959c8cf1c75..0000000000000 --- a/internal/storage/raft/backend_test.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package raft - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/hashicorp/consul/internal/resource" - "github.com/hashicorp/consul/proto-public/pbresource" -) - -func TestIsRetiredType(t *testing.T) { - var retired []*pbresource.Type - { - const ( - GroupName = "hcp" - Version = "v2" - - LinkKind = "Link" - TelemetryStateKind = "TelemetryState" - ) - - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: LinkKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: TelemetryStateKind, - }) - } - { - const ( - GroupName = "tenancy" - Version = "v2beta1" - - NamespaceKind = "Namespace" - PartitionKind = "Partition" - ) - - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: NamespaceKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: PartitionKind, - }) - } - { - const ( - GroupName = "multicluster" - Version = "v2beta1" - - SamenessGroupKind = "SamenessGroup" - ) - - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: SamenessGroupKind, - }) - } - { - const ( - GroupName = "mesh" - Version = "v2beta1" - - APIGatewayKind = "APIGateway" - ComputedExplicitDestinationsKind = "ComputedExplicitDestinations" - ComputedGatewayRoutesKind = "ComputedGatewayRoutes" - ComputedImplicitDestinationsKind = "ComputedImplicitDestinations" - ComputedProxyConfigurationKind = "ComputedProxyConfiguration" - ComputedRoutesKind = "ComputedRoutes" - DestinationPolicyKind = "DestinationPolicy" - DestinationsKind = "Destinations" - DestinationsConfigurationKind = "DestinationsConfiguration" - GRPCRouteKind = "GRPCRoute" - HTTPRouteKind = "HTTPRoute" - MeshConfigurationKind = "MeshConfiguration" - MeshGatewayKind = "MeshGateway" - ProxyConfigurationKind = "ProxyConfiguration" - ProxyStateTemplateKind = "ProxyStateTemplate" - TCPRouteKind = "TCPRoute" - ) - - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: APIGatewayKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedExplicitDestinationsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedGatewayRoutesKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedImplicitDestinationsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedProxyConfigurationKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedRoutesKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: DestinationPolicyKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: DestinationsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: DestinationsConfigurationKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: GRPCRouteKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: HTTPRouteKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: MeshConfigurationKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: MeshGatewayKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ProxyConfigurationKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ProxyStateTemplateKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: TCPRouteKind, - }) - } - { - const ( - GroupName = "auth" - Version = "v2beta1" - - ComputedTrafficPermissionsKind = "ComputedTrafficPermissions" - NamespaceTrafficPermissionsKind = "NamespaceTrafficPermissions" - PartitionTrafficPermissionsKind = "PartitionTrafficPermissions" - TrafficPermissionsKind = "TrafficPermissions" - WorkloadIdentityKind = "WorkloadIdentity" - ) - - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedTrafficPermissionsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: NamespaceTrafficPermissionsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: PartitionTrafficPermissionsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: TrafficPermissionsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: WorkloadIdentityKind, - }) - } - { - const ( - GroupName = "catalog" - Version = "v2beta1" - - ComputedFailoverPolicyKind = "ComputedFailoverPolicy" - FailoverPolicyKind = "FailoverPolicy" - HealthChecksKind = "HealthChecks" - HealthStatusKind = "HealthStatus" - NodeKind = "Node" - NodeHealthStatusKind = "NodeHealthStatus" - ServiceKind = "Service" - ServiceEndpointsKind = "ServiceEndpoints" - VirtualIPsKind = "VirtualIPs" - WorkloadKind = "Workload" - ) - - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedFailoverPolicyKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: FailoverPolicyKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: HealthChecksKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: HealthStatusKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: NodeKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: NodeHealthStatusKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ServiceKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ServiceEndpointsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: VirtualIPsKind, - }) - retired = append(retired, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: WorkloadKind, - }) - } - /* - */ - - var retained []*pbresource.Type - { - const ( - GroupName = "demo" - Version = "v2" - - AlbumKind = "Album" - ArtistKind = "Artist" - FestivalKind = "Festival" - ) - - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: AlbumKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ArtistKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: FestivalKind, - }) - } - { - const ( - GroupName = "demo" - Version = "v1" - - AlbumKind = "Album" - ArtistKind = "Artist" - ConceptKind = "Concept" - ExecutiveKind = "Executive" - RecordLabelKind = "RecordLabel" - ) - - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: AlbumKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ArtistKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ConceptKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ExecutiveKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: RecordLabelKind, - }) - } - { - const ( - GroupName = "multicluster" - Version = "v2" - - ComputedExportedServicesKind = "ComputedExportedServices" - ExportedServicesKind = "ExportedServices" - NamespaceExportedServicesKind = "NamespaceExportedServices" - PartitionExportedServicesKind = "PartitionExportedServices" - ) - - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ComputedExportedServicesKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: ExportedServicesKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: NamespaceExportedServicesKind, - }) - retained = append(retained, &pbresource.Type{ - Group: GroupName, - GroupVersion: Version, - Kind: PartitionExportedServicesKind, - }) - } - - for _, typ := range retired { - t.Run("gone - "+resource.ToGVK(typ), func(t *testing.T) { - require.True(t, isRetiredType(typ)) - }) - } - for _, typ := range retained { - t.Run("allowed - "+resource.ToGVK(typ), func(t *testing.T) { - require.False(t, isRetiredType(typ)) - }) - } -} diff --git a/proto-public/pbhcp/v2/hcp_config.pb.binary.go b/proto-public/pbhcp/v2/hcp_config.pb.binary.go new file mode 100644 index 0000000000000..66197e55b6b57 --- /dev/null +++ b/proto-public/pbhcp/v2/hcp_config.pb.binary.go @@ -0,0 +1,18 @@ +// Code generated by protoc-gen-go-binary. DO NOT EDIT. +// source: pbhcp/v2/hcp_config.proto + +package hcpv2 + +import ( + "google.golang.org/protobuf/proto" +) + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *HCPConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *HCPConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} diff --git a/proto-public/pbhcp/v2/hcp_config.pb.go b/proto-public/pbhcp/v2/hcp_config.pb.go new file mode 100644 index 0000000000000..66e63187920cf --- /dev/null +++ b/proto-public/pbhcp/v2/hcp_config.pb.go @@ -0,0 +1,199 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc (unknown) +// source: pbhcp/v2/hcp_config.proto + +package hcpv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// HCPConfig is used to configure the HCP SDK for communicating with +// the HashiCorp Cloud Platform. All configuration is optional with default +// values provided by the SDK. +type HCPConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // AuthUrl is the URL which will be used to authenticate. + AuthUrl string `protobuf:"bytes,1,opt,name=auth_url,json=authUrl,proto3" json:"auth_url,omitempty"` + // ApiAddress is the address ([:port]) of the HCP api. + ApiAddress string `protobuf:"bytes,2,opt,name=api_address,json=apiAddress,proto3" json:"api_address,omitempty"` + // ScadaAddress is the address ([:port]) of the HCP SCADA endpoint. + ScadaAddress string `protobuf:"bytes,3,opt,name=scada_address,json=scadaAddress,proto3" json:"scada_address,omitempty"` + // TlsInsecureSkipVerify if true will ignore server name verification when making HTTPS requests + TlsInsecureSkipVerify bool `protobuf:"varint,4,opt,name=tls_insecure_skip_verify,json=tlsInsecureSkipVerify,proto3" json:"tls_insecure_skip_verify,omitempty"` +} + +func (x *HCPConfig) Reset() { + *x = HCPConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_pbhcp_v2_hcp_config_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HCPConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HCPConfig) ProtoMessage() {} + +func (x *HCPConfig) ProtoReflect() protoreflect.Message { + mi := &file_pbhcp_v2_hcp_config_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HCPConfig.ProtoReflect.Descriptor instead. +func (*HCPConfig) Descriptor() ([]byte, []int) { + return file_pbhcp_v2_hcp_config_proto_rawDescGZIP(), []int{0} +} + +func (x *HCPConfig) GetAuthUrl() string { + if x != nil { + return x.AuthUrl + } + return "" +} + +func (x *HCPConfig) GetApiAddress() string { + if x != nil { + return x.ApiAddress + } + return "" +} + +func (x *HCPConfig) GetScadaAddress() string { + if x != nil { + return x.ScadaAddress + } + return "" +} + +func (x *HCPConfig) GetTlsInsecureSkipVerify() bool { + if x != nil { + return x.TlsInsecureSkipVerify + } + return false +} + +var File_pbhcp_v2_hcp_config_proto protoreflect.FileDescriptor + +var file_pbhcp_v2_hcp_config_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, 0x32, 0x2f, 0x68, 0x63, 0x70, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, + 0x70, 0x2e, 0x76, 0x32, 0x22, 0xa5, 0x01, 0x0a, 0x09, 0x48, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, + 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, + 0x0a, 0x0d, 0x73, 0x63, 0x61, 0x64, 0x61, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x61, 0x64, 0x61, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x74, 0x6c, 0x73, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x74, 0x6c, 0x73, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x42, 0xe5, 0x01, 0x0a, + 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x42, 0x0e, 0x48, 0x63, + 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, + 0x32, 0x3b, 0x68, 0x63, 0x70, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x48, 0xaa, 0x02, 0x17, + 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x48, 0x63, 0x70, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x17, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x48, 0x63, 0x70, 0x5c, 0x56, + 0x32, 0xe2, 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x48, 0x63, 0x70, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x48, 0x63, 0x70, + 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_pbhcp_v2_hcp_config_proto_rawDescOnce sync.Once + file_pbhcp_v2_hcp_config_proto_rawDescData = file_pbhcp_v2_hcp_config_proto_rawDesc +) + +func file_pbhcp_v2_hcp_config_proto_rawDescGZIP() []byte { + file_pbhcp_v2_hcp_config_proto_rawDescOnce.Do(func() { + file_pbhcp_v2_hcp_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_pbhcp_v2_hcp_config_proto_rawDescData) + }) + return file_pbhcp_v2_hcp_config_proto_rawDescData +} + +var file_pbhcp_v2_hcp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_pbhcp_v2_hcp_config_proto_goTypes = []interface{}{ + (*HCPConfig)(nil), // 0: hashicorp.consul.hcp.v2.HCPConfig +} +var file_pbhcp_v2_hcp_config_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_pbhcp_v2_hcp_config_proto_init() } +func file_pbhcp_v2_hcp_config_proto_init() { + if File_pbhcp_v2_hcp_config_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_pbhcp_v2_hcp_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HCPConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pbhcp_v2_hcp_config_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_pbhcp_v2_hcp_config_proto_goTypes, + DependencyIndexes: file_pbhcp_v2_hcp_config_proto_depIdxs, + MessageInfos: file_pbhcp_v2_hcp_config_proto_msgTypes, + }.Build() + File_pbhcp_v2_hcp_config_proto = out.File + file_pbhcp_v2_hcp_config_proto_rawDesc = nil + file_pbhcp_v2_hcp_config_proto_goTypes = nil + file_pbhcp_v2_hcp_config_proto_depIdxs = nil +} diff --git a/proto-public/pbhcp/v2/hcp_config.proto b/proto-public/pbhcp/v2/hcp_config.proto new file mode 100644 index 0000000000000..a61585a3d2db8 --- /dev/null +++ b/proto-public/pbhcp/v2/hcp_config.proto @@ -0,0 +1,23 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +syntax = "proto3"; + +package hashicorp.consul.hcp.v2; + +// HCPConfig is used to configure the HCP SDK for communicating with +// the HashiCorp Cloud Platform. All configuration is optional with default +// values provided by the SDK. +message HCPConfig { + // AuthUrl is the URL which will be used to authenticate. + string auth_url = 1; + + // ApiAddress is the address ([:port]) of the HCP api. + string api_address = 2; + + // ScadaAddress is the address ([:port]) of the HCP SCADA endpoint. + string scada_address = 3; + + // TlsInsecureSkipVerify if true will ignore server name verification when making HTTPS requests + bool tls_insecure_skip_verify = 4; +} diff --git a/proto-public/pbhcp/v2/hcp_config_deepcopy.gen.go b/proto-public/pbhcp/v2/hcp_config_deepcopy.gen.go new file mode 100644 index 0000000000000..56e40830df09b --- /dev/null +++ b/proto-public/pbhcp/v2/hcp_config_deepcopy.gen.go @@ -0,0 +1,27 @@ +// Code generated by protoc-gen-deepcopy. DO NOT EDIT. +package hcpv2 + +import ( + proto "google.golang.org/protobuf/proto" +) + +// DeepCopyInto supports using HCPConfig within kubernetes types, where deepcopy-gen is used. +func (in *HCPConfig) DeepCopyInto(out *HCPConfig) { + proto.Reset(out) + proto.Merge(out, proto.Clone(in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HCPConfig. Required by controller-gen. +func (in *HCPConfig) DeepCopy() *HCPConfig { + if in == nil { + return nil + } + out := new(HCPConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new HCPConfig. Required by controller-gen. +func (in *HCPConfig) DeepCopyInterface() interface{} { + return in.DeepCopy() +} diff --git a/proto-public/pbhcp/v2/hcp_config_json.gen.go b/proto-public/pbhcp/v2/hcp_config_json.gen.go new file mode 100644 index 0000000000000..efe1d13b85259 --- /dev/null +++ b/proto-public/pbhcp/v2/hcp_config_json.gen.go @@ -0,0 +1,22 @@ +// Code generated by protoc-json-shim. DO NOT EDIT. +package hcpv2 + +import ( + protojson "google.golang.org/protobuf/encoding/protojson" +) + +// MarshalJSON is a custom marshaler for HCPConfig +func (this *HCPConfig) MarshalJSON() ([]byte, error) { + str, err := HcpConfigMarshaler.Marshal(this) + return []byte(str), err +} + +// UnmarshalJSON is a custom unmarshaler for HCPConfig +func (this *HCPConfig) UnmarshalJSON(b []byte) error { + return HcpConfigUnmarshaler.Unmarshal(b, this) +} + +var ( + HcpConfigMarshaler = &protojson.MarshalOptions{} + HcpConfigUnmarshaler = &protojson.UnmarshalOptions{DiscardUnknown: false} +) diff --git a/proto-public/pbhcp/v2/link.pb.binary.go b/proto-public/pbhcp/v2/link.pb.binary.go new file mode 100644 index 0000000000000..7dbfbebae5b28 --- /dev/null +++ b/proto-public/pbhcp/v2/link.pb.binary.go @@ -0,0 +1,18 @@ +// Code generated by protoc-gen-go-binary. DO NOT EDIT. +// source: pbhcp/v2/link.proto + +package hcpv2 + +import ( + "google.golang.org/protobuf/proto" +) + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *Link) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *Link) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} diff --git a/proto-public/pbhcp/v2/link.pb.go b/proto-public/pbhcp/v2/link.pb.go new file mode 100644 index 0000000000000..25b2478458c74 --- /dev/null +++ b/proto-public/pbhcp/v2/link.pb.go @@ -0,0 +1,283 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc (unknown) +// source: pbhcp/v2/link.proto + +package hcpv2 + +import ( + _ "github.com/hashicorp/consul/proto-public/pbresource" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type AccessLevel int32 + +const ( + AccessLevel_ACCESS_LEVEL_UNSPECIFIED AccessLevel = 0 + AccessLevel_ACCESS_LEVEL_GLOBAL_READ_WRITE AccessLevel = 1 + AccessLevel_ACCESS_LEVEL_GLOBAL_READ_ONLY AccessLevel = 2 +) + +// Enum value maps for AccessLevel. +var ( + AccessLevel_name = map[int32]string{ + 0: "ACCESS_LEVEL_UNSPECIFIED", + 1: "ACCESS_LEVEL_GLOBAL_READ_WRITE", + 2: "ACCESS_LEVEL_GLOBAL_READ_ONLY", + } + AccessLevel_value = map[string]int32{ + "ACCESS_LEVEL_UNSPECIFIED": 0, + "ACCESS_LEVEL_GLOBAL_READ_WRITE": 1, + "ACCESS_LEVEL_GLOBAL_READ_ONLY": 2, + } +) + +func (x AccessLevel) Enum() *AccessLevel { + p := new(AccessLevel) + *p = x + return p +} + +func (x AccessLevel) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccessLevel) Descriptor() protoreflect.EnumDescriptor { + return file_pbhcp_v2_link_proto_enumTypes[0].Descriptor() +} + +func (AccessLevel) Type() protoreflect.EnumType { + return &file_pbhcp_v2_link_proto_enumTypes[0] +} + +func (x AccessLevel) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccessLevel.Descriptor instead. +func (AccessLevel) EnumDescriptor() ([]byte, []int) { + return file_pbhcp_v2_link_proto_rawDescGZIP(), []int{0} +} + +type Link struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ResourceId string `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ClientSecret string `protobuf:"bytes,3,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"` + HcpClusterUrl string `protobuf:"bytes,4,opt,name=hcp_cluster_url,json=hcpClusterUrl,proto3" json:"hcp_cluster_url,omitempty"` + AccessLevel AccessLevel `protobuf:"varint,5,opt,name=access_level,json=accessLevel,proto3,enum=hashicorp.consul.hcp.v2.AccessLevel" json:"access_level,omitempty"` + HcpConfig *HCPConfig `protobuf:"bytes,6,opt,name=hcp_config,json=hcpConfig,proto3" json:"hcp_config,omitempty"` +} + +func (x *Link) Reset() { + *x = Link{} + if protoimpl.UnsafeEnabled { + mi := &file_pbhcp_v2_link_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Link) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Link) ProtoMessage() {} + +func (x *Link) ProtoReflect() protoreflect.Message { + mi := &file_pbhcp_v2_link_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Link.ProtoReflect.Descriptor instead. +func (*Link) Descriptor() ([]byte, []int) { + return file_pbhcp_v2_link_proto_rawDescGZIP(), []int{0} +} + +func (x *Link) GetResourceId() string { + if x != nil { + return x.ResourceId + } + return "" +} + +func (x *Link) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *Link) GetClientSecret() string { + if x != nil { + return x.ClientSecret + } + return "" +} + +func (x *Link) GetHcpClusterUrl() string { + if x != nil { + return x.HcpClusterUrl + } + return "" +} + +func (x *Link) GetAccessLevel() AccessLevel { + if x != nil { + return x.AccessLevel + } + return AccessLevel_ACCESS_LEVEL_UNSPECIFIED +} + +func (x *Link) GetHcpConfig() *HCPConfig { + if x != nil { + return x.HcpConfig + } + return nil +} + +var File_pbhcp_v2_link_proto protoreflect.FileDescriptor + +var file_pbhcp_v2_link_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, 0x32, 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x1a, 0x19, + 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, 0x32, 0x2f, 0x68, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x70, 0x62, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa5, 0x02, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x6b, + 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x63, 0x70, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x68, 0x63, + 0x70, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x47, 0x0a, 0x0c, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x24, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x2e, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, + 0x65, 0x76, 0x65, 0x6c, 0x12, 0x41, 0x0a, 0x0a, 0x68, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, + 0x76, 0x32, 0x2e, 0x48, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x68, 0x63, + 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3a, 0x06, 0xa2, 0x93, 0x04, 0x02, 0x08, 0x01, 0x2a, + 0x72, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1c, + 0x0a, 0x18, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, + 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x47, 0x4c, 0x4f, + 0x42, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x57, 0x52, 0x49, 0x54, 0x45, 0x10, 0x01, + 0x12, 0x21, 0x0a, 0x1d, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, + 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x4f, 0x4e, 0x4c, + 0x59, 0x10, 0x02, 0x42, 0xe0, 0x01, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, + 0x2e, 0x76, 0x32, 0x42, 0x09, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x68, 0x63, 0x70, + 0x2f, 0x76, 0x32, 0x3b, 0x68, 0x63, 0x70, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x48, 0xaa, + 0x02, 0x17, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x48, 0x63, 0x70, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x17, 0x48, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x48, 0x63, 0x70, + 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, + 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x48, 0x63, 0x70, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1a, 0x48, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x48, + 0x63, 0x70, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_pbhcp_v2_link_proto_rawDescOnce sync.Once + file_pbhcp_v2_link_proto_rawDescData = file_pbhcp_v2_link_proto_rawDesc +) + +func file_pbhcp_v2_link_proto_rawDescGZIP() []byte { + file_pbhcp_v2_link_proto_rawDescOnce.Do(func() { + file_pbhcp_v2_link_proto_rawDescData = protoimpl.X.CompressGZIP(file_pbhcp_v2_link_proto_rawDescData) + }) + return file_pbhcp_v2_link_proto_rawDescData +} + +var file_pbhcp_v2_link_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_pbhcp_v2_link_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_pbhcp_v2_link_proto_goTypes = []interface{}{ + (AccessLevel)(0), // 0: hashicorp.consul.hcp.v2.AccessLevel + (*Link)(nil), // 1: hashicorp.consul.hcp.v2.Link + (*HCPConfig)(nil), // 2: hashicorp.consul.hcp.v2.HCPConfig +} +var file_pbhcp_v2_link_proto_depIdxs = []int32{ + 0, // 0: hashicorp.consul.hcp.v2.Link.access_level:type_name -> hashicorp.consul.hcp.v2.AccessLevel + 2, // 1: hashicorp.consul.hcp.v2.Link.hcp_config:type_name -> hashicorp.consul.hcp.v2.HCPConfig + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_pbhcp_v2_link_proto_init() } +func file_pbhcp_v2_link_proto_init() { + if File_pbhcp_v2_link_proto != nil { + return + } + file_pbhcp_v2_hcp_config_proto_init() + if !protoimpl.UnsafeEnabled { + file_pbhcp_v2_link_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Link); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pbhcp_v2_link_proto_rawDesc, + NumEnums: 1, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_pbhcp_v2_link_proto_goTypes, + DependencyIndexes: file_pbhcp_v2_link_proto_depIdxs, + EnumInfos: file_pbhcp_v2_link_proto_enumTypes, + MessageInfos: file_pbhcp_v2_link_proto_msgTypes, + }.Build() + File_pbhcp_v2_link_proto = out.File + file_pbhcp_v2_link_proto_rawDesc = nil + file_pbhcp_v2_link_proto_goTypes = nil + file_pbhcp_v2_link_proto_depIdxs = nil +} diff --git a/proto-public/pbhcp/v2/link.proto b/proto-public/pbhcp/v2/link.proto new file mode 100644 index 0000000000000..ac11ca34b5b94 --- /dev/null +++ b/proto-public/pbhcp/v2/link.proto @@ -0,0 +1,26 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +syntax = "proto3"; + +package hashicorp.consul.hcp.v2; + +import "pbhcp/v2/hcp_config.proto"; +import "pbresource/annotations.proto"; + +enum AccessLevel { + ACCESS_LEVEL_UNSPECIFIED = 0; + ACCESS_LEVEL_GLOBAL_READ_WRITE = 1; + ACCESS_LEVEL_GLOBAL_READ_ONLY = 2; +} + +message Link { + option (hashicorp.consul.resource.spec) = {scope: SCOPE_CLUSTER}; + + string resource_id = 1; + string client_id = 2; + string client_secret = 3; + string hcp_cluster_url = 4; + AccessLevel access_level = 5; + HCPConfig hcp_config = 6; +} diff --git a/proto-public/pbhcp/v2/link_deepcopy.gen.go b/proto-public/pbhcp/v2/link_deepcopy.gen.go new file mode 100644 index 0000000000000..9432d81b1eac5 --- /dev/null +++ b/proto-public/pbhcp/v2/link_deepcopy.gen.go @@ -0,0 +1,27 @@ +// Code generated by protoc-gen-deepcopy. DO NOT EDIT. +package hcpv2 + +import ( + proto "google.golang.org/protobuf/proto" +) + +// DeepCopyInto supports using Link within kubernetes types, where deepcopy-gen is used. +func (in *Link) DeepCopyInto(out *Link) { + proto.Reset(out) + proto.Merge(out, proto.Clone(in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Link. Required by controller-gen. +func (in *Link) DeepCopy() *Link { + if in == nil { + return nil + } + out := new(Link) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Link. Required by controller-gen. +func (in *Link) DeepCopyInterface() interface{} { + return in.DeepCopy() +} diff --git a/proto-public/pbhcp/v2/link_json.gen.go b/proto-public/pbhcp/v2/link_json.gen.go new file mode 100644 index 0000000000000..cd476920dd17e --- /dev/null +++ b/proto-public/pbhcp/v2/link_json.gen.go @@ -0,0 +1,22 @@ +// Code generated by protoc-json-shim. DO NOT EDIT. +package hcpv2 + +import ( + protojson "google.golang.org/protobuf/encoding/protojson" +) + +// MarshalJSON is a custom marshaler for Link +func (this *Link) MarshalJSON() ([]byte, error) { + str, err := LinkMarshaler.Marshal(this) + return []byte(str), err +} + +// UnmarshalJSON is a custom unmarshaler for Link +func (this *Link) UnmarshalJSON(b []byte) error { + return LinkUnmarshaler.Unmarshal(b, this) +} + +var ( + LinkMarshaler = &protojson.MarshalOptions{} + LinkUnmarshaler = &protojson.UnmarshalOptions{DiscardUnknown: false} +) diff --git a/proto-public/pbhcp/v2/resources.rtypes.go b/proto-public/pbhcp/v2/resources.rtypes.go new file mode 100644 index 0000000000000..7ef93d0ee2529 --- /dev/null +++ b/proto-public/pbhcp/v2/resources.rtypes.go @@ -0,0 +1,29 @@ +// Code generated by protoc-gen-resource-types. DO NOT EDIT. + +package hcpv2 + +import ( + "github.com/hashicorp/consul/proto-public/pbresource" +) + +const ( + GroupName = "hcp" + Version = "v2" + + LinkKind = "Link" + TelemetryStateKind = "TelemetryState" +) + +var ( + LinkType = &pbresource.Type{ + Group: GroupName, + GroupVersion: Version, + Kind: LinkKind, + } + + TelemetryStateType = &pbresource.Type{ + Group: GroupName, + GroupVersion: Version, + Kind: TelemetryStateKind, + } +) diff --git a/proto-public/pbhcp/v2/telemetry_state.pb.binary.go b/proto-public/pbhcp/v2/telemetry_state.pb.binary.go new file mode 100644 index 0000000000000..278fe7c2bdc4c --- /dev/null +++ b/proto-public/pbhcp/v2/telemetry_state.pb.binary.go @@ -0,0 +1,38 @@ +// Code generated by protoc-gen-go-binary. DO NOT EDIT. +// source: pbhcp/v2/telemetry_state.proto + +package hcpv2 + +import ( + "google.golang.org/protobuf/proto" +) + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *TelemetryState) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *TelemetryState) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *MetricsConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *MetricsConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *ProxyConfig) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *ProxyConfig) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} diff --git a/proto-public/pbhcp/v2/telemetry_state.pb.go b/proto-public/pbhcp/v2/telemetry_state.pb.go new file mode 100644 index 0000000000000..10c48ab9b6023 --- /dev/null +++ b/proto-public/pbhcp/v2/telemetry_state.pb.go @@ -0,0 +1,426 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc (unknown) +// source: pbhcp/v2/telemetry_state.proto + +package hcpv2 + +import ( + _ "github.com/hashicorp/consul/proto-public/pbresource" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// TelemetryState describes configuration required to forward telemetry to the HashiCorp Cloud Platform. +// This resource is managed internally and is only written if the cluster is linked to HCP. Any +// manual changes to the resource will be reconciled and overwritten with the internally computed +// state. +type TelemetryState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // ResourceId is the identifier for the cluster linked with HCP. + ResourceId string `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + // ClientId is the oauth client identifier for cluster. + // This client has capabilities limited to writing telemetry data for this cluster. + ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + // ClientSecret is the oauth secret used to authenticate requests to send telemetry data to HCP. + ClientSecret string `protobuf:"bytes,3,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"` + HcpConfig *HCPConfig `protobuf:"bytes,4,opt,name=hcp_config,json=hcpConfig,proto3" json:"hcp_config,omitempty"` + Proxy *ProxyConfig `protobuf:"bytes,5,opt,name=proxy,proto3" json:"proxy,omitempty"` + Metrics *MetricsConfig `protobuf:"bytes,6,opt,name=metrics,proto3" json:"metrics,omitempty"` +} + +func (x *TelemetryState) Reset() { + *x = TelemetryState{} + if protoimpl.UnsafeEnabled { + mi := &file_pbhcp_v2_telemetry_state_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TelemetryState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TelemetryState) ProtoMessage() {} + +func (x *TelemetryState) ProtoReflect() protoreflect.Message { + mi := &file_pbhcp_v2_telemetry_state_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TelemetryState.ProtoReflect.Descriptor instead. +func (*TelemetryState) Descriptor() ([]byte, []int) { + return file_pbhcp_v2_telemetry_state_proto_rawDescGZIP(), []int{0} +} + +func (x *TelemetryState) GetResourceId() string { + if x != nil { + return x.ResourceId + } + return "" +} + +func (x *TelemetryState) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *TelemetryState) GetClientSecret() string { + if x != nil { + return x.ClientSecret + } + return "" +} + +func (x *TelemetryState) GetHcpConfig() *HCPConfig { + if x != nil { + return x.HcpConfig + } + return nil +} + +func (x *TelemetryState) GetProxy() *ProxyConfig { + if x != nil { + return x.Proxy + } + return nil +} + +func (x *TelemetryState) GetMetrics() *MetricsConfig { + if x != nil { + return x.Metrics + } + return nil +} + +// MetricsConfig configures metric specific collection details +type MetricsConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Endpoint is the HTTPS address and path to forward metrics to + Endpoint string `protobuf:"bytes,1,opt,name=endpoint,proto3" json:"endpoint,omitempty"` + // IncludeList contains patterns to match against metric names. Only matched metrics are forwarded. + IncludeList []string `protobuf:"bytes,2,rep,name=include_list,json=includeList,proto3" json:"include_list,omitempty"` + // Labels contains key value pairs that are associated with all metrics collected and fowarded. + Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Disabled toggles metric forwarding. If true, metric forwarding will stop until disabled is set to false. + Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"` +} + +func (x *MetricsConfig) Reset() { + *x = MetricsConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_pbhcp_v2_telemetry_state_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MetricsConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MetricsConfig) ProtoMessage() {} + +func (x *MetricsConfig) ProtoReflect() protoreflect.Message { + mi := &file_pbhcp_v2_telemetry_state_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MetricsConfig.ProtoReflect.Descriptor instead. +func (*MetricsConfig) Descriptor() ([]byte, []int) { + return file_pbhcp_v2_telemetry_state_proto_rawDescGZIP(), []int{1} +} + +func (x *MetricsConfig) GetEndpoint() string { + if x != nil { + return x.Endpoint + } + return "" +} + +func (x *MetricsConfig) GetIncludeList() []string { + if x != nil { + return x.IncludeList + } + return nil +} + +func (x *MetricsConfig) GetLabels() map[string]string { + if x != nil { + return x.Labels + } + return nil +} + +func (x *MetricsConfig) GetDisabled() bool { + if x != nil { + return x.Disabled + } + return false +} + +// ProxyConfig describes configuration for forwarding requests through an http proxy +type ProxyConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // HttpProxy configures the http proxy to use for HTTP (non-TLS) requests. + HttpProxy string `protobuf:"bytes,1,opt,name=http_proxy,json=httpProxy,proto3" json:"http_proxy,omitempty"` + // HttpsProxy configures the http proxy to use for HTTPS (TLS) requests. + HttpsProxy string `protobuf:"bytes,2,opt,name=https_proxy,json=httpsProxy,proto3" json:"https_proxy,omitempty"` + // NoProxy can be configured to include domains which should NOT be forwarded through the configured http proxy + NoProxy []string `protobuf:"bytes,3,rep,name=no_proxy,json=noProxy,proto3" json:"no_proxy,omitempty"` +} + +func (x *ProxyConfig) Reset() { + *x = ProxyConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_pbhcp_v2_telemetry_state_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProxyConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProxyConfig) ProtoMessage() {} + +func (x *ProxyConfig) ProtoReflect() protoreflect.Message { + mi := &file_pbhcp_v2_telemetry_state_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProxyConfig.ProtoReflect.Descriptor instead. +func (*ProxyConfig) Descriptor() ([]byte, []int) { + return file_pbhcp_v2_telemetry_state_proto_rawDescGZIP(), []int{2} +} + +func (x *ProxyConfig) GetHttpProxy() string { + if x != nil { + return x.HttpProxy + } + return "" +} + +func (x *ProxyConfig) GetHttpsProxy() string { + if x != nil { + return x.HttpsProxy + } + return "" +} + +func (x *ProxyConfig) GetNoProxy() []string { + if x != nil { + return x.NoProxy + } + return nil +} + +var File_pbhcp_v2_telemetry_state_proto protoreflect.FileDescriptor + +var file_pbhcp_v2_telemetry_state_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, + 0x65, 0x74, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x17, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x1a, 0x19, 0x70, 0x62, 0x68, 0x63, 0x70, + 0x2f, 0x76, 0x32, 0x2f, 0x68, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x70, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xbc, 0x02, 0x0a, 0x0e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x0a, 0x68, 0x63, 0x70, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, + 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x09, 0x68, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x05, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, + 0x70, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x05, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x40, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, + 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x3a, 0x06, 0xa2, 0x93, 0x04, 0x02, 0x08, + 0x01, 0x22, 0xf1, 0x01, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x68, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x68, 0x74, 0x74, 0x70, 0x50, 0x72, + 0x6f, 0x78, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x5f, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x50, + 0x72, 0x6f, 0x78, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x42, + 0xea, 0x01, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x42, + 0x13, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x2f, 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, 0x32, 0x3b, 0x68, 0x63, 0x70, 0x76, 0x32, 0xa2, + 0x02, 0x03, 0x48, 0x43, 0x48, 0xaa, 0x02, 0x17, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x48, 0x63, 0x70, 0x2e, 0x56, 0x32, 0xca, + 0x02, 0x17, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x5c, 0x48, 0x63, 0x70, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x48, 0x63, 0x70, + 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x1a, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x48, 0x63, 0x70, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_pbhcp_v2_telemetry_state_proto_rawDescOnce sync.Once + file_pbhcp_v2_telemetry_state_proto_rawDescData = file_pbhcp_v2_telemetry_state_proto_rawDesc +) + +func file_pbhcp_v2_telemetry_state_proto_rawDescGZIP() []byte { + file_pbhcp_v2_telemetry_state_proto_rawDescOnce.Do(func() { + file_pbhcp_v2_telemetry_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_pbhcp_v2_telemetry_state_proto_rawDescData) + }) + return file_pbhcp_v2_telemetry_state_proto_rawDescData +} + +var file_pbhcp_v2_telemetry_state_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_pbhcp_v2_telemetry_state_proto_goTypes = []interface{}{ + (*TelemetryState)(nil), // 0: hashicorp.consul.hcp.v2.TelemetryState + (*MetricsConfig)(nil), // 1: hashicorp.consul.hcp.v2.MetricsConfig + (*ProxyConfig)(nil), // 2: hashicorp.consul.hcp.v2.ProxyConfig + nil, // 3: hashicorp.consul.hcp.v2.MetricsConfig.LabelsEntry + (*HCPConfig)(nil), // 4: hashicorp.consul.hcp.v2.HCPConfig +} +var file_pbhcp_v2_telemetry_state_proto_depIdxs = []int32{ + 4, // 0: hashicorp.consul.hcp.v2.TelemetryState.hcp_config:type_name -> hashicorp.consul.hcp.v2.HCPConfig + 2, // 1: hashicorp.consul.hcp.v2.TelemetryState.proxy:type_name -> hashicorp.consul.hcp.v2.ProxyConfig + 1, // 2: hashicorp.consul.hcp.v2.TelemetryState.metrics:type_name -> hashicorp.consul.hcp.v2.MetricsConfig + 3, // 3: hashicorp.consul.hcp.v2.MetricsConfig.labels:type_name -> hashicorp.consul.hcp.v2.MetricsConfig.LabelsEntry + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_pbhcp_v2_telemetry_state_proto_init() } +func file_pbhcp_v2_telemetry_state_proto_init() { + if File_pbhcp_v2_telemetry_state_proto != nil { + return + } + file_pbhcp_v2_hcp_config_proto_init() + if !protoimpl.UnsafeEnabled { + file_pbhcp_v2_telemetry_state_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TelemetryState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pbhcp_v2_telemetry_state_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MetricsConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pbhcp_v2_telemetry_state_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProxyConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pbhcp_v2_telemetry_state_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_pbhcp_v2_telemetry_state_proto_goTypes, + DependencyIndexes: file_pbhcp_v2_telemetry_state_proto_depIdxs, + MessageInfos: file_pbhcp_v2_telemetry_state_proto_msgTypes, + }.Build() + File_pbhcp_v2_telemetry_state_proto = out.File + file_pbhcp_v2_telemetry_state_proto_rawDesc = nil + file_pbhcp_v2_telemetry_state_proto_goTypes = nil + file_pbhcp_v2_telemetry_state_proto_depIdxs = nil +} diff --git a/proto-public/pbhcp/v2/telemetry_state.proto b/proto-public/pbhcp/v2/telemetry_state.proto new file mode 100644 index 0000000000000..bc9521a5ffd55 --- /dev/null +++ b/proto-public/pbhcp/v2/telemetry_state.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; + +package hashicorp.consul.hcp.v2; + +import "pbhcp/v2/hcp_config.proto"; +import "pbresource/annotations.proto"; + +// TelemetryState describes configuration required to forward telemetry to the HashiCorp Cloud Platform. +// This resource is managed internally and is only written if the cluster is linked to HCP. Any +// manual changes to the resource will be reconciled and overwritten with the internally computed +// state. +message TelemetryState { + option (hashicorp.consul.resource.spec) = {scope: SCOPE_CLUSTER}; + + // ResourceId is the identifier for the cluster linked with HCP. + string resource_id = 1; + + // ClientId is the oauth client identifier for cluster. + // This client has capabilities limited to writing telemetry data for this cluster. + string client_id = 2; + + // ClientSecret is the oauth secret used to authenticate requests to send telemetry data to HCP. + string client_secret = 3; + + HCPConfig hcp_config = 4; + ProxyConfig proxy = 5; + MetricsConfig metrics = 6; +} + +// MetricsConfig configures metric specific collection details +message MetricsConfig { + // Endpoint is the HTTPS address and path to forward metrics to + string endpoint = 1; + + // IncludeList contains patterns to match against metric names. Only matched metrics are forwarded. + repeated string include_list = 2; + + // Labels contains key value pairs that are associated with all metrics collected and fowarded. + map labels = 3; + + // Disabled toggles metric forwarding. If true, metric forwarding will stop until disabled is set to false. + bool disabled = 4; +} + +// ProxyConfig describes configuration for forwarding requests through an http proxy +message ProxyConfig { + // HttpProxy configures the http proxy to use for HTTP (non-TLS) requests. + string http_proxy = 1; + + // HttpsProxy configures the http proxy to use for HTTPS (TLS) requests. + string https_proxy = 2; + + // NoProxy can be configured to include domains which should NOT be forwarded through the configured http proxy + repeated string no_proxy = 3; +} diff --git a/proto-public/pbhcp/v2/telemetry_state_deepcopy.gen.go b/proto-public/pbhcp/v2/telemetry_state_deepcopy.gen.go new file mode 100644 index 0000000000000..7d71330de6a9e --- /dev/null +++ b/proto-public/pbhcp/v2/telemetry_state_deepcopy.gen.go @@ -0,0 +1,69 @@ +// Code generated by protoc-gen-deepcopy. DO NOT EDIT. +package hcpv2 + +import ( + proto "google.golang.org/protobuf/proto" +) + +// DeepCopyInto supports using TelemetryState within kubernetes types, where deepcopy-gen is used. +func (in *TelemetryState) DeepCopyInto(out *TelemetryState) { + proto.Reset(out) + proto.Merge(out, proto.Clone(in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TelemetryState. Required by controller-gen. +func (in *TelemetryState) DeepCopy() *TelemetryState { + if in == nil { + return nil + } + out := new(TelemetryState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new TelemetryState. Required by controller-gen. +func (in *TelemetryState) DeepCopyInterface() interface{} { + return in.DeepCopy() +} + +// DeepCopyInto supports using MetricsConfig within kubernetes types, where deepcopy-gen is used. +func (in *MetricsConfig) DeepCopyInto(out *MetricsConfig) { + proto.Reset(out) + proto.Merge(out, proto.Clone(in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsConfig. Required by controller-gen. +func (in *MetricsConfig) DeepCopy() *MetricsConfig { + if in == nil { + return nil + } + out := new(MetricsConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new MetricsConfig. Required by controller-gen. +func (in *MetricsConfig) DeepCopyInterface() interface{} { + return in.DeepCopy() +} + +// DeepCopyInto supports using ProxyConfig within kubernetes types, where deepcopy-gen is used. +func (in *ProxyConfig) DeepCopyInto(out *ProxyConfig) { + proto.Reset(out) + proto.Merge(out, proto.Clone(in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfig. Required by controller-gen. +func (in *ProxyConfig) DeepCopy() *ProxyConfig { + if in == nil { + return nil + } + out := new(ProxyConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfig. Required by controller-gen. +func (in *ProxyConfig) DeepCopyInterface() interface{} { + return in.DeepCopy() +} diff --git a/proto-public/pbhcp/v2/telemetry_state_json.gen.go b/proto-public/pbhcp/v2/telemetry_state_json.gen.go new file mode 100644 index 0000000000000..a07647002fb3e --- /dev/null +++ b/proto-public/pbhcp/v2/telemetry_state_json.gen.go @@ -0,0 +1,44 @@ +// Code generated by protoc-json-shim. DO NOT EDIT. +package hcpv2 + +import ( + protojson "google.golang.org/protobuf/encoding/protojson" +) + +// MarshalJSON is a custom marshaler for TelemetryState +func (this *TelemetryState) MarshalJSON() ([]byte, error) { + str, err := TelemetryStateMarshaler.Marshal(this) + return []byte(str), err +} + +// UnmarshalJSON is a custom unmarshaler for TelemetryState +func (this *TelemetryState) UnmarshalJSON(b []byte) error { + return TelemetryStateUnmarshaler.Unmarshal(b, this) +} + +// MarshalJSON is a custom marshaler for MetricsConfig +func (this *MetricsConfig) MarshalJSON() ([]byte, error) { + str, err := TelemetryStateMarshaler.Marshal(this) + return []byte(str), err +} + +// UnmarshalJSON is a custom unmarshaler for MetricsConfig +func (this *MetricsConfig) UnmarshalJSON(b []byte) error { + return TelemetryStateUnmarshaler.Unmarshal(b, this) +} + +// MarshalJSON is a custom marshaler for ProxyConfig +func (this *ProxyConfig) MarshalJSON() ([]byte, error) { + str, err := TelemetryStateMarshaler.Marshal(this) + return []byte(str), err +} + +// UnmarshalJSON is a custom unmarshaler for ProxyConfig +func (this *ProxyConfig) UnmarshalJSON(b []byte) error { + return TelemetryStateUnmarshaler.Unmarshal(b, this) +} + +var ( + TelemetryStateMarshaler = &protojson.MarshalOptions{} + TelemetryStateUnmarshaler = &protojson.UnmarshalOptions{DiscardUnknown: false} +) diff --git a/test-integ/go.mod b/test-integ/go.mod index dcbb5ae90b33f..a53bfbd735ae4 100644 --- a/test-integ/go.mod +++ b/test-integ/go.mod @@ -5,7 +5,7 @@ go 1.22 toolchain go1.22.5 require ( - github.com/google/go-cmp v0.6.0 + github.com/google/go-cmp v0.5.9 github.com/hashicorp/consul/api v1.29.4 github.com/hashicorp/consul/proto-public v0.6.2 github.com/hashicorp/consul/sdk v0.16.1 @@ -16,7 +16,7 @@ require ( github.com/mitchellh/copystructure v1.2.0 github.com/rboyer/blankspace v0.2.1 github.com/stretchr/testify v1.8.4 - golang.org/x/net v0.25.0 + golang.org/x/net v0.24.0 google.golang.org/grpc v1.58.3 ) @@ -99,13 +99,12 @@ require ( github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 // indirect github.com/testcontainers/testcontainers-go v0.22.0 // indirect github.com/zclconf/go-cty v1.12.1 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/test-integ/go.sum b/test-integ/go.sum index ede92ac102d71..22d98cfb116da 100644 --- a/test-integ/go.sum +++ b/test-integ/go.sum @@ -98,9 +98,8 @@ github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -311,8 +310,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U 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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -320,8 +319,8 @@ golang.org/x/mod v0.3.0/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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -337,8 +336,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= 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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -347,8 +346,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -382,8 +381,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -396,9 +395,8 @@ 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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -410,8 +408,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= diff --git a/test/integration/consul-container/go.mod b/test/integration/consul-container/go.mod index 4e3e4de0fdc57..ea68d79f1ad2f 100644 --- a/test/integration/consul-container/go.mod +++ b/test/integration/consul-container/go.mod @@ -30,7 +30,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 github.com/testcontainers/testcontainers-go v0.22.0 - golang.org/x/mod v0.17.0 + golang.org/x/mod v0.13.0 google.golang.org/grpc v1.58.3 ) @@ -58,7 +58,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.0.1 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/consul-server-connection-manager v0.1.4 // indirect github.com/hashicorp/consul/proto-public v0.6.2 // indirect @@ -94,13 +94,12 @@ require ( github.com/prometheus/procfs v0.8.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/test/integration/consul-container/go.sum b/test/integration/consul-container/go.sum index 5975d9fcbaa2d..905ae270013e1 100644 --- a/test/integration/consul-container/go.sum +++ b/test/integration/consul-container/go.sum @@ -107,9 +107,8 @@ github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -307,8 +306,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U 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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= @@ -320,8 +319,8 @@ golang.org/x/mod v0.3.0/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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -340,8 +339,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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= @@ -352,8 +351,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -388,8 +387,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -402,9 +401,8 @@ 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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -420,8 +418,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= diff --git a/version/VERSION b/version/VERSION index b148ac3829b7c..558dbb08f9e37 100644 --- a/version/VERSION +++ b/version/VERSION @@ -1 +1 @@ -1.21.0-dev \ No newline at end of file +1.20.2-dev diff --git a/website/content/api-docs/health.mdx b/website/content/api-docs/health.mdx index c6182f441b5d8..dbeea876c0d24 100644 --- a/website/content/api-docs/health.mdx +++ b/website/content/api-docs/health.mdx @@ -222,7 +222,7 @@ The table below shows this endpoint's support for | `YES` 1 | `all` | `background refresh` | `node:read,service:read` |

- 1some query parameters will use the streaming backend for blocking queries. + 1some query parameters will use the streaming backend for blocking queries.

### Path Parameters @@ -265,16 +265,16 @@ The table below shows this endpoint's support for - `merge-central-config` - Include this flag in a request for `connect-proxy` kind or `*-gateway` kind services to return a fully resolved service definition that includes merged values from the - [proxy-defaults/global](/consul/docs/connect/config-entries/proxy-defaults) and + [proxy-defaults/global](/consul/docs/connect/config-entries/proxy-defaults) and [service-defaults/:service](/consul/docs/connect/config-entries/service-defaults) config entries. - Returning a fully resolved service definition is useful when a service was registered using the + Returning a fully resolved service definition is useful when a service was registered using the [/catalog/register](/consul/api-docs/catalog#register_entity) endpoint, which does not automatically merge config entries. - `ns` `(string: "")` - Specifies the namespace of the service. You can also [specify the namespace through other methods](#methods-to-specify-namespace). - `sg` `(string: "")` - Specifies the sameness group the service is a member of to - facilitate requests to identical services in other peers or partitions. + facilitate requests to identical services in other peers or partitions. ### Sample Request diff --git a/website/content/docs/connect/gateways/api-gateway/configuration/routes.mdx b/website/content/docs/connect/gateways/api-gateway/configuration/routes.mdx index 9e2e8265ee681..6723931290e64 100644 --- a/website/content/docs/connect/gateways/api-gateway/configuration/routes.mdx +++ b/website/content/docs/connect/gateways/api-gateway/configuration/routes.mdx @@ -101,7 +101,7 @@ This field specifies backend services that the `Route` references. The following | Parameter | Description | Type | Required | | --- | --- | --- | --- | -| `group` | Specifies the Kubernetes API Group of the referenced backend. You can specify the following values:
  • `""`: Specifies the core Kubernetes API group. This value must be used when `kind` is set to `Service`. This is the default value if unspecified.
  • `consul.hashicorp.com`: This value must be used when `kind` is set to `MeshService`.
| String | Optional | +| `group` | Specifies the Kubernetes API Group of the referenced backend. You can specify the following values:
  • `""`: Specifies the core Kubernetes API group. This value must be used when `kind` is set to `Service`. This is the default value if unspecified.
  • `api-gateway.consul.hashicorp.com`: This value must be used when `kind` is set to `MeshService`.
| String | Optional | | `kind` | Specifies the Kubernetes Kind of the referenced backend. You can specify the following values:
  • `Service` (default): Indicates that the `backendRef` references a Service in the Kubernetes cluster.
  • `MeshService`: Indicates that the `backendRef` references a service in the Consul mesh. Refer to the `MeshService` [documentation](/consul/docs/connect/gateways/api-gateway/configuration/meshservice) for additional information.
| String | Optional | | `name` | Specifies the name of the Kubernetes Service or Consul mesh service resource. | String | Required | | `namespace` | Specifies the Kubernetes namespace containing the Kubernetes Service or Consul mesh service resource. You must specify a value if the Service or Consul mesh service is defined in a different namespace from the `Route`. Defaults to the namespace of the `Route`.
To create a route for a `backendRef` in a different namespace, you must also create a [ReferenceGrant](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.ReferenceGrant). Refer to the [example route](#example-cross-namespace-backendref) configured to reference across namespaces. | String | Optional | diff --git a/website/content/docs/connect/gateways/api-gateway/define-routes/route-to-peered-services.mdx b/website/content/docs/connect/gateways/api-gateway/define-routes/route-to-peered-services.mdx index e323f8ea9e37e..414ce45f53530 100644 --- a/website/content/docs/connect/gateways/api-gateway/define-routes/route-to-peered-services.mdx +++ b/website/content/docs/connect/gateways/api-gateway/define-routes/route-to-peered-services.mdx @@ -67,7 +67,7 @@ spec: ... rules: - backendRefs: - - group: consul.hashicorp.com + - group: api-gateway.consul.hashicorp.com kind: MeshService name: example-mesh-service port: 3000 diff --git a/website/content/docs/dynamic-app-config/sessions/index.mdx b/website/content/docs/dynamic-app-config/sessions/index.mdx index 5bbe65e8f11e8..3eb26f558f520 100644 --- a/website/content/docs/dynamic-app-config/sessions/index.mdx +++ b/website/content/docs/dynamic-app-config/sessions/index.mdx @@ -10,7 +10,7 @@ description: >- Consul provides a session mechanism which can be used to build distributed locks. Sessions act as a binding layer between nodes, health checks, and key/value data. They are designed to provide granular locking and are heavily inspired by -[The Chubby Lock Service for Loosely-Coupled Distributed Systems](https://research.google/pubs/the-chubby-lock-service-for-loosely-coupled-distributed-systems/). +[The Chubby Lock Service for Loosely-Coupled Distributed Systems](http://research.google.com/archive/chubby.html). ## Session Design diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 1276feaa025da..88067dbd40849 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -1727,8 +1727,8 @@ ] }, { - "title": "Enable on dataplanes", - "path": "k8s/dns/enable" + "title": "Enable on dataplanes", + "path": "k8s/dns/enable" } ] }, diff --git a/website/redirects.js b/website/redirects.js index 57590f8025287..6846552841031 100644 --- a/website/redirects.js +++ b/website/redirects.js @@ -218,7 +218,8 @@ module.exports = [ permanent: true, }, { - source: '/consul/docs/:version(v1\.(?:8|9|10|11|12|13|14|15|16|17)\.x)/architecture/catalog/:slug*', + source: + '/consul/docs/:version(v1.(?:8|9|10|11|12|13|14|15|16|17).x)/architecture/catalog/:slug*', destination: '/consul/docs/:version/architecture/catalog/v1/:slug', permanent: true, }, @@ -228,7 +229,8 @@ module.exports = [ permanent: true, }, { - source: '/consul/docs/:version(v1\.(?:8|9|10|11|12|13|14|15|16|17)\.x)/nia/network-drivers/hcp-terraform', + source: + '/consul/docs/:version(v1.(?:8|9|10|11|12|13|14|15|16|17).x)/nia/network-drivers/hcp-terraform', destination: '/consul/docs/:version/nia/network-drivers/terraform-cloud', permanent: true, }, @@ -253,7 +255,8 @@ module.exports = [ permanent: true, }, { - source: '/consul/docs/:version(v1\.(?:11|12|13|14|15|16|17|18)\.x)/k8s/dns/enable', + source: + '/consul/docs/:version(v1.(?:11|12|13|14|15|16|17|18).x)/k8s/dns/enable', destination: '/consul/docs/:version/k8s/dns', permanent: true, },