From b58b3c02b7ab237d0b68884b991ce3014794a5fc Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 12 Apr 2023 10:41:25 -0400 Subject: [PATCH 1/6] r/aws_quicksight_namespace: resource implementation --- internal/service/quicksight/exports_test.go | 3 +- internal/service/quicksight/namespace.go | 365 ++++++++++++++++++ .../service/quicksight/service_package_gen.go | 7 + 3 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 internal/service/quicksight/namespace.go diff --git a/internal/service/quicksight/exports_test.go b/internal/service/quicksight/exports_test.go index d4f8c49de062..5a0bbc5a852b 100644 --- a/internal/service/quicksight/exports_test.go +++ b/internal/service/quicksight/exports_test.go @@ -2,6 +2,7 @@ package quicksight // Exports for use in tests only. var ( - ResourceIngestion = newResourceIngestion ResourceIAMPolicyAssignment = newResourceIAMPolicyAssignment + ResourceIngestion = newResourceIngestion + ResourceNamespace = newResourceNamespace ) diff --git a/internal/service/quicksight/namespace.go b/internal/service/quicksight/namespace.go new file mode 100644 index 000000000000..9d0ef2136562 --- /dev/null +++ b/internal/service/quicksight/namespace.go @@ -0,0 +1,365 @@ +package quicksight + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "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/stringdefault" + "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" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource(name="Namespace") +// @Tags(identifierAttribute="arn") +func newResourceNamespace(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &resourceNamespace{} + r.SetDefaultCreateTimeout(2 * time.Minute) + r.SetDefaultDeleteTimeout(2 * time.Minute) + + return r, nil +} + +const ( + ResNameNamespace = "Namespace" +) + +type resourceNamespace struct { + framework.ResourceWithConfigure + framework.WithTimeouts +} + +func (r *resourceNamespace) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_quicksight_namespace" +} + +func (r *resourceNamespace) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "arn": framework.ARNAttributeComputedOnly(), + "aws_account_id": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + stringplanmodifier.RequiresReplace(), + }, + }, + "capacity_region": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "creation_status": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "id": framework.IDAttribute(), + "identity_store": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString(quicksight.IdentityStoreQuicksight), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "namespace": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + "timeouts": timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Delete: true, + }), + }, + } +} + +func (r *resourceNamespace) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + conn := r.Meta().QuickSightConn() + + var plan resourceNamespaceData + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + if plan.AWSAccountID.IsUnknown() || plan.AWSAccountID.IsNull() { + plan.AWSAccountID = types.StringValue(r.Meta().AccountID) + } + plan.ID = types.StringValue(createNamespaceID(plan.AWSAccountID.ValueString(), plan.Namespace.ValueString())) + + in := quicksight.CreateNamespaceInput{ + AwsAccountId: aws.String(plan.AWSAccountID.ValueString()), + Namespace: aws.String(plan.Namespace.ValueString()), + IdentityStore: aws.String(plan.IdentityStore.ValueString()), + Tags: GetTagsIn(ctx), + } + + out, err := conn.CreateNamespaceWithContext(ctx, &in) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionCreating, ResNameNamespace, plan.Namespace.String(), err), + err.Error(), + ) + return + } + if out == nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionCreating, ResNameNamespace, plan.Namespace.String(), nil), + errors.New("empty output").Error(), + ) + return + } + + createTimeout := r.CreateTimeout(ctx, plan.Timeouts) + waitOut, err := waitNamespaceCreated(ctx, conn, plan.ID.ValueString(), createTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionWaitingForCreation, ResNameNamespace, plan.Namespace.String(), err), + err.Error(), + ) + return + } + plan.ARN = flex.StringToFramework(ctx, waitOut.Arn) + plan.CapacityRegion = flex.StringToFramework(ctx, waitOut.CapacityRegion) + plan.CreationStatus = flex.StringToFramework(ctx, waitOut.CreationStatus) + plan.IdentityStore = flex.StringToFramework(ctx, waitOut.IdentityStore) + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} + +func (r *resourceNamespace) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + conn := r.Meta().QuickSightConn() + + var state resourceNamespaceData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + out, err := FindNamespaceByID(ctx, conn, state.ID.ValueString()) + if tfresource.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionSetting, ResNameNamespace, state.ID.String(), nil), + err.Error(), + ) + return + } + + state.ARN = flex.StringToFramework(ctx, out.Arn) + state.CapacityRegion = flex.StringToFramework(ctx, out.CapacityRegion) + state.CreationStatus = flex.StringToFramework(ctx, out.CreationStatus) + state.IdentityStore = flex.StringToFramework(ctx, out.IdentityStore) + + // To support import, parse the ID for the component keys and set + // individual values in state + awsAccountID, namespace, err := ParseNamespaceID(state.ID.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionSetting, ResNameNamespace, state.ID.String(), nil), + err.Error(), + ) + return + } + state.AWSAccountID = flex.StringValueToFramework(ctx, awsAccountID) + state.Namespace = flex.StringValueToFramework(ctx, namespace) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceNamespace) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + // There is no update API, and tag updates are handled via a "before" + // interceptor. Copy the planned tag attributes to state to ensure + // updates are captured. + var plan resourceNamespaceData + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *resourceNamespace) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().QuickSightConn() + + var state resourceNamespaceData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := conn.DeleteNamespaceWithContext(ctx, &quicksight.DeleteNamespaceInput{ + AwsAccountId: aws.String(state.AWSAccountID.ValueString()), + Namespace: aws.String(state.Namespace.ValueString()), + }) + if err != nil { + if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { + return + } + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionDeleting, ResNameNamespace, state.ID.String(), nil), + err.Error(), + ) + } + + deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) + _, err = waitNamespaceDeleted(ctx, conn, state.ID.ValueString(), deleteTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionWaitingForDeletion, ResNameNamespace, state.ID.String(), err), + err.Error(), + ) + return + } +} + +func (r *resourceNamespace) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func (r *resourceNamespace) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + r.SetTagsAll(ctx, req, resp) +} + +func FindNamespaceByID(ctx context.Context, conn *quicksight.QuickSight, id string) (*quicksight.NamespaceInfoV2, error) { + awsAccountID, namespace, err := ParseNamespaceID(id) + if err != nil { + return nil, err + } + + in := &quicksight.DescribeNamespaceInput{ + AwsAccountId: aws.String(awsAccountID), + Namespace: aws.String(namespace), + } + + out, err := conn.DescribeNamespaceWithContext(ctx, in) + if err != nil { + if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + return nil, err + } + + if out == nil || out.Namespace == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out.Namespace, nil +} + +func ParseNamespaceID(id string) (string, string, error) { + parts := strings.SplitN(id, ",", 3) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%s), expected AWS_ACCOUNT_ID,NAMESPACE", id) + } + return parts[0], parts[1], nil +} + +func createNamespaceID(awsAccountID, namespace string) string { + return fmt.Sprintf("%s,%s", awsAccountID, namespace) +} + +type resourceNamespaceData struct { + ARN types.String `tfsdk:"arn"` + AWSAccountID types.String `tfsdk:"aws_account_id"` + CapacityRegion types.String `tfsdk:"capacity_region"` + CreationStatus types.String `tfsdk:"creation_status"` + ID types.String `tfsdk:"id"` + IdentityStore types.String `tfsdk:"identity_store"` + Namespace types.String `tfsdk:"namespace"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func waitNamespaceCreated(ctx context.Context, conn *quicksight.QuickSight, id string, timeout time.Duration) (*quicksight.NamespaceInfoV2, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{ + quicksight.NamespaceStatusCreating, + }, + Target: []string{ + quicksight.NamespaceStatusCreated, + }, + Refresh: statusNamespace(ctx, conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if output, ok := outputRaw.(*quicksight.NamespaceInfoV2); ok { + return output, err + } + + return nil, err +} + +func waitNamespaceDeleted(ctx context.Context, conn *quicksight.QuickSight, id string, timeout time.Duration) (*quicksight.NamespaceInfoV2, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{ + quicksight.NamespaceStatusDeleting, + }, + Target: []string{}, + Refresh: statusNamespace(ctx, conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if output, ok := outputRaw.(*quicksight.NamespaceInfoV2); ok { + return output, err + } + + return nil, err +} + +func statusNamespace(ctx context.Context, conn *quicksight.QuickSight, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindNamespaceByID(ctx, conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.CreationStatus), nil + } +} diff --git a/internal/service/quicksight/service_package_gen.go b/internal/service/quicksight/service_package_gen.go index 0a439bec9f13..5122d88c2a3d 100644 --- a/internal/service/quicksight/service_package_gen.go +++ b/internal/service/quicksight/service_package_gen.go @@ -23,6 +23,13 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic { Factory: newResourceIngestion, }, + { + Factory: newResourceNamespace, + Name: "Namespace", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: "arn", + }, + }, } } From 3137b7a5e91f54e46c7f4d3b0a48c93944899bfa Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 12 Apr 2023 13:27:34 -0400 Subject: [PATCH 2/6] internal/provider: switch read after tags interceptor to response state --- internal/provider/fwprovider/intercept.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/provider/fwprovider/intercept.go b/internal/provider/fwprovider/intercept.go index 5786d43cde87..c8e017d5c178 100644 --- a/internal/provider/fwprovider/intercept.go +++ b/internal/provider/fwprovider/intercept.go @@ -377,7 +377,7 @@ func (r tagsInterceptor) read(ctx context.Context, request resource.ReadRequest, if identifierAttribute := r.tags.IdentifierAttribute; identifierAttribute != "" { var identifier string - diags.Append(request.State.GetAttribute(ctx, path.Root(identifierAttribute), &identifier)...) + diags.Append(response.State.GetAttribute(ctx, path.Root(identifierAttribute), &identifier)...) if diags.HasError() { return ctx, diags From 1d883f0cd7677a290b8c2fbee992446edba9c728 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 12 Apr 2023 10:41:35 -0400 Subject: [PATCH 3/6] r/aws_quicksight_namespace: tests --- internal/service/quicksight/namespace_test.go | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 internal/service/quicksight/namespace_test.go diff --git a/internal/service/quicksight/namespace_test.go b/internal/service/quicksight/namespace_test.go new file mode 100644 index 000000000000..509ccae9b2ac --- /dev/null +++ b/internal/service/quicksight/namespace_test.go @@ -0,0 +1,198 @@ +package quicksight_test + +import ( + "context" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tfquicksight "github.com/hashicorp/terraform-provider-aws/internal/service/quicksight" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccQuickSightNamespace_basic(t *testing.T) { + ctx := acctest.Context(t) + var namespace quicksight.NamespaceInfoV2 + resourceName := "aws_quicksight_namespace.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckNamespaceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccNamespaceConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNamespaceExists(ctx, resourceName, &namespace), + resource.TestCheckResourceAttr(resourceName, "namespace", rName), + resource.TestCheckResourceAttr(resourceName, "identity_store", quicksight.IdentityStoreQuicksight), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "quicksight", fmt.Sprintf("namespace/%[1]s", rName)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccQuickSightNamespace_disappears(t *testing.T) { + ctx := acctest.Context(t) + var namespace quicksight.NamespaceInfoV2 + resourceName := "aws_quicksight_namespace.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckNamespaceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccNamespaceConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNamespaceExists(ctx, resourceName, &namespace), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfquicksight.ResourceNamespace, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccQuickSightNamespace_tags(t *testing.T) { + ctx := acctest.Context(t) + var namespace quicksight.NamespaceInfoV2 + resourceName := "aws_quicksight_namespace.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckNamespaceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccNamespaceConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckNamespaceExists(ctx, resourceName, &namespace), + resource.TestCheckResourceAttr(resourceName, "namespace", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccNamespaceConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckNamespaceExists(ctx, resourceName, &namespace), + resource.TestCheckResourceAttr(resourceName, "namespace", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccNamespaceConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckNamespaceExists(ctx, resourceName, &namespace), + resource.TestCheckResourceAttr(resourceName, "namespace", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckNamespaceExists(ctx context.Context, resourceName string, namespace *quicksight.NamespaceInfoV2) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightConn() + output, err := tfquicksight.FindNamespaceByID(ctx, conn, rs.Primary.ID) + if err != nil { + return create.Error(names.QuickSight, create.ErrActionCheckingExistence, tfquicksight.ResNameNamespace, rs.Primary.ID, err) + } + + *namespace = *output + + return nil + } +} + +func testAccCheckNamespaceDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightConn() + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_quicksight_namespace" { + continue + } + + output, err := tfquicksight.FindNamespaceByID(ctx, conn, rs.Primary.ID) + if err != nil { + if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { + return nil + } + return err + } + + if output != nil { + return create.Error(names.QuickSight, create.ErrActionCheckingDestroyed, tfquicksight.ResNameNamespace, rs.Primary.ID, err) + } + } + + return nil + } +} + +func testAccNamespaceConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_quicksight_namespace" "test" { + namespace = %[1]q +} +`, rName) +} + +func testAccNamespaceConfig_tags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_quicksight_namespace" "test" { + namespace = %[1]q + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccNamespaceConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_quicksight_namespace" "test" { + namespace = %[1]q + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} From 6edb6013739e37f63f1023d9405d7fef6233d90a Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 12 Apr 2023 13:37:44 -0400 Subject: [PATCH 4/6] r/aws_quicksight_namespace: docs --- .../docs/r/quicksight_namespace.html.markdown | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 website/docs/r/quicksight_namespace.html.markdown diff --git a/website/docs/r/quicksight_namespace.html.markdown b/website/docs/r/quicksight_namespace.html.markdown new file mode 100644 index 000000000000..9d78523b8f68 --- /dev/null +++ b/website/docs/r/quicksight_namespace.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: "QuickSight" +layout: "aws" +page_title: "AWS: aws_quicksight_namespace" +description: |- + Terraform resource for managing an AWS QuickSight Namespace. +--- + +# Resource: aws_quicksight_namespace + +Terraform resource for managing an AWS QuickSight Namespace. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_quicksight_namespace" "example" { + namespace = "example" +} +``` + +## Argument Reference + +The following arguments are required: + +* `namespace` - (Required) Name of the namespace. + +The following arguments are optional: + +* `aws_account_id` - (Optional) AWS account ID. +* `identity_store` - (Optional) User identity directory type. Defaults to `QUICKSIGHT`, the only current valid value. +* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the Namespace. +* `capacity_region` - Namespace AWS Region. +* `creation_status` - Creation status of the namespace. +* `id` - A comma-delimited string joining AWS account ID and namespace. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `2m`) +* `delete` - (Default `2m`) + +## Import + +QuickSight Namespace can be imported using the AWS account ID and namespace separated by commas (`,`) e.g., + +``` +$ terraform import aws_quicksight_namespace.example 123456789012,example +``` From bb89ff292c33323bd241edf0f75ee2d84efe433e Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 12 Apr 2023 13:58:10 -0400 Subject: [PATCH 5/6] [r|d]/quicksight: add missing name annotations --- internal/service/quicksight/account_subscription.go | 2 +- internal/service/quicksight/data_set_data_source.go | 2 +- internal/service/quicksight/group.go | 2 +- internal/service/quicksight/group_membership.go | 2 +- internal/service/quicksight/iam_policy_assignment.go | 4 ++-- internal/service/quicksight/ingestion.go | 2 +- internal/service/quicksight/service_package_gen.go | 7 +++++++ internal/service/quicksight/user.go | 2 +- 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/internal/service/quicksight/account_subscription.go b/internal/service/quicksight/account_subscription.go index 9bf7d0275abe..002347e14a7e 100644 --- a/internal/service/quicksight/account_subscription.go +++ b/internal/service/quicksight/account_subscription.go @@ -22,7 +22,7 @@ import ( ) // Function annotations are used for resource registration to the Provider. DO NOT EDIT. -// @SDKResource("aws_quicksight_account_subscription") +// @SDKResource("aws_quicksight_account_subscription", name="Account Subscription") func ResourceAccountSubscription() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceAccountSubscriptionCreate, diff --git a/internal/service/quicksight/data_set_data_source.go b/internal/service/quicksight/data_set_data_source.go index caf1ca12f9a8..bb207ee87ab0 100644 --- a/internal/service/quicksight/data_set_data_source.go +++ b/internal/service/quicksight/data_set_data_source.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_quicksight_data_set") +// @SDKDataSource("aws_quicksight_data_set", name="Data Set") func DataSourceDataSet() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceDataSetRead, diff --git a/internal/service/quicksight/group.go b/internal/service/quicksight/group.go index 395c45fc8857..f5ecaf5aa1b8 100644 --- a/internal/service/quicksight/group.go +++ b/internal/service/quicksight/group.go @@ -16,7 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" ) -// @SDKResource("aws_quicksight_group") +// @SDKResource("aws_quicksight_group", name="Group") func ResourceGroup() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceGroupCreate, diff --git a/internal/service/quicksight/group_membership.go b/internal/service/quicksight/group_membership.go index 66c33af6e040..0dbd42b8cc1c 100644 --- a/internal/service/quicksight/group_membership.go +++ b/internal/service/quicksight/group_membership.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" ) -// @SDKResource("aws_quicksight_group_membership") +// @SDKResource("aws_quicksight_group_membership", name="Group Membership") func ResourceGroupMembership() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceGroupMembershipCreate, diff --git a/internal/service/quicksight/iam_policy_assignment.go b/internal/service/quicksight/iam_policy_assignment.go index 45313b68d490..7af8cd52af3b 100644 --- a/internal/service/quicksight/iam_policy_assignment.go +++ b/internal/service/quicksight/iam_policy_assignment.go @@ -30,13 +30,13 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkResource +// @FrameworkResource(name="IAM Policy Assignment") func newResourceIAMPolicyAssignment(_ context.Context) (resource.ResourceWithConfigure, error) { return &resourceIAMPolicyAssignment{}, nil } const ( - ResNameIAMPolicyAssignment = "IAMPolicyAssignment" + ResNameIAMPolicyAssignment = "IAM Policy Assignment" DefaultIAMPolicyAssignmentNamespace = "default" iamPropagationTimeout = 2 * time.Minute diff --git a/internal/service/quicksight/ingestion.go b/internal/service/quicksight/ingestion.go index e0d9ef57c6b4..d2e079b98f70 100644 --- a/internal/service/quicksight/ingestion.go +++ b/internal/service/quicksight/ingestion.go @@ -25,7 +25,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkResource +// @FrameworkResource(name="Ingestion") func newResourceIngestion(_ context.Context) (resource.ResourceWithConfigure, error) { return &resourceIngestion{}, nil } diff --git a/internal/service/quicksight/service_package_gen.go b/internal/service/quicksight/service_package_gen.go index 5122d88c2a3d..aa9fbf7f0485 100644 --- a/internal/service/quicksight/service_package_gen.go +++ b/internal/service/quicksight/service_package_gen.go @@ -19,9 +19,11 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic return []*types.ServicePackageFrameworkResource{ { Factory: newResourceIAMPolicyAssignment, + Name: "IAM Policy Assignment", }, { Factory: newResourceIngestion, + Name: "Ingestion", }, { Factory: newResourceNamespace, @@ -38,6 +40,7 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac { Factory: DataSourceDataSet, TypeName: "aws_quicksight_data_set", + Name: "Data Set", }, } } @@ -47,6 +50,7 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka { Factory: ResourceAccountSubscription, TypeName: "aws_quicksight_account_subscription", + Name: "Account Subscription", }, { Factory: ResourceDataSet, @@ -75,14 +79,17 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka { Factory: ResourceGroup, TypeName: "aws_quicksight_group", + Name: "Group", }, { Factory: ResourceGroupMembership, TypeName: "aws_quicksight_group_membership", + Name: "Group Membership", }, { Factory: ResourceUser, TypeName: "aws_quicksight_user", + Name: "User", }, } } diff --git a/internal/service/quicksight/user.go b/internal/service/quicksight/user.go index 341ccfe329d6..ed4c7852caba 100644 --- a/internal/service/quicksight/user.go +++ b/internal/service/quicksight/user.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" ) -// @SDKResource("aws_quicksight_user") +// @SDKResource("aws_quicksight_user", name="User") func ResourceUser() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceUserCreate, From e7fcead78cd24fc3321917a8ee7a7c30b16339ea Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 12 Apr 2023 14:21:56 -0400 Subject: [PATCH 6/6] chore: changelog --- .changelog/30681.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/30681.txt diff --git a/.changelog/30681.txt b/.changelog/30681.txt new file mode 100644 index 000000000000..6cb64234ffaf --- /dev/null +++ b/.changelog/30681.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_quicksight_namespace +```