From 4aca698f0759c4d67589132e7c1be5508d8644c7 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 3 Sep 2024 15:46:07 -0500 Subject: [PATCH 1/3] aws_docdbelastic_cluster: use autoflex --- internal/service/docdbelastic/cluster.go | 160 ++++++++---------- internal/service/docdbelastic/cluster_test.go | 14 +- 2 files changed, 82 insertions(+), 92 deletions(-) diff --git a/internal/service/docdbelastic/cluster.go b/internal/service/docdbelastic/cluster.go index e4c13754ab0..0283a9e2800 100644 --- a/internal/service/docdbelastic/cluster.go +++ b/internal/service/docdbelastic/cluster.go @@ -28,7 +28,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" @@ -48,6 +49,7 @@ func newResourceCluster(context.Context) (resource.ResourceWithConfigure, error) type resourceCluster struct { framework.ResourceWithConfigure framework.WithTimeouts + framework.WithImportByID } const ( @@ -73,13 +75,11 @@ func (r *resourceCluster) Schema(ctx context.Context, _ resource.SchemaRequest, }, names.AttrARN: framework.ARNAttributeComputedOnly(), "auth_type": schema.StringAttribute{ - Required: true, + CustomType: fwtypes.StringEnumType[awstypes.Auth](), + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, - Validators: []validator.String{ - enum.FrameworkValidate[awstypes.Auth](), - }, }, names.AttrEndpoint: schema.StringAttribute{ Computed: true, @@ -103,8 +103,9 @@ func (r *resourceCluster) Schema(ctx context.Context, _ resource.SchemaRequest, }, }, names.AttrPreferredMaintenanceWindow: schema.StringAttribute{ - Optional: true, - Computed: true, + CustomType: fwtypes.OnceAWeekWindowType, + Optional: true, + Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, @@ -119,9 +120,9 @@ func (r *resourceCluster) Schema(ctx context.Context, _ resource.SchemaRequest, }, }, names.AttrSubnetIDs: schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, + CustomType: fwtypes.SetOfStringType, + Optional: true, + Computed: true, PlanModifiers: []planmodifier.Set{ setplanmodifier.UseStateForUnknown(), }, @@ -129,9 +130,9 @@ func (r *resourceCluster) Schema(ctx context.Context, _ resource.SchemaRequest, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), names.AttrVPCSecurityGroupIDs: schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, + CustomType: fwtypes.SetOfStringType, + Optional: true, + Computed: true, PlanModifiers: []planmodifier.Set{ setplanmodifier.UseStateForUnknown(), }, @@ -161,34 +162,17 @@ func (r *resourceCluster) Create(ctx context.Context, request resource.CreateReq return } - input := &docdbelastic.CreateClusterInput{ - ClientToken: aws.String(id.UniqueId()), - AdminUserName: flex.StringFromFramework(ctx, plan.AdminUserName), - AdminUserPassword: flex.StringFromFramework(ctx, plan.AdminUserPassword), - AuthType: awstypes.Auth(plan.AuthType.ValueString()), - ClusterName: flex.StringFromFramework(ctx, plan.Name), - ShardCapacity: flex.Int32FromFramework(ctx, plan.ShardCapacity), - ShardCount: flex.Int32FromFramework(ctx, plan.ShardCount), - Tags: getTagsIn(ctx), - } - - if !plan.KmsKeyID.IsNull() || !plan.KmsKeyID.IsUnknown() { - input.KmsKeyId = flex.StringFromFramework(ctx, plan.KmsKeyID) - } - - if !plan.PreferredMaintenanceWindow.IsNull() || !plan.PreferredMaintenanceWindow.IsUnknown() { - input.PreferredMaintenanceWindow = flex.StringFromFramework(ctx, plan.PreferredMaintenanceWindow) - } - - if !plan.SubnetIds.IsNull() || !plan.SubnetIds.IsUnknown() { - input.SubnetIds = flex.ExpandFrameworkStringValueSet(ctx, plan.SubnetIds) - } + optionPrefix := fwflex.WithFieldNamePrefix("Cluster") + input := docdbelastic.CreateClusterInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, plan, &input, optionPrefix)...) - if !plan.VpcSecurityGroupIds.IsNull() || !plan.VpcSecurityGroupIds.IsUnknown() { - input.VpcSecurityGroupIds = flex.ExpandFrameworkStringValueSet(ctx, plan.VpcSecurityGroupIds) + if response.Diagnostics.HasError() { + return } + input.ClientToken = aws.String(id.UniqueId()) + input.Tags = getTagsIn(ctx) - createOut, err := conn.CreateCluster(ctx, input) + createOut, err := conn.CreateCluster(ctx, &input) if err != nil { response.Diagnostics.AddError( @@ -199,7 +183,14 @@ func (r *resourceCluster) Create(ctx context.Context, request resource.CreateReq } state := plan - state.ID = flex.StringToFramework(ctx, createOut.Cluster.ClusterArn) + state.ID = fwflex.StringToFramework(ctx, createOut.Cluster.ClusterArn) + + // set partial state + response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root("id"), createOut.Cluster.ClusterArn)...) + + if response.Diagnostics.HasError() { + return + } createTimeout := r.CreateTimeout(ctx, plan.Timeouts) out, err := waitClusterCreated(ctx, conn, state.ID.ValueString(), createTimeout) @@ -212,7 +203,12 @@ func (r *resourceCluster) Create(ctx context.Context, request resource.CreateReq return } - state.refreshFromOutput(ctx, out) + response.Diagnostics.Append(fwflex.Flatten(ctx, out, &state, optionPrefix)...) + + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(response.State.Set(ctx, &state)...) } @@ -242,7 +238,12 @@ func (r *resourceCluster) Read(ctx context.Context, request resource.ReadRequest return } - state.refreshFromOutput(ctx, out) + response.Diagnostics.Append(fwflex.Flatten(ctx, out, &state, fwflex.WithFieldNamePrefix("Cluster"))...) + + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(response.State.Set(ctx, &state)...) } @@ -265,35 +266,37 @@ func (r *resourceCluster) Update(ctx context.Context, request resource.UpdateReq if clusterHasChanges(ctx, plan, state) { input := &docdbelastic.UpdateClusterInput{ ClientToken: aws.String(id.UniqueId()), - ClusterArn: flex.StringFromFramework(ctx, state.ID), + ClusterArn: state.ID.ValueStringPointer(), } + // expanding manually because AWS validation throws an error when more than one + // updatable field is included in the request if !plan.AdminUserPassword.Equal(state.AdminUserPassword) { - input.AdminUserPassword = flex.StringFromFramework(ctx, plan.AdminUserPassword) + input.AdminUserPassword = plan.AdminUserPassword.ValueStringPointer() } if !plan.AuthType.Equal(state.AuthType) { - input.AuthType = awstypes.Auth(plan.AuthType.ValueString()) + input.AuthType = plan.AuthType.ValueEnum() } if !plan.PreferredMaintenanceWindow.Equal(state.PreferredMaintenanceWindow) { - input.PreferredMaintenanceWindow = flex.StringFromFramework(ctx, plan.PreferredMaintenanceWindow) + input.PreferredMaintenanceWindow = plan.PreferredMaintenanceWindow.ValueStringPointer() } if !plan.ShardCapacity.Equal(state.ShardCapacity) { - input.ShardCapacity = flex.Int32FromFramework(ctx, plan.ShardCapacity) + input.ShardCapacity = fwflex.Int32FromFramework(ctx, plan.ShardCapacity) } if !plan.ShardCount.Equal(state.ShardCount) { - input.ShardCount = flex.Int32FromFramework(ctx, plan.ShardCount) + input.ShardCount = fwflex.Int32FromFramework(ctx, plan.ShardCount) } if !plan.SubnetIds.Equal(state.SubnetIds) { - input.SubnetIds = flex.ExpandFrameworkStringValueSet(ctx, plan.SubnetIds) + input.SubnetIds = fwflex.ExpandFrameworkStringValueSet(ctx, plan.SubnetIds) } if !plan.VpcSecurityGroupIds.Equal(state.VpcSecurityGroupIds) { - input.VpcSecurityGroupIds = flex.ExpandFrameworkStringValueSet(ctx, plan.VpcSecurityGroupIds) + input.VpcSecurityGroupIds = fwflex.ExpandFrameworkStringValueSet(ctx, plan.VpcSecurityGroupIds) } _, err := conn.UpdateCluster(ctx, input) @@ -317,7 +320,12 @@ func (r *resourceCluster) Update(ctx context.Context, request resource.UpdateReq return } - plan.refreshFromOutput(ctx, out) + response.Diagnostics.Append(fwflex.Flatten(ctx, out, &plan, fwflex.WithFieldNamePrefix("Cluster"))...) + + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(response.State.Set(ctx, &plan)...) } @@ -339,7 +347,7 @@ func (r *resourceCluster) Delete(ctx context.Context, request resource.DeleteReq }) input := &docdbelastic.DeleteClusterInput{ - ClusterArn: flex.StringFromFramework(ctx, state.ID), + ClusterArn: fwflex.StringFromFramework(ctx, state.ID), } _, err := conn.DeleteCluster(ctx, input) @@ -368,31 +376,27 @@ func (r *resourceCluster) Delete(ctx context.Context, request resource.DeleteReq } } -func (r *resourceCluster) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), request, response) -} - func (r *resourceCluster) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { r.SetTagsAll(ctx, request, response) } type resourceClusterData struct { - AdminUserName types.String `tfsdk:"admin_user_name"` - AdminUserPassword types.String `tfsdk:"admin_user_password"` - ARN types.String `tfsdk:"arn"` - AuthType types.String `tfsdk:"auth_type"` - Endpoint types.String `tfsdk:"endpoint"` - ID types.String `tfsdk:"id"` - KmsKeyID types.String `tfsdk:"kms_key_id"` - Name types.String `tfsdk:"name"` - PreferredMaintenanceWindow types.String `tfsdk:"preferred_maintenance_window"` - ShardCapacity types.Int64 `tfsdk:"shard_capacity"` - ShardCount types.Int64 `tfsdk:"shard_count"` - SubnetIds types.Set `tfsdk:"subnet_ids"` - Tags types.Map `tfsdk:"tags"` - TagsAll types.Map `tfsdk:"tags_all"` - Timeouts timeouts.Value `tfsdk:"timeouts"` - VpcSecurityGroupIds types.Set `tfsdk:"vpc_security_group_ids"` + AdminUserName types.String `tfsdk:"admin_user_name"` + AdminUserPassword types.String `tfsdk:"admin_user_password"` + ARN types.String `tfsdk:"arn"` + AuthType fwtypes.StringEnum[awstypes.Auth] `tfsdk:"auth_type"` + Endpoint types.String `tfsdk:"endpoint"` + ID types.String `tfsdk:"id"` + KmsKeyID types.String `tfsdk:"kms_key_id"` + Name types.String `tfsdk:"name"` + PreferredMaintenanceWindow fwtypes.OnceAWeekWindow `tfsdk:"preferred_maintenance_window"` + ShardCapacity types.Int64 `tfsdk:"shard_capacity"` + ShardCount types.Int64 `tfsdk:"shard_count"` + SubnetIds fwtypes.SetValueOf[types.String] `tfsdk:"subnet_ids"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` + VpcSecurityGroupIds fwtypes.SetValueOf[types.String] `tfsdk:"vpc_security_group_ids"` } func waitClusterCreated(ctx context.Context, conn *docdbelastic.Client, id string, timeout time.Duration) (*awstypes.Cluster, error) { @@ -486,20 +490,6 @@ func findClusterByID(ctx context.Context, conn *docdbelastic.Client, id string) return out.Cluster, nil } -func (r *resourceClusterData) refreshFromOutput(ctx context.Context, output *awstypes.Cluster) { - r.AdminUserName = flex.StringToFrameworkLegacy(ctx, output.AdminUserName) - r.AuthType = flex.StringValueToFramework(ctx, string(output.AuthType)) - r.ARN = flex.StringToFramework(ctx, output.ClusterArn) - r.Endpoint = flex.StringToFramework(ctx, output.ClusterEndpoint) - r.KmsKeyID = flex.StringToFramework(ctx, output.KmsKeyId) - r.Name = flex.StringToFramework(ctx, output.ClusterName) - r.PreferredMaintenanceWindow = flex.StringToFramework(ctx, output.PreferredMaintenanceWindow) - r.ShardCapacity = flex.Int32ToFramework(ctx, output.ShardCapacity) - r.ShardCount = flex.Int32ToFramework(ctx, output.ShardCount) - r.SubnetIds = flex.FlattenFrameworkStringValueSet(ctx, output.SubnetIds) - r.VpcSecurityGroupIds = flex.FlattenFrameworkStringValueSet(ctx, output.VpcSecurityGroupIds) -} - func clusterHasChanges(_ context.Context, plan, state resourceClusterData) bool { return !plan.Name.Equal(state.Name) || !plan.AdminUserPassword.Equal(state.AdminUserPassword) || diff --git a/internal/service/docdbelastic/cluster_test.go b/internal/service/docdbelastic/cluster_test.go index 0e9d6e5ba15..60cd1fda97a 100644 --- a/internal/service/docdbelastic/cluster_test.go +++ b/internal/service/docdbelastic/cluster_test.go @@ -54,7 +54,7 @@ func TestAccDocDBElasticCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "admin_user_password", "testpassword"), resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", acctest.Ct2), resource.TestCheckResourceAttr(resourceName, "vpc_security_group_ids.#", acctest.Ct1), - resource.TestCheckResourceAttr(resourceName, names.AttrPreferredMaintenanceWindow, "tue:04:00-tue:04:30"), + resource.TestCheckResourceAttr(resourceName, names.AttrPreferredMaintenanceWindow, "Tue:04:00-Tue:04:30"), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), ), }, @@ -182,7 +182,7 @@ func TestAccDocDBElasticCluster_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "admin_user_password", "testpassword"), resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", acctest.Ct2), resource.TestCheckResourceAttr(resourceName, "vpc_security_group_ids.#", acctest.Ct1), - resource.TestCheckResourceAttr(resourceName, names.AttrPreferredMaintenanceWindow, "tue:04:00-tue:04:30"), + resource.TestCheckResourceAttr(resourceName, names.AttrPreferredMaintenanceWindow, "Tue:04:00-Tue:04:30"), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), ), }, @@ -198,7 +198,7 @@ func TestAccDocDBElasticCluster_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "admin_user_password", "testpassword"), resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", acctest.Ct2), resource.TestCheckResourceAttr(resourceName, "vpc_security_group_ids.#", acctest.Ct1), - resource.TestCheckResourceAttr(resourceName, names.AttrPreferredMaintenanceWindow, "tue:04:00-tue:04:30"), + resource.TestCheckResourceAttr(resourceName, names.AttrPreferredMaintenanceWindow, "Tue:04:00-Tue:04:30"), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), ), }, @@ -296,7 +296,7 @@ resource "aws_docdbelastic_cluster" "test" { admin_user_password = "testpassword" auth_type = "PLAIN_TEXT" - preferred_maintenance_window = "tue:04:00-tue:04:30" + preferred_maintenance_window = "Tue:04:00-Tue:04:30" vpc_security_group_ids = [ aws_security_group.test.id @@ -323,7 +323,7 @@ resource "aws_docdbelastic_cluster" "test" { admin_user_password = "testpassword" auth_type = "PLAIN_TEXT" - preferred_maintenance_window = "tue:04:00-tue:04:30" + preferred_maintenance_window = "Tue:04:00-Tue:04:30" vpc_security_group_ids = [ aws_security_group.test.id @@ -350,7 +350,7 @@ resource "aws_docdbelastic_cluster" "test" { admin_user_password = "testpassword" auth_type = "PLAIN_TEXT" - preferred_maintenance_window = "tue:04:00-tue:04:30" + preferred_maintenance_window = "Tue:04:00-Tue:04:30" vpc_security_group_ids = [ aws_security_group.test.id @@ -381,7 +381,7 @@ resource "aws_docdbelastic_cluster" "test" { admin_user_password = "testpassword" auth_type = "PLAIN_TEXT" - preferred_maintenance_window = "tue:04:00-tue:04:30" + preferred_maintenance_window = "Tue:04:00-Tue:04:30" vpc_security_group_ids = [ aws_security_group.test.id From 4bff0c4c739a30479a68c23af53533dc94e9b697 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 3 Sep 2024 16:29:01 -0500 Subject: [PATCH 2/3] chore: make semgrep-fix --- internal/service/docdbelastic/cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/docdbelastic/cluster.go b/internal/service/docdbelastic/cluster.go index 0283a9e2800..6571a4e57de 100644 --- a/internal/service/docdbelastic/cluster.go +++ b/internal/service/docdbelastic/cluster.go @@ -186,7 +186,7 @@ func (r *resourceCluster) Create(ctx context.Context, request resource.CreateReq state.ID = fwflex.StringToFramework(ctx, createOut.Cluster.ClusterArn) // set partial state - response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root("id"), createOut.Cluster.ClusterArn)...) + response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root(names.AttrID), createOut.Cluster.ClusterArn)...) if response.Diagnostics.HasError() { return From 1b52cf8baf407a199df713bc62e02680afd1c2de Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 4 Sep 2024 15:55:19 -0500 Subject: [PATCH 3/3] chore: golangci-lint --- internal/service/docdbelastic/cluster.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/docdbelastic/cluster.go b/internal/service/docdbelastic/cluster.go index 735f150fb04..be7d9604ae5 100644 --- a/internal/service/docdbelastic/cluster.go +++ b/internal/service/docdbelastic/cluster.go @@ -393,8 +393,8 @@ type resourceClusterData struct { ShardCapacity types.Int64 `tfsdk:"shard_capacity"` ShardCount types.Int64 `tfsdk:"shard_count"` SubnetIds fwtypes.SetValueOf[types.String] `tfsdk:"subnet_ids"` - Tags tftags.Map `tfsdk:"tags"` - TagsAll tftags.Map `tfsdk:"tags_all"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` Timeouts timeouts.Value `tfsdk:"timeouts"` VpcSecurityGroupIds fwtypes.SetValueOf[types.String] `tfsdk:"vpc_security_group_ids"` }