diff --git a/CHANGELOG.md b/CHANGELOG.md index 6470ae10..5964958e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.5.0] - 2024-04-12 + +## Added + +- New `cockroach_metric_export_prometheus_config` resource allows user to configure prometheus metric + export integration in AWS and GCP cloud providers. + ## [1.4.1] - 2024-04-04 ## Added diff --git a/docs/resources/metric_export_prometheus_config.md b/docs/resources/metric_export_prometheus_config.md new file mode 100644 index 00000000..6c2b3296 --- /dev/null +++ b/docs/resources/metric_export_prometheus_config.md @@ -0,0 +1,35 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "cockroach_metric_export_prometheus_config Resource - terraform-provider-cockroach" +subcategory: "" +description: |- + Prometheus metric export configuration for a cluster. +--- + +# cockroach_metric_export_prometheus_config (Resource) + +Prometheus metric export configuration for a cluster. + +## Example Usage + +```terraform +variable "cluster_id" { + type = string +} + +resource "cockroach_metric_export_prometheus_config" "example" { + id = var.cluster_id +} +``` + + +## Schema + +### Required + +- `id` (String) Cluster ID. + +### Read-Only + +- `status` (String) Encodes the possible states that a metric export configuration can be in as it is created, deployed, and disabled. +- `user_message` (String) Elaborates on the metric export status and hints at how to fix issues that may have occurred during asynchronous operations. diff --git a/examples/resources/cockroach_metric_export_prometheus_config/resource.tf b/examples/resources/cockroach_metric_export_prometheus_config/resource.tf new file mode 100644 index 00000000..8516aedb --- /dev/null +++ b/examples/resources/cockroach_metric_export_prometheus_config/resource.tf @@ -0,0 +1,7 @@ +variable "cluster_id" { + type = string +} + +resource "cockroach_metric_export_prometheus_config" "example" { + id = var.cluster_id +} \ No newline at end of file diff --git a/examples/workflows/cockroach_metric_export/aws/main.tf b/examples/workflows/cockroach_metric_export/aws/main.tf index c085dfec..6018b497 100644 --- a/examples/workflows/cockroach_metric_export/aws/main.tf +++ b/examples/workflows/cockroach_metric_export/aws/main.tf @@ -169,4 +169,8 @@ resource "cockroach_metric_export_datadog_config" "example" { id = cockroach_cluster.example.id site = var.datadog_site api_key = var.datadog_api_key +} + +resource "cockroach_metric_export_prometheus_config" "example" { + id = cockroach_cluster.example.id } \ No newline at end of file diff --git a/examples/workflows/cockroach_metric_export/gcp/main.tf b/examples/workflows/cockroach_metric_export/gcp/main.tf index 384c852e..3b54fbf6 100644 --- a/examples/workflows/cockroach_metric_export/gcp/main.tf +++ b/examples/workflows/cockroach_metric_export/gcp/main.tf @@ -70,3 +70,7 @@ resource "cockroach_metric_export_datadog_config" "example" { site = var.datadog_site api_key = var.datadog_api_key } + +resource "cockroach_metric_export_prometheus_config" "example" { + id = cockroach_cluster.example.id +} diff --git a/internal/provider/metric_export_prometheus_config_resource.go b/internal/provider/metric_export_prometheus_config_resource.go new file mode 100644 index 00000000..1ad252d3 --- /dev/null +++ b/internal/provider/metric_export_prometheus_config_resource.go @@ -0,0 +1,390 @@ +package provider + +import ( + "context" + "fmt" + "github.com/cockroachdb/cockroach-cloud-sdk-go/pkg/client" + "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/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "net/http" + "strings" +) + +var metricExportPrometheusConfigAttributes = map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Cluster ID.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "status": schema.StringAttribute{ + Computed: true, + Description: "Encodes the possible states that a metric export configuration can be in as it is created, deployed, and disabled.", + }, + "user_message": schema.StringAttribute{ + Computed: true, + Description: "Elaborates on the metric export status and hints at how to fix issues that may have occurred during asynchronous operations.", + }, +} + +type metricExportPrometheusConfigResource struct { + provider *provider +} + +func (r *metricExportPrometheusConfigResource) Schema( + _ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse, +) { + resp.Schema = schema.Schema{ + Description: "Prometheus metric export configuration for a cluster.", + Attributes: metricExportPrometheusConfigAttributes, + } +} + +func (r *metricExportPrometheusConfigResource) Metadata( + _ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse, +) { + resp.TypeName = req.ProviderTypeName + "_metric_export_prometheus_config" +} + +func (r *metricExportPrometheusConfigResource) Configure( + _ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse, +) { + if req.ProviderData == nil { + return + } + var ok bool + if r.provider, ok = req.ProviderData.(*provider); !ok { + resp.Diagnostics.AddError("Internal provider error", + fmt.Sprintf("Error in Configure: expected %T but got %T", provider{}, req.ProviderData)) + } +} + +// Create +func (r *metricExportPrometheusConfigResource) Create( + ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse, +) { + if r.provider == nil || !r.provider.configured { + addConfigureProviderErr(&resp.Diagnostics) + return + } + + var plan ClusterPrometheusMetricExportConfig + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + clusterID := plan.ID.ValueString() + // Check cluster + cluster, _, err := r.provider.service.GetCluster(ctx, clusterID) + if err != nil { + resp.Diagnostics.AddError( + "Error getting cluster", + fmt.Sprintf("Could not retrieve cluster info: %s", formatAPIErrorMessage(err)), + ) + return + } + + if cluster.Config.Serverless != nil { + resp.Diagnostics.AddError( + "Incompatible cluster type", + "Prometheus metric export services are only available for dedicated clusters", + ) + return + } + + apiObj := &client.PrometheusMetricExportInfo{} + err = retry.RetryContext(ctx, clusterUpdateTimeout, retryEnablePrometheusMetricExport( + ctx, r.provider.service, clusterID, cluster, + apiObj, + )) + if err != nil { + resp.Diagnostics.AddError( + "Error enabling Prometheus metric export", err.Error(), + ) + return + } + + err = retry.RetryContext(ctx, clusterUpdateTimeout, + waitForPrometheusMetricExportReadyFunc(ctx, clusterID, r.provider.service, apiObj)) + if err != nil { + resp.Diagnostics.AddError( + "Error enabling Prometheus metric export", + fmt.Sprintf("Could not enable Prometheus metric export: %s", formatAPIErrorMessage(err)), + ) + return + } + + var state ClusterPrometheusMetricExportConfig + loadPrometheusMetricExportIntoTerraformState(apiObj, &state) + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) +} + +func retryEnablePrometheusMetricExport( + ctx context.Context, + cl client.Service, + clusterID string, + cluster *client.Cluster, + apiObj *client.PrometheusMetricExportInfo, +) retry.RetryFunc { + return func() *retry.RetryError { + body := &map[string]interface{}{} + apiResp, httpResp, err := cl.EnablePrometheusMetricExport(ctx, clusterID, body) + if err != nil { + apiErrMsg := formatAPIErrorMessage(err) + if (httpResp != nil && httpResp.StatusCode == http.StatusServiceUnavailable) || + strings.Contains(apiErrMsg, "lock") { + // Wait for cluster to be ready. + clusterErr := retry.RetryContext(ctx, clusterUpdateTimeout, + waitForClusterReadyFunc(ctx, clusterID, cl, cluster)) + if clusterErr != nil { + return retry.NonRetryableError( + fmt.Errorf("error checking cluster availability: %s", clusterErr.Error())) + } + return retry.RetryableError(fmt.Errorf("cluster was not ready - trying again")) + } + + return retry.NonRetryableError( + fmt.Errorf("could not enable Prometheus metric export: %v", apiErrMsg), + ) + } + *apiObj = *apiResp + return nil + } +} + +func loadPrometheusMetricExportIntoTerraformState( + apiObj *client.PrometheusMetricExportInfo, state *ClusterPrometheusMetricExportConfig, +) { + state.ID = types.StringValue(apiObj.GetClusterId()) + state.Status = types.StringValue(string(apiObj.GetStatus())) + state.UserMessage = types.StringValue(apiObj.GetUserMessage()) +} + +func waitForPrometheusMetricExportReadyFunc( + ctx context.Context, + clusterID string, + cl client.Service, + prometheusMetricExportInfo *client.PrometheusMetricExportInfo, +) retry.RetryFunc { + return func() *retry.RetryError { + apiObj, httpResp, err := cl.GetPrometheusMetricExportInfo(ctx, clusterID) + if err != nil { + if httpResp != nil && httpResp.StatusCode < http.StatusInternalServerError { + return retry.NonRetryableError(fmt.Errorf( + "error getting Prometheus metric export info: %s", formatAPIErrorMessage(err))) + } else { + return retry.RetryableError(fmt.Errorf( + "encountered a server error while reading Prometheus metric export status - trying again")) + } + } + + *prometheusMetricExportInfo = *apiObj + switch prometheusMetricExportInfo.GetStatus() { + case client.METRICEXPORTSTATUSTYPE_ERROR: + errMsg := "an error occurred during Prometheus metric export config update" + if prometheusMetricExportInfo.GetUserMessage() != "" { + errMsg = fmt.Sprintf("%s: %s", errMsg, prometheusMetricExportInfo.GetUserMessage()) + } + return retry.NonRetryableError(fmt.Errorf(errMsg)) + case client.METRICEXPORTSTATUSTYPE_ENABLING, client.METRICEXPORTSTATUSTYPE_DISABLING: + return retry.RetryableError(fmt.Errorf("the Prometheus metric export is not ready yet")) + default: + return nil + } + } +} + +// Read +func (r *metricExportPrometheusConfigResource) Read( + ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse, +) { + if r.provider == nil || !r.provider.configured { + addConfigureProviderErr(&resp.Diagnostics) + return + } + + var state ClusterPrometheusMetricExportConfig + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() || state.ID.IsNull() { + return + } + + clusterID := state.ID.ValueString() + apiObj, httpResp, err := r.provider.service.GetPrometheusMetricExportInfo(ctx, clusterID) + if err != nil { + if httpResp != nil && httpResp.StatusCode == http.StatusNotFound { + resp.Diagnostics.AddWarning( + "Prometheus metric export config not found", + fmt.Sprintf( + "The Prometheus metric export config with cluster ID %s is not found. Removing from state.", + clusterID, + )) + resp.State.RemoveResource(ctx) + return + } else { + // Check cluster existence. + cluster, clusterHttpResp, clusterErr := r.provider.service.GetCluster(ctx, clusterID) + if clusterErr != nil { + if clusterHttpResp != nil && clusterHttpResp.StatusCode == http.StatusNotFound { + resp.Diagnostics.AddWarning( + "Cluster not found", + fmt.Sprintf("The Prometheus metric export config's cluster with ID %s is not found. Removing from state.", + clusterID, + )) + resp.State.RemoveResource(ctx) + return + } else { + resp.Diagnostics.AddError( + "Error getting cluster", + fmt.Sprintf("Unexpected error retrieving the Prometheus metric export config's cluster: %s", + formatAPIErrorMessage(clusterErr), + )) + } + } + + if cluster.State == client.CLUSTERSTATETYPE_DELETED { + resp.Diagnostics.AddWarning( + "Cluster deleted", + fmt.Sprintf("The Prometheus metric export config's cluster with ID %s was deleted. Removing from state.", + clusterID, + )) + resp.State.RemoveResource(ctx) + return + } + + resp.Diagnostics.AddError( + "Error getting Prometheus metric export info", + fmt.Sprintf("Unexpected error retrieving Prometheus metric export info: %s", formatAPIErrorMessage(err))) + } + return + } + + loadPrometheusMetricExportIntoTerraformState(apiObj, &state) + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) +} + +// Update +func (r *metricExportPrometheusConfigResource) Update( + ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse, +) { + // Get plan values + var plan ClusterPrometheusMetricExportConfig + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Get current state + var state ClusterPrometheusMetricExportConfig + diags = req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + clusterID := plan.ID.ValueString() + cluster := &client.Cluster{} + apiObj := &client.PrometheusMetricExportInfo{} + err := retry.RetryContext(ctx, clusterUpdateTimeout, retryEnablePrometheusMetricExport( + ctx, r.provider.service, clusterID, cluster, + apiObj, + )) + if err != nil { + resp.Diagnostics.AddError( + "Error enabling Prometheus metric export", err.Error(), + ) + return + } + + err = retry.RetryContext(ctx, clusterUpdateTimeout, + waitForPrometheusMetricExportReadyFunc(ctx, clusterID, r.provider.service, apiObj)) + if err != nil { + resp.Diagnostics.AddError( + "Error enabling Prometheus metric export", + fmt.Sprintf("Could not enable Prometheus metric export: %s", formatAPIErrorMessage(err)), + ) + return + } + + loadPrometheusMetricExportIntoTerraformState(apiObj, &state) + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) +} + +// Delete +func (r *metricExportPrometheusConfigResource) Delete( + ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse, +) { + var state ClusterPrometheusMetricExportConfig + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + clusterID := state.ID.ValueString() + cluster := &client.Cluster{} + retryFunc := func() retry.RetryFunc { + return func() *retry.RetryError { + _, httpResp, err := r.provider.service.DeletePrometheusMetricExport(ctx, clusterID) + if err != nil { + apiErrMsg := formatAPIErrorMessage(err) + if httpResp != nil { + if httpResp.StatusCode == http.StatusNotFound { + // Prometheus metric export config or cluster is already gone. Swallow the error. + return nil + } + + if httpResp.StatusCode == http.StatusServiceUnavailable || + strings.Contains(apiErrMsg, "lock") { + // Wait for cluster to be ready. + clusterErr := retry.RetryContext(ctx, clusterUpdateTimeout, + waitForClusterReadyFunc(ctx, clusterID, r.provider.service, cluster)) + if clusterErr != nil { + return retry.NonRetryableError( + fmt.Errorf("Error checking cluster availability: %s", clusterErr.Error())) + } + return retry.RetryableError(fmt.Errorf("cluster was not ready - trying again")) + } + } + return retry.NonRetryableError( + fmt.Errorf("could not delete Prometheus metric export config: %v", apiErrMsg)) + } + return nil + } + } + + err := retry.RetryContext(ctx, clusterUpdateTimeout, retryFunc()) + if err != nil { + resp.Diagnostics.AddError( + "Error deleting Prometheus metric export config", err.Error(), + ) + return + } + + // Remove resource from state + resp.State.RemoveResource(ctx) +} + +// Import state +func (r *metricExportPrometheusConfigResource) ImportState( + ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse, +) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func NewMetricExportPrometheusConfigResource() resource.Resource { + return &metricExportPrometheusConfigResource{} +} diff --git a/internal/provider/metric_export_prometheus_config_resource_test.go b/internal/provider/metric_export_prometheus_config_resource_test.go new file mode 100644 index 00000000..c7aa020d --- /dev/null +++ b/internal/provider/metric_export_prometheus_config_resource_test.go @@ -0,0 +1,211 @@ +package provider + +import ( + "context" + "fmt" + "github.com/cockroachdb/cockroach-cloud-sdk-go/pkg/client" + mock_client "github.com/cockroachdb/terraform-provider-cockroach/mock" + "github.com/golang/mock/gomock" + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "log" + "net/http" + "os" + "testing" +) + +// TestAccMetricExportPrometheusConfigResource attempts to create, check, and destroy +// a real cluster. It will be skipped if TF_ACC isn't set. +func TestAccMetricExportPrometheusConfigResource(t *testing.T) { + t.Skip("Skipping until we can either integrate the AWS provider " + + "or import a permanent test fixture.") + t.Parallel() + clusterName := fmt.Sprintf("%s-prometheus-%s", tfTestPrefix, GenerateRandomString(4)) + testMetricExportPrometheusConfigResource(t, clusterName, false) +} + +// TestIntegrationMetricExportPrometheusConfigResource attempts to create, check, +// and destroy a cluster, but uses a mocked API service. +func TestIntegrationMetricExportPrometheusConfigResource(t *testing.T) { + clusterName := fmt.Sprintf("%s-prometheus-%s", tfTestPrefix, GenerateRandomString(4)) + clusterID := uuid.Nil.String() + if os.Getenv(CockroachAPIKey) == "" { + os.Setenv(CockroachAPIKey, "fake") + } + + ctrl := gomock.NewController(t) + s := mock_client.NewMockService(ctrl) + defer HookGlobal(&NewService, func(c *client.Client) client.Service { + return s + })() + + cluster := &client.Cluster{ + Id: clusterID, + Name: clusterName, + CockroachVersion: "v22.2.0", + Plan: "DEDICATED", + CloudProvider: "AWS", + State: "CREATED", + Config: client.ClusterConfig{ + Dedicated: &client.DedicatedHardwareConfig{ + MachineType: "m5.xlarge", + NumVirtualCpus: 4, + StorageGib: 35, + MemoryGib: 8, + }, + }, + Regions: []client.Region{ + { + Name: "us-east-1", + NodeCount: 3, + }, + }, + } + + enabledStatus := client.METRICEXPORTSTATUSTYPE_ENABLED + + createdPrometheusClusterInfo := &client.PrometheusMetricExportInfo{ + ClusterId: clusterID, + Status: &enabledStatus, + } + + updatedPrometheusClusterInfo := &client.PrometheusMetricExportInfo{ + ClusterId: clusterID, + Status: &enabledStatus, + } + + // Create + s.EXPECT().CreateCluster(gomock.Any(), gomock.Any()). + Return(cluster, nil, nil) + s.EXPECT().GetCluster(gomock.Any(), clusterID). + Return(cluster, &http.Response{Status: http.StatusText(http.StatusOK)}, nil). + Times(3) + s.EXPECT().EnablePrometheusMetricExport(gomock.Any(), clusterID, gomock.Any()). + Return(createdPrometheusClusterInfo, nil, nil) + s.EXPECT().GetPrometheusMetricExportInfo(gomock.Any(), clusterID). + Return(createdPrometheusClusterInfo, nil, nil). + Times(3) + + // Update + s.EXPECT().GetCluster(gomock.Any(), clusterID). + Return(cluster, nil, nil). + Times(2) + s.EXPECT().GetPrometheusMetricExportInfo(gomock.Any(), clusterID). + Return(createdPrometheusClusterInfo, nil, nil) + s.EXPECT().EnablePrometheusMetricExport(gomock.Any(), clusterID, gomock.Any()). + Return(updatedPrometheusClusterInfo, nil, nil) + s.EXPECT().GetPrometheusMetricExportInfo(gomock.Any(), clusterID). + Return(updatedPrometheusClusterInfo, nil, nil). + Times(4) + + // Delete + s.EXPECT().DeleteCluster(gomock.Any(), clusterID) + s.EXPECT().DeletePrometheusMetricExport(gomock.Any(), clusterID) + + testMetricExportPrometheusConfigResource(t, clusterName, true) +} + +func testMetricExportPrometheusConfigResource(t *testing.T, clusterName string, useMock bool) { + var ( + clusterResourceName = "cockroach_cluster.test" + metricExportPrometheusConfigResourceName = "cockroach_metric_export_prometheus_config.test" + ) + + resource.Test(t, resource.TestCase{ + IsUnitTest: useMock, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: getTestMetricExportPrometheusConfigResourceCreateConfig(clusterName), + Check: resource.ComposeTestCheckFunc( + testMetricExportPrometheusConfigExists(metricExportPrometheusConfigResourceName, clusterResourceName), + resource.TestCheckResourceAttr(metricExportPrometheusConfigResourceName, "status", "ENABLED"), + ), + }, + { + Config: getTestMetricExportPrometheusConfigResourceUpdateConfig(clusterName), + Check: resource.ComposeTestCheckFunc( + testMetricExportPrometheusConfigExists(metricExportPrometheusConfigResourceName, clusterResourceName), + resource.TestCheckResourceAttr(metricExportPrometheusConfigResourceName, "status", "ENABLED"), + ), + }, + { + ResourceName: metricExportPrometheusConfigResourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testMetricExportPrometheusConfigExists( + resourceName, clusterResourceName string, +) resource.TestCheckFunc { + return func(s *terraform.State) error { + p := testAccProvider.(*provider) + p.service = NewService(cl) + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + clusterRs, ok := s.RootModule().Resources[clusterResourceName] + if !ok { + return fmt.Errorf("not found: %s", clusterResourceName) + } + + clusterID := clusterRs.Primary.Attributes["id"] + log.Printf("[DEBUG] clusterID: %s, name %s", clusterRs.Primary.Attributes["id"], clusterRs.Primary.Attributes["name"]) + + _, _, err := p.service.GetPrometheusMetricExportInfo(context.TODO(), clusterID) + if err == nil { + return nil + } + + return fmt.Errorf("metric export Prometheus config with site %s does not exist", rs.Primary.Attributes["site"]) + } +} + +func getTestMetricExportPrometheusConfigResourceCreateConfig(name string) string { + return fmt.Sprintf(` +resource "cockroach_cluster" "test" { + name = "%s" + cloud_provider = "AWS" + dedicated = { + storage_gib = 35 + num_virtual_cpus = 4 + } + regions = [{ + name = "us-east-1" + node_count: 3 + }] +} + +resource "cockroach_metric_export_prometheus_config" "test" { + id = cockroach_cluster.test.id + } +`, name) +} + +func getTestMetricExportPrometheusConfigResourceUpdateConfig(name string) string { + return fmt.Sprintf(` +resource "cockroach_cluster" "test" { + name = "%s" + cloud_provider = "AWS" + dedicated = { + storage_gib = 35 + num_virtual_cpus = 4 + } + regions = [{ + name = "us-east-1" + node_count: 3 + }] +} + +resource "cockroach_metric_export_prometheus_config" "test" { + id = cockroach_cluster.test.id + } +`, name) +} diff --git a/internal/provider/models.go b/internal/provider/models.go index 36738dd6..3c479539 100644 --- a/internal/provider/models.go +++ b/internal/provider/models.go @@ -248,6 +248,12 @@ type ClusterDatadogMetricExportConfig struct { Status types.String `tfsdk:"status"` } +type ClusterPrometheusMetricExportConfig struct { + ID types.String `tfsdk:"id"` + UserMessage types.String `tfsdk:"user_message"` + Status types.String `tfsdk:"status"` +} + type ClusterMaintenanceWindow struct { ID types.String `tfsdk:"id"` OffsetDuration types.Int64 `tfsdk:"offset_duration"` diff --git a/internal/provider/provider.go b/internal/provider/provider.go index aab7e31f..64b9f919 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -137,6 +137,7 @@ func (p *provider) Resources(_ context.Context) []func() resource.Resource { NewLogExportConfigResource, NewMetricExportDatadogConfigResource, NewMetricExportCloudWatchConfigResource, + NewMetricExportPrometheusConfigResource, NewClientCACertResource, NewUserRoleGrantsResource, NewUserRoleGrantResource,