From ab4bc1a249bf9e3d38659f8fb641124f7eee8ac8 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 14:59:56 -0800 Subject: [PATCH 01/69] memorydb: add new `multi_region_cluster` resource --- .../service/memorydb/multi_region_cluster.go | 673 ++++++++++++++++++ 1 file changed, 673 insertions(+) create mode 100644 internal/service/memorydb/multi_region_cluster.go diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go new file mode 100644 index 00000000000..385cb2b2f26 --- /dev/null +++ b/internal/service/memorydb/multi_region_cluster.go @@ -0,0 +1,673 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package memorydb + +import ( + "context" + "fmt" + "log" + "strconv" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/memorydb" + awstypes "github.com/aws/aws-sdk-go-v2/service/memorydb/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "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" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKResource("aws_memorydb_cluster", name="MultiRegionCluster") +// @Tags(identifierAttribute="arn") +func resourceMultiRegionCluster() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceMultiRegionClusterCreate, + ReadWithoutTimeout: resourceMultiRegionClusterRead, + UpdateWithoutTimeout: resourceMultiRegionClusterUpdate, + DeleteWithoutTimeout: resourceMultiRegionClusterDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(120 * time.Minute), + Update: schema.DefaultTimeout(120 * time.Minute), + Delete: schema.DefaultTimeout(120 * time.Minute), + }, + + CustomizeDiff: verify.SetTagsDiff, + + SchemaFunc: func() map[string]*schema.Schema { + return map[string]*schema.Schema{ + names.AttrARN: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrDescription: { + Type: schema.TypeString, + Optional: true, + Default: "Managed by Terraform", + }, + names.AttrEngine: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateDiagFunc: enum.Validate[clusterEngine](), + }, + names.AttrEngineVersion: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "multi_region_cluster_name": { + Type: schema.TypeString, + Optional: true, + }, + "multi_region_parameter_group_name": { + Type: schema.TypeString, + Optional: true, + }, + "node_type": { + Type: schema.TypeString, + Optional: true, + }, + "number_of_shards": { + Type: schema.TypeInt, + Optional: true, + }, + "status": { + Type: schema.TypeString, + Optional: true, + }, + "tls_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + ForceNew: true, + }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + } + }, + } +} + +func endpointSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrAddress: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrPort: { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + } +} + +func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) + + name := create.Name(d.Get(names.AttrName).(string), d.Get(names.AttrNamePrefix).(string)) + input := &memorydb.CreateMultiRegionClusterInput{ + ACLName: aws.String(d.Get("acl_name").(string)), + AutoMinorVersionUpgrade: aws.Bool(d.Get(names.AttrAutoMinorVersionUpgrade).(bool)), + MultiRegionClusterName: aws.String(name), + NodeType: aws.String(d.Get("node_type").(string)), + NumReplicasPerShard: aws.Int32(int32(d.Get("num_replicas_per_shard").(int))), + NumShards: aws.Int32(int32(d.Get("num_shards").(int))), + Tags: getTagsIn(ctx), + TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), + } + + if v, ok := d.GetOk("data_tiering"); ok { + input.DataTiering = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk(names.AttrDescription); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk(names.AttrEngine); ok { + input.Engine = aws.String(v.(string)) + } + + if v, ok := d.GetOk(names.AttrEngineVersion); ok { + input.EngineVersion = aws.String(v.(string)) + } + + if v, ok := d.GetOk(names.AttrKMSKeyARN); ok { + input.KmsKeyId = aws.String(v.(string)) + } + + if v, ok := d.GetOk("maintenance_window"); ok { + input.MaintenanceWindow = aws.String(v.(string)) + } + + if v, ok := d.GetOk(names.AttrParameterGroupName); ok { + input.ParameterGroupName = aws.String(v.(string)) + } + + if v, ok := d.GetOk(names.AttrPort); ok { + input.Port = aws.Int32(int32(v.(int))) + } + + if v, ok := d.GetOk(names.AttrSecurityGroupIDs); ok { + input.SecurityGroupIds = flex.ExpandStringValueSet(v.(*schema.Set)) + } + + if v, ok := d.GetOk("snapshot_arns"); ok && len(v.([]interface{})) > 0 { + input.SnapshotArns = flex.ExpandStringValueList(v.([]interface{})) + } + + if v, ok := d.GetOk("snapshot_name"); ok { + input.SnapshotName = aws.String(v.(string)) + } + + if v, ok := d.GetOk("snapshot_retention_limit"); ok { + input.SnapshotRetentionLimit = aws.Int32(int32(v.(int))) + } + + if v, ok := d.GetOk("snapshot_window"); ok { + input.SnapshotWindow = aws.String(v.(string)) + } + + if v, ok := d.GetOk(names.AttrSNSTopicARN); ok { + input.SnsTopicArn = aws.String(v.(string)) + } + + if v, ok := d.GetOk("subnet_group_name"); ok { + input.SubnetGroupName = aws.String(v.(string)) + } + + _, err := conn.CreateMultiRegionCluster(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "creating MemoryDB MultiRegionCluster (%s): %s", name, err) + } + + d.SetId(name) + + if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) create: %s", d.Id(), err) + } + + return append(diags, resourceMultiRegionClusterRead(ctx, d, meta)...) +} + +func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) + + cluster, err := findMultiRegionClusterByName(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] MemoryDB MultiRegionCluster (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading MemoryDB MultiRegionCluster (%s): %s", d.Id(), err) + } + + d.Set("acl_name", cluster.ACLName) + d.Set(names.AttrARN, cluster.ARN) + d.Set(names.AttrAutoMinorVersionUpgrade, cluster.AutoMinorVersionUpgrade) + if v := cluster.MultiRegionClusterEndpoint; v != nil { + d.Set("cluster_endpoint", flattenEndpoint(v)) + d.Set(names.AttrPort, v.Port) + } + if v := string(cluster.DataTiering); v != "" { + v, err := strconv.ParseBool(v) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + + d.Set("data_tiering", v) + } + d.Set(names.AttrDescription, cluster.Description) + d.Set("engine_patch_version", cluster.EnginePatchVersion) + d.Set(names.AttrEngine, cluster.Engine) + d.Set(names.AttrEngineVersion, cluster.EngineVersion) + d.Set(names.AttrKMSKeyARN, cluster.KmsKeyId) // KmsKeyId is actually an ARN here. + d.Set("maintenance_window", cluster.MaintenanceWindow) + d.Set(names.AttrName, cluster.Name) + d.Set(names.AttrNamePrefix, create.NamePrefixFromName(aws.ToString(cluster.Name))) + d.Set("node_type", cluster.NodeType) + if v, err := deriveMultiRegionClusterNumReplicasPerShard(cluster); err != nil { + return sdkdiag.AppendFromErr(diags, err) + } else { + d.Set("num_replicas_per_shard", v) + } + d.Set("num_shards", cluster.NumberOfShards) + d.Set(names.AttrParameterGroupName, cluster.ParameterGroupName) + d.Set(names.AttrSecurityGroupIDs, tfslices.ApplyToAll(cluster.SecurityGroups, func(v awstypes.SecurityGroupMembership) string { + return aws.ToString(v.SecurityGroupId) + })) + if err := d.Set("shards", flattenShards(cluster.Shards)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting shards: %s", err) + } + d.Set("snapshot_retention_limit", cluster.SnapshotRetentionLimit) + d.Set("snapshot_window", cluster.SnapshotWindow) + if aws.ToString(cluster.SnsTopicStatus) == clusterSNSTopicStatusActive { + d.Set(names.AttrSNSTopicARN, cluster.SnsTopicArn) + } else { + d.Set(names.AttrSNSTopicARN, "") + } + d.Set("subnet_group_name", cluster.SubnetGroupName) + d.Set("tls_enabled", cluster.TLSEnabled) + + return diags +} + +func resourceMultiRegionClusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) + + if d.HasChangesExcept("final_snapshot_name", names.AttrTags, names.AttrTagsAll) { + waitParameterGroupInSync := false + waitSecurityGroupsActive := false + + input := &memorydb.UpdateMultiRegionClusterInput{ + MultiRegionClusterName: aws.String(d.Id()), + } + + if d.HasChange("acl_name") { + input.ACLName = aws.String(d.Get("acl_name").(string)) + } + + if d.HasChange(names.AttrDescription) { + input.Description = aws.String(d.Get(names.AttrDescription).(string)) + } + + if d.HasChange(names.AttrEngine) { + input.Engine = aws.String(d.Get(names.AttrEngine).(string)) + } + + if d.HasChange(names.AttrEngineVersion) { + input.EngineVersion = aws.String(d.Get(names.AttrEngineVersion).(string)) + } + + if d.HasChange("maintenance_window") { + input.MaintenanceWindow = aws.String(d.Get("maintenance_window").(string)) + } + + if d.HasChange("node_type") { + input.NodeType = aws.String(d.Get("node_type").(string)) + } + + if d.HasChange("num_replicas_per_shard") { + input.ReplicaConfiguration = &awstypes.ReplicaConfigurationRequest{ + ReplicaCount: int32(d.Get("num_replicas_per_shard").(int)), + } + } + + if d.HasChange("num_shards") { + input.ShardConfiguration = &awstypes.ShardConfigurationRequest{ + ShardCount: int32(d.Get("num_shards").(int)), + } + } + + if d.HasChange(names.AttrParameterGroupName) { + input.ParameterGroupName = aws.String(d.Get(names.AttrParameterGroupName).(string)) + waitParameterGroupInSync = true + } + + if d.HasChange(names.AttrSecurityGroupIDs) { + // UpdateMultiRegionCluster reads null and empty slice as "no change", so once + // at least one security group is present, it's no longer possible + // to remove all of them. + + v := d.Get(names.AttrSecurityGroupIDs).(*schema.Set) + + if v.Len() == 0 { + return sdkdiag.AppendErrorf(diags, "unable to update MemoryDB MultiRegionCluster (%s): removing all security groups is not possible", d.Id()) + } + + input.SecurityGroupIds = flex.ExpandStringValueSet(v) + waitSecurityGroupsActive = true + } + + if d.HasChange("snapshot_retention_limit") { + input.SnapshotRetentionLimit = aws.Int32(int32(d.Get("snapshot_retention_limit").(int))) + } + + if d.HasChange("snapshot_window") { + input.SnapshotWindow = aws.String(d.Get("snapshot_window").(string)) + } + + if d.HasChange(names.AttrSNSTopicARN) { + v := d.Get(names.AttrSNSTopicARN).(string) + input.SnsTopicArn = aws.String(v) + if v == "" { + input.SnsTopicStatus = aws.String(clusterSNSTopicStatusInactive) + } else { + input.SnsTopicStatus = aws.String(clusterSNSTopicStatusActive) + } + } + + _, err := conn.UpdateMultiRegionCluster(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating MemoryDB MultiRegionCluster (%s): %s", d.Id(), err) + } + + if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) update: %s", d.Id(), err) + } + + if waitParameterGroupInSync { + if _, err := waitMultiRegionClusterParameterGroupInSync(ctx, conn, d.Id()); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) parameter group: %s", d.Id(), err) + } + } + + if waitSecurityGroupsActive { + if _, err := waitMultiRegionClusterSecurityGroupsActive(ctx, conn, d.Id()); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) security groups: %s", d.Id(), err) + } + } + } + + return append(diags, resourceMultiRegionClusterRead(ctx, d, meta)...) +} + +func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) + + input := &memorydb.DeleteMultiRegionClusterInput{ + MultiRegionClusterName: aws.String(d.Id()), + } + + if v := d.Get("final_snapshot_name"); v != nil && len(v.(string)) > 0 { + input.FinalSnapshotName = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Deleting MemoryDB MultiRegionCluster: (%s)", d.Id()) + _, err := conn.DeleteMultiRegionCluster(ctx, input) + + if errs.IsA[*awstypes.MultiRegionClusterNotFoundFault](err) { + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "deleting MemoryDB MultiRegionCluster (%s): %s", d.Id(), err) + } + + if _, err := waitMultiRegionClusterDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) delete: %s", d.Id(), err) + } + + return diags +} + +func findMultiRegionClusterByName(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { + input := &memorydb.DescribeMultiRegionClustersInput{ + MultiRegionClusterName: aws.String(name), + ShowShardDetails: aws.Bool(true), + } + + return findMultiRegionCluster(ctx, conn, input) +} + +func findMultiRegionCluster(ctx context.Context, conn *memorydb.Client, input *memorydb.DescribeMultiRegionClustersInput) (*awstypes.MultiRegionCluster, error) { + output, err := findMultiRegionClusters(ctx, conn, input) + + if err != nil { + return nil, err + } + + return tfresource.AssertSingleValueResult(output) +} + +func findMultiRegionClusters(ctx context.Context, conn *memorydb.Client, input *memorydb.DescribeMultiRegionClustersInput) ([]awstypes.MultiRegionCluster, error) { + var output []awstypes.MultiRegionCluster + + pages := memorydb.NewDescribeMultiRegionClustersPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if errs.IsA[*awstypes.MultiRegionClusterNotFoundFault](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + output = append(output, page.MultiRegionClusters...) + } + + return output, nil +} + +func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findMultiRegionClusterByName(ctx, conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.ToString(output.Status), nil + } +} + +func statusMultiRegionClusterParameterGroup(ctx context.Context, conn *memorydb.Client, name string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findMultiRegionClusterByName(ctx, conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.ToString(output.ParameterGroupStatus), nil + } +} + +func statusMultiRegionClusterSecurityGroups(ctx context.Context, conn *memorydb.Client, name string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findMultiRegionClusterByName(ctx, conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + for _, v := range output.SecurityGroups { + // When at least one security group change is being applied (whether + // that be adding or removing an SG), say that we're still in progress. + if aws.ToString(v.Status) != clusterSecurityGroupStatusActive { + return output, clusterSecurityGroupStatusModifying, nil + } + } + + return output, clusterSecurityGroupStatusActive, nil + } +} + +func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam + stateConf := &retry.StateChangeConf{ + Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, + Target: []string{clusterStatusAvailable}, + Refresh: statusMultiRegionCluster(ctx, conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.MultiRegionCluster); ok { + return output, err + } + + return nil, err +} + +func waitMultiRegionClusterDeleted(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{clusterStatusDeleting}, + Target: []string{}, + Refresh: statusMultiRegionCluster(ctx, conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.MultiRegionCluster); ok { + return output, err + } + + return nil, err +} + +func waitMultiRegionClusterParameterGroupInSync(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { + const ( + timeout = 60 * time.Minute + ) + stateConf := &retry.StateChangeConf{ + Pending: []string{clusterParameterGroupStatusApplying}, + Target: []string{clusterParameterGroupStatusInSync}, + Refresh: statusMultiRegionClusterParameterGroup(ctx, conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.MultiRegionCluster); ok { + return output, err + } + + return nil, err +} + +func waitMultiRegionClusterSecurityGroupsActive(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { + const ( + timeout = 10 * time.Minute + ) + stateConf := &retry.StateChangeConf{ + Pending: []string{clusterSecurityGroupStatusModifying}, + Target: []string{clusterSecurityGroupStatusActive}, + Refresh: statusMultiRegionClusterSecurityGroups(ctx, conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.MultiRegionCluster); ok { + return output, err + } + + return nil, err +} + +var ( + clusterShardHash = sdkv2.SimpleSchemaSetFunc(names.AttrName) + clusterShardNodeHash = sdkv2.SimpleSchemaSetFunc(names.AttrName) +) + +func flattenEndpoint(apiObject *awstypes.Endpoint) []interface{} { + if apiObject == nil { + return []interface{}{} + } + + tfMap := map[string]interface{}{} + + if v := aws.ToString(apiObject.Address); v != "" { + tfMap[names.AttrAddress] = v + } + + if apiObject.Port != 0 { + tfMap[names.AttrPort] = apiObject.Port + } + + return []interface{}{tfMap} +} + +func flattenShards(apiObjects []awstypes.Shard) *schema.Set { + tfSet := schema.NewSet(clusterShardHash, nil) + + for _, apiObject := range apiObjects { + nodeSet := schema.NewSet(clusterShardNodeHash, nil) + + for _, apiObject := range apiObject.Nodes { + nodeSet.Add(map[string]interface{}{ + names.AttrAvailabilityZone: aws.ToString(apiObject.AvailabilityZone), + names.AttrCreateTime: aws.ToTime(apiObject.CreateTime).Format(time.RFC3339), + names.AttrEndpoint: flattenEndpoint(apiObject.Endpoint), + names.AttrName: aws.ToString(apiObject.Name), + }) + } + + tfSet.Add(map[string]interface{}{ + names.AttrName: aws.ToString(apiObject.Name), + "num_nodes": aws.ToInt32(apiObject.NumberOfNodes), + "nodes": nodeSet, + "slots": aws.ToString(apiObject.Slots), + }) + } + + return tfSet +} + +// deriveMultiRegionClusterNumReplicasPerShard determines the replicas per shard +// configuration of a cluster. As this cannot directly be read back, we +// assume that it's the same as that of the largest shard. +// +// For the sake of caution, this search is limited to stable shards. +func deriveMultiRegionClusterNumReplicasPerShard(cluster *awstypes.MultiRegionCluster) (int, error) { + var maxNumberOfNodesPerShard int32 + + for _, shard := range cluster.Shards { + if aws.ToString(shard.Status) != clusterShardStatusAvailable { + continue + } + + n := aws.ToInt32(shard.NumberOfNodes) + if n > maxNumberOfNodesPerShard { + maxNumberOfNodesPerShard = n + } + } + + if maxNumberOfNodesPerShard == 0 { + return 0, fmt.Errorf("no available shards found") + } + + return int(maxNumberOfNodesPerShard - 1), nil +} From 16f44c68d01e53fa6a0dae60ddc324202c4fd90f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:13:43 -0800 Subject: [PATCH 02/69] memorydb: [wip] implement `multi_region_cluster` resource --- .../service/memorydb/multi_region_cluster.go | 268 ++---------------- 1 file changed, 27 insertions(+), 241 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 385cb2b2f26..c1552308486 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -5,9 +5,7 @@ package memorydb import ( "context" - "fmt" "log" - "strconv" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -22,8 +20,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" - "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" - tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -76,28 +72,36 @@ func resourceMultiRegionCluster() *schema.Resource { "multi_region_cluster_name": { Type: schema.TypeString, Optional: true, + Computed: true, + }, + "multi_region_cluster_name_suffix": { + Type: schema.TypeString, + Required: true, }, "multi_region_parameter_group_name": { Type: schema.TypeString, Optional: true, + Computed: true, }, "node_type": { Type: schema.TypeString, - Optional: true, + Required: true, }, - "number_of_shards": { + "num_shards": { Type: schema.TypeInt, Optional: true, + Computed: true, }, "status": { Type: schema.TypeString, Optional: true, + Computed: true, }, "tls_enabled": { Type: schema.TypeBool, Optional: true, + Computed: true, Default: true, - ForceNew: true, }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), @@ -106,43 +110,16 @@ func resourceMultiRegionCluster() *schema.Resource { } } -func endpointSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrAddress: { - Type: schema.TypeString, - Computed: true, - }, - names.AttrPort: { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - } -} - func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) - name := create.Name(d.Get(names.AttrName).(string), d.Get(names.AttrNamePrefix).(string)) + name := create.Name(d.Get(names.AttrName).(string), "") input := &memorydb.CreateMultiRegionClusterInput{ - ACLName: aws.String(d.Get("acl_name").(string)), - AutoMinorVersionUpgrade: aws.Bool(d.Get(names.AttrAutoMinorVersionUpgrade).(bool)), - MultiRegionClusterName: aws.String(name), - NodeType: aws.String(d.Get("node_type").(string)), - NumReplicasPerShard: aws.Int32(int32(d.Get("num_replicas_per_shard").(int))), - NumShards: aws.Int32(int32(d.Get("num_shards").(int))), - Tags: getTagsIn(ctx), - TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), - } - - if v, ok := d.GetOk("data_tiering"); ok { - input.DataTiering = aws.Bool(v.(bool)) + NodeType: aws.String(d.Get("node_type").(string)), + MultiRegionClusterNameSuffix: aws.String(d.Get("multi_region_cluster_name_suffix").(string)), + TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), + Tags: getTagsIn(ctx), } if v, ok := d.GetOk(names.AttrDescription); ok { @@ -157,60 +134,24 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat input.EngineVersion = aws.String(v.(string)) } - if v, ok := d.GetOk(names.AttrKMSKeyARN); ok { - input.KmsKeyId = aws.String(v.(string)) + if v, ok := d.GetOk("multi_region_parameter_group_name"); ok { + input.MultiRegionParameterGroupName = aws.String(v.(string)) } - if v, ok := d.GetOk("maintenance_window"); ok { - input.MaintenanceWindow = aws.String(v.(string)) - } - - if v, ok := d.GetOk(names.AttrParameterGroupName); ok { - input.ParameterGroupName = aws.String(v.(string)) - } - - if v, ok := d.GetOk(names.AttrPort); ok { + if v, ok := d.GetOk("num_shards"); ok { input.Port = aws.Int32(int32(v.(int))) } - if v, ok := d.GetOk(names.AttrSecurityGroupIDs); ok { - input.SecurityGroupIds = flex.ExpandStringValueSet(v.(*schema.Set)) - } - - if v, ok := d.GetOk("snapshot_arns"); ok && len(v.([]interface{})) > 0 { - input.SnapshotArns = flex.ExpandStringValueList(v.([]interface{})) - } - - if v, ok := d.GetOk("snapshot_name"); ok { - input.SnapshotName = aws.String(v.(string)) - } - - if v, ok := d.GetOk("snapshot_retention_limit"); ok { - input.SnapshotRetentionLimit = aws.Int32(int32(v.(int))) - } - - if v, ok := d.GetOk("snapshot_window"); ok { - input.SnapshotWindow = aws.String(v.(string)) - } - - if v, ok := d.GetOk(names.AttrSNSTopicARN); ok { - input.SnsTopicArn = aws.String(v.(string)) - } - - if v, ok := d.GetOk("subnet_group_name"); ok { - input.SubnetGroupName = aws.String(v.(string)) - } - _, err := conn.CreateMultiRegionCluster(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating MemoryDB MultiRegionCluster (%s): %s", name, err) + return sdkdiag.AppendErrorf(diags, "creating MemoryDB Multi Region cluster (%s): %s", name, err) } d.SetId(name) if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) create: %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region cluster (%s) create: %s", d.Id(), err) } return append(diags, resourceMultiRegionClusterRead(ctx, d, meta)...) @@ -223,61 +164,25 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, cluster, err := findMultiRegionClusterByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] MemoryDB MultiRegionCluster (%s) not found, removing from state", d.Id()) + log.Printf("[WARN] MemoryDB Multi Region cluster (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading MemoryDB MultiRegionCluster (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "reading MemoryDB Multi Region cluster (%s): %s", d.Id(), err) } - d.Set("acl_name", cluster.ACLName) d.Set(names.AttrARN, cluster.ARN) - d.Set(names.AttrAutoMinorVersionUpgrade, cluster.AutoMinorVersionUpgrade) - if v := cluster.MultiRegionClusterEndpoint; v != nil { - d.Set("cluster_endpoint", flattenEndpoint(v)) - d.Set(names.AttrPort, v.Port) - } - if v := string(cluster.DataTiering); v != "" { - v, err := strconv.ParseBool(v) - if err != nil { - return sdkdiag.AppendFromErr(diags, err) - } - - d.Set("data_tiering", v) - } d.Set(names.AttrDescription, cluster.Description) - d.Set("engine_patch_version", cluster.EnginePatchVersion) d.Set(names.AttrEngine, cluster.Engine) d.Set(names.AttrEngineVersion, cluster.EngineVersion) - d.Set(names.AttrKMSKeyARN, cluster.KmsKeyId) // KmsKeyId is actually an ARN here. - d.Set("maintenance_window", cluster.MaintenanceWindow) - d.Set(names.AttrName, cluster.Name) - d.Set(names.AttrNamePrefix, create.NamePrefixFromName(aws.ToString(cluster.Name))) + d.Set("multi_region_cluster_name", cluster.MultiRegionClusterName) d.Set("node_type", cluster.NodeType) - if v, err := deriveMultiRegionClusterNumReplicasPerShard(cluster); err != nil { - return sdkdiag.AppendFromErr(diags, err) - } else { - d.Set("num_replicas_per_shard", v) - } d.Set("num_shards", cluster.NumberOfShards) - d.Set(names.AttrParameterGroupName, cluster.ParameterGroupName) - d.Set(names.AttrSecurityGroupIDs, tfslices.ApplyToAll(cluster.SecurityGroups, func(v awstypes.SecurityGroupMembership) string { - return aws.ToString(v.SecurityGroupId) - })) - if err := d.Set("shards", flattenShards(cluster.Shards)); err != nil { - return sdkdiag.AppendErrorf(diags, "setting shards: %s", err) - } - d.Set("snapshot_retention_limit", cluster.SnapshotRetentionLimit) - d.Set("snapshot_window", cluster.SnapshotWindow) - if aws.ToString(cluster.SnsTopicStatus) == clusterSNSTopicStatusActive { - d.Set(names.AttrSNSTopicARN, cluster.SnsTopicArn) - } else { - d.Set(names.AttrSNSTopicARN, "") - } - d.Set("subnet_group_name", cluster.SubnetGroupName) + d.Set("multi_region_parameter_group_name", cluster.MultiRegionParameterGroupName) d.Set("tls_enabled", cluster.TLSEnabled) + d.Set(names.AttrStatus, cluster.Status) return diags } @@ -427,7 +332,7 @@ func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceDat func findMultiRegionClusterByName(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { input := &memorydb.DescribeMultiRegionClustersInput{ MultiRegionClusterName: aws.String(name), - ShowShardDetails: aws.Bool(true), + ShowClusterDetails: aws.Bool(true), } return findMultiRegionCluster(ctx, conn, input) @@ -499,30 +404,6 @@ func statusMultiRegionClusterParameterGroup(ctx context.Context, conn *memorydb. } } -func statusMultiRegionClusterSecurityGroups(ctx context.Context, conn *memorydb.Client, name string) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - output, err := findMultiRegionClusterByName(ctx, conn, name) - - if tfresource.NotFound(err) { - return nil, "", nil - } - - if err != nil { - return nil, "", err - } - - for _, v := range output.SecurityGroups { - // When at least one security group change is being applied (whether - // that be adding or removing an SG), say that we're still in progress. - if aws.ToString(v.Status) != clusterSecurityGroupStatusActive { - return output, clusterSecurityGroupStatusModifying, nil - } - } - - return output, clusterSecurityGroupStatusActive, nil - } -} - func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, @@ -576,98 +457,3 @@ func waitMultiRegionClusterParameterGroupInSync(ctx context.Context, conn *memor return nil, err } - -func waitMultiRegionClusterSecurityGroupsActive(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { - const ( - timeout = 10 * time.Minute - ) - stateConf := &retry.StateChangeConf{ - Pending: []string{clusterSecurityGroupStatusModifying}, - Target: []string{clusterSecurityGroupStatusActive}, - Refresh: statusMultiRegionClusterSecurityGroups(ctx, conn, name), - Timeout: timeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - - if output, ok := outputRaw.(*awstypes.MultiRegionCluster); ok { - return output, err - } - - return nil, err -} - -var ( - clusterShardHash = sdkv2.SimpleSchemaSetFunc(names.AttrName) - clusterShardNodeHash = sdkv2.SimpleSchemaSetFunc(names.AttrName) -) - -func flattenEndpoint(apiObject *awstypes.Endpoint) []interface{} { - if apiObject == nil { - return []interface{}{} - } - - tfMap := map[string]interface{}{} - - if v := aws.ToString(apiObject.Address); v != "" { - tfMap[names.AttrAddress] = v - } - - if apiObject.Port != 0 { - tfMap[names.AttrPort] = apiObject.Port - } - - return []interface{}{tfMap} -} - -func flattenShards(apiObjects []awstypes.Shard) *schema.Set { - tfSet := schema.NewSet(clusterShardHash, nil) - - for _, apiObject := range apiObjects { - nodeSet := schema.NewSet(clusterShardNodeHash, nil) - - for _, apiObject := range apiObject.Nodes { - nodeSet.Add(map[string]interface{}{ - names.AttrAvailabilityZone: aws.ToString(apiObject.AvailabilityZone), - names.AttrCreateTime: aws.ToTime(apiObject.CreateTime).Format(time.RFC3339), - names.AttrEndpoint: flattenEndpoint(apiObject.Endpoint), - names.AttrName: aws.ToString(apiObject.Name), - }) - } - - tfSet.Add(map[string]interface{}{ - names.AttrName: aws.ToString(apiObject.Name), - "num_nodes": aws.ToInt32(apiObject.NumberOfNodes), - "nodes": nodeSet, - "slots": aws.ToString(apiObject.Slots), - }) - } - - return tfSet -} - -// deriveMultiRegionClusterNumReplicasPerShard determines the replicas per shard -// configuration of a cluster. As this cannot directly be read back, we -// assume that it's the same as that of the largest shard. -// -// For the sake of caution, this search is limited to stable shards. -func deriveMultiRegionClusterNumReplicasPerShard(cluster *awstypes.MultiRegionCluster) (int, error) { - var maxNumberOfNodesPerShard int32 - - for _, shard := range cluster.Shards { - if aws.ToString(shard.Status) != clusterShardStatusAvailable { - continue - } - - n := aws.ToInt32(shard.NumberOfNodes) - if n > maxNumberOfNodesPerShard { - maxNumberOfNodesPerShard = n - } - } - - if maxNumberOfNodesPerShard == 0 { - return 0, fmt.Errorf("no available shards found") - } - - return int(maxNumberOfNodesPerShard - 1), nil -} From 21e99a9e75001612dd599abe9a03480a7977a777 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:16:42 -0800 Subject: [PATCH 03/69] memorydb: gen `multi_region_cluster` --- internal/service/memorydb/multi_region_cluster.go | 2 +- internal/service/memorydb/service_package_gen.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index c1552308486..f6647e33936 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -26,7 +26,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_memorydb_cluster", name="MultiRegionCluster") +// @SDKResource("aws_memorydb_multi_region_cluster", name="MultiRegionCluster") // @Tags(identifierAttribute="arn") func resourceMultiRegionCluster() *schema.Resource { return &schema.Resource{ diff --git a/internal/service/memorydb/service_package_gen.go b/internal/service/memorydb/service_package_gen.go index eb718223ac5..f992d69eb4a 100644 --- a/internal/service/memorydb/service_package_gen.go +++ b/internal/service/memorydb/service_package_gen.go @@ -93,6 +93,14 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: names.AttrARN, }, }, + { + Factory: resourceMultiRegionCluster, + TypeName: "aws_memorydb_multi_region_cluster", + Name: "MultiRegionCluster", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }, + }, { Factory: resourceParameterGroup, TypeName: "aws_memorydb_parameter_group", From 218d5599532c3d1d5d6e30d82eb20b04d0e05bb2 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:20:18 -0800 Subject: [PATCH 04/69] memorydb: fix name --- internal/service/memorydb/multi_region_cluster.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index f6647e33936..ebf87799d65 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -114,10 +114,11 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat var diags diag.Diagnostics conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) - name := create.Name(d.Get(names.AttrName).(string), "") + name := create.Name(d.Get("multi_region_cluster_name").(string), "") input := &memorydb.CreateMultiRegionClusterInput{ - NodeType: aws.String(d.Get("node_type").(string)), + MultiRegionClusterName: aws.String(name), MultiRegionClusterNameSuffix: aws.String(d.Get("multi_region_cluster_name_suffix").(string)), + NodeType: aws.String(d.Get("node_type").(string)), TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), Tags: getTagsIn(ctx), } From b662cc2f0e2224a05efe740a016c3f70a4b3da59 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:33:40 -0800 Subject: [PATCH 05/69] memorydb: [wip] implement cluster flatten and expand --- .../service/memorydb/multi_region_cluster.go | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index ebf87799d65..3153e53a643 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -58,6 +58,30 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, Default: "Managed by Terraform", }, + "clusters": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrARN: { + Type: schema.TypeString, + Computed: true, + }, + "cluster_name": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrRegion: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrStatus: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, names.AttrEngine: { Type: schema.TypeString, Optional: true, @@ -176,6 +200,9 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set(names.AttrARN, cluster.ARN) d.Set(names.AttrDescription, cluster.Description) + if err := d.Set("clusters", flattenClusterConfiguration(cluster.Clusters)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting clusters: %s", err) + } d.Set(names.AttrEngine, cluster.Engine) d.Set(names.AttrEngineVersion, cluster.EngineVersion) d.Set("multi_region_cluster_name", cluster.MultiRegionClusterName) @@ -330,6 +357,58 @@ func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceDat return diags } +func flattenClusters(apiObject *awstypes.Clusters) []interface{} { + if apiObject == nil { + return []interface{}{} + } + + var tfList []interface{} + + for k, apiObject := range apiObjects { + tfList = append(tfList, map[string]interface{}{ + names.AttrARN: aws.ToString(apiObject.Arn), + "cluster_name": aws.ToString(apiObject.Name), + names.AttrRegion: aws.ToString(apiObject.Region), + names.AttrStatus: aws.ToString(apiObject.Status), + }) + } + + return tfList +} +func expandCluster(tfMap map[string]interface{}) *awstypes.Cluster { + if tfMap == nil { + return nil + } + + return &awstypes.Cluster{ + Arn: aws.String(tfMap[names.AttrARN].(string)), + Name: aws.String(tfMap["cluster_name"].(string)), + Region: aws.String(tfMap[names.AttrRegion].(string)), + Status: aws.String(tfMap[names.AttrStatus].(string)), + } +} + +func expandClusters(tfList []interface{}) *awstypes.Clusters { + var clusters []awstypes.Cluster + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + if !ok { + continue + } + + apiObject := expandCluster(tfMap) + + if apiObject != nil { + clusters = append(clusters, *apiObject) + } + } + + return &awstypes.Clusters{ + RegionalClusters: clusters, + } +} + func findMultiRegionClusterByName(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { input := &memorydb.DescribeMultiRegionClustersInput{ MultiRegionClusterName: aws.String(name), From 715dd0176c26c5a24edc98c22e93dfc5bcb7e85f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:34:46 -0800 Subject: [PATCH 06/69] memorydb: remove expand --- .../service/memorydb/multi_region_cluster.go | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 3153e53a643..3254fd42601 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -375,39 +375,6 @@ func flattenClusters(apiObject *awstypes.Clusters) []interface{} { return tfList } -func expandCluster(tfMap map[string]interface{}) *awstypes.Cluster { - if tfMap == nil { - return nil - } - - return &awstypes.Cluster{ - Arn: aws.String(tfMap[names.AttrARN].(string)), - Name: aws.String(tfMap["cluster_name"].(string)), - Region: aws.String(tfMap[names.AttrRegion].(string)), - Status: aws.String(tfMap[names.AttrStatus].(string)), - } -} - -func expandClusters(tfList []interface{}) *awstypes.Clusters { - var clusters []awstypes.Cluster - - for _, tfMapRaw := range tfList { - tfMap, ok := tfMapRaw.(map[string]interface{}) - if !ok { - continue - } - - apiObject := expandCluster(tfMap) - - if apiObject != nil { - clusters = append(clusters, *apiObject) - } - } - - return &awstypes.Clusters{ - RegionalClusters: clusters, - } -} func findMultiRegionClusterByName(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { input := &memorydb.DescribeMultiRegionClustersInput{ From bb6745125d5b949814a568336678cef318ae5432 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:35:12 -0800 Subject: [PATCH 07/69] memorydb: fix flatten --- internal/service/memorydb/multi_region_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 3254fd42601..bd03b7b7f30 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -200,7 +200,7 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set(names.AttrARN, cluster.ARN) d.Set(names.AttrDescription, cluster.Description) - if err := d.Set("clusters", flattenClusterConfiguration(cluster.Clusters)); err != nil { + if err := d.Set("clusters", flattenClusters(cluster.Clusters)); err != nil { return sdkdiag.AppendErrorf(diags, "setting clusters: %s", err) } d.Set(names.AttrEngine, cluster.Engine) From 8e39305e0735f8f5b72f392568ce1da179d24fd8 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:42:41 -0800 Subject: [PATCH 08/69] memorydb: implement update --- .../service/memorydb/multi_region_cluster.go | 133 +++--------------- 1 file changed, 17 insertions(+), 116 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index bd03b7b7f30..68756f7bebf 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -19,7 +19,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" - "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -116,6 +115,11 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, Computed: true, }, + "update_strategy": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "status": { Type: schema.TypeString, Optional: true, @@ -219,108 +223,45 @@ func resourceMultiRegionClusterUpdate(ctx context.Context, d *schema.ResourceDat var diags diag.Diagnostics conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) - if d.HasChangesExcept("final_snapshot_name", names.AttrTags, names.AttrTagsAll) { - waitParameterGroupInSync := false - waitSecurityGroupsActive := false - + if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { input := &memorydb.UpdateMultiRegionClusterInput{ MultiRegionClusterName: aws.String(d.Id()), } - if d.HasChange("acl_name") { - input.ACLName = aws.String(d.Get("acl_name").(string)) - } - if d.HasChange(names.AttrDescription) { input.Description = aws.String(d.Get(names.AttrDescription).(string)) } - if d.HasChange(names.AttrEngine) { - input.Engine = aws.String(d.Get(names.AttrEngine).(string)) - } - if d.HasChange(names.AttrEngineVersion) { input.EngineVersion = aws.String(d.Get(names.AttrEngineVersion).(string)) } - if d.HasChange("maintenance_window") { - input.MaintenanceWindow = aws.String(d.Get("maintenance_window").(string)) - } - - if d.HasChange("node_type") { - input.NodeType = aws.String(d.Get("node_type").(string)) - } - - if d.HasChange("num_replicas_per_shard") { - input.ReplicaConfiguration = &awstypes.ReplicaConfigurationRequest{ - ReplicaCount: int32(d.Get("num_replicas_per_shard").(int)), - } - } - if d.HasChange("num_shards") { input.ShardConfiguration = &awstypes.ShardConfigurationRequest{ ShardCount: int32(d.Get("num_shards").(int)), } } - if d.HasChange(names.AttrParameterGroupName) { - input.ParameterGroupName = aws.String(d.Get(names.AttrParameterGroupName).(string)) - waitParameterGroupInSync = true - } - - if d.HasChange(names.AttrSecurityGroupIDs) { - // UpdateMultiRegionCluster reads null and empty slice as "no change", so once - // at least one security group is present, it's no longer possible - // to remove all of them. - - v := d.Get(names.AttrSecurityGroupIDs).(*schema.Set) - - if v.Len() == 0 { - return sdkdiag.AppendErrorf(diags, "unable to update MemoryDB MultiRegionCluster (%s): removing all security groups is not possible", d.Id()) - } - - input.SecurityGroupIds = flex.ExpandStringValueSet(v) - waitSecurityGroupsActive = true - } - - if d.HasChange("snapshot_retention_limit") { - input.SnapshotRetentionLimit = aws.Int32(int32(d.Get("snapshot_retention_limit").(int))) + if d.HasChange("node_type") { + input.NodeType = aws.String(d.Get("node_type").(string)) } - if d.HasChange("snapshot_window") { - input.SnapshotWindow = aws.String(d.Get("snapshot_window").(string)) + if d.HasChange("node_type") { + input.NodeType = aws.String(d.Get("node_type").(string)) } - if d.HasChange(names.AttrSNSTopicARN) { - v := d.Get(names.AttrSNSTopicARN).(string) - input.SnsTopicArn = aws.String(v) - if v == "" { - input.SnsTopicStatus = aws.String(clusterSNSTopicStatusInactive) - } else { - input.SnsTopicStatus = aws.String(clusterSNSTopicStatusActive) - } + if d.HasChange("multi_region_parameter_group_name") { + input.MultiRegionParameterGroupName = aws.String(d.Get("multi_region_parameter_group_name").(string)) } _, err := conn.UpdateMultiRegionCluster(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "updating MemoryDB MultiRegionCluster (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "updating MemoryDB Multi Region Cluster (%s): %s", d.Id(), err) } if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) update: %s", d.Id(), err) - } - - if waitParameterGroupInSync { - if _, err := waitMultiRegionClusterParameterGroupInSync(ctx, conn, d.Id()); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) parameter group: %s", d.Id(), err) - } - } - - if waitSecurityGroupsActive { - if _, err := waitMultiRegionClusterSecurityGroupsActive(ctx, conn, d.Id()); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) security groups: %s", d.Id(), err) - } + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region Cluster (%s) update: %s", d.Id(), err) } } @@ -335,11 +276,7 @@ func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceDat MultiRegionClusterName: aws.String(d.Id()), } - if v := d.Get("final_snapshot_name"); v != nil && len(v.(string)) > 0 { - input.FinalSnapshotName = aws.String(v.(string)) - } - - log.Printf("[DEBUG] Deleting MemoryDB MultiRegionCluster: (%s)", d.Id()) + log.Printf("[DEBUG] Deleting MemoryDB Multi Region Cluster: (%s)", d.Id()) _, err := conn.DeleteMultiRegionCluster(ctx, input) if errs.IsA[*awstypes.MultiRegionClusterNotFoundFault](err) { @@ -347,11 +284,11 @@ func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceDat } if err != nil { - return sdkdiag.AppendErrorf(diags, "deleting MemoryDB MultiRegionCluster (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "deleting MemoryDB Multi Region Cluster (%s): %s", d.Id(), err) } if _, err := waitMultiRegionClusterDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB MultiRegionCluster (%s) delete: %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region Cluster (%s) delete: %s", d.Id(), err) } return diags @@ -435,22 +372,6 @@ func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name s } } -func statusMultiRegionClusterParameterGroup(ctx context.Context, conn *memorydb.Client, name string) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - output, err := findMultiRegionClusterByName(ctx, conn, name) - - if tfresource.NotFound(err) { - return nil, "", nil - } - - if err != nil { - return nil, "", err - } - - return output, aws.ToString(output.ParameterGroupStatus), nil - } -} - func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, @@ -484,23 +405,3 @@ func waitMultiRegionClusterDeleted(ctx context.Context, conn *memorydb.Client, n return nil, err } - -func waitMultiRegionClusterParameterGroupInSync(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { - const ( - timeout = 60 * time.Minute - ) - stateConf := &retry.StateChangeConf{ - Pending: []string{clusterParameterGroupStatusApplying}, - Target: []string{clusterParameterGroupStatusInSync}, - Refresh: statusMultiRegionClusterParameterGroup(ctx, conn, name), - Timeout: timeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - - if output, ok := outputRaw.(*awstypes.MultiRegionCluster); ok { - return output, err - } - - return nil, err -} From 4435a8c84698d3086b670bde2c39918b8595384b Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sun, 1 Dec 2024 15:47:00 -0800 Subject: [PATCH 09/69] memorydb: change to `name` --- internal/service/memorydb/multi_region_cluster.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 68756f7bebf..da18e7304d1 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -52,6 +52,11 @@ func resourceMultiRegionCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + names.AttrName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, names.AttrDescription: { Type: schema.TypeString, Optional: true, @@ -92,11 +97,6 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, Computed: true, }, - "multi_region_cluster_name": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, "multi_region_cluster_name_suffix": { Type: schema.TypeString, Required: true, @@ -142,7 +142,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat var diags diag.Diagnostics conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) - name := create.Name(d.Get("multi_region_cluster_name").(string), "") + name := create.Name(d.Get(names.AttrName).(string), "") input := &memorydb.CreateMultiRegionClusterInput{ MultiRegionClusterName: aws.String(name), MultiRegionClusterNameSuffix: aws.String(d.Get("multi_region_cluster_name_suffix").(string)), @@ -203,13 +203,13 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, } d.Set(names.AttrARN, cluster.ARN) + d.Set(names.AttrName, cluster.MultiRegionClusterName) d.Set(names.AttrDescription, cluster.Description) if err := d.Set("clusters", flattenClusters(cluster.Clusters)); err != nil { return sdkdiag.AppendErrorf(diags, "setting clusters: %s", err) } d.Set(names.AttrEngine, cluster.Engine) d.Set(names.AttrEngineVersion, cluster.EngineVersion) - d.Set("multi_region_cluster_name", cluster.MultiRegionClusterName) d.Set("node_type", cluster.NodeType) d.Set("num_shards", cluster.NumberOfShards) d.Set("multi_region_parameter_group_name", cluster.MultiRegionParameterGroupName) From f55691bd09870ba1c7fa49c0f21014f4a5d423a7 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 3 Dec 2024 05:49:41 -0800 Subject: [PATCH 10/69] memorydb: fix sdk errors --- .../service/memorydb/multi_region_cluster.go | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index da18e7304d1..6016267046e 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "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" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" @@ -54,7 +53,6 @@ func resourceMultiRegionCluster() *schema.Resource { }, names.AttrName: { Type: schema.TypeString, - Optional: true, Computed: true, }, names.AttrDescription: { @@ -116,9 +114,9 @@ func resourceMultiRegionCluster() *schema.Resource { Computed: true, }, "update_strategy": { - Type: schema.TypeString, - Optional: true, - Computed: true, + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.UpdateStrategy](), }, "status": { Type: schema.TypeString, @@ -142,9 +140,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat var diags diag.Diagnostics conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) - name := create.Name(d.Get(names.AttrName).(string), "") input := &memorydb.CreateMultiRegionClusterInput{ - MultiRegionClusterName: aws.String(name), MultiRegionClusterNameSuffix: aws.String(d.Get("multi_region_cluster_name_suffix").(string)), NodeType: aws.String(d.Get("node_type").(string)), TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), @@ -168,16 +164,16 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat } if v, ok := d.GetOk("num_shards"); ok { - input.Port = aws.Int32(int32(v.(int))) + input.NumShards = aws.Int32(int32(v.(int))) } - _, err := conn.CreateMultiRegionCluster(ctx, input) + output, err := conn.CreateMultiRegionCluster(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating MemoryDB Multi Region cluster (%s): %s", name, err) + return sdkdiag.AppendErrorf(diags, "creating MemoryDB Multi Region cluster (%s): %s", *output.MultiRegionCluster.MultiRegionClusterName, err) } - d.SetId(name) + d.SetId(*output.MultiRegionCluster.MultiRegionClusterName) if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region cluster (%s) create: %s", d.Id(), err) @@ -205,7 +201,7 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set(names.AttrARN, cluster.ARN) d.Set(names.AttrName, cluster.MultiRegionClusterName) d.Set(names.AttrDescription, cluster.Description) - if err := d.Set("clusters", flattenClusters(cluster.Clusters)); err != nil { + if err := d.Set("clusters", flattenClusters(&cluster.Clusters)); err != nil { return sdkdiag.AppendErrorf(diags, "setting clusters: %s", err) } d.Set(names.AttrEngine, cluster.Engine) @@ -216,6 +212,9 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set("tls_enabled", cluster.TLSEnabled) d.Set(names.AttrStatus, cluster.Status) + // Update strategy isn’t returned by the API, so we retain the current value + d.Set("update_strategy", d.Get("update_strategy")) + return diags } @@ -254,6 +253,10 @@ func resourceMultiRegionClusterUpdate(ctx context.Context, d *schema.ResourceDat input.MultiRegionParameterGroupName = aws.String(d.Get("multi_region_parameter_group_name").(string)) } + if d.HasChange("update_strategy") { + input.UpdateStrategy = awstypes.UpdateStrategy(d.Get("update_strategy").(string)) + } + _, err := conn.UpdateMultiRegionCluster(ctx, input) if err != nil { @@ -294,17 +297,17 @@ func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceDat return diags } -func flattenClusters(apiObject *awstypes.Clusters) []interface{} { - if apiObject == nil { +func flattenClusters(apiObjects *[]awstypes.RegionalCluster) []interface{} { + if apiObjects == nil { return []interface{}{} } var tfList []interface{} - for k, apiObject := range apiObjects { + for _, apiObject := range *apiObjects { tfList = append(tfList, map[string]interface{}{ - names.AttrARN: aws.ToString(apiObject.Arn), - "cluster_name": aws.ToString(apiObject.Name), + names.AttrARN: aws.ToString(apiObject.ARN), + "cluster_name": aws.ToString(apiObject.ClusterName), names.AttrRegion: aws.ToString(apiObject.Region), names.AttrStatus: aws.ToString(apiObject.Status), }) From 9dd8e12238dffae2d863c0a8b58bd08b717d5fe6 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 3 Dec 2024 05:55:50 -0800 Subject: [PATCH 11/69] memorydb: add tests for multi region cluster --- internal/service/memorydb/exports_test.go | 30 ++--- .../memorydb/multi_region_cluster_test.go | 105 ++++++++++++++++++ 2 files changed, 121 insertions(+), 14 deletions(-) create mode 100644 internal/service/memorydb/multi_region_cluster_test.go diff --git a/internal/service/memorydb/exports_test.go b/internal/service/memorydb/exports_test.go index dd13a4b546d..07ac2aa928b 100644 --- a/internal/service/memorydb/exports_test.go +++ b/internal/service/memorydb/exports_test.go @@ -5,19 +5,21 @@ package memorydb // Exports for use in tests only. var ( - ResourceACL = resourceACL - ResourceCluster = resourceCluster - ResourceParameterGroup = resourceParameterGroup - ResourceSnapshot = resourceSnapshot - ResourceSubnetGroup = resourceSubnetGroup - ResourceUser = resourceUser + ResourceACL = resourceACL + ResourceCluster = resourceCluster + ResourceMultiRegionCluster = resourceMultiRegionCluster + ResourceParameterGroup = resourceParameterGroup + ResourceSnapshot = resourceSnapshot + ResourceSubnetGroup = resourceSubnetGroup + ResourceUser = resourceUser - FindACLByName = findACLByName - FindClusterByName = findClusterByName - FindParameterGroupByName = findParameterGroupByName - FindSnapshotByName = findSnapshotByName - FindSubnetGroupByName = findSubnetGroupByName - FindUserByName = findUserByName - ParameterChanges = parameterChanges - ParameterHash = parameterHash + FindACLByName = findACLByName + FindClusterByName = findClusterByName + FindMultiRegionClusterByName = findMultiRegionClusterByName + FindParameterGroupByName = findParameterGroupByName + FindSnapshotByName = findSnapshotByName + FindSubnetGroupByName = findSubnetGroupByName + FindUserByName = findUserByName + ParameterChanges = parameterChanges + ParameterHash = parameterHash ) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go new file mode 100644 index 00000000000..044cbbb2372 --- /dev/null +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -0,0 +1,105 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package memorydb_test + +import ( + "context" + "fmt" + "testing" + + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfmemorydb "github.com/hashicorp/terraform-provider-aws/internal/service/memorydb" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckMultiRegionClusterExists(ctx context.Context, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No MemoryDB Multi Region Cluster ID is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).MemoryDBClient(ctx) + + _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes[names.AttrName]) + + return err + } +} + +func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).MemoryDBClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_memorydb_multi_region_cluster" { + continue + } + + _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes[names.AttrName]) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("MemoryDB Multi Region Cluster %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccMultiRegionClusterConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + name = %[1]q + suffix + node_type = "db.t4g.small" + num_shards = 2 + + tags = { + Test = "test" + } +} +`, rName) +} From faa3d6d77b481f245ec33cba1c6088f9610ca4ec Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 3 Dec 2024 05:56:01 -0800 Subject: [PATCH 12/69] memorydb: shorten suffix and parameter group argument --- internal/service/memorydb/multi_region_cluster.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 6016267046e..a7ebfa1e2d8 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -95,11 +95,11 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, Computed: true, }, - "multi_region_cluster_name_suffix": { + "suffix": { Type: schema.TypeString, Required: true, }, - "multi_region_parameter_group_name": { + names.AttrParameterGroupName: { Type: schema.TypeString, Optional: true, Computed: true, @@ -141,7 +141,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) input := &memorydb.CreateMultiRegionClusterInput{ - MultiRegionClusterNameSuffix: aws.String(d.Get("multi_region_cluster_name_suffix").(string)), + MultiRegionClusterNameSuffix: aws.String(d.Get("suffix").(string)), NodeType: aws.String(d.Get("node_type").(string)), TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), Tags: getTagsIn(ctx), @@ -159,7 +159,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat input.EngineVersion = aws.String(v.(string)) } - if v, ok := d.GetOk("multi_region_parameter_group_name"); ok { + if v, ok := d.GetOk(names.AttrParameterGroupName); ok { input.MultiRegionParameterGroupName = aws.String(v.(string)) } @@ -208,7 +208,7 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set(names.AttrEngineVersion, cluster.EngineVersion) d.Set("node_type", cluster.NodeType) d.Set("num_shards", cluster.NumberOfShards) - d.Set("multi_region_parameter_group_name", cluster.MultiRegionParameterGroupName) + d.Set(names.AttrParameterGroupName, cluster.MultiRegionParameterGroupName) d.Set("tls_enabled", cluster.TLSEnabled) d.Set(names.AttrStatus, cluster.Status) @@ -249,8 +249,8 @@ func resourceMultiRegionClusterUpdate(ctx context.Context, d *schema.ResourceDat input.NodeType = aws.String(d.Get("node_type").(string)) } - if d.HasChange("multi_region_parameter_group_name") { - input.MultiRegionParameterGroupName = aws.String(d.Get("multi_region_parameter_group_name").(string)) + if d.HasChange(names.AttrParameterGroupName) { + input.MultiRegionParameterGroupName = aws.String(d.Get(names.AttrParameterGroupName).(string)) } if d.HasChange("update_strategy") { From dee10974f4073a2e456fe6cc1b5deae2649e8b9d Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 3 Dec 2024 06:01:06 -0800 Subject: [PATCH 13/69] memorydb: set test arguments --- internal/service/memorydb/multi_region_cluster_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 044cbbb2372..80399718036 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -92,10 +92,8 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name = %[1]q - suffix - node_type = "db.t4g.small" - num_shards = 2 + suffix = %[1]q + node_type = "db.t4g.small" tags = { Test = "test" From bd8f776300bd3720300e0f35ba366a9fc71a1ec6 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 3 Dec 2024 06:24:35 -0800 Subject: [PATCH 14/69] memorydb: retain `suffix` in read operation --- internal/service/memorydb/multi_region_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index a7ebfa1e2d8..b43f4257b63 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -126,7 +126,6 @@ func resourceMultiRegionCluster() *schema.Resource { "tls_enabled": { Type: schema.TypeBool, Optional: true, - Computed: true, Default: true, }, names.AttrTags: tftags.TagsSchema(), @@ -170,7 +169,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat output, err := conn.CreateMultiRegionCluster(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating MemoryDB Multi Region cluster (%s): %s", *output.MultiRegionCluster.MultiRegionClusterName, err) + return sdkdiag.AppendErrorf(diags, "creating MemoryDB Multi Region cluster: %s", err) } d.SetId(*output.MultiRegionCluster.MultiRegionClusterName) @@ -212,7 +211,8 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set("tls_enabled", cluster.TLSEnabled) d.Set(names.AttrStatus, cluster.Status) - // Update strategy isn’t returned by the API, so we retain the current value + // These attributes aren't returned by the API, so we retain the current value. + d.Set("suffix", d.Get("suffix")) d.Set("update_strategy", d.Get("update_strategy")) return diags From d24c8c3d442c708ed170087abc2f5ae3cecacc8b Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 3 Dec 2024 06:24:46 -0800 Subject: [PATCH 15/69] memorydb: use the right `node_type` for multi region clusters --- internal/service/memorydb/multi_region_cluster_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 80399718036..5a63fb7d64e 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -93,7 +93,7 @@ func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { suffix = %[1]q - node_type = "db.t4g.small" + node_type = "db.r7g.xlarge" tags = { Test = "test" From c071ec625b4f014009c593cb23d3f4a2d7a13479 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Tue, 3 Dec 2024 09:14:53 -0800 Subject: [PATCH 16/69] memorydb: add `multi_region_cluster_name` to memorydb cluster --- internal/service/memorydb/cluster.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/service/memorydb/cluster.go b/internal/service/memorydb/cluster.go index ec8b06cf70b..5c943e16568 100644 --- a/internal/service/memorydb/cluster.go +++ b/internal/service/memorydb/cluster.go @@ -85,6 +85,11 @@ func resourceCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "multi_region_cluster_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, names.AttrEngine: { Type: schema.TypeString, Optional: true, @@ -324,6 +329,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int input.MaintenanceWindow = aws.String(v.(string)) } + if v, ok := d.GetOk("multi_region_cluster_name"); ok { + input.MaintenanceWindow = aws.String(v.(string)) + } + if v, ok := d.GetOk(names.AttrParameterGroupName); ok { input.ParameterGroupName = aws.String(v.(string)) } @@ -408,6 +417,7 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter } d.Set(names.AttrDescription, cluster.Description) d.Set("engine_patch_version", cluster.EnginePatchVersion) + d.Set("multi_region_cluster_name", cluster.MultiRegionClusterName) d.Set(names.AttrEngine, cluster.Engine) d.Set(names.AttrEngineVersion, cluster.EngineVersion) d.Set(names.AttrKMSKeyARN, cluster.KmsKeyId) // KmsKeyId is actually an ARN here. From 6f526733edf06c443899c0894f11df620e04724c Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 04:53:44 -0800 Subject: [PATCH 17/69] memorydb: add `multI_region_cluster_name` test --- internal/service/memorydb/cluster_test.go | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/internal/service/memorydb/cluster_test.go b/internal/service/memorydb/cluster_test.go index 577c9c644d6..ece89588523 100644 --- a/internal/service/memorydb/cluster_test.go +++ b/internal/service/memorydb/cluster_test.go @@ -257,6 +257,33 @@ func TestAccMemoryDBCluster_create_withDataTiering(t *testing.T) { }) } +func TestAccMemoryDBCluster_multiRegionClusterName(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccClusterConfig_multiRegionClusterName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccMemoryDBCluster_create_withKMS(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -1371,6 +1398,49 @@ resource "aws_memorydb_cluster" "test" { ) } +func testAccClusterConfig_multiRegionClusterName(rName string) string { + return acctest.ConfigCompose( + testAccClusterConfig_baseNetwork(rName), + testAccClusterConfig_baseUserAndACL(rName), + fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + + tags = { + Test = "test" + } +} + +resource "aws_memorydb_cluster" "test" { + acl_name = aws_memorydb_acl.test.id + auto_minor_version_upgrade = false + name = %[1]q + node_type = "db.t4g.small" + num_shards = 2 + security_group_ids = [aws_security_group.test.id] + snapshot_retention_limit = 7 + subnet_group_name = aws_memorydb_subnet_group.test.id + + multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.name + + tags = { + Test = "test" + } +} +`, rName), + ) +} + func testAccClusterConfig_kms(rName string) string { return acctest.ConfigCompose( testAccClusterConfig_baseNetwork(rName), From 815fd48caaef4a8801ebe1ca18bf550b1cc7278a Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 05:10:33 -0800 Subject: [PATCH 18/69] memorydb: extract suffix when reading DescribeMultiRegionClusters does not return the suffix argument. Since suffix is required, this conflicts when testing the import. --- .../service/memorydb/multi_region_cluster.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index b43f4257b63..d1ace08fadc 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -5,7 +5,9 @@ package memorydb import ( "context" + "errors" "log" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -212,7 +214,11 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set(names.AttrStatus, cluster.Status) // These attributes aren't returned by the API, so we retain the current value. - d.Set("suffix", d.Get("suffix")) + suffix, err := suffixAfterHyphen(*cluster.MultiRegionClusterName) + if err != nil { + return sdkdiag.AppendErrorf(diags, "extracting suffix from Multi Region Cluster name: %s", err) + } + d.Set("suffix", suffix) d.Set("update_strategy", d.Get("update_strategy")) return diags @@ -408,3 +414,13 @@ func waitMultiRegionClusterDeleted(ctx context.Context, conn *memorydb.Client, n return nil, err } + +// suffixAfterHyphen extracts the substring after the first hyphen ("-") in the input string. +// If no hyphen is found, it returns an error. +func suffixAfterHyphen(input string) (string, error) { + idx := strings.Index(input, "-") + if idx == -1 { + return "", errors.New("no hyphen found in the input string") + } + return input[idx+1:], nil +} From 6076bce7836b20a52476ff94d1c2455dc9911d48 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 05:14:38 -0800 Subject: [PATCH 19/69] names: add suffix attribute --- names/attr_consts_gen.go | 1 + 1 file changed, 1 insertion(+) diff --git a/names/attr_consts_gen.go b/names/attr_consts_gen.go index 783e418eb0f..751cd3b02d9 100644 --- a/names/attr_consts_gen.go +++ b/names/attr_consts_gen.go @@ -203,6 +203,7 @@ const ( AttrSubnetID = "subnet_id" AttrSubnetIDs = "subnet_ids" AttrSubnets = "subnets" + AttrSuffix = "suffix" AttrTableName = "table_name" AttrTags = "tags" AttrTagsAll = "tags_all" From 1e0319d8e682a6b72de9732754e554ba0a77e7ad Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 05:14:46 -0800 Subject: [PATCH 20/69] memorydb: use suffix attribute --- internal/service/memorydb/multi_region_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index d1ace08fadc..28a195ef668 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -97,7 +97,7 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, Computed: true, }, - "suffix": { + names.AttrSuffix: { Type: schema.TypeString, Required: true, }, @@ -142,7 +142,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) input := &memorydb.CreateMultiRegionClusterInput{ - MultiRegionClusterNameSuffix: aws.String(d.Get("suffix").(string)), + MultiRegionClusterNameSuffix: aws.String(d.Get(names.AttrSuffix).(string)), NodeType: aws.String(d.Get("node_type").(string)), TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), Tags: getTagsIn(ctx), @@ -218,7 +218,7 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, if err != nil { return sdkdiag.AppendErrorf(diags, "extracting suffix from Multi Region Cluster name: %s", err) } - d.Set("suffix", suffix) + d.Set(names.AttrSuffix, suffix) d.Set("update_strategy", d.Get("update_strategy")) return diags From 1ad76088904c17eb992801535c96b24963c6e04c Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 05:30:37 -0800 Subject: [PATCH 21/69] memorydb: tls_enabled can't be updated --- internal/service/memorydb/multi_region_cluster.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 28a195ef668..e49f3ee92cf 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -129,6 +129,7 @@ func resourceMultiRegionCluster() *schema.Resource { Type: schema.TypeBool, Optional: true, Default: true, + ForceNew: true, }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), From 81e1aa11d699210d7ba99ff434c00fa7a7e8546e Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 05:46:58 -0800 Subject: [PATCH 22/69] memorydb: change to name attribute for consistency --- internal/service/memorydb/multi_region_cluster.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index e49f3ee92cf..da35e3d9f0e 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -71,7 +71,7 @@ func resourceMultiRegionCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "cluster_name": { + names.AttrName: { Type: schema.TypeString, Computed: true, }, @@ -314,7 +314,7 @@ func flattenClusters(apiObjects *[]awstypes.RegionalCluster) []interface{} { for _, apiObject := range *apiObjects { tfList = append(tfList, map[string]interface{}{ names.AttrARN: aws.ToString(apiObject.ARN), - "cluster_name": aws.ToString(apiObject.ClusterName), + names.AttrName: aws.ToString(apiObject.ClusterName), names.AttrRegion: aws.ToString(apiObject.Region), names.AttrStatus: aws.ToString(apiObject.Status), }) From 459f05f607175a0f4689e3bd9a05cb31cf072bec Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 05:49:12 -0800 Subject: [PATCH 23/69] memorydb: add more multi region cluster tests --- .../memorydb/multi_region_cluster_test.go | 375 ++++++++++++++++++ 1 file changed, 375 insertions(+) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 5a63fb7d64e..4ead7349ae2 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -33,6 +33,20 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { Config: testAccMultiRegionClusterConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), + resource.TestCheckResourceAttrSet(resourceName, names.AttrName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrSuffix), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), + resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), + resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), + resource.TestCheckResourceAttrSet(resourceName, names.AttrParameterGroupName), + resource.TestCheckResourceAttrSet(resourceName, "num_shards"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), + resource.TestCheckResourceAttr(resourceName, "clusters.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtTrue), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Test", "test"), ), }, { @@ -44,6 +58,231 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { }) } +func TestAccMemoryDBMultiRegionCluster_defaults(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_defaults(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), + resource.TestCheckResourceAttrSet(resourceName, names.AttrName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrSuffix), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), + resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), + resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), + resource.TestCheckResourceAttrSet(resourceName, names.AttrParameterGroupName), + resource.TestCheckResourceAttr(resourceName, "num_shards", "1"), + resource.TestCheckResourceAttr(resourceName, "clusters.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtTrue), + resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_description(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_description(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Also managed by Terraform"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_tlsEnabled(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_tlsEnabled(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtFalse), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_engine(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_engine(rName, "valkey"), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, names.AttrEngine, "valkey"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_engineVersion(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_engineVersion(rName, "valkey", "7.3"), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, names.AttrEngine, "valkey"), + resource.TestCheckResourceAttr(resourceName, names.AttrEngineVersion, "7.3"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_clusters(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_clusters(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "clusters.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "clusters.0.arn"), + resource.TestCheckResourceAttrSet(resourceName, "clusters.0.name"), + resource.TestCheckResourceAttrSet(resourceName, "clusters.0.region"), + resource.TestCheckResourceAttrSet(resourceName, "clusters.0.status"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccMultiRegionClusterConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), + ), + }, + { + Config: testAccMultiRegionClusterConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), + ), + }, + }, + }) +} + func testAccCheckMultiRegionClusterExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -101,3 +340,139 @@ resource "aws_memorydb_multi_region_cluster" "test" { } `, rName) } + +func testAccMultiRegionClusterConfig_defaults(rName string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" +} +`, rName) +} + +func testAccMultiRegionClusterConfig_description(rName string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + description = "Also managed by Terraform" + + tags = { + Test = "test" + } +} +`, rName) +} + +func testAccMultiRegionClusterConfig_tlsEnabled(rName string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + tls_enabled = false + + tags = { + Test = "test" + } +} +`, rName) +} + +func testAccMultiRegionClusterConfig_engine(rName, engine string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + engine = %[2]q + + tags = { + Test = "test" + } +} +`, rName, engine) +} + +func testAccMultiRegionClusterConfig_engineVersion(rName, engine, engineVersion string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + engine = %[2]q + engine_version = %[3]q + + tags = { + Test = "test" + } +} +`, rName, engine, engineVersion) +} + +func testAccMultiRegionClusterConfig_clusters(rName string) string { + return acctest.ConfigCompose( + testAccClusterConfig_baseNetwork(rName), + testAccClusterConfig_baseUserAndACL(rName), + fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + + tags = { + Test = "test" + } +} + +resource "aws_memorydb_cluster" "test" { + acl_name = aws_memorydb_acl.test.id + auto_minor_version_upgrade = false + name = %[1]q + node_type = "db.t4g.small" + num_shards = 2 + security_group_ids = [aws_security_group.test.id] + snapshot_retention_limit = 7 + subnet_group_name = aws_memorydb_subnet_group.test.id + + multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.name + + tags = { + Test = "test" + } +} +`, rName), + ) +} + +func testAccMultiRegionClusterConfig_tags1(rName, tag1Key, tag1Value string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + + tags = { + %[2]q = %[3]q + } +} +`, rName, tag1Key, tag1Value) +} + +func testAccMultiRegionClusterConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + suffix = %[1]q + node_type = "db.r7g.xlarge" + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tag1Key, tag1Value, tag2Key, tag2Value) +} From b3aa2e5cec45ea48913c22279b23151ea86ea890 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 05:51:52 -0800 Subject: [PATCH 24/69] memorydb: fix check exists in multi region cluster tags test --- internal/service/memorydb/multi_region_cluster_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 4ead7349ae2..14675b9e92a 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -252,7 +252,7 @@ func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { { Config: testAccMultiRegionClusterConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), Check: resource.ComposeTestCheckFunc( - testAccCheckClusterExists(ctx, resourceName), + testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), ), @@ -265,7 +265,7 @@ func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { { Config: testAccMultiRegionClusterConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), Check: resource.ComposeTestCheckFunc( - testAccCheckClusterExists(ctx, resourceName), + testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), @@ -274,7 +274,7 @@ func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { { Config: testAccMultiRegionClusterConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), Check: resource.ComposeTestCheckFunc( - testAccCheckClusterExists(ctx, resourceName), + testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), ), From 18777816b7a40205363d58408f74f46bb20d827c Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 11:52:48 -0800 Subject: [PATCH 25/69] memorydb: acc test lint --- internal/service/memorydb/cluster_test.go | 4 ++-- .../memorydb/multi_region_cluster_test.go | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/service/memorydb/cluster_test.go b/internal/service/memorydb/cluster_test.go index ece89588523..6d319703908 100644 --- a/internal/service/memorydb/cluster_test.go +++ b/internal/service/memorydb/cluster_test.go @@ -1413,8 +1413,8 @@ resource "aws_security_group" "test" { } resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q - node_type = "db.r7g.xlarge" + suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { Test = "test" diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 14675b9e92a..58425034cd9 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -331,8 +331,8 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q - node_type = "db.r7g.xlarge" + suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { Test = "test" @@ -344,8 +344,8 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_defaults(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q - node_type = "db.r7g.xlarge" + suffix = %[1]q + node_type = "db.r7g.xlarge" } `, rName) } @@ -422,8 +422,8 @@ resource "aws_security_group" "test" { } resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q - node_type = "db.r7g.xlarge" + suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { Test = "test" @@ -453,8 +453,8 @@ resource "aws_memorydb_cluster" "test" { func testAccMultiRegionClusterConfig_tags1(rName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q - node_type = "db.r7g.xlarge" + suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { %[2]q = %[3]q @@ -466,8 +466,8 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q - node_type = "db.r7g.xlarge" + suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { %[2]q = %[3]q From 2848d892d752589641a940fe20e64fbf3e88d30b Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 11:59:40 -0800 Subject: [PATCH 26/69] memorydb: use `name_suffix` --- .../service/memorydb/multi_region_cluster.go | 6 +++--- .../memorydb/multi_region_cluster_test.go | 18 +++++++++--------- names/attr_consts_gen.go | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index da35e3d9f0e..49fbd24dfef 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -97,7 +97,7 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, Computed: true, }, - names.AttrSuffix: { + names.AttrNameSuffix: { Type: schema.TypeString, Required: true, }, @@ -143,7 +143,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) input := &memorydb.CreateMultiRegionClusterInput{ - MultiRegionClusterNameSuffix: aws.String(d.Get(names.AttrSuffix).(string)), + MultiRegionClusterNameSuffix: aws.String(d.Get(names.AttrNameSuffix).(string)), NodeType: aws.String(d.Get("node_type").(string)), TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), Tags: getTagsIn(ctx), @@ -219,7 +219,7 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, if err != nil { return sdkdiag.AppendErrorf(diags, "extracting suffix from Multi Region Cluster name: %s", err) } - d.Set(names.AttrSuffix, suffix) + d.Set(names.AttrNameSuffix, suffix) d.Set("update_strategy", d.Get("update_strategy")) return diags diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 58425034cd9..b36a6a23f94 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -331,7 +331,7 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" tags = { @@ -344,7 +344,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_defaults(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" } `, rName) @@ -353,7 +353,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_description(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" description = "Also managed by Terraform" @@ -367,7 +367,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_tlsEnabled(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" tls_enabled = false @@ -381,7 +381,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_engine(rName, engine string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" engine = %[2]q @@ -395,7 +395,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_engineVersion(rName, engine, engineVersion string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" engine = %[2]q engine_version = %[3]q @@ -422,7 +422,7 @@ resource "aws_security_group" "test" { } resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" tags = { @@ -453,7 +453,7 @@ resource "aws_memorydb_cluster" "test" { func testAccMultiRegionClusterConfig_tags1(rName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" tags = { @@ -466,7 +466,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" tags = { diff --git a/names/attr_consts_gen.go b/names/attr_consts_gen.go index 751cd3b02d9..4f7a060f6ce 100644 --- a/names/attr_consts_gen.go +++ b/names/attr_consts_gen.go @@ -127,6 +127,7 @@ const ( AttrMostRecent = "most_recent" AttrName = "name" AttrNamePrefix = "name_prefix" + AttrNameSuffix = "name_suffix" AttrNames = "names" AttrNamespace = "namespace" AttrNetworkConfiguration = "network_configuration" From 5bd673581751191ae141ee515f4d002c558d6c90 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 12:02:26 -0800 Subject: [PATCH 27/69] memorydb: lint --- .../memorydb/multi_region_cluster_test.go | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index b36a6a23f94..81fd30fb3e8 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -331,8 +331,8 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" + name_suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { Test = "test" @@ -344,8 +344,8 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_defaults(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" + name_suffix = %[1]q + node_type = "db.r7g.xlarge" } `, rName) } @@ -353,7 +353,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_description(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" description = "Also managed by Terraform" @@ -367,7 +367,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_tlsEnabled(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" tls_enabled = false @@ -381,9 +381,9 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_engine(rName, engine string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" - engine = %[2]q + name_suffix = %[1]q + node_type = "db.r7g.xlarge" + engine = %[2]q tags = { Test = "test" @@ -395,7 +395,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_engineVersion(rName, engine, engineVersion string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + name_suffix = %[1]q node_type = "db.r7g.xlarge" engine = %[2]q engine_version = %[3]q @@ -422,8 +422,8 @@ resource "aws_security_group" "test" { } resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" + name_suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { Test = "test" @@ -453,8 +453,8 @@ resource "aws_memorydb_cluster" "test" { func testAccMultiRegionClusterConfig_tags1(rName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" + name_suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { %[2]q = %[3]q @@ -466,8 +466,8 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" + name_suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { %[2]q = %[3]q From 1c05ac8bf93f362f46ee2864f9f281708601a8a4 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 12:07:21 -0800 Subject: [PATCH 28/69] memorydb: add multi region cluster resource docs --- ...emorydb_multi_region_cluster.html.markdown | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 website/docs/r/memorydb_multi_region_cluster.html.markdown diff --git a/website/docs/r/memorydb_multi_region_cluster.html.markdown b/website/docs/r/memorydb_multi_region_cluster.html.markdown new file mode 100644 index 00000000000..848c907b7bc --- /dev/null +++ b/website/docs/r/memorydb_multi_region_cluster.html.markdown @@ -0,0 +1,90 @@ +--- +subcategory: "MemoryDB" +layout: "aws" +page_title: "AWS: aws_memorydb_multi_region_cluster" +description: |- + Provides a MemoryDB Cluster. +--- + +# Resource: aws_memorydb_multi_region_cluster + +Provides a MemoryDB Multi Region Cluster. + +More information about MemoryDB can be found in the [Developer Guide](https://docs.aws.amazon.com/memorydb/latest/devguide/what-is-memorydb-for-redis.html). + +## Example Usage + +```terraform +resource "aws_memorydb_multi_region_cluster" "example" { + suffix = "example" + node_type = "db.r7g.xlarge" +} + +resource "aws_memorydb_cluster" "example" { + acl_name = aws_memorydb_acl.example.id + auto_minor_version_upgrade = false + name = "example" + node_type = "db.t4g.small" + num_shards = 2 + security_group_ids = [aws_security_group.example.id] + snapshot_retention_limit = 7 + subnet_group_name = aws_memorydb_subnet_group.example.id + + multi_region_cluster_name = aws_memorydb_multi_region_cluster.example.name +} +``` + +## Argument Reference + +The following arguments are required: + +* `name_suffix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. +* `node_type` - (Required) The node type to be used for the multi-Region cluster. + +The following arguments are optional: + +* `description` - (Optional) description for the multi-Region cluster. Defaults to `"Managed by Terraform"`. +* `engine` - (Optional) The name of the engine to be used for the multi-Region cluster. Supported values are `redis` and `valkey`. +* `engine_version` - (Optional) The version of the engine to be used for the multi-Region cluster. Downgrades are not supported. +* `num_shards` - (Optional) The number of shards for the multi-Region cluster. +* `parameter_group_name` - (Optional) The name of the multi-Region parameter group to be associated with the cluster. +* `tls_enabled` - (Optional, Forces new resource) A flag to enable in-transit encryption on the cluster. Defaults to `true`. +* `tags` - (Optional) A map of tags to assign to the resource. 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. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `id` - The name of the multi-region cluster.. +* `arn` - The ARN of the multi-region cluster. +* `clusters` - The clusters in this multi-Region cluster. + * `arn` - The Amazon Resource Name (ARN) the Regional cluster. + * `name` - The name of the Regional cluster + * `region` - The Region the current Regional cluster is assigned to. + * `status` - The status of the Regional cluster. +* `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 `120m`) +- `update` - (Default `120m`) +- `delete` - (Default `120m`) + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import a cluster using the `name`. For example: + +```terraform +import { + to = aws_memorydb_multi_region_cluster.example + id = "my-multi-region-cluster" +} +``` + +Using `terraform import`, import a cluster using the `name`. For example: + +```console +% terraform import aws_memorydb_multi_region_cluster.example my-multi-region-cluster +``` From bb916330a697f48c9688e1c21bed539b87ade2f4 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 12:10:03 -0800 Subject: [PATCH 29/69] memorydb: add `aws_memorydb_multi_region_cluster` changelog --- .changelog/40376.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/40376.txt diff --git a/.changelog/40376.txt b/.changelog/40376.txt new file mode 100644 index 00000000000..8c76979a89b --- /dev/null +++ b/.changelog/40376.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_memorydb_multi_region_cluster +``` From ff182e9160cd8d2069883f19ed82d9522664b034 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 12:10:39 -0800 Subject: [PATCH 30/69] memorydb: fix attribute assert --- internal/service/memorydb/multi_region_cluster_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 81fd30fb3e8..dc1b08052a1 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -35,7 +35,7 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), resource.TestCheckResourceAttrSet(resourceName, names.AttrName), - resource.TestCheckResourceAttrSet(resourceName, names.AttrSuffix), + resource.TestCheckResourceAttrSet(resourceName, names.AttrNameSuffix), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), @@ -75,7 +75,7 @@ func TestAccMemoryDBMultiRegionCluster_defaults(t *testing.T) { testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), resource.TestCheckResourceAttrSet(resourceName, names.AttrName), - resource.TestCheckResourceAttrSet(resourceName, names.AttrSuffix), + resource.TestCheckResourceAttrSet(resourceName, names.AttrNameSuffix), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), From faa91e916f18015e9345c01da22f70022b9aa7bc Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 5 Dec 2024 12:18:52 -0800 Subject: [PATCH 31/69] memorydb: add `multi_region_cluster_name` argument to changelog --- .changelog/40376.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.changelog/40376.txt b/.changelog/40376.txt index 8c76979a89b..75b143a7732 100644 --- a/.changelog/40376.txt +++ b/.changelog/40376.txt @@ -1,3 +1,7 @@ ```release-note:new-resource aws_memorydb_multi_region_cluster ``` + +```release-note:enhancement +resource/aws_memorydb_cluster: Add `multi_region_cluster_name` argument +``` From 8f1b4cf9176bdda7d2638cff5757628b03294c96 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 6 Dec 2024 11:00:26 -0800 Subject: [PATCH 32/69] memorydb: fix semgrep findings --- .../service/memorydb/multi_region_cluster.go | 4 ++-- .../memorydb/multi_region_cluster_test.go | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 49fbd24dfef..bdb4cfaa1e4 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -120,7 +120,7 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, ValidateDiagFunc: enum.Validate[awstypes.UpdateStrategy](), }, - "status": { + names.AttrStatus: { Type: schema.TypeString, Optional: true, Computed: true, @@ -175,7 +175,7 @@ func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceDat return sdkdiag.AppendErrorf(diags, "creating MemoryDB Multi Region cluster: %s", err) } - d.SetId(*output.MultiRegionCluster.MultiRegionClusterName) + d.SetId(aws.ToString(output.MultiRegionCluster.MultiRegionClusterName)) if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region cluster (%s) create: %s", d.Id(), err) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index dc1b08052a1..f1b24b77dd4 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -421,15 +421,6 @@ resource "aws_security_group" "test" { } } -resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" - - tags = { - Test = "test" - } -} - resource "aws_memorydb_cluster" "test" { acl_name = aws_memorydb_acl.test.id auto_minor_version_upgrade = false @@ -440,7 +431,14 @@ resource "aws_memorydb_cluster" "test" { snapshot_retention_limit = 7 subnet_group_name = aws_memorydb_subnet_group.test.id - multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.name + tags = { + Test = "test" + } +} + +resource "aws_memorydb_multi_region_cluster" "test" { + name_suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { Test = "test" From 31622990e34dde8c6602109e1d1324b80c048b6c Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 6 Dec 2024 11:36:56 -0800 Subject: [PATCH 33/69] names: add suffix related attributes --- names/attr_constants.csv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/names/attr_constants.csv b/names/attr_constants.csv index 292ca28a602..0beaf7a8c19 100644 --- a/names/attr_constants.csv +++ b/names/attr_constants.csv @@ -120,6 +120,7 @@ mode,Mode most_recent,MostRecent name,Name name_prefix,NamePrefix +name_suffix,NameSuffix names,Names namespace,Namespace network_configuration,NetworkConfiguration @@ -196,6 +197,7 @@ stream_arn,StreamARN subnet_id,SubnetID subnet_ids,SubnetIDs subnets,Subnets +suffix,Suffix table_name,TableName tags,Tags tags_all,TagsAll From 592e19cb1c867e9d2a9864d32fea3d11dac3ed05 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 6 Dec 2024 11:48:33 -0800 Subject: [PATCH 34/69] memorydb: fix typo --- internal/service/memorydb/cluster.go | 2 +- internal/service/memorydb/multi_region_cluster_test.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/service/memorydb/cluster.go b/internal/service/memorydb/cluster.go index 5c943e16568..1e4f1038d69 100644 --- a/internal/service/memorydb/cluster.go +++ b/internal/service/memorydb/cluster.go @@ -330,7 +330,7 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int } if v, ok := d.GetOk("multi_region_cluster_name"); ok { - input.MaintenanceWindow = aws.String(v.(string)) + input.MultiRegionClusterName = aws.String(v.(string)) } if v, ok := d.GetOk(names.AttrParameterGroupName); ok { diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index f1b24b77dd4..540450495d1 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -431,6 +431,8 @@ resource "aws_memorydb_cluster" "test" { snapshot_retention_limit = 7 subnet_group_name = aws_memorydb_subnet_group.test.id + multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.name + tags = { Test = "test" } From e1fa5af6db1da91b0232e274aaf0ac02cc2f9433 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 6 Dec 2024 11:56:08 -0800 Subject: [PATCH 35/69] memorydb: test resource attributes --- internal/service/memorydb/multi_region_cluster_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 540450495d1..97f0ac8e86d 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -425,7 +425,7 @@ resource "aws_memorydb_cluster" "test" { acl_name = aws_memorydb_acl.test.id auto_minor_version_upgrade = false name = %[1]q - node_type = "db.t4g.small" + node_type = "db.r7g.xlarge" num_shards = 2 security_group_ids = [aws_security_group.test.id] snapshot_retention_limit = 7 @@ -441,6 +441,7 @@ resource "aws_memorydb_cluster" "test" { resource "aws_memorydb_multi_region_cluster" "test" { name_suffix = %[1]q node_type = "db.r7g.xlarge" + num_shards = 2 tags = { Test = "test" From 9ee9d91fe9f10d0900d3c30ede5c0140edfe5b02 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 7 Dec 2024 10:15:04 -0800 Subject: [PATCH 36/69] names: generate suffix attributes --- .ci/.semgrep-constants.yml | 36 ++++++++++++++++++++++++++++ names/generate/const_or_quote_gen.go | 2 ++ 2 files changed, 38 insertions(+) diff --git a/.ci/.semgrep-constants.yml b/.ci/.semgrep-constants.yml index 5ef2012983a..ef9b69018c7 100644 --- a/.ci/.semgrep-constants.yml +++ b/.ci/.semgrep-constants.yml @@ -2197,6 +2197,24 @@ rules: options: constant_propagation: false + - id: literal-name_suffix-string-constant + languages: [go] + message: Use the constant `names.AttrNameSuffix` for the string literal "name_suffix" + paths: + include: + - "internal/service/**/*.go" + patterns: + - pattern: '"name_suffix"' + - pattern-not-regex: '"name_suffix":\s+test\w+,' + - pattern-not-inside: 'config.Variables{ ... }' + - pattern-not-inside: 'packageName = ...' + - pattern-not-inside: 'provider.ConflictingEndpointsWarningDiag(...)' + - pattern-not-inside: 'const $X = ...' + severity: ERROR + fix: "names.AttrNameSuffix" + options: + constant_propagation: false + - id: literal-names-string-constant languages: [go] message: Use the constant `names.AttrNames` for the string literal "names" @@ -3565,6 +3583,24 @@ rules: options: constant_propagation: false + - id: literal-suffix-string-constant + languages: [go] + message: Use the constant `names.AttrSuffix` for the string literal "suffix" + paths: + include: + - "internal/service/**/*.go" + patterns: + - pattern: '"suffix"' + - pattern-not-regex: '"suffix":\s+test\w+,' + - pattern-not-inside: 'config.Variables{ ... }' + - pattern-not-inside: 'packageName = ...' + - pattern-not-inside: 'provider.ConflictingEndpointsWarningDiag(...)' + - pattern-not-inside: 'const $X = ...' + severity: ERROR + fix: "names.AttrSuffix" + options: + constant_propagation: false + - id: literal-table_name-string-constant languages: [go] message: Use the constant `names.AttrTableName` for the string literal "table_name" diff --git a/names/generate/const_or_quote_gen.go b/names/generate/const_or_quote_gen.go index 81bf94ad764..bd7f0712183 100644 --- a/names/generate/const_or_quote_gen.go +++ b/names/generate/const_or_quote_gen.go @@ -135,6 +135,7 @@ func ConstOrQuote(constant string) string { "most_recent": "AttrMostRecent", "name": "AttrName", "name_prefix": "AttrNamePrefix", + "name_suffix": "AttrNameSuffix", "names": "AttrNames", "namespace": "AttrNamespace", "network_configuration": "AttrNetworkConfiguration", @@ -211,6 +212,7 @@ func ConstOrQuote(constant string) string { "subnet_id": "AttrSubnetID", "subnet_ids": "AttrSubnetIDs", "subnets": "AttrSubnets", + "suffix": "AttrSuffix", "table_name": "AttrTableName", "tags": "AttrTags", "tags_all": "AttrTagsAll", From 43d0cc9e9e69a6c83ead05bcfc8cb343958d9004 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 7 Dec 2024 10:35:32 -0800 Subject: [PATCH 37/69] memorydb: fix linting --- internal/service/memorydb/cluster_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/memorydb/cluster_test.go b/internal/service/memorydb/cluster_test.go index 6d319703908..001aec5ebb2 100644 --- a/internal/service/memorydb/cluster_test.go +++ b/internal/service/memorydb/cluster_test.go @@ -1413,8 +1413,8 @@ resource "aws_security_group" "test" { } resource "aws_memorydb_multi_region_cluster" "test" { - suffix = %[1]q - node_type = "db.r7g.xlarge" + name_suffix = %[1]q + node_type = "db.r7g.xlarge" tags = { Test = "test" From 48255dc4e5775cd2108e79512af75e810c249d05 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 7 Dec 2024 10:36:03 -0800 Subject: [PATCH 38/69] memorydb: delete associated multi-region cluster when a cluster is removed --- internal/service/memorydb/cluster.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/service/memorydb/cluster.go b/internal/service/memorydb/cluster.go index 1e4f1038d69..eee1b0614e3 100644 --- a/internal/service/memorydb/cluster.go +++ b/internal/service/memorydb/cluster.go @@ -571,6 +571,10 @@ func resourceClusterDelete(ctx context.Context, d *schema.ResourceData, meta int ClusterName: aws.String(d.Id()), } + if v := d.Get("multi_region_cluster_name"); v != nil && len(v.(string)) > 0 { + input.MultiRegionClusterName = aws.String(v.(string)) + } + if v := d.Get("final_snapshot_name"); v != nil && len(v.(string)) > 0 { input.FinalSnapshotName = aws.String(v.(string)) } From 4ed70e68f4b4faad73c0c99e04894938bb4906b8 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 7 Dec 2024 10:36:28 -0800 Subject: [PATCH 39/69] memorydb: remove `clusters` from schema --- .../service/memorydb/multi_region_cluster.go | 46 ------------------- .../memorydb/multi_region_cluster_test.go | 31 ------------- ...emorydb_multi_region_cluster.html.markdown | 5 -- 3 files changed, 82 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index bdb4cfaa1e4..ad0c435b1b6 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -62,30 +62,6 @@ func resourceMultiRegionCluster() *schema.Resource { Optional: true, Default: "Managed by Terraform", }, - "clusters": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrARN: { - Type: schema.TypeString, - Computed: true, - }, - names.AttrName: { - Type: schema.TypeString, - Computed: true, - }, - names.AttrRegion: { - Type: schema.TypeString, - Computed: true, - }, - names.AttrStatus: { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, names.AttrEngine: { Type: schema.TypeString, Optional: true, @@ -203,9 +179,6 @@ func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, d.Set(names.AttrARN, cluster.ARN) d.Set(names.AttrName, cluster.MultiRegionClusterName) d.Set(names.AttrDescription, cluster.Description) - if err := d.Set("clusters", flattenClusters(&cluster.Clusters)); err != nil { - return sdkdiag.AppendErrorf(diags, "setting clusters: %s", err) - } d.Set(names.AttrEngine, cluster.Engine) d.Set(names.AttrEngineVersion, cluster.EngineVersion) d.Set("node_type", cluster.NodeType) @@ -304,25 +277,6 @@ func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceDat return diags } -func flattenClusters(apiObjects *[]awstypes.RegionalCluster) []interface{} { - if apiObjects == nil { - return []interface{}{} - } - - var tfList []interface{} - - for _, apiObject := range *apiObjects { - tfList = append(tfList, map[string]interface{}{ - names.AttrARN: aws.ToString(apiObject.ARN), - names.AttrName: aws.ToString(apiObject.ClusterName), - names.AttrRegion: aws.ToString(apiObject.Region), - names.AttrStatus: aws.ToString(apiObject.Status), - }) - } - - return tfList -} - func findMultiRegionClusterByName(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { input := &memorydb.DescribeMultiRegionClustersInput{ MultiRegionClusterName: aws.String(name), diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 97f0ac8e86d..3b2f6ac4059 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -207,37 +207,6 @@ func TestAccMemoryDBMultiRegionCluster_engineVersion(t *testing.T) { }) } -func TestAccMemoryDBMultiRegionCluster_clusters(t *testing.T) { - ctx := acctest.Context(t) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_memorydb_multi_region_cluster.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccMultiRegionClusterConfig_clusters(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckMultiRegionClusterExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, "clusters.#", "1"), - resource.TestCheckResourceAttrSet(resourceName, "clusters.0.arn"), - resource.TestCheckResourceAttrSet(resourceName, "clusters.0.name"), - resource.TestCheckResourceAttrSet(resourceName, "clusters.0.region"), - resource.TestCheckResourceAttrSet(resourceName, "clusters.0.status"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) diff --git a/website/docs/r/memorydb_multi_region_cluster.html.markdown b/website/docs/r/memorydb_multi_region_cluster.html.markdown index 848c907b7bc..bb854512cc8 100644 --- a/website/docs/r/memorydb_multi_region_cluster.html.markdown +++ b/website/docs/r/memorydb_multi_region_cluster.html.markdown @@ -57,11 +57,6 @@ This resource exports the following attributes in addition to the arguments abov * `id` - The name of the multi-region cluster.. * `arn` - The ARN of the multi-region cluster. -* `clusters` - The clusters in this multi-Region cluster. - * `arn` - The Amazon Resource Name (ARN) the Regional cluster. - * `name` - The name of the Regional cluster - * `region` - The Region the current Regional cluster is assigned to. - * `status` - The status of the Regional cluster. * `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 From 3d1c1606dd5c84248d399c1cee15819cfca1223c Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Sat, 7 Dec 2024 10:36:41 -0800 Subject: [PATCH 40/69] memorydb: add a small delay before waiting --- internal/service/memorydb/multi_region_cluster.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index ad0c435b1b6..e0920343a87 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -338,6 +338,7 @@ func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name s func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ + Delay: 20 * time.Second, Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, Target: []string{clusterStatusAvailable}, Refresh: statusMultiRegionCluster(ctx, conn, name), @@ -355,6 +356,7 @@ func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, func waitMultiRegionClusterDeleted(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { stateConf := &retry.StateChangeConf{ + Delay: 20 * time.Second, Pending: []string{clusterStatusDeleting}, Target: []string{}, Refresh: statusMultiRegionCluster(ctx, conn, name), From d3f7aa88368a2e92b363240e6ab5d1b061acaee0 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 12 Dec 2024 13:46:36 +0100 Subject: [PATCH 41/69] chore: wait until multi region cluster is available if we add a cluster to it --- internal/service/memorydb/cluster.go | 6 ++++++ internal/service/memorydb/cluster_test.go | 3 ++- internal/service/memorydb/multi_region_cluster.go | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/internal/service/memorydb/cluster.go b/internal/service/memorydb/cluster.go index eee1b0614e3..80552faadf4 100644 --- a/internal/service/memorydb/cluster.go +++ b/internal/service/memorydb/cluster.go @@ -381,6 +381,12 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Cluster (%s) create: %s", d.Id(), err) } + if v, ok := d.GetOk("multi_region_cluster_name"); ok { + if _, err := waitMultiRegionClusterAvailable(ctx, conn, v.(string), d.Timeout(schema.TimeoutCreate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi-Region Cluster (%s) create: %s", v.(string), err) + } + } + return append(diags, resourceClusterRead(ctx, d, meta)...) } diff --git a/internal/service/memorydb/cluster_test.go b/internal/service/memorydb/cluster_test.go index 001aec5ebb2..4012e531c7f 100644 --- a/internal/service/memorydb/cluster_test.go +++ b/internal/service/memorydb/cluster_test.go @@ -1415,6 +1415,7 @@ resource "aws_security_group" "test" { resource "aws_memorydb_multi_region_cluster" "test" { name_suffix = %[1]q node_type = "db.r7g.xlarge" + num_shards = 2 tags = { Test = "test" @@ -1425,7 +1426,7 @@ resource "aws_memorydb_cluster" "test" { acl_name = aws_memorydb_acl.test.id auto_minor_version_upgrade = false name = %[1]q - node_type = "db.t4g.small" + node_type = "db.r7g.xlarge" num_shards = 2 security_group_ids = [aws_security_group.test.id] snapshot_retention_limit = 7 diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index e0920343a87..672961d6b7d 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -338,7 +338,7 @@ func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name s func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ - Delay: 20 * time.Second, + Delay: 90 * time.Second, Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, Target: []string{clusterStatusAvailable}, Refresh: statusMultiRegionCluster(ctx, conn, name), @@ -356,7 +356,7 @@ func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, func waitMultiRegionClusterDeleted(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { stateConf := &retry.StateChangeConf{ - Delay: 20 * time.Second, + Delay: 90 * time.Second, Pending: []string{clusterStatusDeleting}, Target: []string{}, Refresh: statusMultiRegionCluster(ctx, conn, name), From 7544b6def54be77725b4eb59b0f9f2ca0d69736e Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 00:01:44 +0100 Subject: [PATCH 42/69] memorydb: rewrite to plugin framework --- .ci/.semgrep-constants.yml | 36 -- internal/service/memorydb/exports_test.go | 2 +- .../service/memorydb/multi_region_cluster.go | 469 +++++++++++------- .../memorydb/multi_region_cluster_test.go | 237 ++++++--- .../service/memorydb/service_package_gen.go | 15 +- names/attr_constants.csv | 2 - names/attr_consts_gen.go | 2 - names/generate/const_or_quote_gen.go | 2 - ...emorydb_multi_region_cluster.html.markdown | 13 +- 9 files changed, 471 insertions(+), 307 deletions(-) diff --git a/.ci/.semgrep-constants.yml b/.ci/.semgrep-constants.yml index ef9b69018c7..5ef2012983a 100644 --- a/.ci/.semgrep-constants.yml +++ b/.ci/.semgrep-constants.yml @@ -2197,24 +2197,6 @@ rules: options: constant_propagation: false - - id: literal-name_suffix-string-constant - languages: [go] - message: Use the constant `names.AttrNameSuffix` for the string literal "name_suffix" - paths: - include: - - "internal/service/**/*.go" - patterns: - - pattern: '"name_suffix"' - - pattern-not-regex: '"name_suffix":\s+test\w+,' - - pattern-not-inside: 'config.Variables{ ... }' - - pattern-not-inside: 'packageName = ...' - - pattern-not-inside: 'provider.ConflictingEndpointsWarningDiag(...)' - - pattern-not-inside: 'const $X = ...' - severity: ERROR - fix: "names.AttrNameSuffix" - options: - constant_propagation: false - - id: literal-names-string-constant languages: [go] message: Use the constant `names.AttrNames` for the string literal "names" @@ -3583,24 +3565,6 @@ rules: options: constant_propagation: false - - id: literal-suffix-string-constant - languages: [go] - message: Use the constant `names.AttrSuffix` for the string literal "suffix" - paths: - include: - - "internal/service/**/*.go" - patterns: - - pattern: '"suffix"' - - pattern-not-regex: '"suffix":\s+test\w+,' - - pattern-not-inside: 'config.Variables{ ... }' - - pattern-not-inside: 'packageName = ...' - - pattern-not-inside: 'provider.ConflictingEndpointsWarningDiag(...)' - - pattern-not-inside: 'const $X = ...' - severity: ERROR - fix: "names.AttrSuffix" - options: - constant_propagation: false - - id: literal-table_name-string-constant languages: [go] message: Use the constant `names.AttrTableName` for the string literal "table_name" diff --git a/internal/service/memorydb/exports_test.go b/internal/service/memorydb/exports_test.go index 07ac2aa928b..aa7670cb211 100644 --- a/internal/service/memorydb/exports_test.go +++ b/internal/service/memorydb/exports_test.go @@ -7,7 +7,7 @@ package memorydb var ( ResourceACL = resourceACL ResourceCluster = resourceCluster - ResourceMultiRegionCluster = resourceMultiRegionCluster + ResourceMultiRegionCluster = newMultiRegionClusterResource ResourceParameterGroup = resourceParameterGroup ResourceSnapshot = resourceSnapshot ResourceSubnetGroup = resourceSubnetGroup diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 672961d6b7d..973c154a12c 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -6,275 +6,394 @@ package memorydb import ( "context" "errors" - "log" "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/memorydb" awstypes "github.com/aws/aws-sdk-go-v2/service/memorydb/types" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "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/booldefault" + "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/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" - "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" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs" - "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_memorydb_multi_region_cluster", name="MultiRegionCluster") +// @FrameworkResource("aws_memorydb_multi_region_cluster", name="Multi Region Cluster") // @Tags(identifierAttribute="arn") -func resourceMultiRegionCluster() *schema.Resource { - return &schema.Resource{ - CreateWithoutTimeout: resourceMultiRegionClusterCreate, - ReadWithoutTimeout: resourceMultiRegionClusterRead, - UpdateWithoutTimeout: resourceMultiRegionClusterUpdate, - DeleteWithoutTimeout: resourceMultiRegionClusterDelete, - - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, +func newMultiRegionClusterResource(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &multiRegionClusterResource{} - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(120 * time.Minute), - Update: schema.DefaultTimeout(120 * time.Minute), - Delete: schema.DefaultTimeout(120 * time.Minute), - }, + r.SetDefaultCreateTimeout(120 * time.Minute) + r.SetDefaultUpdateTimeout(120 * time.Minute) + r.SetDefaultDeleteTimeout(120 * time.Minute) + + return r, nil +} - CustomizeDiff: verify.SetTagsDiff, +const ( + ResNameMultiRegionCluster = "Multi Region Cluster" +) - SchemaFunc: func() map[string]*schema.Schema { - return map[string]*schema.Schema{ - names.AttrARN: { - Type: schema.TypeString, - Computed: true, +type multiRegionClusterResource struct { + framework.ResourceWithConfigure + framework.WithTimeouts +} + +func (*multiRegionClusterResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_memorydb_multi_region_cluster" +} + +func (r *multiRegionClusterResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrID: framework.IDAttribute(), + names.AttrARN: schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - names.AttrName: { - Type: schema.TypeString, - Computed: true, + }, + "multi_region_cluster_name": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - names.AttrDescription: { - Type: schema.TypeString, - Optional: true, - Default: "Managed by Terraform", + }, + names.AttrDescription: schema.StringAttribute{ + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - names.AttrEngine: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateDiagFunc: enum.Validate[clusterEngine](), + Default: stringdefault.StaticString("Managed by Terraform"), + }, + names.AttrEngine: schema.StringAttribute{ + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - names.AttrEngineVersion: { - Type: schema.TypeString, - Optional: true, - Computed: true, + Validators: []validator.String{ + enum.FrameworkValidate[clusterEngine](), }, - names.AttrNameSuffix: { - Type: schema.TypeString, - Required: true, + }, + names.AttrEngineVersion: schema.StringAttribute{ + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - names.AttrParameterGroupName: { - Type: schema.TypeString, - Optional: true, - Computed: true, + }, + "multi_region_cluster_name_suffix": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), }, - "node_type": { - Type: schema.TypeString, - Required: true, + }, + names.AttrStatus: schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "num_shards": { - Type: schema.TypeInt, - Optional: true, - Computed: true, + }, + "multi_region_parameter_group_name": schema.StringAttribute{ + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "update_strategy": { - Type: schema.TypeString, - Optional: true, - ValidateDiagFunc: enum.Validate[awstypes.UpdateStrategy](), + }, + "node_type": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), }, - names.AttrStatus: { - Type: schema.TypeString, - Optional: true, - Computed: true, + }, + "num_shards": schema.Int64Attribute{ + Computed: true, + Optional: true, + }, + "update_strategy": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "tls_enabled": { - Type: schema.TypeBool, - Optional: true, - Default: true, - ForceNew: true, + Validators: []validator.String{ + enum.FrameworkValidate[awstypes.UpdateStrategy](), }, - names.AttrTags: tftags.TagsSchema(), - names.AttrTagsAll: tftags.TagsSchemaComputed(), - } + }, + "tls_enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + Delete: true, + }), }, } } -func resourceMultiRegionClusterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) +func (r *multiRegionClusterResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + conn := r.Meta().MemoryDBClient(ctx) - input := &memorydb.CreateMultiRegionClusterInput{ - MultiRegionClusterNameSuffix: aws.String(d.Get(names.AttrNameSuffix).(string)), - NodeType: aws.String(d.Get("node_type").(string)), - TLSEnabled: aws.Bool(d.Get("tls_enabled").(bool)), - Tags: getTagsIn(ctx), + var plan multiRegionClusterResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return } - if v, ok := d.GetOk(names.AttrDescription); ok { - input.Description = aws.String(v.(string)) + var input memorydb.CreateMultiRegionClusterInput + resp.Diagnostics.Append(flex.Expand(ctx, plan, &input)...) + if resp.Diagnostics.HasError() { + return } + input.Tags = getTagsIn(ctx) - if v, ok := d.GetOk(names.AttrEngine); ok { - input.Engine = aws.String(v.(string)) - } - - if v, ok := d.GetOk(names.AttrEngineVersion); ok { - input.EngineVersion = aws.String(v.(string)) - } - - if v, ok := d.GetOk(names.AttrParameterGroupName); ok { - input.MultiRegionParameterGroupName = aws.String(v.(string)) + out, err := conn.CreateMultiRegionCluster(ctx, &input) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionCreating, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), + err.Error(), + ) + return } - - if v, ok := d.GetOk("num_shards"); ok { - input.NumShards = aws.Int32(int32(v.(int))) + if out == nil || out.MultiRegionCluster.ARN == nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionCreating, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), nil), + errors.New("empty output").Error(), + ) + return } - output, err := conn.CreateMultiRegionCluster(ctx, input) + plan.ID = flex.StringToFramework(ctx, out.MultiRegionCluster.MultiRegionClusterName) + plan.NumShards = flex.Int32ToFramework(ctx, out.MultiRegionCluster.NumberOfShards) + createTimeout := r.CreateTimeout(ctx, plan.Timeouts) + statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), createTimeout) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating MemoryDB Multi Region cluster: %s", err) + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForCreation, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), + err.Error(), + ) + return } - d.SetId(aws.ToString(output.MultiRegionCluster.MultiRegionClusterName)) - - if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region cluster (%s) create: %s", d.Id(), err) + resp.Diagnostics.Append(flex.Flatten(ctx, statusOut, &plan)...) + if resp.Diagnostics.HasError() { + return } - return append(diags, resourceMultiRegionClusterRead(ctx, d, meta)...) + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) } -func resourceMultiRegionClusterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) - - cluster, err := findMultiRegionClusterByName(ctx, conn, d.Id()) +func (r *multiRegionClusterResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + conn := r.Meta().MemoryDBClient(ctx) - if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] MemoryDB Multi Region cluster (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags + var state multiRegionClusterResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return } + out, err := findMultiRegionClusterByName(ctx, conn, state.ID.ValueString()) + if tfresource.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading MemoryDB Multi Region cluster (%s): %s", d.Id(), err) + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionSetting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), + err.Error(), + ) + return } - d.Set(names.AttrARN, cluster.ARN) - d.Set(names.AttrName, cluster.MultiRegionClusterName) - d.Set(names.AttrDescription, cluster.Description) - d.Set(names.AttrEngine, cluster.Engine) - d.Set(names.AttrEngineVersion, cluster.EngineVersion) - d.Set("node_type", cluster.NodeType) - d.Set("num_shards", cluster.NumberOfShards) - d.Set(names.AttrParameterGroupName, cluster.MultiRegionParameterGroupName) - d.Set("tls_enabled", cluster.TLSEnabled) - d.Set(names.AttrStatus, cluster.Status) - - // These attributes aren't returned by the API, so we retain the current value. - suffix, err := suffixAfterHyphen(*cluster.MultiRegionClusterName) + suffix, err := suffixAfterHyphen(*out.MultiRegionClusterName) if err != nil { - return sdkdiag.AppendErrorf(diags, "extracting suffix from Multi Region Cluster name: %s", err) + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionSetting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), + err.Error(), + ) + return + } + state.MultiRegionClusterNameSuffix = flex.StringToFramework(ctx, &suffix) + state.NumShards = flex.Int32ToFramework(ctx, out.NumberOfShards) + + resp.Diagnostics.Append(flex.Flatten(ctx, out, &state)...) + if resp.Diagnostics.HasError() { + return } - d.Set(names.AttrNameSuffix, suffix) - d.Set("update_strategy", d.Get("update_strategy")) - return diags + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } -func resourceMultiRegionClusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) +func (r *multiRegionClusterResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + conn := r.Meta().MemoryDBClient(ctx) - if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { - input := &memorydb.UpdateMultiRegionClusterInput{ - MultiRegionClusterName: aws.String(d.Id()), + var plan, state multiRegionClusterResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + if !plan.MultiRegionClusterName.Equal(state.MultiRegionClusterName) || + !plan.Description.Equal(state.Description) || + !plan.Engine.Equal(state.EngineVersion) || + !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) || + !plan.NodeType.Equal(state.NodeType) || + !plan.NumShards.Equal(state.NumShards) || + !plan.UpdateStrategy.Equal(state.UpdateStrategy) { + input := memorydb.UpdateMultiRegionClusterInput{ + MultiRegionClusterName: state.MultiRegionClusterName.ValueStringPointer(), } - if d.HasChange(names.AttrDescription) { - input.Description = aws.String(d.Get(names.AttrDescription).(string)) + if !plan.MultiRegionClusterName.Equal(state.MultiRegionClusterName) { + input.MultiRegionClusterName = plan.MultiRegionClusterName.ValueStringPointer() } - if d.HasChange(names.AttrEngineVersion) { - input.EngineVersion = aws.String(d.Get(names.AttrEngineVersion).(string)) + if !plan.Description.Equal(state.Description) { + input.Description = plan.Description.ValueStringPointer() } - if d.HasChange("num_shards") { - input.ShardConfiguration = &awstypes.ShardConfigurationRequest{ - ShardCount: int32(d.Get("num_shards").(int)), - } + if !plan.Engine.Equal(state.Engine) { + input.EngineVersion = plan.EngineVersion.ValueStringPointer() } - if d.HasChange("node_type") { - input.NodeType = aws.String(d.Get("node_type").(string)) + if !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) { + input.MultiRegionParameterGroupName = plan.MultiRegionParameterGroupName.ValueStringPointer() } - if d.HasChange("node_type") { - input.NodeType = aws.String(d.Get("node_type").(string)) + if !plan.NodeType.Equal(state.NodeType) { + input.NodeType = plan.NodeType.ValueStringPointer() } - if d.HasChange(names.AttrParameterGroupName) { - input.MultiRegionParameterGroupName = aws.String(d.Get(names.AttrParameterGroupName).(string)) + if !plan.NumShards.Equal(state.NumShards) { + input.ShardConfiguration = &awstypes.ShardConfigurationRequest{ + ShardCount: int32(*plan.NumShards.ValueInt64Pointer()), + } } - if d.HasChange("update_strategy") { - input.UpdateStrategy = awstypes.UpdateStrategy(d.Get("update_strategy").(string)) + if !plan.UpdateStrategy.Equal(state.UpdateStrategy) { + input.UpdateStrategy = awstypes.UpdateStrategy(plan.UpdateStrategy.ValueString()) } - _, err := conn.UpdateMultiRegionCluster(ctx, input) + resp.Diagnostics.Append(flex.Expand(ctx, plan, &input)...) + if resp.Diagnostics.HasError() { + return + } + _, err := conn.UpdateMultiRegionCluster(ctx, &input) if err != nil { - return sdkdiag.AppendErrorf(diags, "updating MemoryDB Multi Region Cluster (%s): %s", d.Id(), err) + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionUpdating, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), + err.Error(), + ) + return } + } - if _, err := waitMultiRegionClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region Cluster (%s) update: %s", d.Id(), err) - } + updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) + statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), updateTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForUpdate, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), + err.Error(), + ) + return } - return append(diags, resourceMultiRegionClusterRead(ctx, d, meta)...) + resp.Diagnostics.Append(flex.Flatten(ctx, statusOut, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } -func resourceMultiRegionClusterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).MemoryDBClient(ctx) +func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().MemoryDBClient(ctx) - input := &memorydb.DeleteMultiRegionClusterInput{ - MultiRegionClusterName: aws.String(d.Id()), + var state multiRegionClusterResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return } - log.Printf("[DEBUG] Deleting MemoryDB Multi Region Cluster: (%s)", d.Id()) - _, err := conn.DeleteMultiRegionCluster(ctx, input) - - if errs.IsA[*awstypes.MultiRegionClusterNotFoundFault](err) { - return diags + input := memorydb.DeleteMultiRegionClusterInput{ + MultiRegionClusterName: state.MultiRegionClusterName.ValueStringPointer(), } + _, err := conn.DeleteMultiRegionCluster(ctx, &input) if err != nil { - return sdkdiag.AppendErrorf(diags, "deleting MemoryDB Multi Region Cluster (%s): %s", d.Id(), err) + if errs.IsA[*awstypes.MultiRegionClusterNotFoundFault](err) { + return + } + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), + err.Error(), + ) + return } - if _, err := waitMultiRegionClusterDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi Region Cluster (%s) delete: %s", d.Id(), err) + deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) + _, err = waitMultiRegionClusterDeleted(ctx, conn, state.ID.ValueString(), deleteTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForDeletion, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), + err.Error(), + ) + return } +} + +func (r *multiRegionClusterResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), request, response) +} + +func (r *multiRegionClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + r.SetTagsAll(ctx, req, resp) +} - return diags +type multiRegionClusterResourceModel struct { + ID types.String `tfsdk:"id"` + ARN types.String `tfsdk:"arn"` + MultiRegionClusterName types.String `tfsdk:"multi_region_cluster_name"` + MultiRegionClusterNameSuffix types.String `tfsdk:"multi_region_cluster_name_suffix"` + Description types.String `tfsdk:"description"` + Engine types.String `tfsdk:"engine"` + EngineVersion types.String `tfsdk:"engine_version"` + MultiRegionParameterGroupName types.String `tfsdk:"multi_region_parameter_group_name"` + NodeType types.String `tfsdk:"node_type"` + NumShards types.Int64 `tfsdk:"num_shards"` + UpdateStrategy types.String `tfsdk:"update_strategy"` + Status types.String `tfsdk:"status"` + TLSEnabled types.Bool `tfsdk:"tls_enabled"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` } func findMultiRegionClusterByName(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { @@ -338,7 +457,7 @@ func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name s func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ - Delay: 90 * time.Second, + Delay: 20 * time.Second, Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, Target: []string{clusterStatusAvailable}, Refresh: statusMultiRegionCluster(ctx, conn, name), @@ -356,7 +475,7 @@ func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, func waitMultiRegionClusterDeleted(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { stateConf := &retry.StateChangeConf{ - Delay: 90 * time.Second, + Delay: 20 * time.Second, Pending: []string{clusterStatusDeleting}, Target: []string{}, Refresh: statusMultiRegionCluster(ctx, conn, name), diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 3b2f6ac4059..688559585df 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -33,14 +33,15 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { Config: testAccMultiRegionClusterConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), - resource.TestCheckResourceAttrSet(resourceName, names.AttrName), - resource.TestCheckResourceAttrSet(resourceName, names.AttrNameSuffix), + resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name"), + resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name_suffix"), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), - resource.TestCheckResourceAttrSet(resourceName, names.AttrParameterGroupName), + resource.TestCheckResourceAttrSet(resourceName, "multi_region_parameter_group_name"), resource.TestCheckResourceAttrSet(resourceName, "num_shards"), resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), resource.TestCheckResourceAttr(resourceName, "clusters.#", "0"), @@ -50,9 +51,10 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, }, }, }) @@ -73,14 +75,15 @@ func TestAccMemoryDBMultiRegionCluster_defaults(t *testing.T) { Config: testAccMultiRegionClusterConfig_defaults(rName), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), - resource.TestCheckResourceAttrSet(resourceName, names.AttrName), - resource.TestCheckResourceAttrSet(resourceName, names.AttrNameSuffix), + resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name"), + resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name_suffix"), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), - resource.TestCheckResourceAttrSet(resourceName, names.AttrParameterGroupName), + resource.TestCheckResourceAttrSet(resourceName, "multi_region_parameter_group_name"), resource.TestCheckResourceAttr(resourceName, "num_shards", "1"), resource.TestCheckResourceAttr(resourceName, "clusters.#", "0"), resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtTrue), @@ -89,9 +92,10 @@ func TestAccMemoryDBMultiRegionCluster_defaults(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, }, }, }) @@ -109,16 +113,26 @@ func TestAccMemoryDBMultiRegionCluster_description(t *testing.T) { CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccMultiRegionClusterConfig_description(rName), + Config: testAccMultiRegionClusterConfig_description(rName, 1), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Also managed by Terraform"), + resource.TestCheckResourceAttr(resourceName, "num_shards", "1"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + }, + { + Config: testAccMultiRegionClusterConfig_description(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Also managed by Terraform, but now with an updated description"), + resource.TestCheckResourceAttr(resourceName, "num_shards", "2"), + ), }, }, }) @@ -143,9 +157,10 @@ func TestAccMemoryDBMultiRegionCluster_tlsEnabled(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, }, }, }) @@ -171,9 +186,10 @@ func TestAccMemoryDBMultiRegionCluster_engine(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, }, }, }) @@ -199,9 +215,89 @@ func TestAccMemoryDBMultiRegionCluster_engineVersion(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_updateStrategy(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "num_shards", "1"), + ), + }, + { + Config: testAccMultiRegionClusterConfig_updateStrategy(rName, "coordinated", 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "update_strategy", "coordinated"), + resource.TestCheckResourceAttr(resourceName, "num_shards", "2"), + ), + }, + { + Config: testAccMultiRegionClusterConfig_updateStrategy(rName, "uncoordinated", 3), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "update_strategy", "uncoordinated"), + resource.TestCheckResourceAttr(resourceName, "num_shards", "3"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll, "update_strategy"}, + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_numShards(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_numShards(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "num_shards", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + }, + { + Config: testAccMultiRegionClusterConfig_numShards(rName, 3), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "num_shards", "3"), + ), }, }, }) @@ -227,9 +323,10 @@ func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, }, { Config: testAccMultiRegionClusterConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), @@ -265,7 +362,7 @@ func testAccCheckMultiRegionClusterExists(ctx context.Context, n string) resourc conn := acctest.Provider.Meta().(*conns.AWSClient).MemoryDBClient(ctx) - _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes[names.AttrName]) + _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes["multi_region_cluster_name"]) return err } @@ -280,7 +377,7 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe continue } - _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes[names.AttrName]) + _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes["multi_region_cluster_name"]) if tfresource.NotFound(err) { continue @@ -300,7 +397,7 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" tags = { @@ -313,19 +410,22 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_defaults(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" } `, rName) } -func testAccMultiRegionClusterConfig_description(rName string) string { +// Sets `num_shards` to also test an update of the resource +func testAccMultiRegionClusterConfig_description(rName string, numShards int) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" description = "Also managed by Terraform" + num_shards = %[2]d + tags = { Test = "test" } @@ -333,10 +433,26 @@ resource "aws_memorydb_multi_region_cluster" "test" { `, rName) } +func testAccMultiRegionClusterConfig_numShards(rName string, numShards int) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + multi_region_cluster_name_suffix = %[1]q + node_type = "db.r7g.xlarge" + description = "Also managed by Terraform" + + num_shards = %[2]d + + tags = { + Test = "test" + } +} +`, rName, numShards) +} + func testAccMultiRegionClusterConfig_tlsEnabled(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" tls_enabled = false @@ -350,7 +466,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_engine(rName, engine string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" engine = %[2]q @@ -364,7 +480,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_engineVersion(rName, engine, engineVersion string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" engine = %[2]q engine_version = %[3]q @@ -376,54 +492,27 @@ resource "aws_memorydb_multi_region_cluster" "test" { `, rName, engine, engineVersion) } -func testAccMultiRegionClusterConfig_clusters(rName string) string { - return acctest.ConfigCompose( - testAccClusterConfig_baseNetwork(rName), - testAccClusterConfig_baseUserAndACL(rName), - fmt.Sprintf(` -resource "aws_security_group" "test" { - name = %[1]q - vpc_id = aws_vpc.test.id - - tags = { - Name = %[1]q - } -} - -resource "aws_memorydb_cluster" "test" { - acl_name = aws_memorydb_acl.test.id - auto_minor_version_upgrade = false - name = %[1]q - node_type = "db.r7g.xlarge" - num_shards = 2 - security_group_ids = [aws_security_group.test.id] - snapshot_retention_limit = 7 - subnet_group_name = aws_memorydb_subnet_group.test.id - - multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.name - - tags = { - Test = "test" - } -} - +// Sets `num_shards` to update the resource +func testAccMultiRegionClusterConfig_updateStrategy(rName, updateStrategy string, numShards int) string { + return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" - num_shards = 2 + + update_strategy = %[2]q + num_shards = %[3]d tags = { Test = "test" } } -`, rName), - ) +`, rName, updateStrategy, numShards) } func testAccMultiRegionClusterConfig_tags1(rName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" tags = { @@ -436,7 +525,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q + multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" tags = { diff --git a/internal/service/memorydb/service_package_gen.go b/internal/service/memorydb/service_package_gen.go index f992d69eb4a..c476539fe70 100644 --- a/internal/service/memorydb/service_package_gen.go +++ b/internal/service/memorydb/service_package_gen.go @@ -19,7 +19,12 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv } func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { - return []*types.ServicePackageFrameworkResource{} + return []*types.ServicePackageFrameworkResource{ + { + Factory: newMultiRegionClusterResource, + Name: "Multi Region Cluster", + }, + } } func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePackageSDKDataSource { @@ -93,14 +98,6 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: names.AttrARN, }, }, - { - Factory: resourceMultiRegionCluster, - TypeName: "aws_memorydb_multi_region_cluster", - Name: "MultiRegionCluster", - Tags: &types.ServicePackageResourceTags{ - IdentifierAttribute: names.AttrARN, - }, - }, { Factory: resourceParameterGroup, TypeName: "aws_memorydb_parameter_group", diff --git a/names/attr_constants.csv b/names/attr_constants.csv index 0beaf7a8c19..292ca28a602 100644 --- a/names/attr_constants.csv +++ b/names/attr_constants.csv @@ -120,7 +120,6 @@ mode,Mode most_recent,MostRecent name,Name name_prefix,NamePrefix -name_suffix,NameSuffix names,Names namespace,Namespace network_configuration,NetworkConfiguration @@ -197,7 +196,6 @@ stream_arn,StreamARN subnet_id,SubnetID subnet_ids,SubnetIDs subnets,Subnets -suffix,Suffix table_name,TableName tags,Tags tags_all,TagsAll diff --git a/names/attr_consts_gen.go b/names/attr_consts_gen.go index 4f7a060f6ce..783e418eb0f 100644 --- a/names/attr_consts_gen.go +++ b/names/attr_consts_gen.go @@ -127,7 +127,6 @@ const ( AttrMostRecent = "most_recent" AttrName = "name" AttrNamePrefix = "name_prefix" - AttrNameSuffix = "name_suffix" AttrNames = "names" AttrNamespace = "namespace" AttrNetworkConfiguration = "network_configuration" @@ -204,7 +203,6 @@ const ( AttrSubnetID = "subnet_id" AttrSubnetIDs = "subnet_ids" AttrSubnets = "subnets" - AttrSuffix = "suffix" AttrTableName = "table_name" AttrTags = "tags" AttrTagsAll = "tags_all" diff --git a/names/generate/const_or_quote_gen.go b/names/generate/const_or_quote_gen.go index bd7f0712183..81bf94ad764 100644 --- a/names/generate/const_or_quote_gen.go +++ b/names/generate/const_or_quote_gen.go @@ -135,7 +135,6 @@ func ConstOrQuote(constant string) string { "most_recent": "AttrMostRecent", "name": "AttrName", "name_prefix": "AttrNamePrefix", - "name_suffix": "AttrNameSuffix", "names": "AttrNames", "namespace": "AttrNamespace", "network_configuration": "AttrNetworkConfiguration", @@ -212,7 +211,6 @@ func ConstOrQuote(constant string) string { "subnet_id": "AttrSubnetID", "subnet_ids": "AttrSubnetIDs", "subnets": "AttrSubnets", - "suffix": "AttrSuffix", "table_name": "AttrTableName", "tags": "AttrTags", "tags_all": "AttrTagsAll", diff --git a/website/docs/r/memorydb_multi_region_cluster.html.markdown b/website/docs/r/memorydb_multi_region_cluster.html.markdown index bb854512cc8..ee8e9ccf5d3 100644 --- a/website/docs/r/memorydb_multi_region_cluster.html.markdown +++ b/website/docs/r/memorydb_multi_region_cluster.html.markdown @@ -16,8 +16,8 @@ More information about MemoryDB can be found in the [Developer Guide](https://do ```terraform resource "aws_memorydb_multi_region_cluster" "example" { - suffix = "example" - node_type = "db.r7g.xlarge" + multi_region_cluster_name_suffix = "example" + node_type = "db.r7g.xlarge" } resource "aws_memorydb_cluster" "example" { @@ -30,7 +30,7 @@ resource "aws_memorydb_cluster" "example" { snapshot_retention_limit = 7 subnet_group_name = aws_memorydb_subnet_group.example.id - multi_region_cluster_name = aws_memorydb_multi_region_cluster.example.name + multi_region_cluster_name = aws_memorydb_multi_region_cluster.example.multi_region_cluster_name } ``` @@ -38,7 +38,7 @@ resource "aws_memorydb_cluster" "example" { The following arguments are required: -* `name_suffix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. +* `multi_region_cluster_name_suffix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. * `node_type` - (Required) The node type to be used for the multi-Region cluster. The following arguments are optional: @@ -47,7 +47,7 @@ The following arguments are optional: * `engine` - (Optional) The name of the engine to be used for the multi-Region cluster. Supported values are `redis` and `valkey`. * `engine_version` - (Optional) The version of the engine to be used for the multi-Region cluster. Downgrades are not supported. * `num_shards` - (Optional) The number of shards for the multi-Region cluster. -* `parameter_group_name` - (Optional) The name of the multi-Region parameter group to be associated with the cluster. +* `multi_region_parameter_group_name` - (Optional) The name of the multi-Region parameter group to be associated with the cluster. * `tls_enabled` - (Optional, Forces new resource) A flag to enable in-transit encryption on the cluster. Defaults to `true`. * `tags` - (Optional) A map of tags to assign to the resource. 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. @@ -55,7 +55,8 @@ The following arguments are optional: This resource exports the following attributes in addition to the arguments above: -* `id` - The name of the multi-region cluster.. +* `id` - The ID of the multi-region cluster. +* `multi_region_cluster_name` - The name of the multi-region cluster. * `arn` - The ARN of the multi-region cluster. * `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). From e4b7b1ee5fe06cf7fa2a2a41662a0ff5123e20de Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 02:19:30 +0100 Subject: [PATCH 43/69] memorydb: fix missing argument --- internal/service/memorydb/multi_region_cluster_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 688559585df..a7f7647dda5 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -430,7 +430,7 @@ resource "aws_memorydb_multi_region_cluster" "test" { Test = "test" } } -`, rName) +`, rName, numShards) } func testAccMultiRegionClusterConfig_numShards(rName string, numShards int) string { From 0c174eb6448280bb546911130fe5d6998aa8bc2c Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 02:37:36 +0100 Subject: [PATCH 44/69] memorydb: remove redundant update arguments --- internal/service/memorydb/multi_region_cluster.go | 8 ++------ .../service/memorydb/multi_region_cluster_test.go | 12 ++++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 973c154a12c..a301d9cf2e7 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -259,13 +259,9 @@ func (r *multiRegionClusterResource) Update(ctx context.Context, req resource.Up return } - if !plan.MultiRegionClusterName.Equal(state.MultiRegionClusterName) || - !plan.Description.Equal(state.Description) || - !plan.Engine.Equal(state.EngineVersion) || - !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) || + if !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) || !plan.NodeType.Equal(state.NodeType) || - !plan.NumShards.Equal(state.NumShards) || - !plan.UpdateStrategy.Equal(state.UpdateStrategy) { + !plan.NumShards.Equal(state.NumShards) { input := memorydb.UpdateMultiRegionClusterInput{ MultiRegionClusterName: state.MultiRegionClusterName.ValueStringPointer(), } diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index a7f7647dda5..22371c845cc 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -113,7 +113,7 @@ func TestAccMemoryDBMultiRegionCluster_description(t *testing.T) { CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccMultiRegionClusterConfig_description(rName, 1), + Config: testAccMultiRegionClusterConfig_description(rName, "Also managed by Terraform", 1), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Also managed by Terraform"), @@ -127,7 +127,7 @@ func TestAccMemoryDBMultiRegionCluster_description(t *testing.T) { ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, }, { - Config: testAccMultiRegionClusterConfig_description(rName, 2), + Config: testAccMultiRegionClusterConfig_description(rName, "Also managed by Terraform, but now with an updated description", 2), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Also managed by Terraform, but now with an updated description"), @@ -417,20 +417,20 @@ resource "aws_memorydb_multi_region_cluster" "test" { } // Sets `num_shards` to also test an update of the resource -func testAccMultiRegionClusterConfig_description(rName string, numShards int) string { +func testAccMultiRegionClusterConfig_description(rName, description string, numShards int) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" - description = "Also managed by Terraform" + description = %[2]q - num_shards = %[2]d + num_shards = %[3]d tags = { Test = "test" } } -`, rName, numShards) +`, rName, description, numShards) } func testAccMultiRegionClusterConfig_numShards(rName string, numShards int) string { From 0967fd9e394dc732970788e6933d1f61d2040fac Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Fri, 13 Dec 2024 17:53:53 +0100 Subject: [PATCH 45/69] memorydb: make gen --- internal/service/memorydb/multi_region_cluster.go | 4 ++++ internal/service/memorydb/multi_region_cluster_test.go | 7 +++---- internal/service/memorydb/service_package_gen.go | 3 +++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index a301d9cf2e7..294600fe5e2 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "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" @@ -127,6 +128,9 @@ func (r *multiRegionClusterResource) Schema(ctx context.Context, request resourc "num_shards": schema.Int64Attribute{ Computed: true, Optional: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, }, "update_strategy": schema.StringAttribute{ Optional: true, diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 22371c845cc..1d1efd374d3 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -323,10 +323,9 @@ func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccMultiRegionClusterConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), diff --git a/internal/service/memorydb/service_package_gen.go b/internal/service/memorydb/service_package_gen.go index c476539fe70..013bde84e80 100644 --- a/internal/service/memorydb/service_package_gen.go +++ b/internal/service/memorydb/service_package_gen.go @@ -23,6 +23,9 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic { Factory: newMultiRegionClusterResource, Name: "Multi Region Cluster", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }, }, } } From 499b33b04fd987ce8b4ad45fc629616cc29b8d7e Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 16 Dec 2024 09:38:58 +0100 Subject: [PATCH 46/69] memorydb: address feedback from @jar-b --- .../service/memorydb/multi_region_cluster.go | 38 ++--- .../memorydb/multi_region_cluster_test.go | 157 +++++++++++++----- 2 files changed, 128 insertions(+), 67 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 294600fe5e2..297a7722de0 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -270,18 +270,6 @@ func (r *multiRegionClusterResource) Update(ctx context.Context, req resource.Up MultiRegionClusterName: state.MultiRegionClusterName.ValueStringPointer(), } - if !plan.MultiRegionClusterName.Equal(state.MultiRegionClusterName) { - input.MultiRegionClusterName = plan.MultiRegionClusterName.ValueStringPointer() - } - - if !plan.Description.Equal(state.Description) { - input.Description = plan.Description.ValueStringPointer() - } - - if !plan.Engine.Equal(state.Engine) { - input.EngineVersion = plan.EngineVersion.ValueStringPointer() - } - if !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) { input.MultiRegionParameterGroupName = plan.MultiRegionParameterGroupName.ValueStringPointer() } @@ -313,21 +301,21 @@ func (r *multiRegionClusterResource) Update(ctx context.Context, req resource.Up ) return } - } - updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) - statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), updateTimeout) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForUpdate, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), - err.Error(), - ) - return - } + updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) + statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), updateTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForUpdate, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), + err.Error(), + ) + return + } - resp.Diagnostics.Append(flex.Flatten(ctx, statusOut, &plan)...) - if resp.Diagnostics.HasError() { - return + resp.Diagnostics.Append(flex.Flatten(ctx, statusOut, &plan)...) + if resp.Diagnostics.HasError() { + return + } } resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 1d1efd374d3..5d28362d1bd 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -51,10 +51,9 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -92,10 +91,9 @@ func TestAccMemoryDBMultiRegionCluster_defaults(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -113,26 +111,16 @@ func TestAccMemoryDBMultiRegionCluster_description(t *testing.T) { CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccMultiRegionClusterConfig_description(rName, "Also managed by Terraform", 1), + Config: testAccMultiRegionClusterConfig_description(rName, "Also managed by Terraform"), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Also managed by Terraform"), - resource.TestCheckResourceAttr(resourceName, "num_shards", "1"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, - }, - { - Config: testAccMultiRegionClusterConfig_description(rName, "Also managed by Terraform, but now with an updated description", 2), - Check: resource.ComposeTestCheckFunc( - testAccCheckMultiRegionClusterExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Also managed by Terraform, but now with an updated description"), - resource.TestCheckResourceAttr(resourceName, "num_shards", "2"), - ), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -157,10 +145,9 @@ func TestAccMemoryDBMultiRegionCluster_tlsEnabled(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -186,10 +173,9 @@ func TestAccMemoryDBMultiRegionCluster_engine(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -215,10 +201,9 @@ func TestAccMemoryDBMultiRegionCluster_engineVersion(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -287,10 +272,9 @@ func TestAccMemoryDBMultiRegionCluster_numShards(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, { Config: testAccMultiRegionClusterConfig_numShards(rName, 3), @@ -303,6 +287,67 @@ func TestAccMemoryDBMultiRegionCluster_numShards(t *testing.T) { }) } +func TestAccMemoryDBMultiRegionCluster_nodeType(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_nodeType(rName, "db.r7g.xlarge"), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccMultiRegionClusterConfig_nodeType(rName, "db.r7g.2xlarge"), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.2xlarge"), + ), + }, + }, + }) +} + +func TestAccMemoryDBMultiRegionCluster_parameterGroup(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_parameterGroup(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "multi_region_parameter_group_name", "default.memorydb-valkey7.multiregion"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -416,20 +461,18 @@ resource "aws_memorydb_multi_region_cluster" "test" { } // Sets `num_shards` to also test an update of the resource -func testAccMultiRegionClusterConfig_description(rName, description string, numShards int) string { +func testAccMultiRegionClusterConfig_description(rName, description string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" description = %[2]q - num_shards = %[3]d - tags = { Test = "test" } } -`, rName, description, numShards) +`, rName, description) } func testAccMultiRegionClusterConfig_numShards(rName string, numShards int) string { @@ -448,6 +491,36 @@ resource "aws_memorydb_multi_region_cluster" "test" { `, rName, numShards) } +func testAccMultiRegionClusterConfig_nodeType(rName string, nodeType string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + multi_region_cluster_name_suffix = %[1]q + node_type = %[2]q + description = "Also managed by Terraform" + + tags = { + Test = "test" + } +} +`, rName, nodeType) +} + +func testAccMultiRegionClusterConfig_parameterGroup(rName string) string { + return fmt.Sprintf(` +resource "aws_memorydb_multi_region_cluster" "test" { + multi_region_cluster_name_suffix = %[1]q + node_type = "db.r7g.xlarge" + description = "Also managed by Terraform" + + multi_region_parameter_group_name = "default.memorydb-valkey7.multiregion" + + tags = { + Test = "test" + } +} +`, rName) +} + func testAccMultiRegionClusterConfig_tlsEnabled(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { From d70701a08f2df1dc208328184291d4bdcd764f85 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 16 Dec 2024 09:40:27 +0100 Subject: [PATCH 47/69] memorydb: fmt acceptance tests --- .../memorydb/multi_region_cluster_test.go | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 5d28362d1bd..bb6b68144c5 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -442,7 +442,7 @@ func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" + node_type = "db.r7g.xlarge" tags = { Test = "test" @@ -455,7 +455,7 @@ func testAccMultiRegionClusterConfig_defaults(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" + node_type = "db.r7g.xlarge" } `, rName) } @@ -465,8 +465,8 @@ func testAccMultiRegionClusterConfig_description(rName, description string) stri return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - description = %[2]q + node_type = "db.r7g.xlarge" + description = %[2]q tags = { Test = "test" @@ -479,8 +479,8 @@ func testAccMultiRegionClusterConfig_numShards(rName string, numShards int) stri return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - description = "Also managed by Terraform" + node_type = "db.r7g.xlarge" + description = "Also managed by Terraform" num_shards = %[2]d @@ -495,8 +495,8 @@ func testAccMultiRegionClusterConfig_nodeType(rName string, nodeType string) str return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = %[2]q - description = "Also managed by Terraform" + node_type = %[2]q + description = "Also managed by Terraform" tags = { Test = "test" @@ -509,8 +509,8 @@ func testAccMultiRegionClusterConfig_parameterGroup(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - description = "Also managed by Terraform" + node_type = "db.r7g.xlarge" + description = "Also managed by Terraform" multi_region_parameter_group_name = "default.memorydb-valkey7.multiregion" @@ -525,8 +525,8 @@ func testAccMultiRegionClusterConfig_tlsEnabled(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - tls_enabled = false + node_type = "db.r7g.xlarge" + tls_enabled = false tags = { Test = "test" @@ -539,8 +539,8 @@ func testAccMultiRegionClusterConfig_engine(rName, engine string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - engine = %[2]q + node_type = "db.r7g.xlarge" + engine = %[2]q tags = { Test = "test" @@ -552,10 +552,10 @@ resource "aws_memorydb_multi_region_cluster" "test" { func testAccMultiRegionClusterConfig_engineVersion(rName, engine, engineVersion string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { - multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - engine = %[2]q - engine_version = %[3]q + multi_region_cluster_name_suffix = %[1]q + node_type = "db.r7g.xlarge" + engine = %[2]q + engine_version = %[3]q tags = { Test = "test" @@ -569,10 +569,10 @@ func testAccMultiRegionClusterConfig_updateStrategy(rName, updateStrategy string return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - + node_type = "db.r7g.xlarge" + update_strategy = %[2]q - num_shards = %[3]d + num_shards = %[3]d tags = { Test = "test" @@ -585,7 +585,7 @@ func testAccMultiRegionClusterConfig_tags1(rName, tag1Key, tag1Value string) str return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" + node_type = "db.r7g.xlarge" tags = { %[2]q = %[3]q @@ -598,7 +598,7 @@ func testAccMultiRegionClusterConfig_tags2(rName, tag1Key, tag1Value, tag2Key, t return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" + node_type = "db.r7g.xlarge" tags = { %[2]q = %[3]q From c1f19a0f2b5d31d81d35f578dca2185323fb6e5f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 16 Dec 2024 13:24:53 +0100 Subject: [PATCH 48/69] memorydb: fmt cluster tests --- internal/service/memorydb/cluster_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/memorydb/cluster_test.go b/internal/service/memorydb/cluster_test.go index 4012e531c7f..587fad56044 100644 --- a/internal/service/memorydb/cluster_test.go +++ b/internal/service/memorydb/cluster_test.go @@ -1413,9 +1413,9 @@ resource "aws_security_group" "test" { } resource "aws_memorydb_multi_region_cluster" "test" { - name_suffix = %[1]q - node_type = "db.r7g.xlarge" - num_shards = 2 + multi_region_cluster_name_suffix = %[1]q + node_type = "db.r7g.xlarge" + num_shards = 2 tags = { Test = "test" @@ -1432,7 +1432,7 @@ resource "aws_memorydb_cluster" "test" { snapshot_retention_limit = 7 subnet_group_name = aws_memorydb_subnet_group.test.id - multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.name + multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.multi_region_cluster_name tags = { Test = "test" From 278ab74ae0c2201cf32843bc39ddfd05d5ee949a Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 16 Dec 2024 13:25:43 +0100 Subject: [PATCH 49/69] memorydb: before deleting the multi-region cluster, ensure it is ready for deletion If a multi-region cluster name is set, ensure the `aws_memorydb_multi_region_cluster` is created and available before proceeding with cluster creation. Otherwise, the cluster creation will fail. --- internal/service/memorydb/cluster.go | 11 +++++++---- internal/service/memorydb/multi_region_cluster.go | 14 +++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/internal/service/memorydb/cluster.go b/internal/service/memorydb/cluster.go index 80552faadf4..f3a35c84e5e 100644 --- a/internal/service/memorydb/cluster.go +++ b/internal/service/memorydb/cluster.go @@ -377,16 +377,19 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int d.SetId(name) - if _, err := waitClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Cluster (%s) create: %s", d.Id(), err) - } - + // If a multi-region cluster name is set, ensure the `aws_memorydb_multi_region_cluster` + // is created and available before proceeding with cluster creation. + // Otherwise, the cluster creation will fail. if v, ok := d.GetOk("multi_region_cluster_name"); ok { if _, err := waitMultiRegionClusterAvailable(ctx, conn, v.(string), d.Timeout(schema.TimeoutCreate)); err != nil { return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Multi-Region Cluster (%s) create: %s", v.(string), err) } } + if _, err := waitClusterAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for MemoryDB Cluster (%s) create: %s", d.Id(), err) + } + return append(diags, resourceClusterRead(ctx, d, meta)...) } diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 297a7722de0..fbb8798be53 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -330,11 +330,23 @@ func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.De return } + // Before deleting the multi-region cluster, ensure it is ready for deletion. + // Removing an `aws_memorydb_cluster` from a multi-region cluster may temporarily block deletion. + createTimeout := r.CreateTimeout(ctx, state.Timeouts) + _, err := waitMultiRegionClusterAvailable(ctx, conn, state.ID.ValueString(), createTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForCreation, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), + err.Error(), + ) + return + } + input := memorydb.DeleteMultiRegionClusterInput{ MultiRegionClusterName: state.MultiRegionClusterName.ValueStringPointer(), } - _, err := conn.DeleteMultiRegionCluster(ctx, &input) + _, err = conn.DeleteMultiRegionCluster(ctx, &input) if err != nil { if errs.IsA[*awstypes.MultiRegionClusterNotFoundFault](err) { return From 867020afe0d2297660cd6cb663cfa562873308b3 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 16 Dec 2024 14:10:45 +0100 Subject: [PATCH 50/69] memorydb: add `aws_memorydb_multi_region_cluster` argument --- website/docs/r/memorydb_cluster.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/r/memorydb_cluster.html.markdown b/website/docs/r/memorydb_cluster.html.markdown index ee5e2186084..755446d10f2 100644 --- a/website/docs/r/memorydb_cluster.html.markdown +++ b/website/docs/r/memorydb_cluster.html.markdown @@ -48,7 +48,8 @@ The following arguments are optional: * `name` - (Optional, Forces new resource) Name of the cluster. If omitted, Terraform will assign a random, unique name. Conflicts with `name_prefix`. * `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. * `num_replicas_per_shard` - (Optional) The number of replicas to apply to each shard, up to a maximum of 5. Defaults to `1` (i.e. 2 nodes per shard). -* `num_shards` - (Optional) The number of shards in the cluster. Defaults to `1`. +* `num_shards` - (Optional) The number of shards in the cluster. Defaults to `1`.' +* `multi_region_cluster_name` - (Optional) The multi region cluster identifier specified on `aws_memorydb_multi_region_cluster`. * `parameter_group_name` - (Optional) The name of the parameter group associated with the cluster. * `port` - (Optional, Forces new resource) The port number on which each of the nodes accepts connections. Defaults to `6379`. * `security_group_ids` - (Optional) Set of VPC Security Group ID-s to associate with this cluster. From ace47249847586293b00e6d1825211fbb26fa708 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 16 Dec 2024 16:14:34 +0100 Subject: [PATCH 51/69] memorydb: add continuous target occurence checking in waiters The MemoryDB API appears to be somewhat inconsistent, performing additional upgrades after create/delete actions, even after reporting an "available" status and successfully passing the waiter. --- .../service/memorydb/multi_region_cluster.go | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index fbb8798be53..e6716d63d6c 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -457,11 +457,12 @@ func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name s func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ - Delay: 20 * time.Second, - Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, - Target: []string{clusterStatusAvailable}, - Refresh: statusMultiRegionCluster(ctx, conn, name), - Timeout: timeout, + Delay: 20 * time.Second, + Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, + Target: []string{clusterStatusAvailable}, + Refresh: statusMultiRegionCluster(ctx, conn, name), + ContinuousTargetOccurence: 3, + Timeout: timeout, } outputRaw, err := stateConf.WaitForStateContext(ctx) @@ -475,11 +476,12 @@ func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, func waitMultiRegionClusterDeleted(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { stateConf := &retry.StateChangeConf{ - Delay: 20 * time.Second, - Pending: []string{clusterStatusDeleting}, - Target: []string{}, - Refresh: statusMultiRegionCluster(ctx, conn, name), - Timeout: timeout, + Delay: 20 * time.Second, + Pending: []string{clusterStatusDeleting}, + Target: []string{}, + Refresh: statusMultiRegionCluster(ctx, conn, name), + ContinuousTargetOccurence: 3, + Timeout: timeout, } outputRaw, err := stateConf.WaitForStateContext(ctx) From 1e6d9c1e3d807e8fffd05210c6bf6037814ad1bd Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 14:20:50 -0500 Subject: [PATCH 52/69] chore: fix golangci-lint finding --- internal/service/memorydb/multi_region_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index e6716d63d6c..d410236d846 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -455,7 +455,7 @@ func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name s } } -func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { //nolint:unparam +func waitMultiRegionClusterAvailable(ctx context.Context, conn *memorydb.Client, name string, timeout time.Duration) (*awstypes.MultiRegionCluster, error) { stateConf := &retry.StateChangeConf{ Delay: 20 * time.Second, Pending: []string{clusterStatusCreating, clusterStatusUpdating, clusterStatusSnapshotting}, From ef6e370ee5892d0b420586dfac05eeae71b00970 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 14:27:34 -0500 Subject: [PATCH 53/69] r/aws_memorydb_multi_region_cluster: prevent nil pointer deref --- internal/service/memorydb/multi_region_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index d410236d846..a908b331b38 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -183,7 +183,7 @@ func (r *multiRegionClusterResource) Create(ctx context.Context, req resource.Cr ) return } - if out == nil || out.MultiRegionCluster.ARN == nil { + if out == nil || out.MultiRegionCluster == nil || out.MultiRegionCluster.ARN == nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.MemoryDB, create.ErrActionCreating, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), nil), errors.New("empty output").Error(), From 00d410cbfd5f466670c57e0f14a414e75b779fe4 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 14:36:32 -0500 Subject: [PATCH 54/69] r/aws_memorydb_multi_region_cluster: avoid nil pointer deref on read --- internal/service/memorydb/multi_region_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index a908b331b38..7247b48a5f8 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -228,16 +228,16 @@ func (r *multiRegionClusterResource) Read(ctx context.Context, req resource.Read } if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionSetting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionReading, ResNameMultiRegionCluster, state.ID.String(), err), err.Error(), ) return } - suffix, err := suffixAfterHyphen(*out.MultiRegionClusterName) + suffix, err := suffixAfterHyphen(aws.ToString(out.MultiRegionClusterName)) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionSetting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionSetting, ResNameMultiRegionCluster, state.ID.String(), err), err.Error(), ) return From 318a2f182daac69f6b9a66f341c8bd1e2a6f2029 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 14:44:43 -0500 Subject: [PATCH 55/69] r/aws_memorydb_multi_region_cluster: alphabetize attributes --- .../service/memorydb/multi_region_cluster.go | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 7247b48a5f8..9a42a1fa3f3 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -62,19 +62,12 @@ func (*multiRegionClusterResource) Metadata(_ context.Context, request resource. func (r *multiRegionClusterResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - names.AttrID: framework.IDAttribute(), names.AttrARN: schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, - "multi_region_cluster_name": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, names.AttrDescription: schema.StringAttribute{ Computed: true, Optional: true, @@ -100,16 +93,17 @@ func (r *multiRegionClusterResource) Schema(ctx context.Context, request resourc stringplanmodifier.UseStateForUnknown(), }, }, - "multi_region_cluster_name_suffix": schema.StringAttribute{ - Required: true, + names.AttrID: framework.IDAttribute(), + "multi_region_cluster_name": schema.StringAttribute{ + Computed: true, PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, }, - names.AttrStatus: schema.StringAttribute{ - Computed: true, + "multi_region_cluster_name_suffix": schema.StringAttribute{ + Required: true, PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), + stringplanmodifier.RequiresReplace(), }, }, "multi_region_parameter_group_name": schema.StringAttribute{ @@ -132,22 +126,28 @@ func (r *multiRegionClusterResource) Schema(ctx context.Context, request resourc int64planmodifier.UseStateForUnknown(), }, }, - "update_strategy": schema.StringAttribute{ - Optional: true, + names.AttrStatus: schema.StringAttribute{ + Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, - Validators: []validator.String{ - enum.FrameworkValidate[awstypes.UpdateStrategy](), - }, }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), "tls_enabled": schema.BoolAttribute{ Optional: true, Computed: true, Default: booldefault.StaticBool(true), }, - names.AttrTags: tftags.TagsAttribute(), - names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + "update_strategy": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + Validators: []validator.String{ + enum.FrameworkValidate[awstypes.UpdateStrategy](), + }, + }, }, Blocks: map[string]schema.Block{ names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ @@ -378,22 +378,22 @@ func (r *multiRegionClusterResource) ModifyPlan(ctx context.Context, req resourc } type multiRegionClusterResourceModel struct { - ID types.String `tfsdk:"id"` ARN types.String `tfsdk:"arn"` - MultiRegionClusterName types.String `tfsdk:"multi_region_cluster_name"` - MultiRegionClusterNameSuffix types.String `tfsdk:"multi_region_cluster_name_suffix"` Description types.String `tfsdk:"description"` Engine types.String `tfsdk:"engine"` EngineVersion types.String `tfsdk:"engine_version"` + ID types.String `tfsdk:"id"` + MultiRegionClusterName types.String `tfsdk:"multi_region_cluster_name"` + MultiRegionClusterNameSuffix types.String `tfsdk:"multi_region_cluster_name_suffix"` MultiRegionParameterGroupName types.String `tfsdk:"multi_region_parameter_group_name"` NodeType types.String `tfsdk:"node_type"` NumShards types.Int64 `tfsdk:"num_shards"` - UpdateStrategy types.String `tfsdk:"update_strategy"` Status types.String `tfsdk:"status"` - TLSEnabled types.Bool `tfsdk:"tls_enabled"` Tags tftags.Map `tfsdk:"tags"` TagsAll tftags.Map `tfsdk:"tags_all"` Timeouts timeouts.Value `tfsdk:"timeouts"` + TLSEnabled types.Bool `tfsdk:"tls_enabled"` + UpdateStrategy types.String `tfsdk:"update_strategy"` } func findMultiRegionClusterByName(ctx context.Context, conn *memorydb.Client, name string) (*awstypes.MultiRegionCluster, error) { From 43321931fe67940801236f70052faa3df6298cee Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 14:58:06 -0500 Subject: [PATCH 56/69] r/aws_memorydb_cluster(test): tweak multi region cluster test config ```console % make testacc PKG=memorydb TESTS="TestAccMemoryDBCluster_multiRegionClusterName" make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... TF_ACC=1 go1.23.3 test ./internal/service/memorydb/... -v -count 1 -parallel 20 -run='TestAccMemoryDBCluster_multiRegionClusterName' -timeout 360m 2024/12/16 14:24:29 Initializing Terraform AWS Provider... --- PASS: TestAccMemoryDBCluster_multiRegionClusterName (1932.43s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/memorydb 1937.485s ``` --- internal/service/memorydb/cluster_test.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/internal/service/memorydb/cluster_test.go b/internal/service/memorydb/cluster_test.go index 587fad56044..654c77b3361 100644 --- a/internal/service/memorydb/cluster_test.go +++ b/internal/service/memorydb/cluster_test.go @@ -261,6 +261,7 @@ func TestAccMemoryDBCluster_multiRegionClusterName(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_memorydb_cluster.test" + multiRegionClusterResourceName := "aws_memorydb_multi_region_cluster.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, @@ -272,7 +273,7 @@ func TestAccMemoryDBCluster_multiRegionClusterName(t *testing.T) { Config: testAccClusterConfig_multiRegionClusterName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckClusterExists(ctx, resourceName), - resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name"), + resource.TestCheckResourceAttrPair(resourceName, "multi_region_cluster_name", multiRegionClusterResourceName, "multi_region_cluster_name"), ), }, { @@ -1416,10 +1417,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" num_shards = 2 - - tags = { - Test = "test" - } } resource "aws_memorydb_cluster" "test" { @@ -1433,10 +1430,6 @@ resource "aws_memorydb_cluster" "test" { subnet_group_name = aws_memorydb_subnet_group.test.id multi_region_cluster_name = aws_memorydb_multi_region_cluster.test.multi_region_cluster_name - - tags = { - Test = "test" - } } `, rName), ) From 8d7950bd0e2147fb86760537d615fb457071f941 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 15:05:54 -0500 Subject: [PATCH 57/69] r/aws_memorydb_cluster(doc): fix typo --- website/docs/r/memorydb_cluster.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/memorydb_cluster.html.markdown b/website/docs/r/memorydb_cluster.html.markdown index 755446d10f2..14602cbfb4a 100644 --- a/website/docs/r/memorydb_cluster.html.markdown +++ b/website/docs/r/memorydb_cluster.html.markdown @@ -48,7 +48,7 @@ The following arguments are optional: * `name` - (Optional, Forces new resource) Name of the cluster. If omitted, Terraform will assign a random, unique name. Conflicts with `name_prefix`. * `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. * `num_replicas_per_shard` - (Optional) The number of replicas to apply to each shard, up to a maximum of 5. Defaults to `1` (i.e. 2 nodes per shard). -* `num_shards` - (Optional) The number of shards in the cluster. Defaults to `1`.' +* `num_shards` - (Optional) The number of shards in the cluster. Defaults to `1`. * `multi_region_cluster_name` - (Optional) The multi region cluster identifier specified on `aws_memorydb_multi_region_cluster`. * `parameter_group_name` - (Optional) The name of the parameter group associated with the cluster. * `port` - (Optional, Forces new resource) The port number on which each of the nodes accepts connections. Defaults to `6379`. From 27dd6ef65b8bca984ffec92f2aca41b758b337cb Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 15:18:45 -0500 Subject: [PATCH 58/69] r/aws_memorydb_multi_region_cluster(doc): tidy argument descriptions, alphabetize --- ...emorydb_multi_region_cluster.html.markdown | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/website/docs/r/memorydb_multi_region_cluster.html.markdown b/website/docs/r/memorydb_multi_region_cluster.html.markdown index ee8e9ccf5d3..f7df4a0945b 100644 --- a/website/docs/r/memorydb_multi_region_cluster.html.markdown +++ b/website/docs/r/memorydb_multi_region_cluster.html.markdown @@ -3,7 +3,7 @@ subcategory: "MemoryDB" layout: "aws" page_title: "AWS: aws_memorydb_multi_region_cluster" description: |- - Provides a MemoryDB Cluster. + Provides a MemoryDB Multi Region Cluster. --- # Resource: aws_memorydb_multi_region_cluster @@ -38,26 +38,26 @@ resource "aws_memorydb_cluster" "example" { The following arguments are required: -* `multi_region_cluster_name_suffix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. -* `node_type` - (Required) The node type to be used for the multi-Region cluster. +* `multi_region_cluster_name_suffix` - (Required, Forces new resource) A suffix to be added to the multi-region cluster name. An AWS generated prefix is automatically applied to the multi-region cluster name when it is created. +* `node_type` - (Required) The node type to be used for the multi-region cluster. The following arguments are optional: -* `description` - (Optional) description for the multi-Region cluster. Defaults to `"Managed by Terraform"`. -* `engine` - (Optional) The name of the engine to be used for the multi-Region cluster. Supported values are `redis` and `valkey`. -* `engine_version` - (Optional) The version of the engine to be used for the multi-Region cluster. Downgrades are not supported. -* `num_shards` - (Optional) The number of shards for the multi-Region cluster. -* `multi_region_parameter_group_name` - (Optional) The name of the multi-Region parameter group to be associated with the cluster. -* `tls_enabled` - (Optional, Forces new resource) A flag to enable in-transit encryption on the cluster. Defaults to `true`. +* `description` - (Optional) description for the multi-region cluster. Defaults to `"Managed by Terraform"`. +* `engine` - (Optional) The name of the engine to be used for the multi-region cluster. Supported values are `redis` and `valkey`. +* `engine_version` - (Optional) The version of the engine to be used for the multi-region cluster. Downgrades are not supported. +* `multi_region_parameter_group_name` - (Optional) The name of the multi-region parameter group to be associated with the cluster. +* `num_shards` - (Optional) The number of shards for the multi-region cluster. * `tags` - (Optional) A map of tags to assign to the resource. 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. +* `tls_enabled` - (Optional, Forces new resource) A flag to enable in-transit encryption on the cluster. Defaults to `true`. ## Attribute Reference This resource exports the following attributes in addition to the arguments above: -* `id` - The ID of the multi-region cluster. -* `multi_region_cluster_name` - The name of the multi-region cluster. * `arn` - The ARN of the multi-region cluster. +* `id` - The name of the multi-region cluster. +* `multi_region_cluster_name` - The name of the multi-region cluster. * `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 @@ -70,7 +70,7 @@ This resource exports the following attributes in addition to the arguments abov ## Import -In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import a cluster using the `name`. For example: +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import a cluster using the `multi_region_cluster_name`. For example: ```terraform import { @@ -79,7 +79,7 @@ import { } ``` -Using `terraform import`, import a cluster using the `name`. For example: +Using `terraform import`, import a cluster using the `multi_region_cluster_name`. For example: ```console % terraform import aws_memorydb_multi_region_cluster.example my-multi-region-cluster From ba633068ae55eba5227ab8be8f3b0aefb4f34ac9 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 16 Dec 2024 16:58:48 -0500 Subject: [PATCH 59/69] r/aws_memorydb_multi_region_cluster: serialize update requests The `Update` API only allows one of node type, shard configuration, or parameter group name to be updated in a single request. The provider will now serialize update requests in the case where more than one of these arguments are modified during a single apply. ```console % make testacc PKG=memorydb TESTS="TestAccMemoryDBMultiRegionCluster_" make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... TF_ACC=1 go1.23.3 test ./internal/service/memorydb/... -v -count 1 -parallel 20 -run='Tes 2024/12/16 16:52:20 Initializing Terraform AWS Provider... --- PASS: TestAccMemoryDBMultiRegionCluster_engineVersion (88.78s) --- PASS: TestAccMemoryDBMultiRegionCluster_defaults (89.07s) --- PASS: TestAccMemoryDBMultiRegionCluster_description (89.07s) --- PASS: TestAccMemoryDBMultiRegionCluster_parameterGroup (89.07s) --- PASS: TestAccMemoryDBMultiRegionCluster_tlsEnabled (89.07s) --- PASS: TestAccMemoryDBMultiRegionCluster_engine (89.09s) --- PASS: TestAccMemoryDBMultiRegionCluster_basic (89.11s) --- PASS: TestAccMemoryDBMultiRegionCluster_tags (108.07s) --- PASS: TestAccMemoryDBMultiRegionCluster_numShards (152.33s) --- PASS: TestAccMemoryDBMultiRegionCluster_nodeType (161.55s) --- PASS: TestAccMemoryDBMultiRegionCluster_updateStrategy (188.85s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/memorydb 194.018s ``` --- .../service/memorydb/multi_region_cluster.go | 95 ++++++++++++++----- .../memorydb/multi_region_cluster_test.go | 2 +- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 9a42a1fa3f3..9dbbe143e42 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -262,47 +262,87 @@ func (r *multiRegionClusterResource) Update(ctx context.Context, req resource.Up if resp.Diagnostics.HasError() { return } - - if !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) || - !plan.NodeType.Equal(state.NodeType) || - !plan.NumShards.Equal(state.NumShards) { - input := memorydb.UpdateMultiRegionClusterInput{ - MultiRegionClusterName: state.MultiRegionClusterName.ValueStringPointer(), + updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) + + // Only one of node type, shard configurations, or parameter group + // can be updated in a single request. Construct a list of update + // requests to execute serially to support cases where multiple attributes + // are changed at once. + updateRequests := []*memorydb.UpdateMultiRegionClusterInput{} + + // Standard updates + if !plan.Description.Equal(state.Description) || + !plan.EngineVersion.Equal(state.EngineVersion) { + input := &memorydb.UpdateMultiRegionClusterInput{ + MultiRegionClusterName: plan.MultiRegionClusterName.ValueStringPointer(), } - - if !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) { - input.MultiRegionParameterGroupName = plan.MultiRegionParameterGroupName.ValueStringPointer() + if !plan.Description.IsNull() { + input.Description = plan.Description.ValueStringPointer() } - - if !plan.NodeType.Equal(state.NodeType) { - input.NodeType = plan.NodeType.ValueStringPointer() + if !plan.EngineVersion.IsNull() { + input.EngineVersion = plan.EngineVersion.ValueStringPointer() + } + if !plan.UpdateStrategy.IsNull() { + input.UpdateStrategy = awstypes.UpdateStrategy(plan.UpdateStrategy.ValueString()) } - if !plan.NumShards.Equal(state.NumShards) { - input.ShardConfiguration = &awstypes.ShardConfigurationRequest{ - ShardCount: int32(*plan.NumShards.ValueInt64Pointer()), - } + updateRequests = append(updateRequests, input) + } + + // Node type + if !plan.NodeType.Equal(state.NodeType) { + input := &memorydb.UpdateMultiRegionClusterInput{ + MultiRegionClusterName: plan.MultiRegionClusterName.ValueStringPointer(), + NodeType: plan.NodeType.ValueStringPointer(), + } + if !plan.UpdateStrategy.IsNull() { + input.UpdateStrategy = awstypes.UpdateStrategy(plan.UpdateStrategy.ValueString()) } - if !plan.UpdateStrategy.Equal(state.UpdateStrategy) { + updateRequests = append(updateRequests, input) + } + + // Shard configurations + if !plan.NumShards.Equal(state.NumShards) { + input := &memorydb.UpdateMultiRegionClusterInput{ + MultiRegionClusterName: plan.MultiRegionClusterName.ValueStringPointer(), + ShardConfiguration: &awstypes.ShardConfigurationRequest{ + ShardCount: int32(plan.NumShards.ValueInt64()), + }, + } + if !plan.UpdateStrategy.IsNull() { input.UpdateStrategy = awstypes.UpdateStrategy(plan.UpdateStrategy.ValueString()) } - resp.Diagnostics.Append(flex.Expand(ctx, plan, &input)...) - if resp.Diagnostics.HasError() { - return + updateRequests = append(updateRequests, input) + } + + // Parameter group name + if !plan.MultiRegionParameterGroupName.Equal(state.MultiRegionParameterGroupName) { + input := &memorydb.UpdateMultiRegionClusterInput{ + MultiRegionClusterName: plan.MultiRegionClusterName.ValueStringPointer(), + MultiRegionParameterGroupName: plan.MultiRegionParameterGroupName.ValueStringPointer(), + } + if !plan.UpdateStrategy.IsNull() { + input.UpdateStrategy = awstypes.UpdateStrategy(plan.UpdateStrategy.ValueString()) } - _, err := conn.UpdateMultiRegionCluster(ctx, &input) - if err != nil { + updateRequests = append(updateRequests, input) + } + + for _, input := range updateRequests { + if err := updateMultiRegionClusterAndWaitAvailable(ctx, conn, input, updateTimeout); err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.MemoryDB, create.ErrActionUpdating, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), err.Error(), ) return } + } - updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) + // If update requests were made, make one last call to the update waiter to + // retreive and write the latest status to state + if len(updateRequests) > 0 { statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), updateTimeout) if err != nil { resp.Diagnostics.AddError( @@ -439,6 +479,15 @@ func findMultiRegionClusters(ctx context.Context, conn *memorydb.Client, input * return output, nil } +func updateMultiRegionClusterAndWaitAvailable(ctx context.Context, conn *memorydb.Client, input *memorydb.UpdateMultiRegionClusterInput, timeout time.Duration) error { + if _, err := conn.UpdateMultiRegionCluster(ctx, input); err != nil { + return err + } + + _, err := waitMultiRegionClusterAvailable(ctx, conn, aws.ToString(input.MultiRegionClusterName), timeout) + return err +} + func statusMultiRegionCluster(ctx context.Context, conn *memorydb.Client, name string) retry.StateRefreshFunc { return func() (interface{}, string, error) { output, err := findMultiRegionClusterByName(ctx, conn, name) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index bb6b68144c5..42c6f1230d5 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -247,7 +247,7 @@ func TestAccMemoryDBMultiRegionCluster_updateStrategy(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrTags, names.AttrTagsAll, "update_strategy"}, + ImportStateVerifyIgnore: []string{"update_strategy"}, }, }, }) From 6e2b8b31b0ca07a4555505611ce47e2bb939c498 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 17 Dec 2024 09:24:04 -0500 Subject: [PATCH 60/69] r/aws_memorydb_multi_region_cluster: fix misspell --- internal/service/memorydb/multi_region_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 9dbbe143e42..e13e48bbd96 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -341,7 +341,7 @@ func (r *multiRegionClusterResource) Update(ctx context.Context, req resource.Up } // If update requests were made, make one last call to the update waiter to - // retreive and write the latest status to state + // retrieve and write the latest status to state if len(updateRequests) > 0 { statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), updateTimeout) if err != nil { From 4bec4759cfe18276276c1cb16a6de92a2f22fa60 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 17 Dec 2024 10:57:02 -0500 Subject: [PATCH 61/69] r/aws_memorydb_multi_region_cluster: handle resource not found during deletion --- .../service/memorydb/multi_region_cluster.go | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index e13e48bbd96..987d444a47f 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -372,16 +372,23 @@ func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.De // Before deleting the multi-region cluster, ensure it is ready for deletion. // Removing an `aws_memorydb_cluster` from a multi-region cluster may temporarily block deletion. - createTimeout := r.CreateTimeout(ctx, state.Timeouts) - _, err := waitMultiRegionClusterAvailable(ctx, conn, state.ID.ValueString(), createTimeout) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForCreation, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), - err.Error(), - ) + output, err := findMultiRegionClusterByName(ctx, conn, state.ID.ValueString()) + if tfresource.NotFound(err) { return } + if aws.ToString(output.Status) != clusterStatusAvailable { + deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) + _, err := waitMultiRegionClusterAvailable(ctx, conn, state.ID.ValueString(), deleteTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.ID.String(), err), + err.Error(), + ) + return + } + } + input := memorydb.DeleteMultiRegionClusterInput{ MultiRegionClusterName: state.MultiRegionClusterName.ValueStringPointer(), } From 43e3af951f862ebf6eed1f0c862e53a9497387f6 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 17 Dec 2024 10:57:17 -0500 Subject: [PATCH 62/69] r/aws_memorydb_multi_region_cluster(test): add _disappears case --- .../memorydb/multi_region_cluster_test.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 42c6f1230d5..ed50bea7a85 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -59,6 +59,29 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { }) } +func TestAccMemoryDBMultiRegionCluster_disappears(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_memorydb_multi_region_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMultiRegionClusterConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfmemorydb.ResourceMultiRegionCluster, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccMemoryDBMultiRegionCluster_defaults(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) From 0f1fc7b00ac975fb4e67055651856289eed22e3a Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 17 Dec 2024 13:14:22 -0500 Subject: [PATCH 63/69] r/aws_memorydb_multi_region_cluster: remove default `description` Also simplifies acceptance test configurations and merges the `defaults` test case with `basic`. ```console % make testacc PKG=memorydb TESTS="TestAccMemoryDBMultiRegionCluster_" make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... TF_ACC=1 go1.23.3 test ./internal/service/memorydb/... -v -count 1 -parallel 20 -run='TestAccMemoryDBMultiRegionCluster_' -timeout 360m 2024/12/17 13:10:16 Initializing Terraform AWS Provider... --- PASS: TestAccMemoryDBMultiRegionCluster_disappears (56.94s) --- PASS: TestAccMemoryDBMultiRegionCluster_basic (66.06s) --- PASS: TestAccMemoryDBMultiRegionCluster_engine (66.08s) --- PASS: TestAccMemoryDBMultiRegionCluster_engineVersion (66.10s) --- PASS: TestAccMemoryDBMultiRegionCluster_tlsEnabled (66.10s) --- PASS: TestAccMemoryDBMultiRegionCluster_description (66.10s) --- PASS: TestAccMemoryDBMultiRegionCluster_parameterGroup (66.10s) --- PASS: TestAccMemoryDBMultiRegionCluster_tags (82.06s) --- PASS: TestAccMemoryDBMultiRegionCluster_numShards (115.65s) --- PASS: TestAccMemoryDBMultiRegionCluster_nodeType (116.70s) --- PASS: TestAccMemoryDBMultiRegionCluster_updateStrategy (164.88s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/memorydb 170.051s ``` --- .../service/memorydb/multi_region_cluster.go | 6 -- .../memorydb/multi_region_cluster_test.go | 93 +------------------ ...emorydb_multi_region_cluster.html.markdown | 2 +- 3 files changed, 4 insertions(+), 97 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 987d444a47f..9d6d64a8f48 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -19,7 +19,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "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/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -69,12 +68,7 @@ func (r *multiRegionClusterResource) Schema(ctx context.Context, request resourc }, }, names.AttrDescription: schema.StringAttribute{ - Computed: true, Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - Default: stringdefault.StaticString("Managed by Terraform"), }, names.AttrEngine: schema.StringAttribute{ Computed: true, diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index ed50bea7a85..a5cd349eac2 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -37,17 +37,15 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name"), resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name_suffix"), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), + resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), resource.TestCheckResourceAttrSet(resourceName, "multi_region_parameter_group_name"), - resource.TestCheckResourceAttrSet(resourceName, "num_shards"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), + resource.TestCheckResourceAttr(resourceName, "num_shards", "1"), resource.TestCheckResourceAttr(resourceName, "clusters.#", "0"), resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtTrue), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Test", "test"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), ), }, { @@ -82,46 +80,6 @@ func TestAccMemoryDBMultiRegionCluster_disappears(t *testing.T) { }) } -func TestAccMemoryDBMultiRegionCluster_defaults(t *testing.T) { - ctx := acctest.Context(t) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_memorydb_multi_region_cluster.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccMultiRegionClusterConfig_defaults(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckMultiRegionClusterExists(ctx, resourceName), - resource.TestCheckResourceAttrSet(resourceName, names.AttrID), - resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), - resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name"), - resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name_suffix"), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Managed by Terraform"), - resource.TestCheckResourceAttr(resourceName, "node_type", "db.r7g.xlarge"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), - resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), - resource.TestCheckResourceAttrSet(resourceName, "multi_region_parameter_group_name"), - resource.TestCheckResourceAttr(resourceName, "num_shards", "1"), - resource.TestCheckResourceAttr(resourceName, "clusters.#", "0"), - resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtTrue), - resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - func TestAccMemoryDBMultiRegionCluster_description(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -463,19 +421,6 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` -resource "aws_memorydb_multi_region_cluster" "test" { - multi_region_cluster_name_suffix = %[1]q - node_type = "db.r7g.xlarge" - - tags = { - Test = "test" - } -} -`, rName) -} - -func testAccMultiRegionClusterConfig_defaults(rName string) string { - return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" @@ -490,10 +435,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" description = %[2]q - - tags = { - Test = "test" - } } `, rName, description) } @@ -506,10 +447,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { description = "Also managed by Terraform" num_shards = %[2]d - - tags = { - Test = "test" - } } `, rName, numShards) } @@ -520,10 +457,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = %[2]q description = "Also managed by Terraform" - - tags = { - Test = "test" - } } `, rName, nodeType) } @@ -536,10 +469,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { description = "Also managed by Terraform" multi_region_parameter_group_name = "default.memorydb-valkey7.multiregion" - - tags = { - Test = "test" - } } `, rName) } @@ -550,10 +479,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" tls_enabled = false - - tags = { - Test = "test" - } } `, rName) } @@ -564,10 +489,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" engine = %[2]q - - tags = { - Test = "test" - } } `, rName, engine) } @@ -579,10 +500,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { node_type = "db.r7g.xlarge" engine = %[2]q engine_version = %[3]q - - tags = { - Test = "test" - } } `, rName, engine, engineVersion) } @@ -596,10 +513,6 @@ resource "aws_memorydb_multi_region_cluster" "test" { update_strategy = %[2]q num_shards = %[3]d - - tags = { - Test = "test" - } } `, rName, updateStrategy, numShards) } diff --git a/website/docs/r/memorydb_multi_region_cluster.html.markdown b/website/docs/r/memorydb_multi_region_cluster.html.markdown index f7df4a0945b..22d6111340d 100644 --- a/website/docs/r/memorydb_multi_region_cluster.html.markdown +++ b/website/docs/r/memorydb_multi_region_cluster.html.markdown @@ -43,7 +43,7 @@ The following arguments are required: The following arguments are optional: -* `description` - (Optional) description for the multi-region cluster. Defaults to `"Managed by Terraform"`. +* `description` - (Optional) description for the multi-region cluster. * `engine` - (Optional) The name of the engine to be used for the multi-region cluster. Supported values are `redis` and `valkey`. * `engine_version` - (Optional) The version of the engine to be used for the multi-region cluster. Downgrades are not supported. * `multi_region_parameter_group_name` - (Optional) The name of the multi-region parameter group to be associated with the cluster. From f679b45485691f022e107f12a46fdc1f5e1865d3 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 17 Dec 2024 13:17:03 -0500 Subject: [PATCH 64/69] r/aws_memorydb_multi_region_cluster: handle all errors from find during delete --- internal/service/memorydb/multi_region_cluster.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 9d6d64a8f48..76a7c4620f9 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -367,8 +367,14 @@ func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.De // Before deleting the multi-region cluster, ensure it is ready for deletion. // Removing an `aws_memorydb_cluster` from a multi-region cluster may temporarily block deletion. output, err := findMultiRegionClusterByName(ctx, conn, state.ID.ValueString()) - if tfresource.NotFound(err) { - return + if err != nil { + if tfresource.NotFound(err) { + return + } + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.ID.String(), err), + err.Error(), + ) } if aws.ToString(output.Status) != clusterStatusAvailable { From 67d34f5afb83bbee288241baba81eeb2620a502d Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 17 Dec 2024 13:36:56 -0500 Subject: [PATCH 65/69] r/aws_memorydb_multi_region_cluster: remove provider default for `tls_enabled` The argument is now changed to optional and computed to allow for the default value to be configured by AWS when omitted, rather than set explicitly to a hardcoded value in the provider. ```console % make testacc PKG=memorydb TESTS="TestAccMemoryDBMultiRegionCluster_" make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... TF_ACC=1 go1.23.3 test ./internal/service/memorydb/... -v -count 1 -parallel 20 -run='TestAccMemoryDBMultiRegionCluster_' -timeout 360m 2024/12/17 13:24:43 Initializing Terraform AWS Provider... --- PASS: TestAccMemoryDBMultiRegionCluster_disappears (57.02s) --- PASS: TestAccMemoryDBMultiRegionCluster_parameterGroup (65.62s) --- PASS: TestAccMemoryDBMultiRegionCluster_description (66.54s) --- PASS: TestAccMemoryDBMultiRegionCluster_engineVersion (66.80s) --- PASS: TestAccMemoryDBMultiRegionCluster_basic (66.90s) --- PASS: TestAccMemoryDBMultiRegionCluster_engine (66.97s) --- PASS: TestAccMemoryDBMultiRegionCluster_tags (88.16s) --- PASS: TestAccMemoryDBMultiRegionCluster_numShards (116.65s) --- PASS: TestAccMemoryDBMultiRegionCluster_tlsEnabled (117.55s) --- PASS: TestAccMemoryDBMultiRegionCluster_nodeType (122.02s) --- PASS: TestAccMemoryDBMultiRegionCluster_updateStrategy (165.72s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/memorydb 171.075s ``` --- .../service/memorydb/multi_region_cluster.go | 7 +++++-- .../memorydb/multi_region_cluster_test.go | 17 ++++++++++++----- .../memorydb_multi_region_cluster.html.markdown | 4 ++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 76a7c4620f9..126e114d0d7 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -16,7 +16,7 @@ import ( "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/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" @@ -131,7 +131,10 @@ func (r *multiRegionClusterResource) Schema(ctx context.Context, request resourc "tls_enabled": schema.BoolAttribute{ Optional: true, Computed: true, - Default: booldefault.StaticBool(true), + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + boolplanmodifier.RequiresReplace(), + }, }, "update_strategy": schema.StringAttribute{ Optional: true, diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index a5cd349eac2..4df3d107837 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -119,10 +119,10 @@ func TestAccMemoryDBMultiRegionCluster_tlsEnabled(t *testing.T) { CheckDestroy: testAccCheckMultiRegionClusterDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccMultiRegionClusterConfig_tlsEnabled(rName), + Config: testAccMultiRegionClusterConfig_tlsEnabled(rName, true), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtFalse), + resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtTrue), ), }, { @@ -130,6 +130,13 @@ func TestAccMemoryDBMultiRegionCluster_tlsEnabled(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccMultiRegionClusterConfig_tlsEnabled(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckMultiRegionClusterExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "tls_enabled", acctest.CtFalse), + ), + }, }, }) } @@ -473,14 +480,14 @@ resource "aws_memorydb_multi_region_cluster" "test" { `, rName) } -func testAccMultiRegionClusterConfig_tlsEnabled(rName string) string { +func testAccMultiRegionClusterConfig_tlsEnabled(rName string, tlsEnabled bool) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { multi_region_cluster_name_suffix = %[1]q node_type = "db.r7g.xlarge" - tls_enabled = false + tls_enabled = %[2]t } -`, rName) +`, rName, tlsEnabled) } func testAccMultiRegionClusterConfig_engine(rName, engine string) string { diff --git a/website/docs/r/memorydb_multi_region_cluster.html.markdown b/website/docs/r/memorydb_multi_region_cluster.html.markdown index 22d6111340d..19a448ff1ed 100644 --- a/website/docs/r/memorydb_multi_region_cluster.html.markdown +++ b/website/docs/r/memorydb_multi_region_cluster.html.markdown @@ -44,12 +44,12 @@ The following arguments are required: The following arguments are optional: * `description` - (Optional) description for the multi-region cluster. -* `engine` - (Optional) The name of the engine to be used for the multi-region cluster. Supported values are `redis` and `valkey`. +* `engine` - (Optional) The name of the engine to be used for the multi-region cluster. Valid values are `redis` and `valkey`. * `engine_version` - (Optional) The version of the engine to be used for the multi-region cluster. Downgrades are not supported. * `multi_region_parameter_group_name` - (Optional) The name of the multi-region parameter group to be associated with the cluster. * `num_shards` - (Optional) The number of shards for the multi-region cluster. * `tags` - (Optional) A map of tags to assign to the resource. 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. -* `tls_enabled` - (Optional, Forces new resource) A flag to enable in-transit encryption on the cluster. Defaults to `true`. +* `tls_enabled` - (Optional, Forces new resource) A flag to enable in-transit encryption on the cluster. ## Attribute Reference From 6b3bfbb044c4e12d4d3fdf18b65b7b74409a9eb1 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 17 Dec 2024 13:55:38 -0500 Subject: [PATCH 66/69] r/aws_memorydb_multi_region_cluster: appease the semgrep overlords --- internal/service/memorydb/multi_region_cluster.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 126e114d0d7..12e46d086d5 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -370,10 +370,10 @@ func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.De // Before deleting the multi-region cluster, ensure it is ready for deletion. // Removing an `aws_memorydb_cluster` from a multi-region cluster may temporarily block deletion. output, err := findMultiRegionClusterByName(ctx, conn, state.ID.ValueString()) + if tfresource.NotFound(err) { + return + } if err != nil { - if tfresource.NotFound(err) { - return - } resp.Diagnostics.AddError( create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.ID.String(), err), err.Error(), From ad8987f35410419d3226bffdeb0b969629c4705b Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 18 Dec 2024 09:40:29 -0500 Subject: [PATCH 67/69] r/aws_memorydb_multi_region_cluster: remove `id` attribute The `multi_region_cluster_name` attribute will be used for import and read operations, aligning with the primary identifer used by the AWS API. ```console % make testacc PKG=memorydb TESTS="TestAccMemoryDBMultiRegionCluster_" make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... TF_ACC=1 go1.23.3 test ./internal/service/memorydb/... -v -count 1 -parallel 20 -run='TestAccMemoryDBMultiRegionCluster_' -timeout 360m 2024/12/18 09:13:35 Initializing Terraform AWS Provider... --- PASS: TestAccMemoryDBMultiRegionCluster_disappears (57.86s) --- PASS: TestAccMemoryDBMultiRegionCluster_parameterGroup (66.57s) --- PASS: TestAccMemoryDBMultiRegionCluster_basic (67.35s) --- PASS: TestAccMemoryDBMultiRegionCluster_engineVersion (67.36s) --- PASS: TestAccMemoryDBMultiRegionCluster_description (67.37s) --- PASS: TestAccMemoryDBMultiRegionCluster_engine (67.47s) --- PASS: TestAccMemoryDBMultiRegionCluster_tags (83.31s) --- PASS: TestAccMemoryDBMultiRegionCluster_numShards (116.48s) --- PASS: TestAccMemoryDBMultiRegionCluster_nodeType (118.62s) --- PASS: TestAccMemoryDBMultiRegionCluster_tlsEnabled (118.65s) --- PASS: TestAccMemoryDBMultiRegionCluster_updateStrategy (165.98s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/memorydb 175.713s ``` --- .../service/memorydb/multi_region_cluster.go | 31 +++-- .../memorydb/multi_region_cluster_test.go | 107 +++++++++++------- ...emorydb_multi_region_cluster.html.markdown | 5 +- 3 files changed, 86 insertions(+), 57 deletions(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 12e46d086d5..258a39cb41c 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -87,7 +87,6 @@ func (r *multiRegionClusterResource) Schema(ctx context.Context, request resourc stringplanmodifier.UseStateForUnknown(), }, }, - names.AttrID: framework.IDAttribute(), "multi_region_cluster_name": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ @@ -187,12 +186,10 @@ func (r *multiRegionClusterResource) Create(ctx context.Context, req resource.Cr ) return } - - plan.ID = flex.StringToFramework(ctx, out.MultiRegionCluster.MultiRegionClusterName) - plan.NumShards = flex.Int32ToFramework(ctx, out.MultiRegionCluster.NumberOfShards) + name := aws.ToString(out.MultiRegionCluster.MultiRegionClusterName) createTimeout := r.CreateTimeout(ctx, plan.Timeouts) - statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), createTimeout) + statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, name, createTimeout) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForCreation, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), @@ -205,6 +202,9 @@ func (r *multiRegionClusterResource) Create(ctx context.Context, req resource.Cr if resp.Diagnostics.HasError() { return } + // Account for field name mismatches between the Create + // and Describe data structures + plan.NumShards = flex.Int32ToFramework(ctx, statusOut.NumberOfShards) resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) } @@ -218,14 +218,14 @@ func (r *multiRegionClusterResource) Read(ctx context.Context, req resource.Read return } - out, err := findMultiRegionClusterByName(ctx, conn, state.ID.ValueString()) + out, err := findMultiRegionClusterByName(ctx, conn, state.MultiRegionClusterName.ValueString()) if tfresource.NotFound(err) { resp.State.RemoveResource(ctx) return } if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionReading, ResNameMultiRegionCluster, state.ID.String(), err), + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionReading, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), err.Error(), ) return @@ -234,7 +234,7 @@ func (r *multiRegionClusterResource) Read(ctx context.Context, req resource.Read suffix, err := suffixAfterHyphen(aws.ToString(out.MultiRegionClusterName)) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionSetting, ResNameMultiRegionCluster, state.ID.String(), err), + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionSetting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), err.Error(), ) return @@ -340,7 +340,7 @@ func (r *multiRegionClusterResource) Update(ctx context.Context, req resource.Up // If update requests were made, make one last call to the update waiter to // retrieve and write the latest status to state if len(updateRequests) > 0 { - statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.ID.ValueString(), updateTimeout) + statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, plan.MultiRegionClusterName.ValueString(), updateTimeout) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForUpdate, ResNameMultiRegionCluster, plan.MultiRegionClusterName.String(), err), @@ -369,23 +369,23 @@ func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.De // Before deleting the multi-region cluster, ensure it is ready for deletion. // Removing an `aws_memorydb_cluster` from a multi-region cluster may temporarily block deletion. - output, err := findMultiRegionClusterByName(ctx, conn, state.ID.ValueString()) + output, err := findMultiRegionClusterByName(ctx, conn, state.MultiRegionClusterName.ValueString()) if tfresource.NotFound(err) { return } if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.ID.String(), err), + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), err.Error(), ) } if aws.ToString(output.Status) != clusterStatusAvailable { deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) - _, err := waitMultiRegionClusterAvailable(ctx, conn, state.ID.ValueString(), deleteTimeout) + _, err := waitMultiRegionClusterAvailable(ctx, conn, state.MultiRegionClusterName.ValueString(), deleteTimeout) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.ID.String(), err), + create.ProblemStandardMessage(names.MemoryDB, create.ErrActionDeleting, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), err.Error(), ) return @@ -409,7 +409,7 @@ func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.De } deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) - _, err = waitMultiRegionClusterDeleted(ctx, conn, state.ID.ValueString(), deleteTimeout) + _, err = waitMultiRegionClusterDeleted(ctx, conn, state.MultiRegionClusterName.ValueString(), deleteTimeout) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.MemoryDB, create.ErrActionWaitingForDeletion, ResNameMultiRegionCluster, state.MultiRegionClusterName.String(), err), @@ -420,7 +420,7 @@ func (r *multiRegionClusterResource) Delete(ctx context.Context, req resource.De } func (r *multiRegionClusterResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), request, response) + resource.ImportStatePassthroughID(ctx, path.Root("multi_region_cluster_name"), request, response) } func (r *multiRegionClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { @@ -432,7 +432,6 @@ type multiRegionClusterResourceModel struct { Description types.String `tfsdk:"description"` Engine types.String `tfsdk:"engine"` EngineVersion types.String `tfsdk:"engine_version"` - ID types.String `tfsdk:"id"` MultiRegionClusterName types.String `tfsdk:"multi_region_cluster_name"` MultiRegionClusterNameSuffix types.String `tfsdk:"multi_region_cluster_name_suffix"` MultiRegionParameterGroupName types.String `tfsdk:"multi_region_parameter_group_name"` diff --git a/internal/service/memorydb/multi_region_cluster_test.go b/internal/service/memorydb/multi_region_cluster_test.go index 4df3d107837..91924d7ffc2 100644 --- a/internal/service/memorydb/multi_region_cluster_test.go +++ b/internal/service/memorydb/multi_region_cluster_test.go @@ -33,7 +33,6 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { Config: testAccMultiRegionClusterConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckMultiRegionClusterExists(ctx, resourceName), - resource.TestCheckResourceAttrSet(resourceName, names.AttrID), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name"), resource.TestCheckResourceAttrSet(resourceName, "multi_region_cluster_name_suffix"), @@ -49,9 +48,11 @@ func TestAccMemoryDBMultiRegionCluster_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, }, }) @@ -99,9 +100,11 @@ func TestAccMemoryDBMultiRegionCluster_description(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, }, }) @@ -126,9 +129,11 @@ func TestAccMemoryDBMultiRegionCluster_tlsEnabled(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, { Config: testAccMultiRegionClusterConfig_tlsEnabled(rName, false), @@ -161,9 +166,11 @@ func TestAccMemoryDBMultiRegionCluster_engine(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, }, }) @@ -189,9 +196,11 @@ func TestAccMemoryDBMultiRegionCluster_engineVersion(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, }, }) @@ -232,10 +241,12 @@ func TestAccMemoryDBMultiRegionCluster_updateStrategy(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"update_strategy"}, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", + ImportStateVerifyIgnore: []string{"update_strategy"}, }, }, }) @@ -260,9 +271,11 @@ func TestAccMemoryDBMultiRegionCluster_numShards(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, { Config: testAccMultiRegionClusterConfig_numShards(rName, 3), @@ -294,9 +307,11 @@ func TestAccMemoryDBMultiRegionCluster_nodeType(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, { Config: testAccMultiRegionClusterConfig_nodeType(rName, "db.r7g.2xlarge"), @@ -328,9 +343,11 @@ func TestAccMemoryDBMultiRegionCluster_parameterGroup(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, }, }) @@ -356,9 +373,11 @@ func TestAccMemoryDBMultiRegionCluster_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccMultiRegionClusterImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "multi_region_cluster_name", }, { Config: testAccMultiRegionClusterConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), @@ -388,13 +407,13 @@ func testAccCheckMultiRegionClusterExists(ctx context.Context, n string) resourc return fmt.Errorf("Not found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No MemoryDB Multi Region Cluster ID is set") + name := rs.Primary.Attributes["multi_region_cluster_name"] + if name == "" { + return fmt.Errorf("No MemoryDB Multi Region Cluster Name is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).MemoryDBClient(ctx) - - _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes["multi_region_cluster_name"]) + _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, name) return err } @@ -409,8 +428,9 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe continue } - _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, rs.Primary.Attributes["multi_region_cluster_name"]) + name := rs.Primary.Attributes["multi_region_cluster_name"] + _, err := tfmemorydb.FindMultiRegionClusterByName(ctx, conn, name) if tfresource.NotFound(err) { continue } @@ -419,13 +439,24 @@ func testAccCheckMultiRegionClusterDestroy(ctx context.Context) resource.TestChe return err } - return fmt.Errorf("MemoryDB Multi Region Cluster %s still exists", rs.Primary.ID) + return fmt.Errorf("MemoryDB Multi Region Cluster %s still exists", name) } return nil } } +func testAccMultiRegionClusterImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not found: %s", resourceName) + } + + return rs.Primary.Attributes["multi_region_cluster_name"], nil + } +} + func testAccMultiRegionClusterConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_multi_region_cluster" "test" { diff --git a/website/docs/r/memorydb_multi_region_cluster.html.markdown b/website/docs/r/memorydb_multi_region_cluster.html.markdown index 19a448ff1ed..a54a25f679b 100644 --- a/website/docs/r/memorydb_multi_region_cluster.html.markdown +++ b/website/docs/r/memorydb_multi_region_cluster.html.markdown @@ -56,7 +56,6 @@ The following arguments are optional: This resource exports the following attributes in addition to the arguments above: * `arn` - The ARN of the multi-region cluster. -* `id` - The name of the multi-region cluster. * `multi_region_cluster_name` - The name of the multi-region cluster. * `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). @@ -75,12 +74,12 @@ In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashico ```terraform import { to = aws_memorydb_multi_region_cluster.example - id = "my-multi-region-cluster" + id = "virxk-example" } ``` Using `terraform import`, import a cluster using the `multi_region_cluster_name`. For example: ```console -% terraform import aws_memorydb_multi_region_cluster.example my-multi-region-cluster +% terraform import aws_memorydb_multi_region_cluster.example virxk-example ``` From 393d984b40c1bd1142cc441f2a942b051d537518 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 18 Dec 2024 10:33:04 -0500 Subject: [PATCH 68/69] r/aws_memorydb_multi_region_cluster: set partial state before waiting Set a partial state so that this resource taints if the waiter fails. Co-authored-by: Adrian Johnson --- internal/service/memorydb/multi_region_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 258a39cb41c..0a03d2066c2 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -187,7 +187,7 @@ func (r *multiRegionClusterResource) Create(ctx context.Context, req resource.Cr return } name := aws.ToString(out.MultiRegionCluster.MultiRegionClusterName) - + resp.State.SetAttribute(ctx, path.Root("multi_region_cluster_name"), name) createTimeout := r.CreateTimeout(ctx, plan.Timeouts) statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, name, createTimeout) if err != nil { From 27715d213a1bbe38915f59a9ea74f068521bc124 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Wed, 18 Dec 2024 10:33:53 -0500 Subject: [PATCH 69/69] chore: make fmt --- internal/service/memorydb/multi_region_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/memorydb/multi_region_cluster.go b/internal/service/memorydb/multi_region_cluster.go index 0a03d2066c2..42b0fc1d42e 100644 --- a/internal/service/memorydb/multi_region_cluster.go +++ b/internal/service/memorydb/multi_region_cluster.go @@ -187,7 +187,7 @@ func (r *multiRegionClusterResource) Create(ctx context.Context, req resource.Cr return } name := aws.ToString(out.MultiRegionCluster.MultiRegionClusterName) - resp.State.SetAttribute(ctx, path.Root("multi_region_cluster_name"), name) + resp.State.SetAttribute(ctx, path.Root("multi_region_cluster_name"), name) createTimeout := r.CreateTimeout(ctx, plan.Timeouts) statusOut, err := waitMultiRegionClusterAvailable(ctx, conn, name, createTimeout) if err != nil {