From 974c6f9d56cd127e0353d3caae671613256d77cb Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Mon, 16 Jan 2023 23:56:50 -0800 Subject: [PATCH 01/13] Add authentication_mode to aws_elasticache_user --- internal/service/elasticache/user.go | 56 ++++++- internal/service/elasticache/user_test.go | 189 ++++++++++++++++++++++ 2 files changed, 243 insertions(+), 2 deletions(-) diff --git a/internal/service/elasticache/user.go b/internal/service/elasticache/user.go index 7cfc7f12ecf1..bb25d9cf449f 100644 --- a/internal/service/elasticache/user.go +++ b/internal/service/elasticache/user.go @@ -38,6 +38,34 @@ func ResourceUser() *schema.Resource { Optional: true, Computed: true, }, + "authentication_mode": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "passwords": { + Type: schema.TypeSet, + Optional: true, + MinItems: 1, + Set: schema.HashString, + Sensitive: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "password_count": { + Type: schema.TypeInt, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(elasticache.InputAuthenticationType_Values(), false), + }, + }, + }, + }, "engine": { Type: schema.TypeString, Required: true, @@ -83,7 +111,11 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error { tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) input := &elasticache.CreateUserInput{ - AccessString: aws.String(d.Get("access_string").(string)), + AccessString: aws.String(d.Get("access_string").(string)), + AuthenticationMode: &elasticache.AuthenticationMode{ + Passwords: flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)), + Type: aws.String(d.Get("authentication_mode.0.type").(string)), + }, Engine: aws.String(d.Get("engine").(string)), NoPasswordRequired: aws.Bool(d.Get("no_password_required").(bool)), UserId: aws.String(d.Get("user_id").(string)), @@ -147,10 +179,23 @@ func resourceUserRead(d *schema.ResourceData, meta interface{}) error { } d.Set("access_string", resp.AccessString) + d.Set("arn", resp.ARN) + + if v := resp.Authentication; v != nil { + authenticationMode := map[string]interface{}{ + "passwords": d.Get("authentication_mode.0.passwords"), + "password_count": aws.Int64Value(v.PasswordCount), + "type": aws.StringValue(v.Type), + } + + if err := d.Set("authentication_mode", []interface{}{authenticationMode}); err != nil { + return fmt.Errorf("failed to set authentication_mode of ElastiCache User (%s): %s", d.Id(), err) + } + } + d.Set("engine", resp.Engine) d.Set("user_id", resp.UserId) d.Set("user_name", resp.UserName) - d.Set("arn", resp.ARN) tags, err := ListTags(conn, aws.StringValue(resp.ARN)) @@ -193,6 +238,13 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error { hasChange = true } + if d.HasChange("authentication_mode") { + req.AuthenticationMode = &elasticache.AuthenticationMode{ + Passwords: flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)), + Type: aws.String(d.Get("authentication_mode.0.type").(string)), + } + } + if d.HasChange("no_password_required") { req.NoPasswordRequired = aws.Bool(d.Get("no_password_required").(bool)) hasChange = true diff --git a/internal/service/elasticache/user_test.go b/internal/service/elasticache/user_test.go index 7878eda1194b..0510867a5cb9 100644 --- a/internal/service/elasticache/user_test.go +++ b/internal/service/elasticache/user_test.go @@ -50,6 +50,99 @@ func TestAccElastiCacheUser_basic(t *testing.T) { }) } +func TestAccElastiCacheUserWithPasswordAuthMode_basic(t *testing.T) { + var user elasticache.User + rName := sdkacctest.RandomWithPrefix("tf-acc") + resourceName := "aws_elasticache_user.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccUserConfigWithPasswordAuthMode_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckUserExists(resourceName, &user), + resource.TestCheckResourceAttr(resourceName, "user_id", rName), + resource.TestCheckResourceAttr(resourceName, "user_name", "username1"), + resource.TestCheckResourceAttr(resourceName, "engine", "redis"), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.password_count", "1"), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.passwords.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "authentication_mode.0.passwords.*", "aaaaaaaaaaaaaaaa"), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "password"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccElastiCacheUserWithIamAuthMode_basic(t *testing.T) { + var user elasticache.User + rName := sdkacctest.RandomWithPrefix("tf-acc") + resourceName := "aws_elasticache_user.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccUserConfigWithIamAuthMode_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckUserExists(resourceName, &user), + resource.TestCheckResourceAttr(resourceName, "user_id", rName), + resource.TestCheckResourceAttr(resourceName, "user_name", "username1"), + resource.TestCheckResourceAttr(resourceName, "engine", "redis"), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "iam"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccElastiCacheUserWithNoPassRequiredAuthMode_basic(t *testing.T) { + var user elasticache.User + rName := sdkacctest.RandomWithPrefix("tf-acc") + resourceName := "aws_elasticache_user.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccUserConfigWithNoPassRequiredAuthMode_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckUserExists(resourceName, &user), + resource.TestCheckResourceAttr(resourceName, "user_id", rName), + resource.TestCheckResourceAttr(resourceName, "user_name", "username1"), + resource.TestCheckResourceAttr(resourceName, "engine", "redis"), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "no-password-required"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccElastiCacheUser_update(t *testing.T) { var user elasticache.User rName := sdkacctest.RandomWithPrefix("tf-acc") @@ -87,6 +180,40 @@ func TestAccElastiCacheUser_update(t *testing.T) { }) } +func TestAccElastiCacheUserWithPasswordAuthMode_update_password(t *testing.T) { + var user elasticache.User + rName := sdkacctest.RandomWithPrefix("tf-acc") + resourceName := "aws_elasticache_user.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccUserConfigWithPasswordAuthMode_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckUserExists(resourceName, &user), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.password_count", "1"), + ), + }, + { + Config: testAccUserConfigWithPasswordAuthMode_update(rName, "bbbbbbbbbbbbbbbb", "cccccccccccc"), + Check: resource.ComposeTestCheckFunc( + testAccCheckUserExists(resourceName, &user), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.password_count", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccElastiCacheUser_tags(t *testing.T) { var user elasticache.User rName := sdkacctest.RandomWithPrefix("tf-acc") @@ -230,6 +357,52 @@ resource "aws_elasticache_user" "test" { `, rName)) } +func testAccUserConfigWithPasswordAuthMode_basic(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +resource "aws_elasticache_user" "test" { + user_id = %[1]q + user_name = "username1" + access_string = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember" + engine = "REDIS" + + authentication_mode { + type = "password" + passwords = ["aaaaaaaaaaaaaaaa"] + } +} +`, rName)) +} + +func testAccUserConfigWithIamAuthMode_basic(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +resource "aws_elasticache_user" "test" { + user_id = %[1]q + user_name = "username1" + access_string = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember" + engine = "REDIS" + + authentication_mode { + type = "iam" + } +} +`, rName)) +} + +func testAccUserConfigWithNoPassRequiredAuthMode_basic(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +resource "aws_elasticache_user" "test" { + user_id = %[1]q + user_name = "username1" + access_string = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember" + engine = "REDIS" + + authentication_mode { + type = "no-password-required" + } +} +`, rName)) +} + func testAccUserConfig_update(rName string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_elasticache_user" "test" { @@ -242,6 +415,22 @@ resource "aws_elasticache_user" "test" { `, rName)) } +func testAccUserConfigWithPasswordAuthMode_update(rName string, password1 string, password2 string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +resource "aws_elasticache_user" "test" { + user_id = %[1]q + user_name = "username1" + access_string = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember" + engine = "REDIS" + + authentication_mode { + type = "password" + passwords = [%[2]q, %[3]q] + } +} +`, rName, password1, password2)) +} + func testAccUserConfig_tags(rName, tagKey, tagValue string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_elasticache_user" "test" { From 0d0895f418962f781d6115c785655b34fb6bacc7 Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Tue, 17 Jan 2023 00:45:48 -0800 Subject: [PATCH 02/13] add changelog --- .changelog/28928.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/28928.txt diff --git a/.changelog/28928.txt b/.changelog/28928.txt new file mode 100644 index 000000000000..05fdb4c35eb1 --- /dev/null +++ b/.changelog/28928.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_elasticache_user: Add `authentication_mode` argument +``` \ No newline at end of file From 7eb57aa6a277689e08ccd26ae75b25f035335ea5 Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Tue, 17 Jan 2023 01:17:17 -0800 Subject: [PATCH 03/13] doc changes --- website/docs/r/elasticache_user.html.markdown | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/website/docs/r/elasticache_user.html.markdown b/website/docs/r/elasticache_user.html.markdown index bc9efdea0eee..13717118f2c5 100644 --- a/website/docs/r/elasticache_user.html.markdown +++ b/website/docs/r/elasticache_user.html.markdown @@ -25,6 +25,19 @@ resource "aws_elasticache_user" "test" { } ``` +```terraform +resource "aws_elasticache_user" "test" { + user_id = "testUserId" + user_name = "testUserName" + access_string = "on ~* +@all" + engine = "REDIS" + + authentication_mode { + type = "iam" + } +} +``` + ## Argument Reference The following arguments are required: @@ -36,10 +49,16 @@ The following arguments are required: The following arguments are optional: +* `authentication_mode` - (Optional) Denotes the user's authentication properties. Detailed below. * `no_password_required` - (Optional) Indicates a password is not required for this user. * `passwords` - (Optional) Passwords used for this user. You can create up to two passwords for each user. * `tags` - (Optional) A list of tags to be added to this resource. A tag is a key-value pair. +### authentication_mode Configuration Block + +* `passwords` - (Optional) Specifies the passwords to use for authentication if `type` is set to `password`. +* `type` - (Required) Specifies the authentication type. Possible options are: `password`, `no-password-required` or `iam`. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 989085804e46e6caa10bd9bbe0c752f26d5bf485 Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Fri, 3 Feb 2023 17:37:57 -0800 Subject: [PATCH 04/13] fix markdown --- website/docs/r/elasticache_user.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/elasticache_user.html.markdown b/website/docs/r/elasticache_user.html.markdown index 13717118f2c5..514303c0aca9 100644 --- a/website/docs/r/elasticache_user.html.markdown +++ b/website/docs/r/elasticache_user.html.markdown @@ -33,7 +33,7 @@ resource "aws_elasticache_user" "test" { engine = "REDIS" authentication_mode { - type = "iam" + type = "iam" } } ``` From 66a4a26ca90464d9e69204997d9a45637a064547 Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Thu, 23 Feb 2023 23:02:33 -0800 Subject: [PATCH 05/13] fix password set length validation error --- internal/service/elasticache/user.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/internal/service/elasticache/user.go b/internal/service/elasticache/user.go index bb25d9cf449f..dca605bf7fa7 100644 --- a/internal/service/elasticache/user.go +++ b/internal/service/elasticache/user.go @@ -111,17 +111,25 @@ func resourceUserCreate(d *schema.ResourceData, meta interface{}) error { tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) input := &elasticache.CreateUserInput{ - AccessString: aws.String(d.Get("access_string").(string)), - AuthenticationMode: &elasticache.AuthenticationMode{ - Passwords: flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)), - Type: aws.String(d.Get("authentication_mode.0.type").(string)), - }, + AccessString: aws.String(d.Get("access_string").(string)), Engine: aws.String(d.Get("engine").(string)), NoPasswordRequired: aws.Bool(d.Get("no_password_required").(bool)), UserId: aws.String(d.Get("user_id").(string)), UserName: aws.String(d.Get("user_name").(string)), } + if v, ok := d.GetOk("authentication_mode"); ok && v != nil { + passwords := flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)) + if passwords != nil && len(passwords) < 1 { + passwords = nil + } + + input.AuthenticationMode = &elasticache.AuthenticationMode{ + Passwords: passwords, + Type: aws.String(d.Get("authentication_mode.0.type").(string)), + } + } + if v, ok := d.GetOk("passwords"); ok { input.Passwords = flex.ExpandStringSet(v.(*schema.Set)) } From b0e783a0d5f3b238a067c7a8b3381479f03d6d0e Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Sun, 26 Feb 2023 23:43:38 -0800 Subject: [PATCH 06/13] fix tests --- .../elasticache/user_data_source_test.go | 6 ++ .../user_group_association_test.go | 31 ++++++- .../service/elasticache/user_group_test.go | 43 +++++++++- internal/service/elasticache/user_test.go | 85 +++++++++++++++++-- 4 files changed, 150 insertions(+), 15 deletions(-) diff --git a/internal/service/elasticache/user_data_source_test.go b/internal/service/elasticache/user_data_source_test.go index a18a9c5b6533..3a5dd7b59988 100644 --- a/internal/service/elasticache/user_data_source_test.go +++ b/internal/service/elasticache/user_data_source_test.go @@ -29,6 +29,12 @@ func TestAccElastiCacheUserDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "access_string", resourceName, "access_string"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, }, }) } diff --git a/internal/service/elasticache/user_group_association_test.go b/internal/service/elasticache/user_group_association_test.go index 75ae385d12a5..0fb4bf7110a0 100644 --- a/internal/service/elasticache/user_group_association_test.go +++ b/internal/service/elasticache/user_group_association_test.go @@ -39,9 +39,10 @@ func TestAccElastiCacheUserGroupAssociation_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, }, }, }) @@ -69,6 +70,12 @@ func TestAccElastiCacheUserGroupAssociation_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "user_group_id", rName), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserGroupAssociationConfig_update(rName), Check: resource.ComposeTestCheckFunc( @@ -77,6 +84,12 @@ func TestAccElastiCacheUserGroupAssociation_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "user_group_id", rName), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, }, }) } @@ -121,6 +134,12 @@ func TestAccElastiCacheUserGroupAssociation_multiple(t *testing.T) { { Config: testAccUserGroupAssociationConfig_preMultiple(rName), }, + { + ResourceName: "aws_elasticache_user.test3", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserGroupAssociationConfig_multiple(rName), Check: resource.ComposeTestCheckFunc( @@ -128,6 +147,12 @@ func TestAccElastiCacheUserGroupAssociation_multiple(t *testing.T) { testAccCheckUserGroupAssociationExists(resourceName2), ), }, + { + ResourceName: "aws_elasticache_user.test3", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, }, }) } diff --git a/internal/service/elasticache/user_group_test.go b/internal/service/elasticache/user_group_test.go index da0b1e964259..b68a6605a893 100644 --- a/internal/service/elasticache/user_group_test.go +++ b/internal/service/elasticache/user_group_test.go @@ -36,9 +36,10 @@ func TestAccElastiCacheUserGroup_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, }, }, }) @@ -64,6 +65,12 @@ func TestAccElastiCacheUserGroup_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "redis"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserGroupConfig_multiple(rName), Check: resource.ComposeTestCheckFunc( @@ -73,6 +80,12 @@ func TestAccElastiCacheUserGroup_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "redis"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( @@ -82,6 +95,12 @@ func TestAccElastiCacheUserGroup_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "redis"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, }, }) } @@ -105,6 +124,12 @@ func TestAccElastiCacheUserGroup_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserGroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( @@ -114,6 +139,12 @@ func TestAccElastiCacheUserGroup_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserGroupConfig_tags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( @@ -122,6 +153,12 @@ func TestAccElastiCacheUserGroup_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, }, }) } diff --git a/internal/service/elasticache/user_test.go b/internal/service/elasticache/user_test.go index 0510867a5cb9..908afb9a83a2 100644 --- a/internal/service/elasticache/user_test.go +++ b/internal/service/elasticache/user_test.go @@ -44,6 +44,7 @@ func TestAccElastiCacheUser_basic(t *testing.T) { ImportStateVerifyIgnore: []string{ "no_password_required", "passwords", + "authentication_mode", }, }, }, @@ -78,6 +79,11 @@ func TestAccElastiCacheUserWithPasswordAuthMode_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "no_password_required", + "passwords", + "authentication_mode.0.passwords", + }, }, }, }) @@ -99,7 +105,7 @@ func TestAccElastiCacheUserWithIamAuthMode_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckUserExists(resourceName, &user), resource.TestCheckResourceAttr(resourceName, "user_id", rName), - resource.TestCheckResourceAttr(resourceName, "user_name", "username1"), + resource.TestCheckResourceAttr(resourceName, "user_name", rName), resource.TestCheckResourceAttr(resourceName, "engine", "redis"), resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "iam"), ), @@ -131,7 +137,7 @@ func TestAccElastiCacheUserWithNoPassRequiredAuthMode_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "user_id", rName), resource.TestCheckResourceAttr(resourceName, "user_name", "username1"), resource.TestCheckResourceAttr(resourceName, "engine", "redis"), - resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "no-password-required"), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "no-password"), ), }, { @@ -160,6 +166,12 @@ func TestAccElastiCacheUser_update(t *testing.T) { testAccCheckUserExists(resourceName, &user), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserConfig_update(rName), Check: resource.ComposeTestCheckFunc( @@ -174,6 +186,7 @@ func TestAccElastiCacheUser_update(t *testing.T) { ImportStateVerifyIgnore: []string{ "no_password_required", "passwords", + "authentication_mode", }, }, }, @@ -192,23 +205,43 @@ func TestAccElastiCacheUserWithPasswordAuthMode_update_password(t *testing.T) { CheckDestroy: testAccCheckUserDestroy, Steps: []resource.TestStep{ { - Config: testAccUserConfigWithPasswordAuthMode_basic(rName), + Config: testAccUserConfigWithPasswordAuthMode_twoPasswords(rName, "aaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbb"), + Check: resource.ComposeTestCheckFunc( + testAccCheckUserExists(resourceName, &user), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.password_count", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode.0.passwords"}, + }, + { + Config: testAccUserConfigWithPasswordAuthMode_onePassword(rName, "aaaaaaaaaaaaaaaa"), Check: resource.ComposeTestCheckFunc( testAccCheckUserExists(resourceName, &user), resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.password_count", "1"), ), }, { - Config: testAccUserConfigWithPasswordAuthMode_update(rName, "bbbbbbbbbbbbbbbb", "cccccccccccc"), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode.0.passwords"}, + }, + { + Config: testAccUserConfigWithPasswordAuthMode_twoPasswords(rName, "cccccccccccccccc", "dddddddddddddddd"), Check: resource.ComposeTestCheckFunc( testAccCheckUserExists(resourceName, &user), resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.password_count", "2"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode.0.passwords"}, }, }, }) @@ -237,6 +270,12 @@ func TestAccElastiCacheUser_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.tagKey", "tagVal"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserConfig_tags(rName, "tagKey", "tagVal2"), Check: resource.ComposeTestCheckFunc( @@ -249,6 +288,12 @@ func TestAccElastiCacheUser_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.tagKey", "tagVal2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, { Config: testAccUserConfig_basic(rName), Check: resource.ComposeTestCheckFunc( @@ -260,6 +305,12 @@ func TestAccElastiCacheUser_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"authentication_mode"}, + }, }, }) } @@ -377,7 +428,7 @@ func testAccUserConfigWithIamAuthMode_basic(rName string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q - user_name = "username1" + user_name = %[1]q access_string = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember" engine = "REDIS" @@ -415,7 +466,7 @@ resource "aws_elasticache_user" "test" { `, rName)) } -func testAccUserConfigWithPasswordAuthMode_update(rName string, password1 string, password2 string) string { +func testAccUserConfigWithPasswordAuthMode_twoPasswords(rName string, password1 string, password2 string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q @@ -431,6 +482,22 @@ resource "aws_elasticache_user" "test" { `, rName, password1, password2)) } +func testAccUserConfigWithPasswordAuthMode_onePassword(rName string, password string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +resource "aws_elasticache_user" "test" { + user_id = %[1]q + user_name = "username1" + access_string = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember" + engine = "REDIS" + + authentication_mode { + type = "password" + passwords = [%[2]q] + } +} +`, rName, password)) +} + func testAccUserConfig_tags(rName, tagKey, tagValue string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_elasticache_user" "test" { From d628979bc9466076c06037d07569d5e595b04a84 Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Tue, 28 Feb 2023 23:44:54 -0800 Subject: [PATCH 07/13] fix tests --- internal/service/elasticache/user.go | 2 + .../service/elasticache/user_data_source.go | 28 +++++ .../elasticache/user_data_source_test.go | 6 -- .../user_group_association_test.go | 31 +----- .../service/elasticache/user_group_test.go | 43 +------- internal/service/elasticache/user_test.go | 102 +++++------------- 6 files changed, 65 insertions(+), 147 deletions(-) diff --git a/internal/service/elasticache/user.go b/internal/service/elasticache/user.go index dca605bf7fa7..41a001713de2 100644 --- a/internal/service/elasticache/user.go +++ b/internal/service/elasticache/user.go @@ -41,6 +41,7 @@ func ResourceUser() *schema.Resource { "authentication_mode": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -251,6 +252,7 @@ func resourceUserUpdate(d *schema.ResourceData, meta interface{}) error { Passwords: flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)), Type: aws.String(d.Get("authentication_mode.0.type").(string)), } + hasChange = true } if d.HasChange("no_password_required") { diff --git a/internal/service/elasticache/user_data_source.go b/internal/service/elasticache/user_data_source.go index 2f0fe0f78fac..66fff038baf0 100644 --- a/internal/service/elasticache/user_data_source.go +++ b/internal/service/elasticache/user_data_source.go @@ -19,6 +19,22 @@ func DataSourceUser() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "authentication_mode": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "password_count": { + Optional: true, + Type: schema.TypeInt, + }, + "type": { + Optional: true, + Type: schema.TypeString, + }, + }, + }, + }, "engine": { Type: schema.TypeString, Optional: true, @@ -68,6 +84,18 @@ func dataSourceUserRead(d *schema.ResourceData, meta interface{}) error { d.SetId(aws.StringValue(user.UserId)) d.Set("access_string", user.AccessString) + + if v := user.Authentication; v != nil { + authenticationMode := map[string]interface{}{ + "password_count": aws.Int64Value(v.PasswordCount), + "type": aws.StringValue(v.Type), + } + + if err := d.Set("authentication_mode", []interface{}{authenticationMode}); err != nil { + return fmt.Errorf("failed to set authentication_mode of ElastiCache User (%s): %s", d.Id(), err) + } + } + d.Set("engine", user.Engine) d.Set("user_id", user.UserId) d.Set("user_name", user.UserName) diff --git a/internal/service/elasticache/user_data_source_test.go b/internal/service/elasticache/user_data_source_test.go index 3a5dd7b59988..a18a9c5b6533 100644 --- a/internal/service/elasticache/user_data_source_test.go +++ b/internal/service/elasticache/user_data_source_test.go @@ -29,12 +29,6 @@ func TestAccElastiCacheUserDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "access_string", resourceName, "access_string"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, }, }) } diff --git a/internal/service/elasticache/user_group_association_test.go b/internal/service/elasticache/user_group_association_test.go index 0fb4bf7110a0..75ae385d12a5 100644 --- a/internal/service/elasticache/user_group_association_test.go +++ b/internal/service/elasticache/user_group_association_test.go @@ -39,10 +39,9 @@ func TestAccElastiCacheUserGroupAssociation_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -70,12 +69,6 @@ func TestAccElastiCacheUserGroupAssociation_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "user_group_id", rName), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserGroupAssociationConfig_update(rName), Check: resource.ComposeTestCheckFunc( @@ -84,12 +77,6 @@ func TestAccElastiCacheUserGroupAssociation_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "user_group_id", rName), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, }, }) } @@ -134,12 +121,6 @@ func TestAccElastiCacheUserGroupAssociation_multiple(t *testing.T) { { Config: testAccUserGroupAssociationConfig_preMultiple(rName), }, - { - ResourceName: "aws_elasticache_user.test3", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserGroupAssociationConfig_multiple(rName), Check: resource.ComposeTestCheckFunc( @@ -147,12 +128,6 @@ func TestAccElastiCacheUserGroupAssociation_multiple(t *testing.T) { testAccCheckUserGroupAssociationExists(resourceName2), ), }, - { - ResourceName: "aws_elasticache_user.test3", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, }, }) } diff --git a/internal/service/elasticache/user_group_test.go b/internal/service/elasticache/user_group_test.go index b68a6605a893..da0b1e964259 100644 --- a/internal/service/elasticache/user_group_test.go +++ b/internal/service/elasticache/user_group_test.go @@ -36,10 +36,9 @@ func TestAccElastiCacheUserGroup_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -65,12 +64,6 @@ func TestAccElastiCacheUserGroup_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "redis"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserGroupConfig_multiple(rName), Check: resource.ComposeTestCheckFunc( @@ -80,12 +73,6 @@ func TestAccElastiCacheUserGroup_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "redis"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( @@ -95,12 +82,6 @@ func TestAccElastiCacheUserGroup_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "redis"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, }, }) } @@ -124,12 +105,6 @@ func TestAccElastiCacheUserGroup_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserGroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( @@ -139,12 +114,6 @@ func TestAccElastiCacheUserGroup_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserGroupConfig_tags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( @@ -153,12 +122,6 @@ func TestAccElastiCacheUserGroup_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, }, }) } diff --git a/internal/service/elasticache/user_test.go b/internal/service/elasticache/user_test.go index 908afb9a83a2..37df1024dd6a 100644 --- a/internal/service/elasticache/user_test.go +++ b/internal/service/elasticache/user_test.go @@ -44,14 +44,13 @@ func TestAccElastiCacheUser_basic(t *testing.T) { ImportStateVerifyIgnore: []string{ "no_password_required", "passwords", - "authentication_mode", }, }, }, }) } -func TestAccElastiCacheUserWithPasswordAuthMode_basic(t *testing.T) { +func TestAccElastiCacheUser_password_auth_mode(t *testing.T) { var user elasticache.User rName := sdkacctest.RandomWithPrefix("tf-acc") resourceName := "aws_elasticache_user.test" @@ -80,16 +79,16 @@ func TestAccElastiCacheUserWithPasswordAuthMode_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{ + "authentication_mode.0.passwords.#", + "authentication_mode.0.passwords.0", "no_password_required", - "passwords", - "authentication_mode.0.passwords", }, }, }, }) } -func TestAccElastiCacheUserWithIamAuthMode_basic(t *testing.T) { +func TestAccElastiCacheUser_iam_auth_mode(t *testing.T) { var user elasticache.User rName := sdkacctest.RandomWithPrefix("tf-acc") resourceName := "aws_elasticache_user.test" @@ -114,36 +113,9 @@ func TestAccElastiCacheUserWithIamAuthMode_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - }, - }, - }) -} - -func TestAccElastiCacheUserWithNoPassRequiredAuthMode_basic(t *testing.T) { - var user elasticache.User - rName := sdkacctest.RandomWithPrefix("tf-acc") - resourceName := "aws_elasticache_user.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, elasticache.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckUserDestroy, - Steps: []resource.TestStep{ - { - Config: testAccUserConfigWithNoPassRequiredAuthMode_basic(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckUserExists(resourceName, &user), - resource.TestCheckResourceAttr(resourceName, "user_id", rName), - resource.TestCheckResourceAttr(resourceName, "user_name", "username1"), - resource.TestCheckResourceAttr(resourceName, "engine", "redis"), - resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "no-password"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "no_password_required", + }, }, }, }) @@ -166,12 +138,6 @@ func TestAccElastiCacheUser_update(t *testing.T) { testAccCheckUserExists(resourceName, &user), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserConfig_update(rName), Check: resource.ComposeTestCheckFunc( @@ -186,14 +152,13 @@ func TestAccElastiCacheUser_update(t *testing.T) { ImportStateVerifyIgnore: []string{ "no_password_required", "passwords", - "authentication_mode", }, }, }, }) } -func TestAccElastiCacheUserWithPasswordAuthMode_update_password(t *testing.T) { +func TestAccElastiCacheUser_update_password_auth_mode(t *testing.T) { var user elasticache.User rName := sdkacctest.RandomWithPrefix("tf-acc") resourceName := "aws_elasticache_user.test" @@ -212,10 +177,13 @@ func TestAccElastiCacheUserWithPasswordAuthMode_update_password(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode.0.passwords"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "authentication_mode.0.passwords", + "no_password_required", + }, }, { Config: testAccUserConfigWithPasswordAuthMode_onePassword(rName, "aaaaaaaaaaaaaaaa"), @@ -225,10 +193,13 @@ func TestAccElastiCacheUserWithPasswordAuthMode_update_password(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode.0.passwords"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "authentication_mode.0.passwords", + "no_password_required", + }, }, { Config: testAccUserConfigWithPasswordAuthMode_twoPasswords(rName, "cccccccccccccccc", "dddddddddddddddd"), @@ -238,10 +209,13 @@ func TestAccElastiCacheUserWithPasswordAuthMode_update_password(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode.0.passwords"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "authentication_mode.0.passwords", + "no_password_required", + }, }, }, }) @@ -270,12 +244,6 @@ func TestAccElastiCacheUser_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.tagKey", "tagVal"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserConfig_tags(rName, "tagKey", "tagVal2"), Check: resource.ComposeTestCheckFunc( @@ -288,12 +256,6 @@ func TestAccElastiCacheUser_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.tagKey", "tagVal2"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, { Config: testAccUserConfig_basic(rName), Check: resource.ComposeTestCheckFunc( @@ -305,12 +267,6 @@ func TestAccElastiCacheUser_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"authentication_mode"}, - }, }, }) } From eb5211e7c225d3397d89a029ddbe85a0bd48aa6b Mon Sep 17 00:00:00 2001 From: Constantin Scacun Date: Wed, 1 Mar 2023 12:44:26 -0800 Subject: [PATCH 08/13] add password example to the docs --- website/docs/r/elasticache_user.html.markdown | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/website/docs/r/elasticache_user.html.markdown b/website/docs/r/elasticache_user.html.markdown index 514303c0aca9..6511c05f7a7d 100644 --- a/website/docs/r/elasticache_user.html.markdown +++ b/website/docs/r/elasticache_user.html.markdown @@ -38,6 +38,20 @@ resource "aws_elasticache_user" "test" { } ``` +```terraform +resource "aws_elasticache_user" "test" { + user_id = "testUserId" + user_name = "testUserName" + access_string = "on ~* +@all" + engine = "REDIS" + + authentication_mode { + type = "password" + passwords = ["password1", "password2"] + } +} +``` + ## Argument Reference The following arguments are required: From 06674c675e9298c0c72df96ff22faa696cf098e9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 15 Mar 2023 15:31:15 -0400 Subject: [PATCH 09/13] r/aws_elasticache_user: 'User_id' is ForceNew. --- .changelog/28928.txt | 4 + internal/service/elasticache/find.go | 24 --- internal/service/elasticache/status.go | 21 --- internal/service/elasticache/user.go | 208 ++++++++++++++++------ internal/service/elasticache/user_test.go | 65 +++---- internal/service/elasticache/wait.go | 31 ---- 6 files changed, 181 insertions(+), 172 deletions(-) diff --git a/.changelog/28928.txt b/.changelog/28928.txt index 05fdb4c35eb1..470da24180e7 100644 --- a/.changelog/28928.txt +++ b/.changelog/28928.txt @@ -1,3 +1,7 @@ ```release-note:enhancement resource/aws_elasticache_user: Add `authentication_mode` argument +``` + +```release-note:bug +resource/aws_elasticache_user: Change `user_id` to [ForceNew](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors#forcenew) ``` \ No newline at end of file diff --git a/internal/service/elasticache/find.go b/internal/service/elasticache/find.go index 1cbbe6cf2c7f..dba86b440647 100644 --- a/internal/service/elasticache/find.go +++ b/internal/service/elasticache/find.go @@ -183,30 +183,6 @@ func FindGlobalReplicationGroupMemberByID(ctx context.Context, conn *elasticache } } -func FindUserByID(ctx context.Context, conn *elasticache.ElastiCache, userID string) (*elasticache.User, error) { - input := &elasticache.DescribeUsersInput{ - UserId: aws.String(userID), - } - out, err := conn.DescribeUsersWithContext(ctx, input) - - if err != nil { - return nil, err - } - - switch len(out.Users) { - case 0: - return nil, &resource.NotFoundError{ - Message: "empty result", - } - case 1: - return out.Users[0], nil - default: - return nil, &resource.NotFoundError{ - Message: "too many results", - } - } -} - func FindUserGroupByID(ctx context.Context, conn *elasticache.ElastiCache, groupID string) (*elasticache.UserGroup, error) { input := &elasticache.DescribeUserGroupsInput{ UserGroupId: aws.String(groupID), diff --git a/internal/service/elasticache/status.go b/internal/service/elasticache/status.go index 09dd9ac2755d..4169466b9487 100644 --- a/internal/service/elasticache/status.go +++ b/internal/service/elasticache/status.go @@ -16,10 +16,6 @@ const ( ReplicationGroupStatusDeleting = "deleting" ReplicationGroupStatusCreateFailed = "create-failed" ReplicationGroupStatusSnapshotting = "snapshotting" - - UserStatusActive = "active" - UserStatusDeleting = "deleting" - UserStatusModifying = "modifying" ) // StatusReplicationGroup fetches the Replication Group and its Status @@ -130,20 +126,3 @@ func statusGlobalReplicationGroupMember(ctx context.Context, conn *elasticache.E return member, aws.StringValue(member.Status), nil } } - -// StatusUser fetches the ElastiCache user and its Status -func StatusUser(ctx context.Context, conn *elasticache.ElastiCache, userId string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - user, err := FindUserByID(ctx, conn, userId) - - if tfresource.NotFound(err) { - return nil, "", nil - } - - if err != nil { - return nil, "", err - } - - return user, aws.StringValue(user.Status), nil - } -} diff --git a/internal/service/elasticache/user.go b/internal/service/elasticache/user.go index 6d145c650f2e..278b024b5faf 100644 --- a/internal/service/elasticache/user.go +++ b/internal/service/elasticache/user.go @@ -4,11 +4,13 @@ import ( "context" "log" "strings" + "time" "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/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/conns" @@ -38,7 +40,6 @@ func ResourceUser() *schema.Resource { }, "arn": { Type: schema.TypeString, - Optional: true, Computed: true, }, "authentication_mode": { @@ -98,6 +99,7 @@ func ResourceUser() *schema.Resource { "user_id": { Type: schema.TypeString, Required: true, + ForceNew: true, }, "user_name": { Type: schema.TypeString, @@ -114,28 +116,20 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) - username := d.Get("user_name").(string) + userID := d.Get("user_id").(string) input := &elasticache.CreateUserInput{ AccessString: aws.String(d.Get("access_string").(string)), Engine: aws.String(d.Get("engine").(string)), NoPasswordRequired: aws.Bool(d.Get("no_password_required").(bool)), UserId: aws.String(d.Get("user_id").(string)), - UserName: aws.String(username), + UserName: aws.String(d.Get("user_name").(string)), } - if v, ok := d.GetOk("authentication_mode"); ok && v != nil { - passwords := flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)) - if passwords != nil && len(passwords) < 1 { - passwords = nil - } - - input.AuthenticationMode = &elasticache.AuthenticationMode{ - Passwords: passwords, - Type: aws.String(d.Get("authentication_mode.0.type").(string)), - } + if v, ok := d.GetOk("authentication_mode"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.AuthenticationMode = expandAuthenticationMode(v.([]interface{})[0].(map[string]interface{})) } - if v, ok := d.GetOk("passwords"); ok { + if v, ok := d.GetOk("passwords"); ok && v.(*schema.Set).Len() > 0 { input.Passwords = flex.ExpandStringSet(v.(*schema.Set)) } @@ -153,7 +147,7 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf } if err != nil { - return sdkdiag.AppendErrorf(diags, "creating ElastiCache User (%s): %s", username, err) + return sdkdiag.AppendErrorf(diags, "creating ElastiCache User (%s): %s", userID, err) } d.SetId(aws.StringValue(output.UserId)) @@ -181,22 +175,21 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - resp, err := FindUserByID(ctx, conn, d.Id()) + user, err := FindUserByID(ctx, conn, d.Id()) - if !d.IsNewResource() && (tfresource.NotFound(err) || tfawserr.ErrCodeEquals(err, elasticache.ErrCodeUserNotFoundFault)) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] ElastiCache User (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "describing ElastiCache User (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "reading ElastiCache User (%s): %s", d.Id(), err) } - d.Set("access_string", resp.AccessString) - d.Set("arn", resp.ARN) - - if v := resp.Authentication; v != nil { + d.Set("access_string", user.AccessString) + d.Set("arn", user.ARN) + if v := user.Authentication; v != nil { authenticationMode := map[string]interface{}{ "passwords": d.Get("authentication_mode.0.passwords"), "password_count": aws.Int64Value(v.PasswordCount), @@ -206,21 +199,22 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac if err := d.Set("authentication_mode", []interface{}{authenticationMode}); err != nil { return sdkdiag.AppendErrorf(diags, "setting authentication_mode: %s", err) } + } else { + d.Set("authentication_mode", nil) } + d.Set("engine", user.Engine) + d.Set("user_id", user.UserId) + d.Set("user_name", user.UserName) - d.Set("engine", resp.Engine) - d.Set("user_id", resp.UserId) - d.Set("user_name", resp.UserName) - - tags, err := ListTags(ctx, conn, aws.StringValue(resp.ARN)) + tags, err := ListTags(ctx, conn, aws.StringValue(user.ARN)) if err != nil && !verify.ErrorISOUnsupported(conn.PartitionID, err) { - return sdkdiag.AppendErrorf(diags, "listing tags for ElastiCache User (%s): %s", aws.StringValue(resp.ARN), err) + return sdkdiag.AppendErrorf(diags, "listing tags for ElastiCache User (%s): %s", aws.StringValue(user.ARN), err) } // tags not supported in all partitions if err != nil { - log.Printf("[WARN] failed listing tags for ElastiCache User (%s): %s", aws.StringValue(resp.ARN), err) + log.Printf("[WARN] failed listing tags for ElastiCache User (%s): %s", aws.StringValue(user.ARN), err) } if tags != nil { @@ -242,45 +236,38 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).ElastiCacheConn() - hasChange := false if d.HasChangesExcept("tags", "tags_all") { - req := &elasticache.ModifyUserInput{ + input := &elasticache.ModifyUserInput{ UserId: aws.String(d.Id()), } if d.HasChange("access_string") { - req.AccessString = aws.String(d.Get("access_string").(string)) - hasChange = true + input.AccessString = aws.String(d.Get("access_string").(string)) } if d.HasChange("authentication_mode") { - req.AuthenticationMode = &elasticache.AuthenticationMode{ - Passwords: flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)), - Type: aws.String(d.Get("authentication_mode.0.type").(string)), + if v, ok := d.GetOk("authentication_mode"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.AuthenticationMode = expandAuthenticationMode(v.([]interface{})[0].(map[string]interface{})) } - hasChange = true } if d.HasChange("no_password_required") { - req.NoPasswordRequired = aws.Bool(d.Get("no_password_required").(bool)) - hasChange = true + input.NoPasswordRequired = aws.Bool(d.Get("no_password_required").(bool)) } if d.HasChange("passwords") { - req.Passwords = flex.ExpandStringSet(d.Get("passwords").(*schema.Set)) - hasChange = true + input.Passwords = flex.ExpandStringSet(d.Get("passwords").(*schema.Set)) } - if hasChange { - _, err := conn.ModifyUserWithContext(ctx, req) - if err != nil { - return sdkdiag.AppendErrorf(diags, "updating ElastiCache User (%s): %s", d.Id(), err) - } + _, err := conn.ModifyUserWithContext(ctx, input) - if err := WaitUserActive(ctx, conn, d.Id()); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for ElastiCache User (%s) to be modified: %s", d.Id(), err) - } + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating ElastiCache User (%s): %s", d.Id(), err) + } + + if _, err := waitUserUpdated(ctx, conn, d.Id()); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for ElastiCache User (%s) update: %s", d.Id(), err) } } @@ -306,11 +293,10 @@ func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interf var diags diag.Diagnostics conn := meta.(*conns.AWSClient).ElastiCacheConn() - input := &elasticache.DeleteUserInput{ + log.Printf("[INFO] Deleting ElastiCache User: %s", d.Id()) + _, err := conn.DeleteUserWithContext(ctx, &elasticache.DeleteUserInput{ UserId: aws.String(d.Id()), - } - - _, err := conn.DeleteUserWithContext(ctx, input) + }) if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeUserNotFoundFault) { return diags @@ -320,12 +306,118 @@ func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interf return sdkdiag.AppendErrorf(diags, "deleting ElastiCache User (%s): %s", d.Id(), err) } - if err := WaitUserDeleted(ctx, conn, d.Id()); err != nil { - if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeUserNotFoundFault) { - return diags - } - return sdkdiag.AppendErrorf(diags, "waiting for ElastiCache User (%s) to be deleted: %s", d.Id(), err) + if _, err := waitUserDeleted(ctx, conn, d.Id()); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for ElastiCache User (%s) delete: %s", d.Id(), err) } return diags } + +func FindUserByID(ctx context.Context, conn *elasticache.ElastiCache, userID string) (*elasticache.User, error) { + input := &elasticache.DescribeUsersInput{ + UserId: aws.String(userID), + } + + output, err := conn.DescribeUsersWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeUserNotFoundFault) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || len(output.Users) == 0 || output.Users[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output.Users); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output.Users[0], nil +} + +func statusUser(ctx context.Context, conn *elasticache.ElastiCache, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + user, err := FindUserByID(ctx, conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return user, aws.StringValue(user.Status), nil + } +} + +const ( + UserStatusActive = "active" + UserStatusDeleting = "deleting" + UserStatusModifying = "modifying" +) + +func waitUserUpdated(ctx context.Context, conn *elasticache.ElastiCache, id string) (*elasticache.User, error) { + const ( + timeout = 5 * time.Minute + ) + stateConf := &resource.StateChangeConf{ + Pending: []string{UserStatusModifying}, + Target: []string{UserStatusActive}, + Refresh: statusUser(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*elasticache.User); ok { + return output, err + } + + return nil, err +} + +func waitUserDeleted(ctx context.Context, conn *elasticache.ElastiCache, id string) (*elasticache.User, error) { + const ( + timeout = 5 * time.Minute + ) + stateConf := &resource.StateChangeConf{ + Pending: []string{UserStatusDeleting}, + Target: []string{}, + Refresh: statusUser(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*elasticache.User); ok { + return output, err + } + + return nil, err +} + +func expandAuthenticationMode(tfMap map[string]interface{}) *elasticache.AuthenticationMode { + if tfMap == nil { + return nil + } + + apiObject := &elasticache.AuthenticationMode{} + + if v, ok := tfMap["passwords"].(*schema.Set); ok && v.Len() > 0 { + apiObject.Passwords = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["type"].(string); ok && v != "" { + apiObject.Type = aws.String(v) + } + + return apiObject +} diff --git a/internal/service/elasticache/user_test.go b/internal/service/elasticache/user_test.go index 32ed7c1fa1a3..8fca5fd54305 100644 --- a/internal/service/elasticache/user_test.go +++ b/internal/service/elasticache/user_test.go @@ -6,10 +6,8 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/elasticache" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -303,21 +301,17 @@ func TestAccElastiCacheUser_disappears(t *testing.T) { } func testAccCheckUserDestroy(ctx context.Context) resource.TestCheckFunc { - return func(s *terraform.State) error { return testAccCheckUserDestroyWithProvider(ctx)(s, acctest.Provider) } -} - -func testAccCheckUserDestroyWithProvider(ctx context.Context) acctest.TestCheckWithProviderFunc { - return func(s *terraform.State, provider *schema.Provider) error { - conn := provider.Meta().(*conns.AWSClient).ElastiCacheConn() + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ElastiCacheConn() for _, rs := range s.RootModule().Resources { if rs.Type != "aws_elasticache_user" { continue } - user, err := tfelasticache.FindUserByID(ctx, conn, rs.Primary.ID) + _, err := tfelasticache.FindUserByID(ctx, conn, rs.Primary.ID) - if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeUserNotFoundFault) || tfresource.NotFound(err) { + if tfresource.NotFound(err) { continue } @@ -325,9 +319,7 @@ func testAccCheckUserDestroyWithProvider(ctx context.Context) acctest.TestCheckW return err } - if user != nil { - return fmt.Errorf("ElastiCache User (%s) still exists", rs.Primary.ID) - } + return fmt.Errorf("ElastiCache User (%s) still exists", rs.Primary.ID) } return nil @@ -335,10 +327,6 @@ func testAccCheckUserDestroyWithProvider(ctx context.Context) acctest.TestCheckW } func testAccCheckUserExists(ctx context.Context, n string, v *elasticache.User) resource.TestCheckFunc { - return testAccCheckUserExistsWithProvider(ctx, n, v, func() *schema.Provider { return acctest.Provider }) -} - -func testAccCheckUserExistsWithProvider(ctx context.Context, n string, v *elasticache.User, providerF func() *schema.Provider) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -349,21 +337,22 @@ func testAccCheckUserExistsWithProvider(ctx context.Context, n string, v *elasti return fmt.Errorf("No ElastiCache User ID is set") } - provider := providerF() - conn := provider.Meta().(*conns.AWSClient).ElastiCacheConn() - resp, err := tfelasticache.FindUserByID(ctx, conn, rs.Primary.ID) + conn := acctest.Provider.Meta().(*conns.AWSClient).ElastiCacheConn() + + output, err := tfelasticache.FindUserByID(ctx, conn, rs.Primary.ID) + if err != nil { - return fmt.Errorf("ElastiCache User (%s) not found: %w", rs.Primary.ID, err) + return err } - *v = *resp + *v = *output return nil } } func testAccUserConfig_basic(rName string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = "username1" @@ -371,11 +360,11 @@ resource "aws_elasticache_user" "test" { engine = "REDIS" passwords = ["password123456789"] } -`, rName)) +`, rName) } func testAccUserConfigWithPasswordAuthMode_basic(rName string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = "username1" @@ -387,11 +376,11 @@ resource "aws_elasticache_user" "test" { passwords = ["aaaaaaaaaaaaaaaa"] } } -`, rName)) +`, rName) } func testAccUserConfigWithIamAuthMode_basic(rName string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = %[1]q @@ -402,11 +391,11 @@ resource "aws_elasticache_user" "test" { type = "iam" } } -`, rName)) +`, rName) } func testAccUserConfigWithNoPassRequiredAuthMode_basic(rName string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = "username1" @@ -417,11 +406,11 @@ resource "aws_elasticache_user" "test" { type = "no-password-required" } } -`, rName)) +`, rName) } func testAccUserConfig_update(rName string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = "username1" @@ -429,11 +418,11 @@ resource "aws_elasticache_user" "test" { engine = "REDIS" passwords = ["password234567891", "password345678912"] } -`, rName)) +`, rName) } func testAccUserConfigWithPasswordAuthMode_twoPasswords(rName string, password1 string, password2 string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = "username1" @@ -445,11 +434,11 @@ resource "aws_elasticache_user" "test" { passwords = [%[2]q, %[3]q] } } -`, rName, password1, password2)) +`, rName, password1, password2) } func testAccUserConfigWithPasswordAuthMode_onePassword(rName string, password string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = "username1" @@ -461,11 +450,11 @@ resource "aws_elasticache_user" "test" { passwords = [%[2]q] } } -`, rName, password)) +`, rName, password) } func testAccUserConfig_tags(rName, tagKey, tagValue string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q user_name = "username1" @@ -477,5 +466,5 @@ resource "aws_elasticache_user" "test" { %[2]s = %[3]q } } -`, rName, tagKey, tagValue)) +`, rName, tagKey, tagValue) } diff --git a/internal/service/elasticache/wait.go b/internal/service/elasticache/wait.go index dee0f218f051..637607dfd90c 100644 --- a/internal/service/elasticache/wait.go +++ b/internal/service/elasticache/wait.go @@ -18,9 +18,6 @@ const ( replicationGroupDeletedMinTimeout = 10 * time.Second replicationGroupDeletedDelay = 30 * time.Second - - UserActiveTimeout = 5 * time.Minute - UserDeletedTimeout = 5 * time.Minute ) // WaitReplicationGroupAvailable waits for a ReplicationGroup to return Available @@ -234,31 +231,3 @@ func waitGlobalReplicationGroupMemberDetached(ctx context.Context, conn *elastic } return nil, err } - -// WaitUserActive waits for an ElastiCache user to reach an active state after modifications -func WaitUserActive(ctx context.Context, conn *elasticache.ElastiCache, userId string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{UserStatusModifying}, - Target: []string{UserStatusActive}, - Refresh: StatusUser(ctx, conn, userId), - Timeout: UserActiveTimeout, - } - - _, err := stateConf.WaitForStateContext(ctx) - - return err -} - -// WaitUserDeleted waits for an ElastiCache user to be deleted -func WaitUserDeleted(ctx context.Context, conn *elasticache.ElastiCache, userId string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{UserStatusDeleting}, - Target: []string{}, - Refresh: StatusUser(ctx, conn, userId), - Timeout: UserDeletedTimeout, - } - - _, err := stateConf.WaitForStateContext(ctx) - - return err -} From 011e145a982bc8e48c265d66022cb429bf238152 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 15 Mar 2023 15:42:50 -0400 Subject: [PATCH 10/13] Fix terrafmt errors. --- internal/service/elasticache/user_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/elasticache/user_test.go b/internal/service/elasticache/user_test.go index 8fca5fd54305..7155e886b835 100644 --- a/internal/service/elasticache/user_test.go +++ b/internal/service/elasticache/user_test.go @@ -388,7 +388,7 @@ resource "aws_elasticache_user" "test" { engine = "REDIS" authentication_mode { - type = "iam" + type = "iam" } } `, rName) @@ -403,7 +403,7 @@ resource "aws_elasticache_user" "test" { engine = "REDIS" authentication_mode { - type = "no-password-required" + type = "no-password-required" } } `, rName) @@ -432,7 +432,7 @@ resource "aws_elasticache_user" "test" { authentication_mode { type = "password" passwords = [%[2]q, %[3]q] - } + } } `, rName, password1, password2) } @@ -448,7 +448,7 @@ resource "aws_elasticache_user" "test" { authentication_mode { type = "password" passwords = [%[2]q] - } + } } `, rName, password) } From 34a7d80735e976b462ea33939c0f2e88ddbe6582 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 15 Mar 2023 15:43:55 -0400 Subject: [PATCH 11/13] Fix semgrep 'ci.caps4-in-func-name'. --- internal/service/elasticache/user_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/elasticache/user_test.go b/internal/service/elasticache/user_test.go index 7155e886b835..238d85a53da3 100644 --- a/internal/service/elasticache/user_test.go +++ b/internal/service/elasticache/user_test.go @@ -102,7 +102,7 @@ func TestAccElastiCacheUser_iam_auth_mode(t *testing.T) { CheckDestroy: testAccCheckUserDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccUserConfigWithIamAuthMode_basic(rName), + Config: testAccUserConfigWithIAMAuthMode_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckUserExists(ctx, resourceName, &user), resource.TestCheckResourceAttr(resourceName, "user_id", rName), @@ -379,7 +379,7 @@ resource "aws_elasticache_user" "test" { `, rName) } -func testAccUserConfigWithIamAuthMode_basic(rName string) string { +func testAccUserConfigWithIAMAuthMode_basic(rName string) string { return fmt.Sprintf(` resource "aws_elasticache_user" "test" { user_id = %[1]q From 5dfcc1f6b8013f415c5ffbf86c4044a8c5710fbf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 15 Mar 2023 15:45:03 -0400 Subject: [PATCH 12/13] Fix terrafmt errors in documentation. --- website/docs/r/elasticache_user.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/elasticache_user.html.markdown b/website/docs/r/elasticache_user.html.markdown index 6511c05f7a7d..fb3a20cda708 100644 --- a/website/docs/r/elasticache_user.html.markdown +++ b/website/docs/r/elasticache_user.html.markdown @@ -31,10 +31,10 @@ resource "aws_elasticache_user" "test" { user_name = "testUserName" access_string = "on ~* +@all" engine = "REDIS" - + authentication_mode { type = "iam" - } + } } ``` @@ -44,11 +44,11 @@ resource "aws_elasticache_user" "test" { user_name = "testUserName" access_string = "on ~* +@all" engine = "REDIS" - + authentication_mode { type = "password" passwords = ["password1", "password2"] - } + } } ``` From 3557d3a1f54db64b1f13f3acf91bc175c313f453 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 15 Mar 2023 15:45:44 -0400 Subject: [PATCH 13/13] Remove unused 'testAccUserConfigWithNoPassRequiredAuthMode_basic'. --- internal/service/elasticache/user_test.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/internal/service/elasticache/user_test.go b/internal/service/elasticache/user_test.go index 238d85a53da3..acf7f17ba152 100644 --- a/internal/service/elasticache/user_test.go +++ b/internal/service/elasticache/user_test.go @@ -394,21 +394,6 @@ resource "aws_elasticache_user" "test" { `, rName) } -func testAccUserConfigWithNoPassRequiredAuthMode_basic(rName string) string { - return fmt.Sprintf(` -resource "aws_elasticache_user" "test" { - user_id = %[1]q - user_name = "username1" - access_string = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember" - engine = "REDIS" - - authentication_mode { - type = "no-password-required" - } -} -`, rName) -} - func testAccUserConfig_update(rName string) string { return fmt.Sprintf(` resource "aws_elasticache_user" "test" {