Skip to content

Commit

Permalink
Merge pull request #38476 from hashicorp/b-aws_elasticache_replicatio…
Browse files Browse the repository at this point in the history
…n_group-state-migration-regression

r/aws_elasticache_replication_group: Fix `error marshaling prior state` when upgrading from v4.67.0 to v5.59.0
  • Loading branch information
ewbankkit committed Jul 23, 2024
2 parents 3a37341 + 4cdea3f commit ae85642
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 111 deletions.
3 changes: 3 additions & 0 deletions .changelog/38476.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_elasticache_replication_group: Fix `error marshaling prior state` when upgrading from v4.67.0 to v5.59.0
```
174 changes: 63 additions & 111 deletions internal/service/elasticache/replication_group_migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import (

awstypes "github.com/aws/aws-sdk-go-v2/service/elasticache/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/enum"
tfmaps "github.com/hashicorp/terraform-provider-aws/internal/maps"
"github.com/hashicorp/terraform-provider-aws/internal/sdkv2/types/nullable"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
"github.com/hashicorp/terraform-provider-aws/names"
)

Expand All @@ -22,9 +20,20 @@ func replicationGroupStateUpgradeV1(ctx context.Context, rawState map[string]int
rawState = map[string]interface{}{}
}

// Set auth_token_update_strategy to new default value
// Set auth_token_update_strategy to new default value.
rawState["auth_token_update_strategy"] = awstypes.AuthTokenUpdateStrategyTypeRotate

// The v4.67.0 schema contained block attribute named 'cluster_mode'.
// It was removed at v5.0.0.
// The v5.59.0 schema introduced a new string attribute named 'cluster_mode'.
// Remove any trace of the old cluster_mode block.
for _, k := range tfmaps.Keys(rawState) {
if strings.HasPrefix(k, "cluster_mode.") {
delete(rawState, k)
}
}
delete(rawState, "cluster_mode")

return rawState, nil
}

Expand All @@ -48,17 +57,14 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
Computed: true,
},
"auth_token": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ValidateFunc: validReplicationGroupAuthToken,
ConflictsWith: []string{"user_group_ids"},
},
names.AttrAutoMinorVersionUpgrade: {
Type: nullable.TypeNullableBool,
Optional: true,
Computed: true,
ValidateFunc: nullable.ValidateTypeStringNullableBool,
Type: schema.TypeString,
Optional: true,
Sensitive: true,
},
names.AttrAutoMinorVersionUpgrade: { // nosemgrep:ci.semgrep.types.valid-nullable-bool
Type: nullable.TypeNullableBool,
Optional: true,
Computed: true,
},
"automatic_failover_enabled": {
Type: schema.TypeBool,
Expand All @@ -80,23 +86,20 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
ForceNew: true,
},
names.AttrDescription: {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringIsNotEmpty,
Type: schema.TypeString,
Optional: true,
Computed: true,
},
names.AttrEngine: {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: engineRedis,
ValidateFunc: validation.StringInSlice([]string{engineRedis}, true),
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: engineRedis,
},
names.AttrEngineVersion: {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validRedisVersionString,
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"engine_version_actual": {
Type: schema.TypeString,
Expand All @@ -107,24 +110,11 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
Optional: true,
ForceNew: true,
Computed: true,
ConflictsWith: []string{
"num_node_groups",
names.AttrParameterGroupName,
names.AttrEngine,
names.AttrEngineVersion,
"node_type",
"security_group_names",
"transit_encryption_enabled",
"at_rest_encryption_enabled",
"snapshot_arns",
"snapshot_name",
},
},
"ip_discovery": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateDiagFunc: enum.Validate[awstypes.IpDiscovery](),
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"log_delivery_configuration": {
Type: schema.TypeSet,
Expand All @@ -133,23 +123,20 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"destination_type": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: enum.Validate[awstypes.DestinationType](),
Type: schema.TypeString,
Required: true,
},
names.AttrDestination: {
Type: schema.TypeString,
Required: true,
},
"log_format": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: enum.Validate[awstypes.LogFormat](),
Type: schema.TypeString,
Required: true,
},
"log_type": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: enum.Validate[awstypes.LogType](),
Type: schema.TypeString,
Required: true,
},
},
},
Expand All @@ -158,71 +145,51 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
Type: schema.TypeString,
Optional: true,
Computed: true,
StateFunc: func(val interface{}) string {
// ElastiCache always changes the maintenance to lowercase
return strings.ToLower(val.(string))
},
ValidateFunc: verify.ValidOnceAWeekWindowFormat,
},
"member_clusters": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"multi_az_enabled": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"network_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateDiagFunc: enum.Validate[awstypes.NetworkType](),
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"node_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"notification_topic_arn": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidARN,
Type: schema.TypeString,
Optional: true,
},
"num_cache_clusters": {
Type: schema.TypeInt,
Computed: true,
Optional: true,
ConflictsWith: []string{"num_node_groups"},
Type: schema.TypeInt,
Computed: true,
Optional: true,
},
"num_node_groups": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ConflictsWith: []string{"num_cache_clusters", "global_replication_group_id"},
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
names.AttrParameterGroupName: {
Type: schema.TypeString,
Optional: true,
Computed: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return strings.HasPrefix(old, "global-datastore-")
},
},
names.AttrPort: {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// Suppress default Redis ports when not defined
if !d.IsNewResource() && new == "0" && old == defaultRedisPort {
return true
}
return false
},
},
"preferred_cache_cluster_azs": {
Type: schema.TypeList,
Expand All @@ -243,28 +210,22 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
Computed: true,
},
"replication_group_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateReplicationGroupID,
StateFunc: func(val interface{}) string {
return strings.ToLower(val.(string))
},
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"security_group_names": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
names.AttrSecurityGroupIDs: {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"snapshot_arns": {
Type: schema.TypeSet,
Expand All @@ -273,23 +234,16 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
// Note: Unlike aws_elasticache_cluster, this does not have a limit of 1 item.
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.All(
verify.ValidARN,
validation.StringDoesNotContainAny(","),
),
},
Set: schema.HashString,
},
"snapshot_retention_limit": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntAtMost(35),
Type: schema.TypeInt,
Optional: true,
},
"snapshot_window": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: verify.ValidOnceADayWindowFormat,
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"snapshot_name": {
Type: schema.TypeString,
Expand All @@ -311,11 +265,9 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
Computed: true,
},
"user_group_ids": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
ConflictsWith: []string{"auth_token"},
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
names.AttrKMSKeyID: {
Type: schema.TypeString,
Expand Down
39 changes: 39 additions & 0 deletions internal/service/elasticache/replication_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,45 @@ func TestAccElastiCacheReplicationGroup_stateUpgrade5270(t *testing.T) {
})
}

// https://github.com/hashicorp/terraform-provider-aws/issues/38464.
func TestAccElastiCacheReplicationGroup_stateUpgrade5590(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

var rg awstypes.ReplicationGroup
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_elasticache_replication_group.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.ElastiCacheServiceID),
CheckDestroy: testAccCheckReplicationGroupDestroy(ctx),
Steps: []resource.TestStep{
{
ExternalProviders: map[string]resource.ExternalProvider{
"aws": {
Source: "hashicorp/aws",
VersionConstraint: "4.67.0",
},
},
Config: testAccReplicationGroupConfig_basic(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckReplicationGroupExists(ctx, resourceName, &rg),
),
},
{
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Config: testAccReplicationGroupConfig_basic(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckReplicationGroupExists(ctx, resourceName, &rg),
),
},
},
})
}

func TestAccElastiCacheReplicationGroup_vpc(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
Expand Down

0 comments on commit ae85642

Please sign in to comment.