diff --git a/datadog/fwprovider/framework_provider.go b/datadog/fwprovider/framework_provider.go index fd8fb60443..43d96a06b7 100644 --- a/datadog/fwprovider/framework_provider.go +++ b/datadog/fwprovider/framework_provider.go @@ -39,6 +39,7 @@ var Resources = []func() resource.Resource{ NewApmRetentionFilterResource, NewApmRetentionFiltersOrderResource, NewIntegrationAwsAccountResource, + NewIntegrationAwsAccountCcmConfigResource, NewCatalogEntityResource, NewDashboardListResource, NewDatasetResource, diff --git a/datadog/fwprovider/resource_datadog_integration_aws_account_ccm_config.go b/datadog/fwprovider/resource_datadog_integration_aws_account_ccm_config.go new file mode 100644 index 0000000000..02904d6777 --- /dev/null +++ b/datadog/fwprovider/resource_datadog_integration_aws_account_ccm_config.go @@ -0,0 +1,301 @@ +package fwprovider + +import ( + "context" + _nethttp "net/http" + + "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2" + "github.com/hashicorp/terraform-plugin-framework/diag" + frameworkPath "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/types" + + "github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils" +) + +var ( + _ resource.ResourceWithConfigure = &integrationAwsAccountCcmConfigResource{} + _ resource.ResourceWithImportState = &integrationAwsAccountCcmConfigResource{} +) + +type integrationAwsAccountCcmConfigResource struct { + Api *datadogV2.AWSIntegrationApi + Auth context.Context +} + +type integrationAwsAccountCcmConfigModel struct { + ID types.String `tfsdk:"id"` + AwsAccountConfigId types.String `tfsdk:"aws_account_config_id"` + CcmConfig *awsCcmConfigModel `tfsdk:"ccm_config"` +} + +type awsCcmConfigModel struct { + DataExportConfigs []*awsDataExportConfigModel `tfsdk:"data_export_configs"` +} + +type awsDataExportConfigModel struct { + ReportName types.String `tfsdk:"report_name"` + ReportPrefix types.String `tfsdk:"report_prefix"` + ReportType types.String `tfsdk:"report_type"` + BucketName types.String `tfsdk:"bucket_name"` + BucketRegion types.String `tfsdk:"bucket_region"` +} + +func NewIntegrationAwsAccountCcmConfigResource() resource.Resource { + return &integrationAwsAccountCcmConfigResource{} +} + +func (r *integrationAwsAccountCcmConfigResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) { + providerData, _ := request.ProviderData.(*FrameworkProvider) + r.Api = providerData.DatadogApiInstances.GetAWSIntegrationApiV2() + r.Auth = providerData.Auth +} + +func (r *integrationAwsAccountCcmConfigResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "integration_aws_account_ccm_config" +} + +func (r *integrationAwsAccountCcmConfigResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Description: "Provides a Datadog IntegrationAwsAccountCcmConfig resource. This can be used to create and manage Cloud Cost Management configuration for an AWS Account Integration.", + Attributes: map[string]schema.Attribute{ + "id": utils.ResourceIDAttribute(), + "aws_account_config_id": schema.StringAttribute{ + Required: true, + Description: "Unique Datadog ID of the AWS Account Integration Config.", + }, + }, + Blocks: map[string]schema.Block{ + "ccm_config": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{}, + Blocks: map[string]schema.Block{ + "data_export_configs": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "report_name": schema.StringAttribute{ + Optional: true, + Description: "Name of the Cost and Usage Report.", + }, + "report_prefix": schema.StringAttribute{ + Optional: true, + Description: "S3 prefix where the Cost and Usage Report is stored.", + }, + "report_type": schema.StringAttribute{ + Optional: true, + Description: "Type of the Cost and Usage Report.", + }, + "bucket_name": schema.StringAttribute{ + Optional: true, + Description: "Name of the S3 bucket where the Cost and Usage Report is stored.", + }, + "bucket_region": schema.StringAttribute{ + Optional: true, + Description: "AWS region of the S3 bucket.", + }, + }, + }, + }, + }, + }, + }, + } +} + +func (r *integrationAwsAccountCcmConfigResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, frameworkPath.Root("aws_account_config_id"), request, response) +} + +func (r *integrationAwsAccountCcmConfigResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var state integrationAwsAccountCcmConfigModel + response.Diagnostics.Append(request.State.Get(ctx, &state)...) + if response.Diagnostics.HasError() { + return + } + awsAccountConfigId := state.AwsAccountConfigId.ValueString() + + var resp datadogV2.AWSCcmConfigResponse + err := utils.Retry(5, 10, func() error { + var httpResp *_nethttp.Response + var err error + resp, httpResp, err = r.Api.GetAWSAccountCCMConfig(r.Auth, awsAccountConfigId) + if err != nil { + if httpResp != nil && httpResp.StatusCode == 404 { + return &utils.RetryableError{Prob: "CCM config not found yet, retrying"} + } + return err + } + return nil + }) + if err != nil { + if _, ok := err.(*utils.RetryableError); ok { + // Still 404 after retries - resource doesn't exist + response.State.RemoveResource(ctx) + return + } + response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error retrieving IntegrationAwsAccountCcmConfig")) + return + } + if err := utils.CheckForUnparsed(resp); err != nil { + response.Diagnostics.AddError("response contains unparsedObject", err.Error()) + return + } + + r.updateState(ctx, &state, &resp) + + // Save data into Terraform state + response.Diagnostics.Append(response.State.Set(ctx, &state)...) +} + +func (r *integrationAwsAccountCcmConfigResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var state integrationAwsAccountCcmConfigModel + response.Diagnostics.Append(request.Plan.Get(ctx, &state)...) + if response.Diagnostics.HasError() { + return + } + + awsAccountConfigId := state.AwsAccountConfigId.ValueString() + + body, diags := r.buildIntegrationAwsAccountCcmConfigRequestBody(ctx, &state) + response.Diagnostics.Append(diags...) + if response.Diagnostics.HasError() { + return + } + + resp, _, err := r.Api.CreateAWSAccountCCMConfig(r.Auth, awsAccountConfigId, *body) + if err != nil { + response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating IntegrationAwsAccountCcmConfig")) + return + } + if err := utils.CheckForUnparsed(resp); err != nil { + response.Diagnostics.AddError("response contains unparsedObject", err.Error()) + return + } + r.updateState(ctx, &state, &resp) + + // Save data into Terraform state + response.Diagnostics.Append(response.State.Set(ctx, &state)...) +} + +func (r *integrationAwsAccountCcmConfigResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var state integrationAwsAccountCcmConfigModel + response.Diagnostics.Append(request.Plan.Get(ctx, &state)...) + if response.Diagnostics.HasError() { + return + } + + awsAccountConfigId := state.AwsAccountConfigId.ValueString() + + body, diags := r.buildIntegrationAwsAccountCcmConfigRequestBody(ctx, &state) + response.Diagnostics.Append(diags...) + if response.Diagnostics.HasError() { + return + } + + resp, _, err := r.Api.UpdateAWSAccountCCMConfig(r.Auth, awsAccountConfigId, *body) + if err != nil { + response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating IntegrationAwsAccountCcmConfig")) + return + } + if err := utils.CheckForUnparsed(resp); err != nil { + response.Diagnostics.AddError("response contains unparsedObject", err.Error()) + return + } + r.updateState(ctx, &state, &resp) + + // Save data into Terraform state + response.Diagnostics.Append(response.State.Set(ctx, &state)...) +} + +func (r *integrationAwsAccountCcmConfigResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var state integrationAwsAccountCcmConfigModel + response.Diagnostics.Append(request.State.Get(ctx, &state)...) + if response.Diagnostics.HasError() { + return + } + + awsAccountConfigId := state.AwsAccountConfigId.ValueString() + + httpResp, err := r.Api.DeleteAWSAccountCCMConfig(r.Auth, awsAccountConfigId) + if err != nil { + if httpResp != nil && httpResp.StatusCode == 404 { + return + } + response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error deleting integration_aws_account_ccm_config")) + return + } +} + +func (r *integrationAwsAccountCcmConfigResource) updateState(ctx context.Context, state *integrationAwsAccountCcmConfigModel, resp *datadogV2.AWSCcmConfigResponse) { + state.ID = types.StringValue(resp.Data.GetId()) + + data := resp.GetData() + attributes := data.GetAttributes() + + if dataExportConfigs, ok := attributes.GetDataExportConfigsOk(); ok && len(*dataExportConfigs) > 0 { + if state.CcmConfig == nil { + state.CcmConfig = &awsCcmConfigModel{} + } + state.CcmConfig.DataExportConfigs = []*awsDataExportConfigModel{} + for _, dataExportConfigsDd := range *dataExportConfigs { + dataExportConfigsTf := &awsDataExportConfigModel{} + if reportName, ok := dataExportConfigsDd.GetReportNameOk(); ok { + dataExportConfigsTf.ReportName = types.StringValue(*reportName) + } + if reportPrefix, ok := dataExportConfigsDd.GetReportPrefixOk(); ok { + dataExportConfigsTf.ReportPrefix = types.StringValue(*reportPrefix) + } + if reportType, ok := dataExportConfigsDd.GetReportTypeOk(); ok { + dataExportConfigsTf.ReportType = types.StringValue(*reportType) + } + if bucketName, ok := dataExportConfigsDd.GetBucketNameOk(); ok { + dataExportConfigsTf.BucketName = types.StringValue(*bucketName) + } + if bucketRegion, ok := dataExportConfigsDd.GetBucketRegionOk(); ok { + dataExportConfigsTf.BucketRegion = types.StringValue(*bucketRegion) + } + state.CcmConfig.DataExportConfigs = append(state.CcmConfig.DataExportConfigs, dataExportConfigsTf) + } + } +} + +func (r *integrationAwsAccountCcmConfigResource) buildIntegrationAwsAccountCcmConfigRequestBody(ctx context.Context, state *integrationAwsAccountCcmConfigModel) (*datadogV2.AWSCcmConfigRequest, diag.Diagnostics) { + diags := diag.Diagnostics{} + attributes := datadogV2.NewAWSCcmConfigRequestAttributesWithDefaults() + + if state.CcmConfig != nil { + var ccmConfig datadogV2.AWSCcmConfig + + if state.CcmConfig.DataExportConfigs != nil { + var dataExportConfigs []datadogV2.DataExportConfig + for _, dataExportConfigsTFItem := range state.CcmConfig.DataExportConfigs { + dataExportConfigsDDItem := datadogV2.NewDataExportConfigWithDefaults() + + if !dataExportConfigsTFItem.ReportName.IsNull() { + dataExportConfigsDDItem.SetReportName(dataExportConfigsTFItem.ReportName.ValueString()) + } + if !dataExportConfigsTFItem.ReportPrefix.IsNull() { + dataExportConfigsDDItem.SetReportPrefix(dataExportConfigsTFItem.ReportPrefix.ValueString()) + } + if !dataExportConfigsTFItem.ReportType.IsNull() { + dataExportConfigsDDItem.SetReportType(dataExportConfigsTFItem.ReportType.ValueString()) + } + if !dataExportConfigsTFItem.BucketName.IsNull() { + dataExportConfigsDDItem.SetBucketName(dataExportConfigsTFItem.BucketName.ValueString()) + } + if !dataExportConfigsTFItem.BucketRegion.IsNull() { + dataExportConfigsDDItem.SetBucketRegion(dataExportConfigsTFItem.BucketRegion.ValueString()) + } + dataExportConfigs = append(dataExportConfigs, *dataExportConfigsDDItem) + } + ccmConfig.SetDataExportConfigs(dataExportConfigs) + } + attributes.CcmConfig = &ccmConfig + } + + req := datadogV2.NewAWSCcmConfigRequestWithDefaults() + req.Data = *datadogV2.NewAWSCcmConfigRequestDataWithDefaults() + req.Data.SetAttributes(*attributes) + + return req, diags +} diff --git a/datadog/tests/cassettes/TestAccIntegrationAwsAccountCcmConfigBasic.freeze b/datadog/tests/cassettes/TestAccIntegrationAwsAccountCcmConfigBasic.freeze new file mode 100644 index 0000000000..6db7e2cc85 --- /dev/null +++ b/datadog/tests/cassettes/TestAccIntegrationAwsAccountCcmConfigBasic.freeze @@ -0,0 +1 @@ +2026-01-14T11:44:20.191397-05:00 \ No newline at end of file diff --git a/datadog/tests/cassettes/TestAccIntegrationAwsAccountCcmConfigBasic.yaml b/datadog/tests/cassettes/TestAccIntegrationAwsAccountCcmConfigBasic.yaml new file mode 100644 index 0000000000..0009d8e073 --- /dev/null +++ b/datadog/tests/cassettes/TestAccIntegrationAwsAccountCcmConfigBasic.yaml @@ -0,0 +1,268 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 226 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: | + {"data":{"attributes":{"ccm_config":{"data_export_configs":[{"bucket_name":"billing","bucket_region":"us-east-1","report_name":"cost-and-usage-report","report_prefix":"reports","report_type":"CUR2.0"}]}},"type":"ccm_config"}} + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 254 + uncompressed: false + body: '{"data":{"id":"b2087a32-4d4f-45b1-9321-1a0a48e9d7cf","type":"ccm_config","attributes":{"data_export_configs":[{"report_name":"cost-and-usage-report","report_prefix":"reports","report_type":"CUR2.0","bucket_name":"billing","bucket_region":"us-east-1"}]}}}' + headers: + Content-Type: + - application/vnd.api+json + status: 200 OK + code: 200 + duration: 85.429625ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept: + - application/json + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 106 + uncompressed: false + body: '{"errors":[{"status":"404","title":"Account not found","detail":"CCM config not found for this account"}]}' + headers: + Content-Type: + - application/vnd.api+json + status: 404 Not Found + code: 404 + duration: 32.14675ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept: + - application/json + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 106 + uncompressed: false + body: '{"errors":[{"status":"404","title":"Account not found","detail":"CCM config not found for this account"}]}' + headers: + Content-Type: + - application/vnd.api+json + status: 404 Not Found + code: 404 + duration: 29.512125ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept: + - application/json + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 254 + uncompressed: false + body: '{"data":{"id":"b2087a32-4d4f-45b1-9321-1a0a48e9d7cf","type":"ccm_config","attributes":{"data_export_configs":[{"report_name":"cost-and-usage-report","report_prefix":"reports","report_type":"CUR2.0","bucket_name":"billing","bucket_region":"us-east-1"}]}}}' + headers: + Content-Type: + - application/vnd.api+json + status: 200 OK + code: 200 + duration: 27.448459ms + - id: 4 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept: + - application/json + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 254 + uncompressed: false + body: '{"data":{"id":"b2087a32-4d4f-45b1-9321-1a0a48e9d7cf","type":"ccm_config","attributes":{"data_export_configs":[{"report_name":"cost-and-usage-report","report_prefix":"reports","report_type":"CUR2.0","bucket_name":"billing","bucket_region":"us-east-1"}]}}}' + headers: + Content-Type: + - application/vnd.api+json + status: 200 OK + code: 200 + duration: 37.808959ms + - id: 5 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept: + - '*/*' + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: {} + status: 204 No Content + code: 204 + duration: 47.214292ms + - id: 6 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept: + - application/json + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 254 + uncompressed: false + body: '{"data":{"id":"b2087a32-4d4f-45b1-9321-1a0a48e9d7cf","type":"ccm_config","attributes":{"data_export_configs":[{"report_name":"cost-and-usage-report","report_prefix":"reports","report_type":"CUR2.0","bucket_name":"billing","bucket_region":"us-east-1"}]}}}' + headers: + Content-Type: + - application/vnd.api+json + status: 200 OK + code: 200 + duration: 33.948916ms + - id: 7 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: api.datad0g.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Accept: + - application/json + url: https://api.datad0g.com/api/v2/integration/aws/accounts/b2087a32-4d4f-45b1-9321-1a0a48e9d7cf/ccm_config + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 106 + uncompressed: false + body: '{"errors":[{"status":"404","title":"Account not found","detail":"CCM config not found for this account"}]}' + headers: + Content-Type: + - application/vnd.api+json + status: 404 Not Found + code: 404 + duration: 26.321041ms diff --git a/datadog/tests/provider_test.go b/datadog/tests/provider_test.go index 89e87546d2..4ecd50efd8 100644 --- a/datadog/tests/provider_test.go +++ b/datadog/tests/provider_test.go @@ -219,6 +219,7 @@ var testFiles2EndpointTags = map[string]string{ "tests/resource_datadog_integration_aws_tag_filter_test": "integration-aws", "tests/resource_datadog_integration_aws_test": "integration-aws", "tests/resource_datadog_integration_aws_account_test": "integration-aws", + "tests/resource_datadog_integration_aws_account_ccm_config_test": "integration-aws", "tests/resource_datadog_integration_aws_event_bridge_test": "integration-aws", "tests/resource_datadog_integration_aws_external_id_test": "integration-aws", "tests/resource_datadog_integration_azure_test": "integration-azure", diff --git a/datadog/tests/resource_datadog_integration_aws_account_ccm_config_test.go b/datadog/tests/resource_datadog_integration_aws_account_ccm_config_test.go new file mode 100644 index 0000000000..e0d21ee18a --- /dev/null +++ b/datadog/tests/resource_datadog_integration_aws_account_ccm_config_test.go @@ -0,0 +1,108 @@ +package test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + + "github.com/terraform-providers/terraform-provider-datadog/datadog/fwprovider" + "github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils" +) + +func TestAccIntegrationAwsAccountCcmConfigBasic(t *testing.T) { + t.Parallel() + _, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t) + + resource.Test(t, resource.TestCase{ + ProtoV5ProviderFactories: accProviders, + CheckDestroy: testAccCheckDatadogIntegrationAwsAccountCcmConfigDestroy(providers.frameworkProvider), + Steps: []resource.TestStep{ + { + Config: testAccCheckDatadogIntegrationAwsAccountCcmConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckDatadogIntegrationAwsAccountCcmConfigExists(providers.frameworkProvider), + ), + }, + }, + }) +} + +func testAccCheckDatadogIntegrationAwsAccountCcmConfig() string { + return `resource "datadog_integration_aws_account_ccm_config" "foo" { + aws_account_config_id = "b2087a32-4d4f-45b1-9321-1a0a48e9d7cf" + + ccm_config { + data_export_configs { + report_name = "cost-and-usage-report" + report_prefix = "reports" + report_type = "CUR2.0" + bucket_name = "billing" + bucket_region = "us-east-1" + } + } +}` +} + +func testAccCheckDatadogIntegrationAwsAccountCcmConfigDestroy(accProvider *fwprovider.FrameworkProvider) func(*terraform.State) error { + return func(s *terraform.State) error { + apiInstances := accProvider.DatadogApiInstances + auth := accProvider.Auth + + if err := IntegrationAwsAccountCcmConfigDestroyHelper(auth, s, apiInstances); err != nil { + return err + } + return nil + } +} + +func IntegrationAwsAccountCcmConfigDestroyHelper(auth context.Context, s *terraform.State, apiInstances *utils.ApiInstances) error { + err := utils.Retry(2, 10, func() error { + for _, r := range s.RootModule().Resources { + if r.Type != "datadog_integration_aws_account_ccm_config" { + continue + } + awsAccountConfigId := r.Primary.Attributes["aws_account_config_id"] + + _, httpResp, err := apiInstances.GetAWSIntegrationApiV2().GetAWSAccountCCMConfig(auth, awsAccountConfigId) + if err != nil { + if httpResp != nil && httpResp.StatusCode == 404 { + return nil + } + return &utils.RetryableError{Prob: fmt.Sprintf("received an error retrieving IntegrationAwsAccountCcmConfig %s", err)} + } + return &utils.RetryableError{Prob: "IntegrationAwsAccountCcmConfig still exists"} + } + return nil + }) + return err +} + +func testAccCheckDatadogIntegrationAwsAccountCcmConfigExists(accProvider *fwprovider.FrameworkProvider) resource.TestCheckFunc { + return func(s *terraform.State) error { + apiInstances := accProvider.DatadogApiInstances + auth := accProvider.Auth + + if err := integrationAwsAccountCcmConfigExistsHelper(auth, s, apiInstances); err != nil { + return err + } + return nil + } +} + +func integrationAwsAccountCcmConfigExistsHelper(auth context.Context, s *terraform.State, apiInstances *utils.ApiInstances) error { + for _, r := range s.RootModule().Resources { + if r.Type != "datadog_integration_aws_account_ccm_config" { + continue + } + awsAccountConfigId := r.Primary.Attributes["aws_account_config_id"] + + _, httpResp, err := apiInstances.GetAWSIntegrationApiV2().GetAWSAccountCCMConfig(auth, awsAccountConfigId) + if err != nil { + return utils.TranslateClientError(err, httpResp, "error retrieving IntegrationAwsAccountCcmConfig") + } + } + return nil +} diff --git a/examples/resources/datadog_integration_aws_account_ccm_config/import.sh b/examples/resources/datadog_integration_aws_account_ccm_config/import.sh new file mode 100644 index 0000000000..e386352e67 --- /dev/null +++ b/examples/resources/datadog_integration_aws_account_ccm_config/import.sh @@ -0,0 +1 @@ +terraform import datadog_integration_aws_account_ccm_config.foo "" diff --git a/examples/resources/datadog_integration_aws_account_ccm_config/resource.tf b/examples/resources/datadog_integration_aws_account_ccm_config/resource.tf new file mode 100644 index 0000000000..c1a22e0922 --- /dev/null +++ b/examples/resources/datadog_integration_aws_account_ccm_config/resource.tf @@ -0,0 +1,15 @@ +# Create new integration_aws_account_ccm_config resource + +resource "datadog_integration_aws_account_ccm_config" "foo" { + aws_account_config_id = "00000000-0000-0000-0000-000000000000" + + ccm_config { + data_export_configs { + report_name = "cost-and-usage-report" + report_prefix = "reports" + report_type = "CUR2.0" + bucket_name = "billing" + bucket_region = "us-east-1" + } + } +}