From a3eeb05075cad91f2b4c4682a89d3f52233de109 Mon Sep 17 00:00:00 2001 From: Enny Frick Date: Tue, 23 Apr 2024 17:56:49 -0700 Subject: [PATCH 1/9] add account observability resource --- go.mod | 3 +- go.sum | 3 + internal/client/client.go | 88 ++++- internal/provider/account_metrics_resource.go | 300 ++++++++++++++++++ .../provider/account_metrics_resource_test.go | 44 +++ internal/provider/namespace_resource.go | 16 +- internal/provider/namespace_resource_test.go | 4 +- .../namespace_search_attribute_resource.go | 5 +- internal/provider/namespaces_datasource.go | 7 +- internal/provider/provider.go | 13 +- internal/provider/regions_datasource.go | 8 +- internal/provider/user_resource.go | 4 +- 12 files changed, 457 insertions(+), 38 deletions(-) create mode 100644 internal/provider/account_metrics_resource.go create mode 100644 internal/provider/account_metrics_resource_test.go diff --git a/go.mod b/go.mod index 2e93eaf..87f6718 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,8 @@ require ( github.com/russross/blackfriday v1.6.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/stretchr/testify v1.8.2 // indirect + github.com/stretchr/testify v1.8.4 // indirect + github.com/temporalio/tcld v0.22.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 96dbb1e..7e95f7e 100644 --- a/go.sum +++ b/go.sum @@ -197,6 +197,9 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/temporalio/tcld v0.22.0 h1:6Vf2yV2nOP4mN81bb6QZIM9MZTczovWY9P0k1lb5LYM= +github.com/temporalio/tcld v0.22.0/go.mod h1:BESY34o2kPGyAjlMLBhXFvg4n9LrnMOg2SR8Q2biukg= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= diff --git a/internal/client/client.go b/internal/client/client.go index 2539a5c..87ba78a 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -32,28 +32,42 @@ import ( "time" "github.com/hashicorp/terraform-plugin-log/tflog" - cloudservicev1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/cloudservice/v1" - operationv1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/operation/v1" + "github.com/temporalio/tcld/protogen/api/accountservice/v1" + "github.com/temporalio/tcld/protogen/api/request/v1" + "github.com/temporalio/tcld/protogen/api/requestservice/v1" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" + + cloudservicev1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/cloudservice/v1" + operationv1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/operation/v1" ) const TemporalCloudAPIVersionHeader = "temporal-cloud-api-version" var TemporalCloudAPIVersion = "2023-10-01-00" -// Client is a client for the Temporal Cloud API. -type Client struct { - cloudservicev1.CloudServiceClient +// ClientStore is a client for the Temporal Cloud API. +type ClientStore struct { + c cloudservicev1.CloudServiceClient + a accountservice.AccountServiceClient + r requestservice.RequestServiceClient } -var ( - _ cloudservicev1.CloudServiceClient = &Client{} -) +func (c *ClientStore) CloudServiceClient() cloudservicev1.CloudServiceClient { + return c.c +} + +func (c *ClientStore) AccountServiceClient() accountservice.AccountServiceClient { + return c.a +} -func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, opts ...grpc.DialOption) (*Client, error) { +func (c *ClientStore) RequestServiceClient() requestservice.RequestServiceClient { + return c.r +} + +func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, opts ...grpc.DialOption) (*ClientStore, error) { return newConnection( addrStr, allowInsecure, @@ -61,7 +75,7 @@ func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, ) } -func newConnection(addrStr string, allowInsecure bool, opts ...grpc.DialOption) (*Client, error) { +func newConnection(addrStr string, allowInsecure bool, opts ...grpc.DialOption) (*ClientStore, error) { addr, err := url.Parse(addrStr) if err != nil { return nil, fmt.Errorf("unable to parse server address: %s", err) @@ -76,7 +90,9 @@ func newConnection(addrStr string, allowInsecure bool, opts ...grpc.DialOption) } cloudClient := cloudservicev1.NewCloudServiceClient(conn) - return &Client{CloudServiceClient: cloudClient}, nil + accountClient := accountservice.NewAccountServiceClient(conn) + reqClient := requestservice.NewRequestServiceClient(conn) + return &ClientStore{c: cloudClient, a: accountClient, r: reqClient}, nil } func AwaitAsyncOperation(ctx context.Context, client cloudservicev1.CloudServiceClient, op *operationv1.AsyncOperation) error { @@ -130,6 +146,56 @@ func AwaitAsyncOperation(ctx context.Context, client cloudservicev1.CloudService } } +func AwaitRequestStatus(ctx context.Context, c requestservice.RequestServiceClient, op *request.RequestStatus) error { + if op == nil { + return fmt.Errorf("failed to await response: nil operation") + } + ctx = tflog.SetField(ctx, "operation_id", op.GetRequestId()) + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + status, err := c.GetRequestStatus(ctx, &requestservice.GetRequestStatusRequest{ + RequestId: op.GetRequestId(), + }) + if err != nil { + return fmt.Errorf("failed to query request status: %w", err) + } + newOp := status.GetRequestStatus() + tflog.Debug(ctx, "responded with state", map[string]any{ + "state": newOp.GetState().String(), + }) + + // https://github.com/temporalio/tcld/blob/main/protogen/api/request/v1/message.pb.go#L31 + switch newOp.GetState() { + case request.STATE_PENDING: + case request.STATE_IN_PROGRESS: + tflog.Debug(ctx, "retrying in 1 second", map[string]any{ + "state": newOp.GetState().String(), + }) + continue + case request.STATE_FAILED: + tflog.Debug(ctx, "request failed") + return errors.New(newOp.GetFailureReason()) + case request.STATE_CANCELLED: + tflog.Debug(ctx, "request cancelled") + return errors.New("request cancelled") + case request.STATE_FULFILLED: + tflog.Debug(ctx, "request fulfilled, terminating loop") + return nil + default: + tflog.Warn(ctx, "unknown state, continuing", map[string]any{ + "state": newOp.GetState().String(), + }) + continue + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + func defaultDialOptions(addr *url.URL, allowInsecure bool) []grpc.DialOption { var opts []grpc.DialOption diff --git a/internal/provider/account_metrics_resource.go b/internal/provider/account_metrics_resource.go new file mode 100644 index 0000000..82a5daa --- /dev/null +++ b/internal/provider/account_metrics_resource.go @@ -0,0 +1,300 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/temporalio/tcld/protogen/api/account/v1" + "github.com/temporalio/tcld/protogen/api/accountservice/v1" + "github.com/temporalio/tcld/protogen/api/requestservice/v1" + + "github.com/temporalio/terraform-provider-temporalcloud/internal/client" +) + +type ( + accountMetricsResource struct { + accountClient accountservice.AccountServiceClient + requestClient requestservice.RequestServiceClient + } + + accountMetricsResourceModel struct { + ID types.String `tfsdk:"id"` + Enabled types.Bool `tfsdk:"enabled"` + AcceptedClientCA types.String `tfsdk:"accepted_client_ca"` + Endpoint types.String `tfsdk:"endpoint"` + + Timeouts timeouts.Value `tfsdk:"timeouts"` + } +) + +var ( + _ resource.Resource = (*accountMetricsResource)(nil) + _ resource.ResourceWithConfigure = (*accountMetricsResource)(nil) + _ resource.ResourceWithImportState = (*accountMetricsResource)(nil) + _ resource.ResourceWithValidateConfig = (*accountMetricsResource)(nil) +) + +func NewAccountMetricsResource() resource.Resource { + return &accountMetricsResource{} +} + +func (r *accountMetricsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + clientStore, ok := req.ProviderData.(client.ClientStore) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected client.CloudClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.accountClient = clientStore.AccountServiceClient() + r.requestClient = clientStore.RequestServiceClient() +} + +func (r *accountMetricsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "account_metrics" +} + +func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Configures a Temporal Cloud account's metrics", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "A unique identifier for the account's metrics configuration", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "enabled": schema.BoolAttribute{ + Description: "If true, enables metrics for the account", + Required: true, + }, + "accepted_client_ca": schema.StringAttribute{ + Description: "The Base64-encoded CA cert in PEM format used to authenticate clients connecting to the metrics endpoint. Required when enabled is true.", + }, + "endpoint": schema.StringAttribute{ + Description: "The Prometheus metrics endpoint URI", + Computed: true, + }, + }, + Blocks: map[string]schema.Block{ + "timeouts": timeouts.Block( + ctx, timeouts.Opts{ + Create: true, + Delete: true, + Update: true, + }, + ), + }, + } +} + +func (r *accountMetricsResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + var data accountMetricsResourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + if data.Enabled.ValueBool() && (data.AcceptedClientCA.IsNull() || data.AcceptedClientCA.IsUnknown() || data.AcceptedClientCA.ValueString() == "") { + resp.Diagnostics.AddAttributeError( + path.Root("accepted_client_ca"), + "Missing Attribute Configuration", + "Expected accepted_client_ca to be configured when enabled is true", + ) + + return + } +} + +func (r *accountMetricsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan accountMetricsResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + createTimeout, diags := plan.Timeouts.Create(ctx, defaultCreateTimeout) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + accResp, err := r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) + if err != nil { + resp.Diagnostics.AddError("Failed to get account information", err.Error()) + return + } + + ctx, cancel := context.WithTimeout(ctx, createTimeout) + defer cancel() + + metricsReq := &accountservice.UpdateAccountRequest{ + ResourceVersion: accResp.GetAccount().GetResourceVersion(), + Spec: &account.AccountSpec{ + Metrics: &account.MetricsSpec{ + Enabled: plan.Enabled.ValueBool(), + AcceptedClientCa: plan.AcceptedClientCA.ValueString(), + }, + OutputSinks: accResp.GetAccount().GetSpec().GetOutputSinks(), + }, + } + + metricsResp, err := r.accountClient.UpdateAccount(ctx, metricsReq) + if err != nil { + resp.Diagnostics.AddError("Failed to create metrics resource", err.Error()) + return + } + + if err := client.AwaitRequestStatus(ctx, r.requestClient, metricsResp.GetRequestStatus()); err != nil { + resp.Diagnostics.AddError("Failed to create metrics resource", err.Error()) + return + } + + accResp, err = r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) + if err != nil { + resp.Diagnostics.AddError("Failed to get resource state", err.Error()) + return + } + + updateAccountMetricsModelFromSpec(&plan, accResp.GetAccount()) + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} + +func (r *accountMetricsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state accountMetricsResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + accResp, err := r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) + if err != nil { + resp.Diagnostics.AddError("Failed to get account metrics", err.Error()) + return + } + + updateAccountMetricsModelFromSpec(&state, accResp.GetAccount()) + resp.Diagnostics.Append(resp.State.Set(ctx, state)...) +} + +func (r *accountMetricsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan accountMetricsResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + updateTimeout, diags := plan.Timeouts.Create(ctx, defaultCreateTimeout) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + accResp, err := r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) + if err != nil { + resp.Diagnostics.AddError("Failed to get current account metrics status", err.Error()) + return + } + + ctx, cancel := context.WithTimeout(ctx, updateTimeout) + defer cancel() + + metricsReq := &accountservice.UpdateAccountRequest{ + ResourceVersion: accResp.GetAccount().GetResourceVersion(), + Spec: &account.AccountSpec{ + Metrics: &account.MetricsSpec{ + Enabled: plan.Enabled.ValueBool(), + AcceptedClientCa: plan.AcceptedClientCA.ValueString(), + }, + OutputSinks: accResp.GetAccount().GetSpec().GetOutputSinks(), + }, + } + + metricsResp, err := r.accountClient.UpdateAccount(ctx, metricsReq) + if err != nil { + resp.Diagnostics.AddError("Failed to update account metrics", err.Error()) + return + } + + if err := client.AwaitRequestStatus(ctx, r.requestClient, metricsResp.GetRequestStatus()); err != nil { + resp.Diagnostics.AddError("Failed to update account metrics", err.Error()) + return + } + + accResp, err = r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) + if err != nil { + resp.Diagnostics.AddError("Failed to get account metrics after update", err.Error()) + return + } + + updateAccountMetricsModelFromSpec(&plan, accResp.GetAccount()) + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} + +func (r *accountMetricsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state accountMetricsResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + deleteTimeout, diags := state.Timeouts.Delete(ctx, defaultDeleteTimeout) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + accResp, err := r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) + if err != nil { + resp.Diagnostics.AddError("Failed to get current account metrics status", err.Error()) + return + } + + ctx, cancel := context.WithTimeout(ctx, deleteTimeout) + defer cancel() + + metricsReq := &accountservice.UpdateAccountRequest{ + ResourceVersion: accResp.GetAccount().GetResourceVersion(), + Spec: &account.AccountSpec{ + Metrics: &account.MetricsSpec{ + Enabled: false, + }, + OutputSinks: accResp.GetAccount().GetSpec().GetOutputSinks(), + }, + } + + metricsResp, err := r.accountClient.UpdateAccount(ctx, metricsReq) + if err != nil { + resp.Diagnostics.AddError("Failed to delete metrics resource", err.Error()) + return + } + + if err := client.AwaitRequestStatus(ctx, r.requestClient, metricsResp.GetRequestStatus()); err != nil { + resp.Diagnostics.AddError("Failed to delete metrics resource", err.Error()) + return + } +} + +func (r *accountMetricsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func updateAccountMetricsModelFromSpec(state *accountMetricsResourceModel, spec *account.Account) { + state.Enabled = types.BoolValue(spec.GetSpec().GetMetrics().GetEnabled()) + state.AcceptedClientCA = types.StringValue(spec.GetSpec().GetMetrics().GetAcceptedClientCa()) + state.Endpoint = types.StringValue(spec.GetMetrics().GetUri()) + state.ID = types.StringValue("account-metrics") +} diff --git a/internal/provider/account_metrics_resource_test.go b/internal/provider/account_metrics_resource_test.go new file mode 100644 index 0000000..b996ef6 --- /dev/null +++ b/internal/provider/account_metrics_resource_test.go @@ -0,0 +1,44 @@ +package provider + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccBasicAccountMetrics(t *testing.T) { + config := ` +provider "temporalcloud" { + +} + +resource "temporalcloud_account_metrics" "terraform" { + enabled = true + accepted_client_ca = base64encode(< Date: Wed, 24 Apr 2024 09:47:52 -0700 Subject: [PATCH 2/9] add comments --- internal/provider/account_metrics_resource.go | 11 ++++++++++- internal/provider/regions_datasource.go | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/provider/account_metrics_resource.go b/internal/provider/account_metrics_resource.go index 82a5daa..7203f3a 100644 --- a/internal/provider/account_metrics_resource.go +++ b/internal/provider/account_metrics_resource.go @@ -64,10 +64,12 @@ func (r *accountMetricsResource) Configure(_ context.Context, req resource.Confi r.requestClient = clientStore.RequestServiceClient() } +// Metadata returns the resource type name func (r *accountMetricsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "account_metrics" } +// Schema defines the schema for the resource func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Description: "Configures a Temporal Cloud account's metrics", @@ -103,6 +105,7 @@ func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRe } } +// ValidateConfig validates the resource's config func (r *accountMetricsResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { var data accountMetricsResourceModel resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) @@ -121,6 +124,7 @@ func (r *accountMetricsResource) ValidateConfig(ctx context.Context, req resourc } } +// Create creates the resource and sets the initial Terraform state func (r *accountMetricsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan accountMetricsResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) @@ -143,6 +147,7 @@ func (r *accountMetricsResource) Create(ctx context.Context, req resource.Create ctx, cancel := context.WithTimeout(ctx, createTimeout) defer cancel() + // account metrics config always exists, "create" only really sets the state metricsReq := &accountservice.UpdateAccountRequest{ ResourceVersion: accResp.GetAccount().GetResourceVersion(), Spec: &account.AccountSpec{ @@ -175,6 +180,7 @@ func (r *accountMetricsResource) Create(ctx context.Context, req resource.Create resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) } +// Read refreshes the Terraform state with the latest data func (r *accountMetricsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state accountMetricsResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) @@ -191,6 +197,7 @@ func (r *accountMetricsResource) Read(ctx context.Context, req resource.ReadRequ resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } +// Update updates the resource and sets the updated Terraform state on success func (r *accountMetricsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan accountMetricsResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) @@ -245,6 +252,7 @@ func (r *accountMetricsResource) Update(ctx context.Context, req resource.Update resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) } +// Delete deletes the resource and removes the Terraform state on success func (r *accountMetricsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state accountMetricsResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) @@ -266,6 +274,7 @@ func (r *accountMetricsResource) Delete(ctx context.Context, req resource.Delete ctx, cancel := context.WithTimeout(ctx, deleteTimeout) defer cancel() + // can't actually "delete" account metrics config, setting to disabled implicitly is the best equivalent metricsReq := &accountservice.UpdateAccountRequest{ ResourceVersion: accResp.GetAccount().GetResourceVersion(), Spec: &account.AccountSpec{ @@ -296,5 +305,5 @@ func updateAccountMetricsModelFromSpec(state *accountMetricsResourceModel, spec state.Enabled = types.BoolValue(spec.GetSpec().GetMetrics().GetEnabled()) state.AcceptedClientCA = types.StringValue(spec.GetSpec().GetMetrics().GetAcceptedClientCa()) state.Endpoint = types.StringValue(spec.GetMetrics().GetUri()) - state.ID = types.StringValue("account-metrics") + state.ID = types.StringValue("account-metrics") // no real ID to key off of here other than account ID, which is hard to get via the API } diff --git a/internal/provider/regions_datasource.go b/internal/provider/regions_datasource.go index fdc56a4..f3ebefa 100644 --- a/internal/provider/regions_datasource.go +++ b/internal/provider/regions_datasource.go @@ -17,7 +17,7 @@ var ( _ datasource.DataSourceWithConfigure = ®ionsDataSource{} ) -// NewCoffeesDataSource is a helper function to simplify the provider implementation. +// NewRegionsDataSource is a helper function to simplify the provider implementation. func NewRegionsDataSource() datasource.DataSource { return ®ionsDataSource{} } From 852bfa18f01c339aa226240f8e75c9dcfea4d776 Mon Sep 17 00:00:00 2001 From: Enny Frick Date: Wed, 24 Apr 2024 09:48:46 -0700 Subject: [PATCH 3/9] go mod tidy --- go.mod | 4 ++-- go.sum | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 87f6718..e1d95b1 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-testing v1.4.0 github.com/jpillora/maplock v0.0.0-20160420012925-5c725ac6e22a + github.com/temporalio/tcld v0.22.0 google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 google.golang.org/grpc v1.61.1 google.golang.org/protobuf v1.31.0 @@ -30,6 +31,7 @@ require ( github.com/bgentry/speakeasy v0.1.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/fatih/color v1.16.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.4.0 // indirect @@ -66,8 +68,6 @@ require ( github.com/russross/blackfriday v1.6.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect - github.com/temporalio/tcld v0.22.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 7e95f7e..4744e88 100644 --- a/go.sum +++ b/go.sum @@ -47,6 +47,8 @@ github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKn github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -130,6 +132,8 @@ github.com/jpillora/maplock v0.0.0-20160420012925-5c725ac6e22a h1:40K0UjFKjfaXcJ github.com/jpillora/maplock v0.0.0-20160420012925-5c725ac6e22a/go.mod h1:bn3xq9G+QDq2j6fczyaTq47L6980t7/NnqCnCK7kqD0= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -186,17 +190,12 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/temporalio/tcld v0.22.0 h1:6Vf2yV2nOP4mN81bb6QZIM9MZTczovWY9P0k1lb5LYM= github.com/temporalio/tcld v0.22.0/go.mod h1:BESY34o2kPGyAjlMLBhXFvg4n9LrnMOg2SR8Q2biukg= @@ -209,6 +208,8 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -217,6 +218,8 @@ github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBv github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -225,12 +228,16 @@ golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.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.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -240,11 +247,15 @@ golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -276,12 +287,16 @@ 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.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.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= From 1bd09c8cae21fcd0a8a980a2a72458f441b5aa36 Mon Sep 17 00:00:00 2001 From: Enny Frick Date: Wed, 24 Apr 2024 09:49:36 -0700 Subject: [PATCH 4/9] fix schema error --- internal/provider/account_metrics_resource.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/provider/account_metrics_resource.go b/internal/provider/account_metrics_resource.go index 7203f3a..3046356 100644 --- a/internal/provider/account_metrics_resource.go +++ b/internal/provider/account_metrics_resource.go @@ -64,12 +64,12 @@ func (r *accountMetricsResource) Configure(_ context.Context, req resource.Confi r.requestClient = clientStore.RequestServiceClient() } -// Metadata returns the resource type name +// Metadata returns the resource type name. func (r *accountMetricsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "account_metrics" + resp.TypeName = req.ProviderTypeName + "_account_metrics" } -// Schema defines the schema for the resource +// Schema defines the schema for the resource. func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Description: "Configures a Temporal Cloud account's metrics", @@ -87,6 +87,7 @@ func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRe }, "accepted_client_ca": schema.StringAttribute{ Description: "The Base64-encoded CA cert in PEM format used to authenticate clients connecting to the metrics endpoint. Required when enabled is true.", + Optional: true, }, "endpoint": schema.StringAttribute{ Description: "The Prometheus metrics endpoint URI", @@ -105,7 +106,7 @@ func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRe } } -// ValidateConfig validates the resource's config +// ValidateConfig validates the resource's config. func (r *accountMetricsResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { var data accountMetricsResourceModel resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) @@ -124,7 +125,7 @@ func (r *accountMetricsResource) ValidateConfig(ctx context.Context, req resourc } } -// Create creates the resource and sets the initial Terraform state +// Create creates the resource and sets the initial Terraform state. func (r *accountMetricsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan accountMetricsResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) @@ -180,7 +181,7 @@ func (r *accountMetricsResource) Create(ctx context.Context, req resource.Create resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) } -// Read refreshes the Terraform state with the latest data +// Read refreshes the Terraform state with the latest data. func (r *accountMetricsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state accountMetricsResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) @@ -197,7 +198,7 @@ func (r *accountMetricsResource) Read(ctx context.Context, req resource.ReadRequ resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } -// Update updates the resource and sets the updated Terraform state on success +// Update updates the resource and sets the updated Terraform state on success. func (r *accountMetricsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan accountMetricsResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) @@ -252,7 +253,7 @@ func (r *accountMetricsResource) Update(ctx context.Context, req resource.Update resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) } -// Delete deletes the resource and removes the Terraform state on success +// Delete deletes the resource and removes the Terraform state on success. func (r *accountMetricsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state accountMetricsResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) From 6f7bc9479f19cbfc5ffddf781033fcf8eefa3c87 Mon Sep 17 00:00:00 2001 From: Enny Frick Date: Wed, 24 Apr 2024 09:55:19 -0700 Subject: [PATCH 5/9] add example + generate docs --- docs/resources/account_metrics.md | 66 +++++++++++++++++++ .../temporalcloud_account_metrics/ca.pem | 12 ++++ .../temporalcloud_account_metrics/import.sh | 1 + .../temporalcloud_account_metrics/resource.tf | 16 +++++ internal/provider/namespace_resource.go | 2 +- internal/provider/namespace_resource_test.go | 2 +- internal/provider/namespaces_datasource.go | 2 +- internal/provider/provider.go | 6 +- internal/provider/regions_datasource.go | 2 +- 9 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 docs/resources/account_metrics.md create mode 100644 examples/resources/temporalcloud_account_metrics/ca.pem create mode 100644 examples/resources/temporalcloud_account_metrics/import.sh create mode 100644 examples/resources/temporalcloud_account_metrics/resource.tf diff --git a/docs/resources/account_metrics.md b/docs/resources/account_metrics.md new file mode 100644 index 0000000..248851a --- /dev/null +++ b/docs/resources/account_metrics.md @@ -0,0 +1,66 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "temporalcloud_account_metrics Resource - terraform-provider-temporalcloud" +subcategory: "" +description: |- + Configures a Temporal Cloud account's metrics +--- + +# temporalcloud_account_metrics (Resource) + +Configures a Temporal Cloud account's metrics + +## Example Usage + +```terraform +terraform { + required_providers { + temporalcloud = { + source = "temporalio/temporalcloud" + } + } +} + +provider "temporalcloud" { + +} + +resource "temporalcloud_account_metrics" "terraform" { + enabled = true + accepted_client_ca = base64encode(file("${path.module}/ca.pem")) +} +``` + + +## Schema + +### Required + +- `enabled` (Boolean) If true, enables metrics for the account + +### Optional + +- `accepted_client_ca` (String) The Base64-encoded CA cert in PEM format used to authenticate clients connecting to the metrics endpoint. Required when enabled is true. +- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) + +### Read-Only + +- `endpoint` (String) The Prometheus metrics endpoint URI +- `id` (String) A unique identifier for the account's metrics configuration + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). +- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs. +- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). + +## Import + +Import is supported using the following syntax: + +```shell +terraform import temporalcloud_namespace.terraform terraform.account-metrics +``` diff --git a/examples/resources/temporalcloud_account_metrics/ca.pem b/examples/resources/temporalcloud_account_metrics/ca.pem new file mode 100644 index 0000000..453649e --- /dev/null +++ b/examples/resources/temporalcloud_account_metrics/ca.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIByTCCAVCgAwIBAgIRAWHkC+6JUf3s9Tq43mdp2zgwCgYIKoZIzj0EAwMwEzER +MA8GA1UEChMIdGVtcG9yYWwwHhcNMjMwODEwMDAwOTQ1WhcNMjQwODA5MDAxMDQ1 +WjATMREwDwYDVQQKEwh0ZW1wb3JhbDB2MBAGByqGSM49AgEGBSuBBAAiA2IABCzQ +7DwwGSQKM6Zrx3Qtw7IubfxiJ3RSXCqmcGhEbFVeocwAdEgMYlwSlUiWtDZVR2dM +XM9UZLWK4aGGnDNS5Mhcz6ibSBS7Owf4tRZZA9SpFCjNw2HraaiUVV+EUgxoe6No +MGYwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFG4N +8lIXqQKxwVs/ixVzdF6XGZm+MCQGA1UdEQQdMBuCGWNsaWVudC5yb290LnRlbXBv +cmFsLlB1VHMwCgYIKoZIzj0EAwMDZwAwZAIwRLfm9S7rKGd30KdQvUMcOcDJlmDw +6/oM6UOJFxLeGcpYbgxQ/bFize+Yx9Q9kNeMAjA7GiFsaipaKtWHy5MCOCas3ZP6 ++ttLaXNXss3Z5Wk5vhDQnyE8JR3rPeQ2cHXLiA0= +-----END CERTIFICATE----- diff --git a/examples/resources/temporalcloud_account_metrics/import.sh b/examples/resources/temporalcloud_account_metrics/import.sh new file mode 100644 index 0000000..df798c1 --- /dev/null +++ b/examples/resources/temporalcloud_account_metrics/import.sh @@ -0,0 +1 @@ +terraform import temporalcloud_namespace.terraform terraform.account-metrics \ No newline at end of file diff --git a/examples/resources/temporalcloud_account_metrics/resource.tf b/examples/resources/temporalcloud_account_metrics/resource.tf new file mode 100644 index 0000000..3963010 --- /dev/null +++ b/examples/resources/temporalcloud_account_metrics/resource.tf @@ -0,0 +1,16 @@ +terraform { + required_providers { + temporalcloud = { + source = "temporalio/temporalcloud" + } + } +} + +provider "temporalcloud" { + +} + +resource "temporalcloud_account_metrics" "terraform" { + enabled = true + accepted_client_ca = base64encode(file("${path.module}/ca.pem")) +} \ No newline at end of file diff --git a/internal/provider/namespace_resource.go b/internal/provider/namespace_resource.go index 586f80e..7970998 100644 --- a/internal/provider/namespace_resource.go +++ b/internal/provider/namespace_resource.go @@ -174,7 +174,7 @@ func (r *namespaceResource) Schema(ctx context.Context, _ resource.SchemaRequest Required: true, }, "certificate_filters": schema.ListNestedAttribute{ - Description: "A list of filters to apply to client certificates when initiating a connection Temporal Cloud. If present, connections will only be allowed from accountClient certificates whose distinguished name properties match at least one of the filters.", + Description: "A list of filters to apply to client certificates when initiating a connection Temporal Cloud. If present, connections will only be allowed from client certificates whose distinguished name properties match at least one of the filters.", Optional: true, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ diff --git a/internal/provider/namespace_resource_test.go b/internal/provider/namespace_resource_test.go index 931722c..955c70c 100644 --- a/internal/provider/namespace_resource_test.go +++ b/internal/provider/namespace_resource_test.go @@ -354,7 +354,7 @@ func newConnection(t *testing.T) cloudservicev1.CloudServiceClient { client, err := client.NewConnectionWithAPIKey(endpoint, allowInsecure, apiKey) if err != nil { - t.Fatalf("Failed to create accountClient: %v", err) + t.Fatalf("Failed to create client: %v", err) } return client.CloudServiceClient() diff --git a/internal/provider/namespaces_datasource.go b/internal/provider/namespaces_datasource.go index a6508ef..90594fc 100644 --- a/internal/provider/namespaces_datasource.go +++ b/internal/provider/namespaces_datasource.go @@ -158,7 +158,7 @@ func (d *namespacesDataSource) Schema(_ context.Context, _ datasource.SchemaRequ "certificate_filters": schema.ListNestedAttribute{ Computed: true, Optional: true, - Description: "A list of filters to apply to accountClient certificates when initiating a connection Temporal Cloud. If present, connections will only be allowed from accountClient certificates whose distinguished name properties match at least one of the filters.", + Description: "A list of filters to apply to client certificates when initiating a connection Temporal Cloud. If present, connections will only be allowed from client certificates whose distinguished name properties match at least one of the filters.", NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "common_name": schema.StringAttribute{ diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 14dad6e..b65dbce 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -84,7 +84,7 @@ func (p *TerraformCloudProvider) Configure(ctx context.Context, req provider.Con resp.Diagnostics.AddAttributeError( path.Root("api_key"), "Unknown Terraform Cloud API Key", - "The provider cannot create a Terraform Cloud API accountClient as there is an unknown configuration value for the Temporal Cloud API Key."+ + "The provider cannot create a Terraform Cloud API client as there is an unknown configuration value for the Temporal Cloud API Key."+ " Either apply the source of the value first, or statically set the API Key via environment variable or in configuration.") return } @@ -93,7 +93,7 @@ func (p *TerraformCloudProvider) Configure(ctx context.Context, req provider.Con resp.Diagnostics.AddAttributeError( path.Root("endpoint"), "Unknown Terraform Cloud Endpoint", - "The provider cannot create a Terraform Cloud API accountClient as there is an unknown configuration value for the Temporal Cloud API Endpoint."+ + "The provider cannot create a Terraform Cloud API client as there is an unknown configuration value for the Temporal Cloud API Endpoint."+ " Either apply the source of the value first, or statically set the API Key via environment variable or in configuration.") } @@ -101,7 +101,7 @@ func (p *TerraformCloudProvider) Configure(ctx context.Context, req provider.Con resp.Diagnostics.AddAttributeError( path.Root("allow_insecure"), "Unknown Terraform Cloud Endpoint", - "The provider cannot create a Terraform Cloud API accountClient as there is an unknown configuration value for `allow_insecure`."+ + "The provider cannot create a Terraform Cloud API client as there is an unknown configuration value for `allow_insecure`."+ " Either apply the source of the value first, or statically set the API Key via environment variable or in configuration.") } diff --git a/internal/provider/regions_datasource.go b/internal/provider/regions_datasource.go index f3ebefa..26420db 100644 --- a/internal/provider/regions_datasource.go +++ b/internal/provider/regions_datasource.go @@ -41,7 +41,7 @@ type ( } ) -// Configure adds the provider configured accountClient to the data source. +// Configure adds the provider configured client to the data source. func (d *regionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { if req.ProviderData == nil { return From 32f5e5051d6cdb7ab9524588bae1f76f243841fe Mon Sep 17 00:00:00 2001 From: Enny Frick Date: Wed, 24 Apr 2024 14:31:17 -0700 Subject: [PATCH 6/9] rename account_metrics resource to metrics_endpoint resource + refactor schema --- ...account_metrics.md => metrics_endpoint.md} | 14 +-- .../temporalcloud_account_metrics/import.sh | 1 - .../ca.pem | 0 .../temporalcloud_metrics_endpoint/import.sh | 1 + .../resource.tf | 3 +- ...source.go => metrics_endpoint_resource.go} | 106 +++++++----------- ...t.go => metrics_endpoint_resource_test.go} | 0 internal/provider/provider.go | 2 +- 8 files changed, 49 insertions(+), 78 deletions(-) rename docs/resources/{account_metrics.md => metrics_endpoint.md} (80%) delete mode 100644 examples/resources/temporalcloud_account_metrics/import.sh rename examples/resources/{temporalcloud_account_metrics => temporalcloud_metrics_endpoint}/ca.pem (100%) create mode 100644 examples/resources/temporalcloud_metrics_endpoint/import.sh rename examples/resources/{temporalcloud_account_metrics => temporalcloud_metrics_endpoint}/resource.tf (71%) rename internal/provider/{account_metrics_resource.go => metrics_endpoint_resource.go} (63%) rename internal/provider/{account_metrics_resource_test.go => metrics_endpoint_resource_test.go} (100%) diff --git a/docs/resources/account_metrics.md b/docs/resources/metrics_endpoint.md similarity index 80% rename from docs/resources/account_metrics.md rename to docs/resources/metrics_endpoint.md index 248851a..72e6c29 100644 --- a/docs/resources/account_metrics.md +++ b/docs/resources/metrics_endpoint.md @@ -1,12 +1,12 @@ --- # generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "temporalcloud_account_metrics Resource - terraform-provider-temporalcloud" +page_title: "temporalcloud_metrics_endpoint Resource - terraform-provider-temporalcloud" subcategory: "" description: |- Configures a Temporal Cloud account's metrics --- -# temporalcloud_account_metrics (Resource) +# temporalcloud_metrics_endpoint (Resource) Configures a Temporal Cloud account's metrics @@ -25,8 +25,7 @@ provider "temporalcloud" { } -resource "temporalcloud_account_metrics" "terraform" { - enabled = true +resource "temporalcloud_metrics_endpoint" "terraform" { accepted_client_ca = base64encode(file("${path.module}/ca.pem")) } ``` @@ -36,17 +35,16 @@ resource "temporalcloud_account_metrics" "terraform" { ### Required -- `enabled` (Boolean) If true, enables metrics for the account +- `accepted_client_ca` (String) The Base64-encoded CA cert in PEM format used to authenticate clients connecting to the metrics endpoint. ### Optional -- `accepted_client_ca` (String) The Base64-encoded CA cert in PEM format used to authenticate clients connecting to the metrics endpoint. Required when enabled is true. - `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) ### Read-Only -- `endpoint` (String) The Prometheus metrics endpoint URI - `id` (String) A unique identifier for the account's metrics configuration +- `uri` (String) The Prometheus metrics endpoint URI ### Nested Schema for `timeouts` @@ -62,5 +60,5 @@ Optional: Import is supported using the following syntax: ```shell -terraform import temporalcloud_namespace.terraform terraform.account-metrics +terraform import temporalcloud_metrics_endpoint.terraform terraform.account-metrics ``` diff --git a/examples/resources/temporalcloud_account_metrics/import.sh b/examples/resources/temporalcloud_account_metrics/import.sh deleted file mode 100644 index df798c1..0000000 --- a/examples/resources/temporalcloud_account_metrics/import.sh +++ /dev/null @@ -1 +0,0 @@ -terraform import temporalcloud_namespace.terraform terraform.account-metrics \ No newline at end of file diff --git a/examples/resources/temporalcloud_account_metrics/ca.pem b/examples/resources/temporalcloud_metrics_endpoint/ca.pem similarity index 100% rename from examples/resources/temporalcloud_account_metrics/ca.pem rename to examples/resources/temporalcloud_metrics_endpoint/ca.pem diff --git a/examples/resources/temporalcloud_metrics_endpoint/import.sh b/examples/resources/temporalcloud_metrics_endpoint/import.sh new file mode 100644 index 0000000..03e405a --- /dev/null +++ b/examples/resources/temporalcloud_metrics_endpoint/import.sh @@ -0,0 +1 @@ +terraform import temporalcloud_metrics_endpoint.terraform terraform.account-metrics \ No newline at end of file diff --git a/examples/resources/temporalcloud_account_metrics/resource.tf b/examples/resources/temporalcloud_metrics_endpoint/resource.tf similarity index 71% rename from examples/resources/temporalcloud_account_metrics/resource.tf rename to examples/resources/temporalcloud_metrics_endpoint/resource.tf index 3963010..1116a9a 100644 --- a/examples/resources/temporalcloud_account_metrics/resource.tf +++ b/examples/resources/temporalcloud_metrics_endpoint/resource.tf @@ -10,7 +10,6 @@ provider "temporalcloud" { } -resource "temporalcloud_account_metrics" "terraform" { - enabled = true +resource "temporalcloud_metrics_endpoint" "terraform" { accepted_client_ca = base64encode(file("${path.module}/ca.pem")) } \ No newline at end of file diff --git a/internal/provider/account_metrics_resource.go b/internal/provider/metrics_endpoint_resource.go similarity index 63% rename from internal/provider/account_metrics_resource.go rename to internal/provider/metrics_endpoint_resource.go index 3046356..7545c97 100644 --- a/internal/provider/account_metrics_resource.go +++ b/internal/provider/metrics_endpoint_resource.go @@ -19,33 +19,31 @@ import ( ) type ( - accountMetricsResource struct { + metricsEndpointResource struct { accountClient accountservice.AccountServiceClient requestClient requestservice.RequestServiceClient } - accountMetricsResourceModel struct { + metricsEndpointResourceModel struct { ID types.String `tfsdk:"id"` - Enabled types.Bool `tfsdk:"enabled"` AcceptedClientCA types.String `tfsdk:"accepted_client_ca"` - Endpoint types.String `tfsdk:"endpoint"` + Uri types.String `tfsdk:"uri"` Timeouts timeouts.Value `tfsdk:"timeouts"` } ) var ( - _ resource.Resource = (*accountMetricsResource)(nil) - _ resource.ResourceWithConfigure = (*accountMetricsResource)(nil) - _ resource.ResourceWithImportState = (*accountMetricsResource)(nil) - _ resource.ResourceWithValidateConfig = (*accountMetricsResource)(nil) + _ resource.Resource = (*metricsEndpointResource)(nil) + _ resource.ResourceWithConfigure = (*metricsEndpointResource)(nil) + _ resource.ResourceWithImportState = (*metricsEndpointResource)(nil) ) -func NewAccountMetricsResource() resource.Resource { - return &accountMetricsResource{} +func NewMetricsEndpointResource() resource.Resource { + return &metricsEndpointResource{} } -func (r *accountMetricsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *metricsEndpointResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { if req.ProviderData == nil { return } @@ -65,12 +63,12 @@ func (r *accountMetricsResource) Configure(_ context.Context, req resource.Confi } // Metadata returns the resource type name. -func (r *accountMetricsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_account_metrics" +func (r *metricsEndpointResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_metrics_endpoint" } // Schema defines the schema for the resource. -func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *metricsEndpointResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Description: "Configures a Temporal Cloud account's metrics", Attributes: map[string]schema.Attribute{ @@ -81,15 +79,11 @@ func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRe stringplanmodifier.UseStateForUnknown(), }, }, - "enabled": schema.BoolAttribute{ - Description: "If true, enables metrics for the account", - Required: true, - }, "accepted_client_ca": schema.StringAttribute{ - Description: "The Base64-encoded CA cert in PEM format used to authenticate clients connecting to the metrics endpoint. Required when enabled is true.", - Optional: true, + Description: "The Base64-encoded CA cert in PEM format used to authenticate clients connecting to the metrics endpoint.", + Required: true, }, - "endpoint": schema.StringAttribute{ + "uri": schema.StringAttribute{ Description: "The Prometheus metrics endpoint URI", Computed: true, }, @@ -106,28 +100,9 @@ func (r *accountMetricsResource) Schema(ctx context.Context, _ resource.SchemaRe } } -// ValidateConfig validates the resource's config. -func (r *accountMetricsResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - var data accountMetricsResourceModel - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if resp.Diagnostics.HasError() { - return - } - - if data.Enabled.ValueBool() && (data.AcceptedClientCA.IsNull() || data.AcceptedClientCA.IsUnknown() || data.AcceptedClientCA.ValueString() == "") { - resp.Diagnostics.AddAttributeError( - path.Root("accepted_client_ca"), - "Missing Attribute Configuration", - "Expected accepted_client_ca to be configured when enabled is true", - ) - - return - } -} - // Create creates the resource and sets the initial Terraform state. -func (r *accountMetricsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var plan accountMetricsResourceModel +func (r *metricsEndpointResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan metricsEndpointResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) if resp.Diagnostics.HasError() { return @@ -148,12 +123,12 @@ func (r *accountMetricsResource) Create(ctx context.Context, req resource.Create ctx, cancel := context.WithTimeout(ctx, createTimeout) defer cancel() - // account metrics config always exists, "create" only really sets the state + // create just flips "enabled" to true metricsReq := &accountservice.UpdateAccountRequest{ ResourceVersion: accResp.GetAccount().GetResourceVersion(), Spec: &account.AccountSpec{ Metrics: &account.MetricsSpec{ - Enabled: plan.Enabled.ValueBool(), + Enabled: true, AcceptedClientCa: plan.AcceptedClientCA.ValueString(), }, OutputSinks: accResp.GetAccount().GetSpec().GetOutputSinks(), @@ -162,12 +137,12 @@ func (r *accountMetricsResource) Create(ctx context.Context, req resource.Create metricsResp, err := r.accountClient.UpdateAccount(ctx, metricsReq) if err != nil { - resp.Diagnostics.AddError("Failed to create metrics resource", err.Error()) + resp.Diagnostics.AddError("Failed to create metrics endpoint resource", err.Error()) return } if err := client.AwaitRequestStatus(ctx, r.requestClient, metricsResp.GetRequestStatus()); err != nil { - resp.Diagnostics.AddError("Failed to create metrics resource", err.Error()) + resp.Diagnostics.AddError("Failed to create metrics endpoint resource", err.Error()) return } @@ -182,15 +157,15 @@ func (r *accountMetricsResource) Create(ctx context.Context, req resource.Create } // Read refreshes the Terraform state with the latest data. -func (r *accountMetricsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state accountMetricsResourceModel +func (r *metricsEndpointResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state metricsEndpointResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return } accResp, err := r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) if err != nil { - resp.Diagnostics.AddError("Failed to get account metrics", err.Error()) + resp.Diagnostics.AddError("Failed to get metrics endpoint", err.Error()) return } @@ -199,8 +174,8 @@ func (r *accountMetricsResource) Read(ctx context.Context, req resource.ReadRequ } // Update updates the resource and sets the updated Terraform state on success. -func (r *accountMetricsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var plan accountMetricsResourceModel +func (r *metricsEndpointResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan metricsEndpointResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) if resp.Diagnostics.HasError() { return @@ -214,7 +189,7 @@ func (r *accountMetricsResource) Update(ctx context.Context, req resource.Update accResp, err := r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) if err != nil { - resp.Diagnostics.AddError("Failed to get current account metrics status", err.Error()) + resp.Diagnostics.AddError("Failed to get current metrics endpoint status", err.Error()) return } @@ -225,7 +200,7 @@ func (r *accountMetricsResource) Update(ctx context.Context, req resource.Update ResourceVersion: accResp.GetAccount().GetResourceVersion(), Spec: &account.AccountSpec{ Metrics: &account.MetricsSpec{ - Enabled: plan.Enabled.ValueBool(), + Enabled: accResp.GetAccount().GetSpec().GetMetrics().GetEnabled(), AcceptedClientCa: plan.AcceptedClientCA.ValueString(), }, OutputSinks: accResp.GetAccount().GetSpec().GetOutputSinks(), @@ -234,18 +209,18 @@ func (r *accountMetricsResource) Update(ctx context.Context, req resource.Update metricsResp, err := r.accountClient.UpdateAccount(ctx, metricsReq) if err != nil { - resp.Diagnostics.AddError("Failed to update account metrics", err.Error()) + resp.Diagnostics.AddError("Failed to update metrics endpoint endpoint", err.Error()) return } if err := client.AwaitRequestStatus(ctx, r.requestClient, metricsResp.GetRequestStatus()); err != nil { - resp.Diagnostics.AddError("Failed to update account metrics", err.Error()) + resp.Diagnostics.AddError("Failed to update metrics endpoint endpoint", err.Error()) return } accResp, err = r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) if err != nil { - resp.Diagnostics.AddError("Failed to get account metrics after update", err.Error()) + resp.Diagnostics.AddError("Failed to get metrics endpoint after update", err.Error()) return } @@ -254,8 +229,8 @@ func (r *accountMetricsResource) Update(ctx context.Context, req resource.Update } // Delete deletes the resource and removes the Terraform state on success. -func (r *accountMetricsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var state accountMetricsResourceModel +func (r *metricsEndpointResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state metricsEndpointResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return @@ -268,14 +243,14 @@ func (r *accountMetricsResource) Delete(ctx context.Context, req resource.Delete accResp, err := r.accountClient.GetAccount(ctx, &accountservice.GetAccountRequest{}) if err != nil { - resp.Diagnostics.AddError("Failed to get current account metrics status", err.Error()) + resp.Diagnostics.AddError("Failed to get current metrics endpoint status", err.Error()) return } ctx, cancel := context.WithTimeout(ctx, deleteTimeout) defer cancel() - // can't actually "delete" account metrics config, setting to disabled implicitly is the best equivalent + // can't actually "delete" account metrics config, setting to disabled is the best equivalent metricsReq := &accountservice.UpdateAccountRequest{ ResourceVersion: accResp.GetAccount().GetResourceVersion(), Spec: &account.AccountSpec{ @@ -288,23 +263,22 @@ func (r *accountMetricsResource) Delete(ctx context.Context, req resource.Delete metricsResp, err := r.accountClient.UpdateAccount(ctx, metricsReq) if err != nil { - resp.Diagnostics.AddError("Failed to delete metrics resource", err.Error()) + resp.Diagnostics.AddError("Failed to delete metrics endpoint resource", err.Error()) return } if err := client.AwaitRequestStatus(ctx, r.requestClient, metricsResp.GetRequestStatus()); err != nil { - resp.Diagnostics.AddError("Failed to delete metrics resource", err.Error()) + resp.Diagnostics.AddError("Failed to delete metrics endpoint resource", err.Error()) return } } -func (r *accountMetricsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *metricsEndpointResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } -func updateAccountMetricsModelFromSpec(state *accountMetricsResourceModel, spec *account.Account) { - state.Enabled = types.BoolValue(spec.GetSpec().GetMetrics().GetEnabled()) +func updateAccountMetricsModelFromSpec(state *metricsEndpointResourceModel, spec *account.Account) { state.AcceptedClientCA = types.StringValue(spec.GetSpec().GetMetrics().GetAcceptedClientCa()) - state.Endpoint = types.StringValue(spec.GetMetrics().GetUri()) + state.Uri = types.StringValue(spec.GetMetrics().GetUri()) state.ID = types.StringValue("account-metrics") // no real ID to key off of here other than account ID, which is hard to get via the API } diff --git a/internal/provider/account_metrics_resource_test.go b/internal/provider/metrics_endpoint_resource_test.go similarity index 100% rename from internal/provider/account_metrics_resource_test.go rename to internal/provider/metrics_endpoint_resource_test.go diff --git a/internal/provider/provider.go b/internal/provider/provider.go index b65dbce..6eb317c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -138,7 +138,7 @@ func (p *TerraformCloudProvider) Resources(ctx context.Context) []func() resourc NewNamespaceResource, NewNamespaceSearchAttributeResource, NewUserResource, - NewAccountMetricsResource, + NewMetricsEndpointResource, } } From de12b76f9e3d2e4f580513c1cadcce988d3bc314 Mon Sep 17 00:00:00 2001 From: Enny Frick Date: Mon, 29 Apr 2024 16:57:16 -0700 Subject: [PATCH 7/9] fix metric endpoint test --- internal/provider/metrics_endpoint_resource_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/provider/metrics_endpoint_resource_test.go b/internal/provider/metrics_endpoint_resource_test.go index b996ef6..4bd33da 100644 --- a/internal/provider/metrics_endpoint_resource_test.go +++ b/internal/provider/metrics_endpoint_resource_test.go @@ -13,7 +13,6 @@ provider "temporalcloud" { } resource "temporalcloud_account_metrics" "terraform" { - enabled = true accepted_client_ca = base64encode(< Date: Tue, 25 Jun 2024 12:08:08 -0700 Subject: [PATCH 8/9] fix configure type error --- internal/provider/metrics_endpoint_resource.go | 6 +++--- internal/provider/namespace_resource.go | 6 +++--- internal/provider/namespace_search_attribute_resource.go | 6 +++--- internal/provider/namespaces_datasource.go | 4 ++-- internal/provider/regions_datasource.go | 4 ++-- internal/provider/user_resource.go | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/provider/metrics_endpoint_resource.go b/internal/provider/metrics_endpoint_resource.go index 7545c97..8c88d73 100644 --- a/internal/provider/metrics_endpoint_resource.go +++ b/internal/provider/metrics_endpoint_resource.go @@ -48,11 +48,11 @@ func (r *metricsEndpointResource) Configure(_ context.Context, req resource.Conf return } - clientStore, ok := req.ProviderData.(client.ClientStore) + clientStore, ok := req.ProviderData.(*client.ClientStore) if !ok { resp.Diagnostics.AddError( - "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected client.CloudClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/namespace_resource.go b/internal/provider/namespace_resource.go index 7970998..68ca772 100644 --- a/internal/provider/namespace_resource.go +++ b/internal/provider/namespace_resource.go @@ -120,11 +120,11 @@ func (r *namespaceResource) Configure(_ context.Context, req resource.ConfigureR return } - clientStore, ok := req.ProviderData.(client.ClientStore) + clientStore, ok := req.ProviderData.(*client.ClientStore) if !ok { resp.Diagnostics.AddError( - "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected client.CloudClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/namespace_search_attribute_resource.go b/internal/provider/namespace_search_attribute_resource.go index 4a23489..9523d99 100644 --- a/internal/provider/namespace_search_attribute_resource.go +++ b/internal/provider/namespace_search_attribute_resource.go @@ -52,11 +52,11 @@ func (r *namespaceSearchAttributeResource) Configure(_ context.Context, req reso return } - clientStore, ok := req.ProviderData.(client.ClientStore) + clientStore, ok := req.ProviderData.(*client.ClientStore) if !ok { resp.Diagnostics.AddError( - "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected cloudservicev1.CloudServiceClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/namespaces_datasource.go b/internal/provider/namespaces_datasource.go index 90594fc..cadd0ed 100644 --- a/internal/provider/namespaces_datasource.go +++ b/internal/provider/namespaces_datasource.go @@ -99,11 +99,11 @@ func (d *namespacesDataSource) Configure(_ context.Context, req datasource.Confi return } - clientStore, ok := req.ProviderData.(client.ClientStore) + clientStore, ok := req.ProviderData.(*client.ClientStore) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected cloudservicev1.CloudServiceClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/regions_datasource.go b/internal/provider/regions_datasource.go index 26420db..11856ef 100644 --- a/internal/provider/regions_datasource.go +++ b/internal/provider/regions_datasource.go @@ -47,11 +47,11 @@ func (d *regionsDataSource) Configure(_ context.Context, req datasource.Configur return } - clientStore, ok := req.ProviderData.(client.ClientStore) + clientStore, ok := req.ProviderData.(*client.ClientStore) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected cloudservicev1.CloudServiceClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.ClientStore,, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/user_resource.go b/internal/provider/user_resource.go index eadba1f..5b71222 100644 --- a/internal/provider/user_resource.go +++ b/internal/provider/user_resource.go @@ -64,11 +64,11 @@ func (r *userResource) Configure(_ context.Context, req resource.ConfigureReques return } - clientStore, ok := req.ProviderData.(client.ClientStore) + clientStore, ok := req.ProviderData.(*client.ClientStore) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected cloudservicev1.CloudServiceClient, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return From 1c1a4e672ec4629f3c1bd95fd2a020b418f73c94 Mon Sep 17 00:00:00 2001 From: "Enny J. Frick" Date: Wed, 26 Jun 2024 10:17:47 -0700 Subject: [PATCH 9/9] rename ClientStore --- internal/client/client.go | 34 ++++++++++++------- .../provider/metrics_endpoint_resource.go | 4 +-- internal/provider/namespace_resource.go | 4 +-- .../namespace_search_attribute_resource.go | 4 +-- internal/provider/namespaces_datasource.go | 4 +-- internal/provider/regions_datasource.go | 4 +-- internal/provider/user_resource.go | 4 +-- 7 files changed, 34 insertions(+), 24 deletions(-) diff --git a/internal/client/client.go b/internal/client/client.go index 87ba78a..383ef04 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -28,7 +28,7 @@ import ( "errors" "fmt" "net/url" - "strings" + "regexp" "time" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -44,30 +44,36 @@ import ( operationv1 "github.com/temporalio/terraform-provider-temporalcloud/proto/go/temporal/api/cloud/operation/v1" ) -const TemporalCloudAPIVersionHeader = "temporal-cloud-api-version" +const ( + TemporalCloudAPIVersionHeader = "temporal-cloud-api-version" + LegacyTemporalCloudAPIVersion = "2024-03-18-00" + TemporalCloudAPIVersion = "2024-05-13-00" +) -var TemporalCloudAPIVersion = "2023-10-01-00" +var ( + TemporalCloudAPIMethodRegex = regexp.MustCompile(`^\/temporal\.api\.cloud\.cloudservice\.v1\.CloudService\/[^\/]*$`) +) -// ClientStore is a client for the Temporal Cloud API. -type ClientStore struct { +// Store is a client for the Temporal Cloud API. +type Store struct { c cloudservicev1.CloudServiceClient a accountservice.AccountServiceClient r requestservice.RequestServiceClient } -func (c *ClientStore) CloudServiceClient() cloudservicev1.CloudServiceClient { +func (c *Store) CloudServiceClient() cloudservicev1.CloudServiceClient { return c.c } -func (c *ClientStore) AccountServiceClient() accountservice.AccountServiceClient { +func (c *Store) AccountServiceClient() accountservice.AccountServiceClient { return c.a } -func (c *ClientStore) RequestServiceClient() requestservice.RequestServiceClient { +func (c *Store) RequestServiceClient() requestservice.RequestServiceClient { return c.r } -func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, opts ...grpc.DialOption) (*ClientStore, error) { +func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, opts ...grpc.DialOption) (*Store, error) { return newConnection( addrStr, allowInsecure, @@ -75,7 +81,7 @@ func NewConnectionWithAPIKey(addrStr string, allowInsecure bool, apiKey string, ) } -func newConnection(addrStr string, allowInsecure bool, opts ...grpc.DialOption) (*ClientStore, error) { +func newConnection(addrStr string, allowInsecure bool, opts ...grpc.DialOption) (*Store, error) { addr, err := url.Parse(addrStr) if err != nil { return nil, fmt.Errorf("unable to parse server address: %s", err) @@ -92,7 +98,7 @@ func newConnection(addrStr string, allowInsecure bool, opts ...grpc.DialOption) cloudClient := cloudservicev1.NewCloudServiceClient(conn) accountClient := accountservice.NewAccountServiceClient(conn) reqClient := requestservice.NewRequestServiceClient(conn) - return &ClientStore{c: cloudClient, a: accountClient, r: reqClient}, nil + return &Store{c: cloudClient, a: accountClient, r: reqClient}, nil } func AwaitAsyncOperation(ctx context.Context, client cloudservicev1.CloudServiceClient, op *operationv1.AsyncOperation) error { @@ -220,6 +226,10 @@ func setAPIVersionInterceptor( invoker grpc.UnaryInvoker, opts ...grpc.CallOption, ) error { - ctx = metadata.AppendToOutgoingContext(ctx, TemporalCloudAPIVersionHeader, strings.TrimSpace(TemporalCloudAPIVersion)) + if TemporalCloudAPIMethodRegex.MatchString(method) { + ctx = metadata.AppendToOutgoingContext(ctx, TemporalCloudAPIVersionHeader, TemporalCloudAPIVersion) + } else { + ctx = metadata.AppendToOutgoingContext(ctx, TemporalCloudAPIVersionHeader, LegacyTemporalCloudAPIVersion) + } return invoker(ctx, method, req, reply, cc, opts...) } diff --git a/internal/provider/metrics_endpoint_resource.go b/internal/provider/metrics_endpoint_resource.go index 8c88d73..f7a4261 100644 --- a/internal/provider/metrics_endpoint_resource.go +++ b/internal/provider/metrics_endpoint_resource.go @@ -48,11 +48,11 @@ func (r *metricsEndpointResource) Configure(_ context.Context, req resource.Conf return } - clientStore, ok := req.ProviderData.(*client.ClientStore) + clientStore, ok := req.ProviderData.(*client.Store) if !ok { resp.Diagnostics.AddError( "Unexpected Resource Configure Type", - fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.Store, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/namespace_resource.go b/internal/provider/namespace_resource.go index 68ca772..ba53497 100644 --- a/internal/provider/namespace_resource.go +++ b/internal/provider/namespace_resource.go @@ -120,11 +120,11 @@ func (r *namespaceResource) Configure(_ context.Context, req resource.ConfigureR return } - clientStore, ok := req.ProviderData.(*client.ClientStore) + clientStore, ok := req.ProviderData.(*client.Store) if !ok { resp.Diagnostics.AddError( "Unexpected Resource Configure Type", - fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.Store, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/namespace_search_attribute_resource.go b/internal/provider/namespace_search_attribute_resource.go index 9523d99..07c8377 100644 --- a/internal/provider/namespace_search_attribute_resource.go +++ b/internal/provider/namespace_search_attribute_resource.go @@ -52,11 +52,11 @@ func (r *namespaceSearchAttributeResource) Configure(_ context.Context, req reso return } - clientStore, ok := req.ProviderData.(*client.ClientStore) + clientStore, ok := req.ProviderData.(*client.Store) if !ok { resp.Diagnostics.AddError( "Unexpected Resource Configure Type", - fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.Store, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/namespaces_datasource.go b/internal/provider/namespaces_datasource.go index cadd0ed..8862de6 100644 --- a/internal/provider/namespaces_datasource.go +++ b/internal/provider/namespaces_datasource.go @@ -99,11 +99,11 @@ func (d *namespacesDataSource) Configure(_ context.Context, req datasource.Confi return } - clientStore, ok := req.ProviderData.(*client.ClientStore) + clientStore, ok := req.ProviderData.(*client.Store) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.Store, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/regions_datasource.go b/internal/provider/regions_datasource.go index 11856ef..ef6fe09 100644 --- a/internal/provider/regions_datasource.go +++ b/internal/provider/regions_datasource.go @@ -47,11 +47,11 @@ func (d *regionsDataSource) Configure(_ context.Context, req datasource.Configur return } - clientStore, ok := req.ProviderData.(*client.ClientStore) + clientStore, ok := req.ProviderData.(*client.Store) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *client.ClientStore,, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.Store,, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return diff --git a/internal/provider/user_resource.go b/internal/provider/user_resource.go index 5b71222..4a2de39 100644 --- a/internal/provider/user_resource.go +++ b/internal/provider/user_resource.go @@ -64,11 +64,11 @@ func (r *userResource) Configure(_ context.Context, req resource.ConfigureReques return } - clientStore, ok := req.ProviderData.(*client.ClientStore) + clientStore, ok := req.ProviderData.(*client.Store) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *client.ClientStore, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *client.Store, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return