diff --git a/.changelog/30422.txt b/.changelog/30422.txt new file mode 100644 index 000000000000..7ffd1740e85d --- /dev/null +++ b/.changelog/30422.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_quicksight_data_set +``` \ No newline at end of file diff --git a/internal/service/quicksight/data_set.go b/internal/service/quicksight/data_set.go index 19d0f3805235..61cb3d59009a 100644 --- a/internal/service/quicksight/data_set.go +++ b/internal/service/quicksight/data_set.go @@ -870,11 +870,11 @@ func resourceDataSetRead(ctx context.Context, d *schema.ResourceData, meta inter return diag.Errorf("error setting field_folders: %s", err) } - if err := d.Set("logical_table_map", flattenLogicalTableMap(dataSet.LogicalTableMap)); err != nil { + if err := d.Set("logical_table_map", flattenLogicalTableMap(dataSet.LogicalTableMap, logicalTableMapSchema())); err != nil { return diag.Errorf("error setting logical_table_map: %s", err) } - if err := d.Set("physical_table_map", flattenPhysicalTableMap(dataSet.PhysicalTableMap)); err != nil { + if err := d.Set("physical_table_map", flattenPhysicalTableMap(dataSet.PhysicalTableMap, physicalTableMapSchema())); err != nil { return diag.Errorf("error setting physical_table_map: %s", err) } @@ -1928,7 +1928,7 @@ func fieldFoldersHash(v interface{}) int { return create.StringHashcode(buf.String()) } -func flattenLogicalTableMap(apiObject map[string]*quicksight.LogicalTable) *schema.Set { +func flattenLogicalTableMap(apiObject map[string]*quicksight.LogicalTable, resourceSchema *schema.Resource) *schema.Set { if len(apiObject) == 0 { return nil } @@ -1954,7 +1954,7 @@ func flattenLogicalTableMap(apiObject map[string]*quicksight.LogicalTable) *sche tfList = append(tfList, tfMap) } - return schema.NewSet(schema.HashResource(logicalTableMapSchema()), tfList) + return schema.NewSet(schema.HashResource(resourceSchema), tfList) } func flattenDataTransforms(apiObject []*quicksight.TransformOperation) []interface{} { @@ -2076,7 +2076,7 @@ func flattenProjectOperation(apiObject *quicksight.ProjectOperation) []interface tfMap := map[string]interface{}{} if apiObject.ProjectedColumns != nil { - tfMap["project_columns"] = aws.StringValueSlice(apiObject.ProjectedColumns) + tfMap["projected_columns"] = flex.FlattenStringList(apiObject.ProjectedColumns) } return []interface{}{tfMap} @@ -2228,7 +2228,7 @@ func flattenJoinKeyProperties(apiObject *quicksight.JoinKeyProperties) map[strin return tfMap } -func flattenPhysicalTableMap(apiObject map[string]*quicksight.PhysicalTable) *schema.Set { +func flattenPhysicalTableMap(apiObject map[string]*quicksight.PhysicalTable, resourceSchema *schema.Resource) *schema.Set { if len(apiObject) == 0 { return nil } @@ -2254,7 +2254,7 @@ func flattenPhysicalTableMap(apiObject map[string]*quicksight.PhysicalTable) *sc tfList = append(tfList, tfMap) } - return schema.NewSet(schema.HashResource(physicalTableMapSchema()), tfList) + return schema.NewSet(schema.HashResource(resourceSchema), tfList) } func flattenCustomSQL(apiObject *quicksight.CustomSql) []interface{} { diff --git a/internal/service/quicksight/data_set_data_source.go b/internal/service/quicksight/data_set_data_source.go new file mode 100644 index 000000000000..caf1ca12f9a8 --- /dev/null +++ b/internal/service/quicksight/data_set_data_source.go @@ -0,0 +1,699 @@ +package quicksight + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKDataSource("aws_quicksight_data_set") +func DataSourceDataSet() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceDataSetRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "aws_account_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: verify.ValidAccountID, + }, + "column_groups": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "geo_spatial_column_group": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "columns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "country_code": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "column_level_permission_rules": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_names": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "principals": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "data_set_id": { + Type: schema.TypeString, + Required: true, + }, + "data_set_usage_configuration": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "disable_use_as_direct_query_source": { + Type: schema.TypeBool, + Computed: true, + }, + "disable_use_as_imported_source": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "field_folders": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_folders_id": { + Type: schema.TypeString, + Computed: true, + }, + "columns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "import_mode": { + Type: schema.TypeString, + Computed: true, + }, + "logical_table_map": { + Type: schema.TypeSet, + Computed: true, + Elem: logicalTableMapDataSourceSchema(), + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "permissions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "principal": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "physical_table_map": { + Type: schema.TypeSet, + Computed: true, + Elem: physicalTableMapDataSourceSchema(), + }, + "row_level_permission_data_set": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "format_version": { + Type: schema.TypeString, + Computed: true, + }, + "namespace": { + Type: schema.TypeString, + Computed: true, + }, + "permission_policy": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "row_level_permission_tag_configuration": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Computed: true, + }, + "tag_rules": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_name": { + Type: schema.TypeString, + Computed: true, + }, + "match_all_value": { + Type: schema.TypeString, + Computed: true, + }, + "tag_key": { + Type: schema.TypeString, + Computed: true, + }, + "tag_multi_value_delimiter": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "tags": tftags.TagsSchemaComputed(), + "tags_all": tftags.TagsSchemaComputed(), + }, + } +} + +func logicalTableMapDataSourceSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alias": { + Type: schema.TypeString, + Computed: true, + }, + "data_transforms": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cast_column_type_operation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_name": { + Type: schema.TypeString, + Computed: true, + }, + "format": { + Type: schema.TypeString, + Computed: true, + }, + "new_column_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "create_columns_operation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "columns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_id": { + Type: schema.TypeString, + Computed: true, + }, + "column_name": { + Type: schema.TypeString, + Computed: true, + }, + "expression": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "filter_operation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "condition_expression": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "project_operation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "projected_columns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "rename_column_operation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_name": { + Type: schema.TypeString, + Computed: true, + }, + "new_column_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "tag_column_operation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_name": { + Type: schema.TypeString, + Computed: true, + }, + "tags": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_description": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "text": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "column_geographic_role": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "untag_column_operation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column_name": { + Type: schema.TypeString, + Computed: true, + }, + "tag_names": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + "logical_table_map_id": { + Type: schema.TypeString, + Computed: true, + }, + "source": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data_set_arn": { + Type: schema.TypeString, + Computed: true, + }, + "join_instruction": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "left_join_key_properties": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unique_key": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "left_operand": { + Type: schema.TypeString, + Computed: true, + }, + "on_clause": { + Type: schema.TypeString, + Computed: true, + }, + "right_join_key_properties": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unique_key": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "right_operand": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "physical_table_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func physicalTableMapDataSourceSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "custom_sql": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "columns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "data_source_arn": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "sql_query": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "physical_table_map_id": { + Type: schema.TypeString, + Computed: true, + }, + "relational_table": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "catalog": { + Type: schema.TypeString, + Computed: true, + }, + "data_source_arn": { + Type: schema.TypeString, + Computed: true, + }, + "input_columns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "schema": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "s3_source": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data_source_arn": { + Type: schema.TypeString, + Computed: true, + }, + "input_columns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "upload_settings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "contains_header": { + Type: schema.TypeBool, + Computed: true, + }, + "delimiter": { + Type: schema.TypeString, + Computed: true, + }, + "format": { + Type: schema.TypeString, + Computed: true, + }, + "start_from_row": { + Type: schema.TypeInt, + Computed: true, + }, + "text_qualifier": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +const ( + DSNameDataSet = "Data Set Data Source" +) + +func dataSourceDataSetRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).QuickSightConn() + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + awsAccountId := meta.(*conns.AWSClient).AccountID + if v, ok := d.GetOk("aws_account_id"); ok { + awsAccountId = v.(string) + } + dataSetId := d.Get("data_set_id").(string) + + descOpts := &quicksight.DescribeDataSetInput{ + AwsAccountId: aws.String(awsAccountId), + DataSetId: aws.String(dataSetId), + } + + output, err := conn.DescribeDataSetWithContext(ctx, descOpts) + if err != nil { + return create.DiagError(names.QuickSight, create.ErrActionReading, DSNameDataSet, dataSetId, err) + } + + dataSet := output.DataSet + + d.SetId(createDataSetID(awsAccountId, dataSetId)) + + d.Set("arn", dataSet.Arn) + d.Set("aws_account_id", awsAccountId) + d.Set("data_set_id", dataSet.DataSetId) + d.Set("name", dataSet.Name) + d.Set("import_mode", dataSet.ImportMode) + + if err := d.Set("column_groups", flattenColumnGroups(dataSet.ColumnGroups)); err != nil { + return diag.Errorf("error setting column_groups: %s", err) + } + + if err := d.Set("column_level_permission_rules", flattenColumnLevelPermissionRules(dataSet.ColumnLevelPermissionRules)); err != nil { + return diag.Errorf("error setting column_level_permission_rules: %s", err) + } + + if err := d.Set("data_set_usage_configuration", flattenDataSetUsageConfiguration(dataSet.DataSetUsageConfiguration)); err != nil { + return diag.Errorf("error setting data_set_usage_configuration: %s", err) + } + + if err := d.Set("field_folders", flattenFieldFolders(dataSet.FieldFolders)); err != nil { + return diag.Errorf("error setting field_folders: %s", err) + } + + if err := d.Set("logical_table_map", flattenLogicalTableMap(dataSet.LogicalTableMap, logicalTableMapDataSourceSchema())); err != nil { + return diag.Errorf("error setting logical_table_map: %s", err) + } + + if err := d.Set("physical_table_map", flattenPhysicalTableMap(dataSet.PhysicalTableMap, physicalTableMapDataSourceSchema())); err != nil { + return diag.Errorf("error setting physical_table_map: %s", err) + } + + if err := d.Set("row_level_permission_data_set", flattenRowLevelPermissionDataSet(dataSet.RowLevelPermissionDataSet)); err != nil { + return diag.Errorf("error setting row_level_permission_data_set: %s", err) + } + + if err := d.Set("row_level_permission_tag_configuration", flattenRowLevelPermissionTagConfiguration(dataSet.RowLevelPermissionTagConfiguration)); err != nil { + return diag.Errorf("error setting row_level_permission_tag_configuration: %s", err) + } + + tags, err := ListTags(ctx, conn, d.Get("arn").(string)) + + if err != nil { + return diag.Errorf("error listing tags for QuickSight Data Set (%s): %s", d.Id(), err) + } + + tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return diag.Errorf("error setting tags: %s", err) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return diag.Errorf("error setting tags_all: %s", err) + } + + permsResp, err := conn.DescribeDataSetPermissionsWithContext(ctx, &quicksight.DescribeDataSetPermissionsInput{ + AwsAccountId: aws.String(awsAccountId), + DataSetId: aws.String(dataSetId), + }) + + if err != nil { + return diag.Errorf("error describing QuickSight Data Source (%s) Permissions: %s", d.Id(), err) + } + + if err := d.Set("permissions", flattenPermissions(permsResp.Permissions)); err != nil { + return diag.Errorf("error setting permissions: %s", err) + } + return nil +} diff --git a/internal/service/quicksight/data_set_data_source_test.go b/internal/service/quicksight/data_set_data_source_test.go new file mode 100644 index 000000000000..907e5a8f85c2 --- /dev/null +++ b/internal/service/quicksight/data_set_data_source_test.go @@ -0,0 +1,65 @@ +package quicksight_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/quicksight" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestAccQuickSightDataSetDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + rId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_quicksight_data_set.test" + dataSourceName := "data.aws_quicksight_data_set.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSetDataSourceConfig_basic(rId, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + ), + }, + }, + }) +} + +func testAccDataSetDataSourceConfig_basic(rId, rName string) string { + return acctest.ConfigCompose( + testAccDataSetConfigBase(rId, rName), + fmt.Sprintf(` +resource "aws_quicksight_data_set" "test" { + data_set_id = %[1]q + name = %[2]q + import_mode = "SPICE" + + physical_table_map { + physical_table_map_id = %[1]q + s3_source { + data_source_arn = aws_quicksight_data_source.test.arn + input_columns { + name = "Column1" + type = "STRING" + } + upload_settings { + format = "JSON" + } + } + } +} + +data "aws_quicksight_data_set" "test" { + data_set_id = aws_quicksight_data_set.test.data_set_id +} +`, rId, rName)) +} diff --git a/internal/service/quicksight/service_package_gen.go b/internal/service/quicksight/service_package_gen.go index d51d16c355ee..1ffe989bb9c2 100644 --- a/internal/service/quicksight/service_package_gen.go +++ b/internal/service/quicksight/service_package_gen.go @@ -20,7 +20,12 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic } func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePackageSDKDataSource { - return []*types.ServicePackageSDKDataSource{} + return []*types.ServicePackageSDKDataSource{ + { + Factory: DataSourceDataSet, + TypeName: "aws_quicksight_data_set", + }, + } } func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePackageSDKResource { diff --git a/website/docs/d/quicksight_data_set.html.markdown b/website/docs/d/quicksight_data_set.html.markdown new file mode 100644 index 000000000000..e08d309d3ae3 --- /dev/null +++ b/website/docs/d/quicksight_data_set.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "QuickSight" +layout: "aws" +page_title: "AWS: aws_quicksight_data_set" +description: |- + Use this data source to fetch information about a QuickSight Data Set. +--- + +# Data Source: aws_quicksight_data_set + +Data source for managing a QuickSight Data Set. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_quicksight_data_set" "example" { + data_set_id = "example-id" +} +``` + +## Argument Reference + +The following arguments are required: + +* `data_set_id` - (Required) Identifier for the data set. + +The following arguments are optional: + +* `aws_account_id` - (Optional) AWS account ID. + +## Attributes Reference + +See the [Data Set Resource](/docs/providers/aws/r/quicksight_data_set.html) for details on the +returned attributes - they are identical.