Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/aws_elasticache_replication_group: Fix error marshaling prior state when upgrading from v4.67.0 to v5.59.0 #38476

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading