Skip to content

Commit

Permalink
Merge pull request #38182 from hashicorp/b-aws_cognito_user-regression
Browse files Browse the repository at this point in the history
r/aws_cognito_user: Fix resource recreation for pre-v5.56.0 resources imported with certain import IDs
  • Loading branch information
ewbankkit authored Jun 28, 2024
2 parents 5b43711 + 1463b80 commit e6b88f2
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .changelog/38182.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_cognito_user: Fix a bug that caused resource recreation for resources imported with certain [import ID](https://developer.hashicorp.com/terraform/language/import#import-id) formats
```
49 changes: 21 additions & 28 deletions internal/service/cognitoidp/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,18 @@ func resourceUser() *schema.Resource {
DeleteWithoutTimeout: resourceUserDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), userResourceIDSeparator)

if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return nil, fmt.Errorf("unexpected format for ID (%[1]s), expected UserPoolID%[2]sUsername", d.Id(), userResourceIDSeparator)
}

d.Set(names.AttrUserPoolID, parts[0])
d.Set(names.AttrUsername, parts[1])

return []*schema.ResourceData{d}, nil
},
},

Schema: map[string]*schema.Schema{
Expand Down Expand Up @@ -179,11 +190,11 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
}

if v, ok := d.GetOk(names.AttrAttributes); ok {
input.UserAttributes = expandAttributeTypess(v.(map[string]interface{}))
input.UserAttributes = expandAttributeTypes(v.(map[string]interface{}))
}

if v, ok := d.GetOk("validation_data"); ok {
input.ValidationData = expandAttributeTypess(v.(map[string]interface{}))
input.ValidationData = expandAttributeTypes(v.(map[string]interface{}))
}

_, err := conn.AdminCreateUser(ctx, input)
Expand Down Expand Up @@ -229,11 +240,7 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).CognitoIDPClient(ctx)

userPoolID, username, err := userParseResourceID(d.Id())
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}

userPoolID, username := d.Get(names.AttrUserPoolID).(string), d.Get(names.AttrUsername).(string)
user, err := findUserByTwoPartKey(ctx, conn, userPoolID, username)

if !d.IsNewResource() && tfresource.NotFound(err) {
Expand Down Expand Up @@ -268,10 +275,7 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).CognitoIDPClient(ctx)

userPoolID, username, err := userParseResourceID(d.Id())
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
userPoolID, username := d.Get(names.AttrUserPoolID).(string), d.Get(names.AttrUsername).(string)

if d.HasChange(names.AttrAttributes) {
o, n := d.GetChange(names.AttrAttributes)
Expand All @@ -280,7 +284,7 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
if len(upd) > 0 {
input := &cognitoidentityprovider.AdminUpdateUserAttributesInput{
Username: aws.String(username),
UserAttributes: expandAttributeTypess(upd),
UserAttributes: expandAttributeTypes(upd),
UserPoolId: aws.String(userPoolID),
}

Expand Down Expand Up @@ -381,13 +385,10 @@ func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interf
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).CognitoIDPClient(ctx)

userPoolID, username, err := userParseResourceID(d.Id())
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
userPoolID, username := d.Get(names.AttrUserPoolID).(string), d.Get(names.AttrUsername).(string)

log.Printf("[DEBUG] Deleting Cognito User: %s", d.Id())
_, err = conn.AdminDeleteUser(ctx, &cognitoidentityprovider.AdminDeleteUserInput{
_, err := conn.AdminDeleteUser(ctx, &cognitoidentityprovider.AdminDeleteUserInput{
Username: aws.String(username),
UserPoolId: aws.String(userPoolID),
})
Expand All @@ -412,15 +413,7 @@ func userCreateResourceID(userPoolID, username string) string {
return id
}

func userParseResourceID(id string) (string, string, error) {
parts := strings.Split(id, userResourceIDSeparator)

if len(parts) == 2 && parts[0] != "" && parts[1] != "" {
return parts[0], parts[1], nil
}

return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected UserPoolID%[2]sUsername", id, userResourceIDSeparator)
}
// No userParseResourceID as pre-v5.56.0, the ID wasn't parsed -- user_pool_id and username attribute were used directly.

func findUserByTwoPartKey(ctx context.Context, conn *cognitoidentityprovider.Client, userPoolID, username string) (*cognitoidentityprovider.AdminGetUserOutput, error) {
input := &cognitoidentityprovider.AdminGetUserInput{
Expand Down Expand Up @@ -448,7 +441,7 @@ func findUserByTwoPartKey(ctx context.Context, conn *cognitoidentityprovider.Cli
return output, nil
}

func expandAttributeTypess(tfMap map[string]interface{}) []awstypes.AttributeType {
func expandAttributeTypes(tfMap map[string]interface{}) []awstypes.AttributeType {
if len(tfMap) == 0 {
return nil
}
Expand Down
60 changes: 60 additions & 0 deletions internal/service/cognitoidp/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,47 @@ func TestAccCognitoIDPUser_enabled(t *testing.T) {
})
}

// https://github.com/hashicorp/terraform-provider-aws/issues/38175.
func TestAccCognitoIDPUser_v5560Regression(t *testing.T) {
ctx := acctest.Context(t)
rUserPoolName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
domain := acctest.RandomDomainName()
rUserName := acctest.RandomEmailAddress(domain)
resourceName := "aws_cognito_user.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.CognitoIDPServiceID),
CheckDestroy: testAccCheckUserDestroy(ctx),
Steps: []resource.TestStep{
{
ExternalProviders: map[string]resource.ExternalProvider{
"aws": {
Source: "hashicorp/aws",
VersionConstraint: "5.53.0",
},
},
Config: testAccUserConfig_v5560Regression(rUserPoolName, rUserName),
Check: resource.ComposeTestCheckFunc(
testAccCheckUserExists(ctx, resourceName),
resource.TestCheckResourceAttrSet(resourceName, names.AttrCreationDate),
resource.TestCheckResourceAttrSet(resourceName, "last_modified_date"),
resource.TestCheckResourceAttrSet(resourceName, "sub"),
resource.TestCheckResourceAttr(resourceName, "preferred_mfa_setting", ""),
resource.TestCheckResourceAttr(resourceName, "mfa_setting_list.#", acctest.Ct0),
resource.TestCheckResourceAttr(resourceName, names.AttrEnabled, acctest.CtTrue),
resource.TestCheckResourceAttr(resourceName, names.AttrStatus, string(awstypes.UserStatusTypeForceChangePassword)),
),
},
{
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Config: testAccUserConfig_v5560Regression(rUserPoolName, rUserName),
PlanOnly: true,
},
},
})
}

func testAccCheckUserExists(ctx context.Context, n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -611,3 +652,22 @@ resource "aws_cognito_user" "test" {
}
`, userPoolName, userName, enabled)
}

func testAccUserConfig_v5560Regression(userPoolName string, userName string) string {
return fmt.Sprintf(`
resource "aws_cognito_user_pool" "test" {
name = %[1]q
}
resource "aws_cognito_user" "test" {
user_pool_id = aws_cognito_user_pool.test.id
username = %[2]q
attributes = {
"name" = "test"
"email" = %[2]q
"email_verified" = "true"
}
}
`, userPoolName, userName)
}

0 comments on commit e6b88f2

Please sign in to comment.