diff --git a/.changelog/32669.txt b/.changelog/32669.txt new file mode 100644 index 00000000000..fa34eff87c7 --- /dev/null +++ b/.changelog/32669.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_elasticache_parameter_group: Remove from state on resource Read if deleted outside of Terraform +``` \ No newline at end of file diff --git a/internal/service/elasticache/find.go b/internal/service/elasticache/find.go index 3371482ddf1..3469c30e284 100644 --- a/internal/service/elasticache/find.go +++ b/internal/service/elasticache/find.go @@ -190,7 +190,8 @@ func FindParameterGroupByName(ctx context.Context, conn *elasticache.ElastiCache input := elasticache.DescribeCacheParameterGroupsInput{ CacheParameterGroupName: aws.String(name), } - out, err := conn.DescribeCacheParameterGroupsWithContext(ctx, &input) + + output, err := conn.DescribeCacheParameterGroupsWithContext(ctx, &input) if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeCacheParameterGroupNotFoundFault) { return nil, &retry.NotFoundError{ @@ -198,18 +199,16 @@ func FindParameterGroupByName(ctx context.Context, conn *elasticache.ElastiCache LastRequest: input, } } + if err != nil { return nil, err } - switch count := len(out.CacheParameterGroups); count { - case 0: + if output == nil { return nil, tfresource.NewEmptyResultError(input) - case 1: - return out.CacheParameterGroups[0], nil - default: - return nil, tfresource.NewTooManyResultsError(count, input) } + + return tfresource.AssertSinglePtrResult(output.CacheParameterGroups) } type redisParameterGroupFilter func(group *elasticache.CacheParameterGroup) bool diff --git a/internal/service/elasticache/parameter_group.go b/internal/service/elasticache/parameter_group.go index a0ce4260fd8..f1545bec927 100644 --- a/internal/service/elasticache/parameter_group.go +++ b/internal/service/elasticache/parameter_group.go @@ -34,32 +34,34 @@ func ResourceParameterGroup() *schema.Resource { ReadWithoutTimeout: resourceParameterGroupRead, UpdateWithoutTimeout: resourceParameterGroupUpdate, DeleteWithoutTimeout: resourceParameterGroupDelete, + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + Schema: map[string]*schema.Schema{ - "name": { + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "description": { Type: schema.TypeString, + Optional: true, ForceNew: true, - Required: true, - StateFunc: func(val interface{}) string { - return strings.ToLower(val.(string)) - }, + Default: "Managed by Terraform", }, "family": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "description": { + "name": { Type: schema.TypeString, - Optional: true, ForceNew: true, - Default: "Managed by Terraform", - }, - "arn": { - Type: schema.TypeString, - Computed: true, + Required: true, + StateFunc: func(val interface{}) string { + return strings.ToLower(val.(string)) + }, }, "parameter": { Type: schema.TypeSet, @@ -81,6 +83,7 @@ func ResourceParameterGroup() *schema.Resource { names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), }, + CustomizeDiff: verify.SetTagsDiff, } } @@ -89,29 +92,29 @@ func resourceParameterGroupCreate(ctx context.Context, d *schema.ResourceData, m var diags diag.Diagnostics conn := meta.(*conns.AWSClient).ElastiCacheConn(ctx) - input := elasticache.CreateCacheParameterGroupInput{ - CacheParameterGroupName: aws.String(d.Get("name").(string)), + name := d.Get("name").(string) + input := &elasticache.CreateCacheParameterGroupInput{ + CacheParameterGroupName: aws.String(name), CacheParameterGroupFamily: aws.String(d.Get("family").(string)), Description: aws.String(d.Get("description").(string)), Tags: getTagsIn(ctx), } - resp, err := conn.CreateCacheParameterGroupWithContext(ctx, &input) + output, err := conn.CreateCacheParameterGroupWithContext(ctx, input) if input.Tags != nil && verify.ErrorISOUnsupported(conn.PartitionID, err) { log.Printf("[WARN] failed creating ElastiCache Parameter Group with tags: %s. Trying create without tags.", err) input.Tags = nil - resp, err = conn.CreateCacheParameterGroupWithContext(ctx, &input) + output, err = conn.CreateCacheParameterGroupWithContext(ctx, input) } if err != nil { - return sdkdiag.AppendErrorf(diags, "creating ElastiCache Parameter Group: %s", err) + return sdkdiag.AppendErrorf(diags, "creating ElastiCache Parameter Group (%s): %s", name, err) } - d.SetId(aws.StringValue(resp.CacheParameterGroup.CacheParameterGroupName)) - d.Set("arn", resp.CacheParameterGroup.ARN) - log.Printf("[INFO] ElastiCache Parameter Group ID: %s", d.Id()) + d.SetId(aws.StringValue(output.CacheParameterGroup.CacheParameterGroupName)) + d.Set("arn", output.CacheParameterGroup.ARN) return append(diags, resourceParameterGroupUpdate(ctx, d, meta)...) } @@ -121,27 +124,35 @@ func resourceParameterGroupRead(ctx context.Context, d *schema.ResourceData, met conn := meta.(*conns.AWSClient).ElastiCacheConn(ctx) parameterGroup, err := FindParameterGroupByName(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] ElastiCache Parameter Group (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags + } + if err != nil { - return sdkdiag.AppendErrorf(diags, "unable to find ElastiCache Parameter Group (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "reading ElastiCache Parameter Group (%s): %s", d.Id(), err) } - d.Set("name", parameterGroup.CacheParameterGroupName) - d.Set("family", parameterGroup.CacheParameterGroupFamily) - d.Set("description", parameterGroup.Description) d.Set("arn", parameterGroup.ARN) + d.Set("description", parameterGroup.Description) + d.Set("family", parameterGroup.CacheParameterGroupFamily) + d.Set("name", parameterGroup.CacheParameterGroupName) - // Only include user customized parameters as there's hundreds of system/default ones - describeParametersOpts := elasticache.DescribeCacheParametersInput{ + // Only include user customized parameters as there's hundreds of system/default ones. + input := &elasticache.DescribeCacheParametersInput{ CacheParameterGroupName: aws.String(d.Id()), Source: aws.String("user"), } - describeParametersResp, err := conn.DescribeCacheParametersWithContext(ctx, &describeParametersOpts) + output, err := conn.DescribeCacheParametersWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "reading ElastiCache Parameter Group (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "reading ElastiCache Parameter Group (%s) parameters: %s", d.Id(), err) } - d.Set("parameter", FlattenParameters(describeParametersResp.Parameters)) + d.Set("parameter", FlattenParameters(output.Parameters)) return diags } diff --git a/internal/service/elasticache/parameter_group_test.go b/internal/service/elasticache/parameter_group_test.go index 11e028e9121..b4b0e93762c 100644 --- a/internal/service/elasticache/parameter_group_test.go +++ b/internal/service/elasticache/parameter_group_test.go @@ -11,7 +11,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/elasticache" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -19,13 +18,14 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfelasticache "github.com/hashicorp/terraform-provider-aws/internal/service/elasticache" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccElastiCacheParameterGroup_basic(t *testing.T) { ctx := acctest.Context(t) var v elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -53,11 +53,35 @@ func TestAccElastiCacheParameterGroup_basic(t *testing.T) { }) } +func TestAccElastiCacheParameterGroup_disappears(t *testing.T) { + ctx := acctest.Context(t) + var v elasticache.CacheParameterGroup + resourceName := "aws_elasticache_parameter_group.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccParameterGroupConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfelasticache.ResourceParameterGroup(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccElastiCacheParameterGroup_addParameter(t *testing.T) { ctx := acctest.Context(t) var v elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -105,7 +129,7 @@ func TestAccElastiCacheParameterGroup_removeAllParameters(t *testing.T) { ctx := acctest.Context(t) var v elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -145,7 +169,7 @@ func TestAccElastiCacheParameterGroup_RemoveReservedMemoryParameter_allParameter ctx := acctest.Context(t) var cacheParameterGroup1 elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -186,7 +210,7 @@ func TestAccElastiCacheParameterGroup_RemoveReservedMemoryParameter_remainingPar ctx := acctest.Context(t) var cacheParameterGroup1 elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -235,7 +259,7 @@ func TestAccElastiCacheParameterGroup_switchReservedMemoryParameter(t *testing.T ctx := acctest.Context(t) var cacheParameterGroup1 elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -280,7 +304,7 @@ func TestAccElastiCacheParameterGroup_updateReservedMemoryParameter(t *testing.T ctx := acctest.Context(t) var cacheParameterGroup1 elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -352,7 +376,7 @@ func TestAccElastiCacheParameterGroup_description(t *testing.T) { ctx := acctest.Context(t) var v elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -380,7 +404,7 @@ func TestAccElastiCacheParameterGroup_tags(t *testing.T) { ctx := acctest.Context(t) var cacheParameterGroup1 elasticache.CacheParameterGroup resourceName := "aws_elasticache_parameter_group.test" - rName := fmt.Sprintf("parameter-group-test-terraform-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -430,37 +454,17 @@ func testAccCheckParameterGroupDestroy(ctx context.Context) resource.TestCheckFu continue } - resp, err := conn.DescribeCacheParameterGroupsWithContext(ctx, &elasticache.DescribeCacheParameterGroupsInput{ - CacheParameterGroupName: aws.String(rs.Primary.ID), - }) + _, err := tfelasticache.FindParameterGroupByName(ctx, conn, rs.Primary.ID) - if err == nil { - if len(resp.CacheParameterGroups) != 0 && - *resp.CacheParameterGroups[0].CacheParameterGroupName == rs.Primary.ID { - return fmt.Errorf("Cache Parameter Group still exists") - } + if tfresource.NotFound(err) { + continue } - if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeCacheParameterGroupNotFoundFault) { - return nil - } if err != nil { return err } - } - - return nil - } -} -func testAccCheckParameterGroupAttributes(v *elasticache.CacheParameterGroup, rName string) resource.TestCheckFunc { - return func(s *terraform.State) error { - if *v.CacheParameterGroupName != rName { - return fmt.Errorf("bad name: %#v", v.CacheParameterGroupName) - } - - if *v.CacheParameterGroupFamily != "redis2.8" { - return fmt.Errorf("bad family: %#v", v.CacheParameterGroupFamily) + return fmt.Errorf("ElastiCache Parameter Group %s still exists", rs.Primary.ID) } return nil @@ -475,27 +479,32 @@ func testAccCheckParameterGroupExists(ctx context.Context, n string, v *elastica } if rs.Primary.ID == "" { - return fmt.Errorf("No Cache Parameter Group ID is set") + return fmt.Errorf("No ElastiCache Parameter Group ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).ElastiCacheConn(ctx) - opts := elasticache.DescribeCacheParameterGroupsInput{ - CacheParameterGroupName: aws.String(rs.Primary.ID), - } - - resp, err := conn.DescribeCacheParameterGroupsWithContext(ctx, &opts) + output, err := tfelasticache.FindParameterGroupByName(ctx, conn, rs.Primary.ID) if err != nil { return err } - if len(resp.CacheParameterGroups) != 1 || - *resp.CacheParameterGroups[0].CacheParameterGroupName != rs.Primary.ID { - return fmt.Errorf("Cache Parameter Group not found") + *v = *output + + return nil + } +} + +func testAccCheckParameterGroupAttributes(v *elasticache.CacheParameterGroup, rName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + if *v.CacheParameterGroupName != rName { + return fmt.Errorf("bad name: %#v", v.CacheParameterGroupName) } - *v = *resp.CacheParameterGroups[0] + if *v.CacheParameterGroupFamily != "redis2.8" { + return fmt.Errorf("bad family: %#v", v.CacheParameterGroupFamily) + } return nil } @@ -505,7 +514,7 @@ func testAccParameterGroupConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_elasticache_parameter_group" "test" { family = "redis2.8" - name = %q + name = %[1]q } `, rName) } @@ -513,9 +522,9 @@ resource "aws_elasticache_parameter_group" "test" { func testAccParameterGroupConfig_description(rName, description string) string { return fmt.Sprintf(` resource "aws_elasticache_parameter_group" "test" { - description = %q + description = %[1]q family = "redis2.8" - name = %q + name = %[2]q } `, description, rName) } @@ -523,12 +532,12 @@ resource "aws_elasticache_parameter_group" "test" { func testAccParameterGroupConfig_1(rName, family, parameterName1, parameterValue1 string) string { return fmt.Sprintf(` resource "aws_elasticache_parameter_group" "test" { - family = %q - name = %q + family = %[1]q + name = %[2]q parameter { - name = %q - value = %q + name = %[3]q + value = %[4]q } } `, family, rName, parameterName1, parameterValue1) @@ -537,17 +546,17 @@ resource "aws_elasticache_parameter_group" "test" { func testAccParameterGroupConfig_2(rName, family, parameterName1, parameterValue1, parameterName2, parameterValue2 string) string { return fmt.Sprintf(` resource "aws_elasticache_parameter_group" "test" { - family = %q - name = %q + family = %[1]q + name = %[2]q parameter { - name = %q - value = %q + name = %[3]q + value = %[4]q } parameter { - name = %q - value = %q + name = %[5]q + value = %[6]q } } `, family, rName, parameterName1, parameterValue1, parameterName2, parameterValue2)