diff --git a/.changelog/36778.txt b/.changelog/36778.txt new file mode 100644 index 000000000000..650079af3ddc --- /dev/null +++ b/.changelog/36778.txt @@ -0,0 +1,11 @@ +```release-note:bug +data-source/aws_resourceexplorer2_search: Fix panic caused by bad mappping between Terraform and AWS schemas +``` + +```release-note:bug +data-source/aws_resourceexplorer2_search: Fix 401 unauthorized error due to missing `view_arn` in the AWS API request +``` + +```release-note:bug +data-source/aws_resourceexplorer2_search: Fix state persistence and data types +``` diff --git a/internal/service/resourceexplorer2/search_data_source.go b/internal/service/resourceexplorer2/search_data_source.go index 9aa1f913bba3..b339a1795555 100644 --- a/internal/service/resourceexplorer2/search_data_source.go +++ b/internal/service/resourceexplorer2/search_data_source.go @@ -5,9 +5,12 @@ package resourceexplorer2 import ( "context" + "fmt" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/resourceexplorer2" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -40,75 +43,27 @@ func (d *dataSourceSearch) Metadata(_ context.Context, req datasource.MetadataRe func (d *dataSourceSearch) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": framework.IDAttribute(), "query_string": schema.StringAttribute{ Required: true, }, - "id": framework.IDAttribute(), + "resource_count": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[countData](ctx), + Computed: true, + }, + "resources": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourcesData](ctx), + ElementType: fwtypes.NewObjectTypeOf[resourcesData](ctx), + Computed: true, + }, "view_arn": schema.StringAttribute{ - Optional: true, + CustomType: fwtypes.ARNType, + Optional: true, Validators: []validator.String{ stringvalidator.LengthBetween(0, 1011), }, }, }, - Blocks: map[string]schema.Block{ - "resource_count": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[countData](ctx), - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "complete": schema.BoolAttribute{ - Computed: true, - }, - "total_resources": schema.Int64Attribute{ - Computed: true, - }, - }, - }, - }, - "resources": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourcesData](ctx), - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "arn": schema.StringAttribute{ - Computed: true, - }, - "last_reported_at": schema.StringAttribute{ - Computed: true, - }, - "owning_account_id": schema.StringAttribute{ - Computed: true, - }, - "region": schema.StringAttribute{ - Computed: true, - }, - "resource_type": schema.StringAttribute{ - Computed: true, - }, - "service": schema.StringAttribute{ - Computed: true, - }, - }, - Blocks: map[string]schema.Block{ - "resource_property": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourcePropertyData](ctx), - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "data": schema.StringAttribute{ - Computed: true, - }, - "last_reported_at": schema.StringAttribute{ - Computed: true, - }, - "name": schema.StringAttribute{ - Computed: true, - }, - }, - }, - }, - }, - }, - }, - }, } } @@ -121,15 +76,23 @@ func (d *dataSourceSearch) Read(ctx context.Context, req datasource.ReadRequest, return } - data.ID = types.StringValue(data.QueryString.ValueString()) + if data.ViewArn.IsNull() { + data.ID = types.StringValue(fmt.Sprintf(",%s", data.QueryString.ValueString())) + } else { + data.ID = types.StringValue(fmt.Sprintf("%s,%s", data.ViewArn.ValueString(), data.QueryString.ValueString())) + } input := &resourceexplorer2.SearchInput{ QueryString: aws.String(data.QueryString.ValueString()), } + if !data.ViewArn.IsNull() { + input.ViewArn = aws.String(data.ViewArn.ValueString()) + } paginator := resourceexplorer2.NewSearchPaginator(conn, input) var out resourceexplorer2.SearchOutput + commonFieldsSet := false for paginator.HasMorePages() { page, err := paginator.NextPage(ctx) if err != nil { @@ -141,6 +104,11 @@ func (d *dataSourceSearch) Read(ctx context.Context, req datasource.ReadRequest, } if page != nil && len(page.Resources) > 0 { + if !commonFieldsSet { + out.Count = page.Count + out.ViewArn = page.ViewArn + commonFieldsSet = true + } out.Resources = append(out.Resources, page.Resources...) } } @@ -149,33 +117,35 @@ func (d *dataSourceSearch) Read(ctx context.Context, req datasource.ReadRequest, if resp.Diagnostics.HasError() { return } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } type dataSourceSearchData struct { - ResourceCount fwtypes.ListNestedObjectValueOf[countData] `tfsdk:"resource_count"` - Resources fwtypes.ListNestedObjectValueOf[resourcesData] `tfsdk:"resources"` - ID types.String `tfsdk:"id"` - ViewArn types.String `tfsdk:"view_arn"` - QueryString types.String `tfsdk:"query_string"` + Count fwtypes.ObjectValueOf[countData] `tfsdk:"resource_count"` + ID types.String `tfsdk:"id"` + QueryString types.String `tfsdk:"query_string"` + Resources fwtypes.ListNestedObjectValueOf[resourcesData] `tfsdk:"resources"` + ViewArn fwtypes.ARN `tfsdk:"view_arn"` } type countData struct { - Completed types.Bool `tfsdk:"completed"` + Complete types.Bool `tfsdk:"complete"` TotalResources types.Int64 `tfsdk:"total_resources"` } type resourcesData struct { - ARN types.String `tfsdk:"arn"` - LastReportedAt types.String `tfsdk:"last_reported_at"` - OwningAccountID types.String `tfsdk:"owning_account_id"` - Region types.String `tfsdk:"region"` - ResourceProperty fwtypes.ListNestedObjectValueOf[resourcePropertyData] `tfsdk:"resource_property"` - ResourceType types.String `tfsdk:"resource_type"` - Service types.String `tfsdk:"service"` + ARN fwtypes.ARN `tfsdk:"arn"` + LastReportedAt timetypes.RFC3339 `tfsdk:"last_reported_at"` + OwningAccountID types.String `tfsdk:"owning_account_id"` + Properties fwtypes.ListNestedObjectValueOf[propertiesData] `tfsdk:"properties"` + Region types.String `tfsdk:"region"` + ResourceType types.String `tfsdk:"resource_type"` + Service types.String `tfsdk:"service"` } -type resourcePropertyData struct { - Data types.String `tfsdk:"data"` - LastReportedAt types.String `tfsdk:"last_reported_at"` - Name types.String `tfsdk:"name"` +type propertiesData struct { + Data jsontypes.Normalized `tfsdk:"data"` + LastReportedAt timetypes.RFC3339 `tfsdk:"last_reported_at"` + Name types.String `tfsdk:"name"` } diff --git a/internal/service/resourceexplorer2/search_data_source_test.go b/internal/service/resourceexplorer2/search_data_source_test.go index 2bfe975b7ffb..397afb0512f5 100644 --- a/internal/service/resourceexplorer2/search_data_source_test.go +++ b/internal/service/resourceexplorer2/search_data_source_test.go @@ -37,8 +37,15 @@ func testAccSearchDataSource_basic(t *testing.T) { Config: testAccSearchDataSourceConfig_basic(rName, "LOCAL"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "view_arn", viewResourceName, "arn"), - resource.TestCheckResourceAttrSet(dataSourceName, "resource_count.#"), - resource.TestCheckResourceAttrSet(dataSourceName, "resources.#"), + resource.TestCheckResourceAttrSet(dataSourceName, "resource_count.complete"), + resource.TestCheckResourceAttrSet(dataSourceName, "resource_count.total_resources"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.arn"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.last_reported_at"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.owning_account_id"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.properties.#"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.region"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.resource_type"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.service"), ), }, }, @@ -72,8 +79,15 @@ func testAccSearchDataSource_IndexType(t *testing.T) { Config: testAccSearchDataSourceConfig_basic(rName, "AGGREGATOR"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "view_arn", viewResourceName, "arn"), - resource.TestCheckResourceAttrSet(dataSourceName, "resource_count.#"), - resource.TestCheckResourceAttrSet(dataSourceName, "resources.#"), + resource.TestCheckResourceAttrSet(dataSourceName, "resource_count.complete"), + resource.TestCheckResourceAttrSet(dataSourceName, "resource_count.total_resources"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.arn"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.last_reported_at"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.owning_account_id"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.properties.#"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.region"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.resource_type"), + resource.TestCheckResourceAttrSet(dataSourceName, "resources.0.service"), ), }, }, diff --git a/website/docs/d/resourceexplorer2_search.html.markdown b/website/docs/d/resourceexplorer2_search.html.markdown index b34dba6e2717..d0e24494d919 100644 --- a/website/docs/d/resourceexplorer2_search.html.markdown +++ b/website/docs/d/resourceexplorer2_search.html.markdown @@ -48,12 +48,12 @@ This data source exports the following attributes in addition to the arguments a * `arn` - Amazon resource name of resource. * `last_reported_at` - Date and time that Resource Explorer last queried this resource and updated the index with the latest information about the resource. * `owning_account_id` - Amazon Web Services account that owns the resource. -* `resource_property` - Structure with additional type-specific details about the resource. See [`resource_property`](#resource_property-attribute-reference) below. +* `properties` - Structure with additional type-specific details about the resource. See [`properties`](#resource_properties-attribute-reference) below. * `region` - Amazon Web Services Region in which the resource was created and exists. * `resource_type` - Type of the resource. * `service` - Amazon Web Service that owns the resource and is responsible for creating and updating it. -### `resource_property` Attribute Reference +### `properties` Attribute Reference * `data` - Details about this property. The content of this field is a JSON object that varies based on the resource type. * `last_reported_at` - The date and time that the information about this resource property was last updated.