Skip to content
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/42336.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:breaking-change
resource/aws_elasticache_replication_group: `auth_token_update_strategy` no longer has a default value. If `auth_token` is set, `auth_token_update_strategy` must also be explicitly configured.
```
13 changes: 10 additions & 3 deletions internal/service/elasticache/replication_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func resourceReplicationGroup() *schema.Resource {
Type: schema.TypeString,
Optional: true,
ValidateDiagFunc: enum.Validate[awstypes.AuthTokenUpdateStrategyType](),
Default: awstypes.AuthTokenUpdateStrategyTypeRotate,
RequiredWith: []string{"auth_token"},
},
names.AttrAutoMinorVersionUpgrade: {
Type: nullable.TypeNullableBool,
Expand Down Expand Up @@ -371,7 +371,7 @@ func resourceReplicationGroup() *schema.Resource {
},
},

SchemaVersion: 2,
SchemaVersion: 3,
// SchemaVersion: 1 did not include any state changes via MigrateState.
// Perform a no-operation state upgrade for Terraform 0.12 compatibility.
// Future state migrations should be performed with StateUpgraders.
Expand All @@ -386,9 +386,16 @@ func resourceReplicationGroup() *schema.Resource {
// must be written to state via a state upgrader.
{
Type: resourceReplicationGroupConfigV1().CoreConfigSchema().ImpliedType(),
Upgrade: replicationGroupStateUpgradeV1,
Upgrade: replicationGroupStateUpgradeFromV1,
Version: 1,
},
// v6.0.0 removed the default auth_token_update_strategy value. To prevent
// differences, the default value is removed when auth_token is not set.
{
Type: resourceReplicationGroupConfigV2().CoreConfigSchema().ImpliedType(),
Upgrade: replicationGroupStateUpgradeFromV2,
Version: 2,
},
},

Timeouts: &schema.ResourceTimeout{
Expand Down
37 changes: 36 additions & 1 deletion internal/service/elasticache/replication_group_migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/hashicorp/terraform-provider-aws/names"
)

func replicationGroupStateUpgradeV1(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) {
func replicationGroupStateUpgradeFromV1(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) {
if rawState == nil {
rawState = map[string]any{}
}
Expand Down Expand Up @@ -283,3 +283,38 @@ func resourceReplicationGroupConfigV1() *schema.Resource {
},
}
}

func replicationGroupStateUpgradeFromV2(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) {
if rawState == nil {
rawState = map[string]any{}
}

// Remove auth_token_update_strategy default value if auth_token is not set
if v, ok := rawState["auth_token"].(string); !ok || v == "" {
delete(rawState, "auth_token_update_strategy")
}

return rawState, nil
}

func resourceReplicationGroupConfigV2() *schema.Resource {
s := resourceReplicationGroupConfigV1()

// Attributes added in V2 of the schema
s.Schema["auth_token_update_strategy"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
}
s.Schema["cluster_mode"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
}
s.Schema["transit_encryption_mode"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
}

return s
}
113 changes: 113 additions & 0 deletions internal/service/elasticache/replication_group_migrate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package elasticache

import (
"reflect"
"testing"

awstypes "github.com/aws/aws-sdk-go-v2/service/elasticache/types"
)

func Test_replicationGroupStateUpgradeFromV1(t *testing.T) {
t.Parallel()

tests := []struct {
name string
rawState map[string]any
want map[string]any
wantErr bool
}{
{
name: "empty rawState",
rawState: nil,
want: map[string]any{
"auth_token_update_strategy": awstypes.AuthTokenUpdateStrategyTypeRotate,
},
},
{
name: "auth_token",
rawState: map[string]any{
"auth_token": "foo",
},
want: map[string]any{
"auth_token": "foo",
"auth_token_update_strategy": awstypes.AuthTokenUpdateStrategyTypeRotate,
},
},
{
name: "cluster_mode block",
rawState: map[string]any{
"cluster_mode.num_node_groups": "2",
"cluster_mode.replicas_per_node_group": "2",
},
want: map[string]any{
"auth_token_update_strategy": awstypes.AuthTokenUpdateStrategyTypeRotate,
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := replicationGroupStateUpgradeFromV1(t.Context(), tt.rawState, nil)
if (err != nil) != tt.wantErr {
t.Errorf("replicationGroupStateUpgradeFromV1() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("replicationGroupStateUpgradeFromV1() = %v, want %v", got, tt.want)
}
})
}
}

func Test_replicationGroupStateUpgradeFromV2(t *testing.T) {
t.Parallel()

tests := []struct {
name string
rawState map[string]any
want map[string]any
wantErr bool
}{
{
name: "empty rawState",
rawState: nil,
want: map[string]any{},
},
{
name: "no auth_token, default auth_token_update_strategy",
rawState: map[string]any{
"auth_token_update_strategy": string(awstypes.AuthTokenUpdateStrategyTypeRotate),
},
want: map[string]any{},
},
{
name: "auth_token and auth_token_update_strategy",
rawState: map[string]any{
"auth_token": "foo",
"auth_token_update_strategy": string(awstypes.AuthTokenUpdateStrategyTypeSet),
},
want: map[string]any{
"auth_token": "foo",
"auth_token_update_strategy": string(awstypes.AuthTokenUpdateStrategyTypeSet),
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := replicationGroupStateUpgradeFromV2(t.Context(), tt.rawState, nil)
if (err != nil) != tt.wantErr {
t.Errorf("replicationGroupStateUpgradeFromV2() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("replicationGroupStateUpgradeFromV2() = %v, want %v", got, tt.want)
}
})
}
}
64 changes: 61 additions & 3 deletions internal/service/elasticache/replication_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,11 @@ func TestAccElastiCacheReplicationGroup_disappears(t *testing.T) {
acctest.CheckResourceDisappears(ctx, acctest.Provider, tfelasticache.ResourceReplicationGroup(), resourceName),
),
ExpectNonEmptyPlan: true,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate),
},
},
},
},
})
Expand Down Expand Up @@ -702,7 +707,51 @@ func TestAccElastiCacheReplicationGroup_authToken(t *testing.T) {
})
}

func TestAccElastiCacheReplicationGroup_stateUpgrade5270(t *testing.T) {
func TestAccElastiCacheReplicationGroup_upgrade_6_0_0(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: "5.95.0",
},
},
Config: testAccReplicationGroupConfig_basic_engine(rName, "redis"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckReplicationGroupExists(ctx, resourceName, &rg),
),
},
{
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Config: testAccReplicationGroupConfig_basic_engine(rName, "redis"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckReplicationGroupExists(ctx, resourceName, &rg),
),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
},
},
})
}

// At v5.26.0 the resource's schema is v1 and auth_token_update_strategy is not an argument
func TestAccElastiCacheReplicationGroup_upgrade_5_27_0(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
Expand All @@ -718,7 +767,6 @@ func TestAccElastiCacheReplicationGroup_stateUpgrade5270(t *testing.T) {
CheckDestroy: testAccCheckReplicationGroupDestroy(ctx),
Steps: []resource.TestStep{
{
// At v5.26.0 the resource's schema is v1 and auth_token_update_strategy is not an argument
ExternalProviders: map[string]resource.ExternalProvider{
"aws": {
Source: "hashicorp/aws",
Expand All @@ -736,13 +784,18 @@ func TestAccElastiCacheReplicationGroup_stateUpgrade5270(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckReplicationGroupExists(ctx, resourceName, &rg),
),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
},
},
})
}

// https://github.com/hashicorp/terraform-provider-aws/issues/38464.
func TestAccElastiCacheReplicationGroup_stateUpgrade5590(t *testing.T) {
func TestAccElastiCacheReplicationGroup_upgrade_4_68_0(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
Expand Down Expand Up @@ -775,6 +828,11 @@ func TestAccElastiCacheReplicationGroup_stateUpgrade5590(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckReplicationGroupExists(ctx, resourceName, &rg),
),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
},
},
})
Expand Down
6 changes: 6 additions & 0 deletions website/docs/guides/version-6-upgrade.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Upgrade topics:
- [resource/aws_cloudfront_response_headers_policy](#resourceaws_cloudfront_response_headers_policy)
- [resource/aws_dx_gateway_association](#resourceaws_dx_gateway_association)
- [resource/aws_ecs_task_definition](#resourceaws_ecs_task_definition)
- [resource/aws_elasticache_replication_group](#resourceaws_elasticache_replication_group)
- [resource/aws_eks_addon](#resourceaws_eks_addon)
- [resource/aws_guardduty_organization_configuration](#resourceaws_guardduty_organization_configuration)
- [resource/aws_instance](#resourceaws_instance)
Expand Down Expand Up @@ -319,6 +320,11 @@ Use the `associated_gateway_id` attribute instead.

Remove `inference_accelerator` from your configuration—it no longer exists. Amazon Elastic Inference reached end of life in April 2024.

## resource/aws_elasticache_replication_group

The `auth_token_update_strategy` argument no longer has a default value.
If `auth_token` is set, this argument must also be explicitly configured.

## resource/aws_eks_addon

The `resolve_conflicts` argument has been removed. Use `resolve_conflicts_on_create` and `resolve_conflicts_on_update` instead.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ The following arguments are optional:
When `engine` is `redis`, default is `false`.
When `engine` is `valkey`, default is `true`.
* `auth_token` - (Optional) Password used to access a password protected server. Can be specified only if `transit_encryption_enabled = true`.
* `auth_token_update_strategy` - (Optional) Strategy to use when updating the `auth_token`. Valid values are `SET`, `ROTATE`, and `DELETE`. Defaults to `ROTATE`.
* `auth_token_update_strategy` - (Optional) Strategy to use when updating the `auth_token`. Valid values are `SET`, `ROTATE`, and `DELETE`. Required if `auth_token` is set.
* `auto_minor_version_upgrade` - (Optional) Specifies whether minor version engine upgrades will be applied automatically to the underlying Cache Cluster instances during the maintenance window.
Only supported for engine types `"redis"` and `"valkey"` and if the engine version is 6 or higher.
Defaults to `true`.
Expand Down
Loading