From 4b57a5a7c0c1ab31f1c28a8fc7c2b074b1e40e10 Mon Sep 17 00:00:00 2001 From: Aurel Canciu Date: Fri, 18 Oct 2024 00:53:51 +0200 Subject: [PATCH] Handle redis -> valkey engine updates on aws_elasticache_serverless_cache Fixes #39711 Signed-off-by: Aurel Canciu --- .../service/elasticache/serverless_cache.go | 15 +++- .../elasticache/serverless_cache_test.go | 90 ++++++++++--------- 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/internal/service/elasticache/serverless_cache.go b/internal/service/elasticache/serverless_cache.go index 112547de5cb..bb7f36bf1ea 100644 --- a/internal/service/elasticache/serverless_cache.go +++ b/internal/service/elasticache/serverless_cache.go @@ -24,6 +24,7 @@ import ( "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-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-provider-aws/internal/errs" @@ -94,7 +95,11 @@ func (r *serverlessCacheResource) Schema(ctx context.Context, request resource.S names.AttrEngine: schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.RequiresReplaceIf(func(ctx context.Context, sr planmodifier.StringRequest, rrifr *stringplanmodifier.RequiresReplaceIfFuncResponse) { + configIsRedis := sr.ConfigValue.Equal(basetypes.NewStringValue(engineRedis)) + planIsValkey := sr.PlanValue.Equal(basetypes.NewStringValue(engineValkey)) + rrifr.RequiresReplace = !(configIsRedis && planIsValkey) + }, "Replace engine diff", "Replace engine diff"), }, }, "full_engine_version": schema.StringAttribute{ @@ -338,6 +343,14 @@ func (r *serverlessCacheResource) Update(ctx context.Context, request resource.U if serverlessCacheHasChanges(ctx, new, old) { input := &elasticache.ModifyServerlessCacheInput{} response.Diagnostics.Append(fwflex.Expand(ctx, new, input)...) + // Unset engine related stuff to prevent the following error: + // This API supports only cross-engine upgrades to Valkey engine currently. + if new.Engine.Equal(old.Engine) { + input.Engine = nil + } + if new.MajorEngineVersion.Equal(old.MajorEngineVersion) { + input.MajorEngineVersion = nil + } if response.Diagnostics.HasError() { return } diff --git a/internal/service/elasticache/serverless_cache_test.go b/internal/service/elasticache/serverless_cache_test.go index 59923d95b86..e11316b07f5 100644 --- a/internal/service/elasticache/serverless_cache_test.go +++ b/internal/service/elasticache/serverless_cache_test.go @@ -21,49 +21,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccElastiCacheServerlessCache_basic(t *testing.T) { - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_elasticache_serverless_cache.test" - var serverlessElasticCache awstypes.ServerlessCache - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.ElastiCacheServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: resource.ComposeAggregateTestCheckFunc( - testAccCheckServerlessCacheDestroy(ctx), - ), - Steps: []resource.TestStep{ - { - Config: testAccServerlessCacheConfig_basic(rName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckServerlessCacheExists(ctx, resourceName, &serverlessElasticCache), - resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), - resource.TestCheckResourceAttrSet(resourceName, "cache_usage_limits.#"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrCreateTime), - resource.TestCheckResourceAttrSet(resourceName, "endpoint.#"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), - resource.TestCheckResourceAttrSet(resourceName, "full_engine_version"), - resource.TestCheckResourceAttrSet(resourceName, "reader_endpoint.#"), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), - resource.TestCheckResourceAttrSet(resourceName, "subnet_ids.#"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - func TestAccElastiCacheServerlessCache_basicRedis(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -449,6 +406,42 @@ func TestAccElastiCacheServerlessCache_updatesc(t *testing.T) { }) } +func TestAccElastiCacheServerlessCache_update_RedisToValkey(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_elasticache_serverless_cache.test" + var v1, v2 awstypes.ServerlessCache + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ElastiCacheServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: resource.ComposeAggregateTestCheckFunc( + testAccCheckServerlessCacheDestroy(ctx), + ), + Steps: []resource.TestStep{ + { + Config: testAccServerlessCacheConfig_basicRedis(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckServerlessCacheExists(ctx, resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, names.AttrEngine, "redis"), + ), + }, + { + Config: testAccServerlessCacheConfig_updateValkey(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckServerlessCacheExists(ctx, resourceName, &v2), + resource.TestCheckResourceAttr(resourceName, names.AttrEngine, "valkey"), + ), + }, + }, + }) +} + func TestAccElastiCacheServerlessCache_disappears(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -624,6 +617,15 @@ resource "aws_elasticache_serverless_cache" "test" { `, rName) } +func testAccServerlessCacheConfig_updateValkey(rName string) string { + return fmt.Sprintf(` +resource "aws_elasticache_serverless_cache" "test" { + engine = "valkey" + name = %[1]q +} +`, rName) +} + func testAccServerlessCacheConfig_full(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` resource "aws_elasticache_serverless_cache" "test" { @@ -739,7 +741,7 @@ resource "aws_elasticache_serverless_cache" "test" { } daily_snapshot_time = "09:00" - description = "Test Full Redis Attributes" + description = "Test Full Valkey Attributes" kms_key_id = aws_kms_key.test.arn major_engine_version = "7" snapshot_retention_limit = 1