Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
coderGo93 committed Nov 17, 2021
1 parent 969b46c commit 40e7c23
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 62 deletions.
2 changes: 1 addition & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ func Provider() *schema.Provider {
"aws_appstream_fleet": appstream.ResourceFleet(),
"aws_appstream_image_builder": appstream.ResourceImageBuilder(),
"aws_appstream_stack": appstream.ResourceStack(),
"aws_appstream_stack_user_association": appstream.ResourceUserStackAssociation(),
"aws_appstream_user_stack_association": appstream.ResourceUserStackAssociation(),
"aws_appstream_user": appstream.ResourceUser(),

"aws_appsync_api_key": appsync.ResourceAPIKey(),
Expand Down
2 changes: 1 addition & 1 deletion internal/service/appstream/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ func statusUserAvailable(ctx context.Context, conn *appstream.AppStream, usernam
return nil, "", err
}

return user, "AVAILABLE", nil
return user, userAvailable, nil
}
}
38 changes: 15 additions & 23 deletions internal/service/appstream/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ func ResourceUser() *schema.Resource {
ForceNew: true,
ValidateFunc: validation.StringLenBetween(0, 2048),
},
"status": {
Type: schema.TypeString,
Computed: true,
"send_email_notification": {
Type: schema.TypeBool,
Optional: true,
},
"user_name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -91,46 +91,40 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf
input.LastName = aws.String(v.(string))
}

if v, ok := d.GetOk("message_action"); ok {
input.MessageAction = aws.String(v.(string))
if v, ok := d.GetOk("send_email_notification"); ok {
if !v.(bool) {
input.MessageAction = aws.String(appstream.MessageActionSuppress)
}
}

_, err := conn.CreateUserWithContext(ctx, input)

id := EncodeUserID(userName, authType)

if err != nil {
return diag.FromErr(fmt.Errorf("error creating AppStream User (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error creating AppStream User (%s): %w", id, err))
}

if _, err = waitUserAvailable(ctx, conn, userName, authType); err != nil {
return diag.FromErr(fmt.Errorf("error waiting for AppStream User (%s) to be available: %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error waiting for AppStream User (%s) to be available: %w", id, err))
}

// Enabling/disabling workflow
if v, ok := d.GetOk("enabled"); ok {
if v.(bool) {
input := &appstream.EnableUserInput{
AuthenticationType: aws.String(authType),
UserName: aws.String(userName),
}

_, err = conn.EnableUserWithContext(ctx, input)
if err != nil {
return diag.FromErr(fmt.Errorf("error enabling AppStream User (%s): %w", d.Id(), err))
}
} else {
if v, ok := d.GetOkExists("enabled"); ok {
if !v.(bool) {
input := &appstream.DisableUserInput{
AuthenticationType: aws.String(authType),
UserName: aws.String(userName),
}

_, err = conn.DisableUserWithContext(ctx, input)
if err != nil {
return diag.FromErr(fmt.Errorf("error disabling AppStream User (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error disabling AppStream User (%s): %w", id, err))
}
}
}

d.SetId(EncodeUserID(userName, authType))
d.SetId(id)

return resourceUserRead(ctx, d, meta)
}
Expand Down Expand Up @@ -160,7 +154,6 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta interfac
d.Set("first_name", user.FirstName)

d.Set("last_name", user.LastName)
d.Set("status", user.Status)
d.Set("user_name", user.UserName)

return nil
Expand Down Expand Up @@ -196,7 +189,6 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf
return diag.FromErr(fmt.Errorf("error disabling AppStream User (%s): %w", d.Id(), err))
}
}

}

return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func ResourceUserStackAssociation() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceUserStackAssociationCreate,
ReadWithoutTimeout: resourceUserStackAssociationRead,
UpdateWithoutTimeout: schema.NoopContext,
DeleteWithoutTimeout: resourceUserStackAssociationDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
Expand All @@ -31,6 +32,10 @@ func ResourceUserStackAssociation() *schema.Resource {
ForceNew: true,
ValidateFunc: validation.StringInSlice(appstream.AuthenticationType_Values(), false),
},
"send_email_notification": {
Type: schema.TypeBool,
Optional: true,
},
"stack_name": {
Type: schema.TypeString,
Required: true,
Expand All @@ -55,33 +60,40 @@ func resourceUserStackAssociationCreate(ctx context.Context, d *schema.ResourceD
UserName: aws.String(d.Get("user_name").(string)),
}

var output *appstream.BatchAssociateUserStackOutput
if v, ok := d.GetOk("send_email_notification"); ok {
input.SendEmailNotification = aws.Bool(v.(bool))
}

id := EncodeStackUserID(d.Get("stack_name").(string), d.Get("user_name").(string), d.Get("authentication_type").(string))

output, err := conn.BatchAssociateUserStackWithContext(ctx, &appstream.BatchAssociateUserStackInput{
UserStackAssociations: []*appstream.UserStackAssociation{input},
})

if err != nil {
return diag.FromErr(fmt.Errorf("error creating Appstream Stack User Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error creating AppStream User Stack Association (%s): %w", id, err))
}
if len(output.Errors) > 0 {
var errs *multierror.Error

for _, err := range output.Errors {
errs = multierror.Append(errs, fmt.Errorf("%s: %s", aws.StringValue(err.ErrorCode), aws.StringValue(err.ErrorMessage)))
}
return diag.FromErr(fmt.Errorf("error creating AppStream User Stack Association (%s): %w", id, errs))

}

d.SetId(EncodeStackUserID(d.Get("stack_name").(string), d.Get("user_name").(string), d.Get("authentication_type").(string)))
d.SetId(id)

return resourceUserStackAssociationRead(ctx, d, meta)
}

func resourceUserStackAssociationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).AppStreamConn

stackName, userName, authType, err := DecodeStackUserID(d.Id())
userName, stackName, authType, err := DecodeStackUserID(d.Id())
if err != nil {
return diag.FromErr(fmt.Errorf("error decoding id Appstream Stack User Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error decoding id AppStream User Stack Association (%s): %w", d.Id(), err))
}

resp, err := conn.DescribeUserStackAssociationsWithContext(ctx,
Expand All @@ -92,13 +104,13 @@ func resourceUserStackAssociationRead(ctx context.Context, d *schema.ResourceDat
})

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appstream.ErrCodeResourceNotFoundException) {
log.Printf("[WARN] Appstream Stack User Association (%s) not found, removing from state", d.Id())
log.Printf("[WARN] AppStream User Stack Association (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if len(resp.UserStackAssociations) == 0 {
log.Printf("[WARN] Appstream User (%s) not found, removing from state", d.Id())
log.Printf("[WARN] AppStream User Stack Association (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}
Expand All @@ -115,9 +127,9 @@ func resourceUserStackAssociationRead(ctx context.Context, d *schema.ResourceDat
func resourceUserStackAssociationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).AppStreamConn

stackName, userName, authType, err := DecodeStackUserID(d.Id())
userName, stackName, authType, err := DecodeStackUserID(d.Id())
if err != nil {
return diag.FromErr(fmt.Errorf("error decoding id Appstream Stack User Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error decoding id AppStream User Stack Association (%s): %w", d.Id(), err))
}

input := &appstream.UserStackAssociation{
Expand All @@ -134,19 +146,19 @@ func resourceUserStackAssociationDelete(ctx context.Context, d *schema.ResourceD
if tfawserr.ErrCodeEquals(err, appstream.ErrCodeResourceNotFoundException) {
return nil
}
return diag.FromErr(fmt.Errorf("error deleting Appstream Stack User Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error deleting AppStream User Stack Association (%s): %w", d.Id(), err))
}
return nil
}

func EncodeStackUserID(stackName, userName, authType string) string {
return fmt.Sprintf("%s/%s/%s", stackName, userName, authType)
return fmt.Sprintf("%s/%s/%s", userName, stackName, authType)
}

func DecodeStackUserID(id string) (string, string, string, error) {
idParts := strings.SplitN(id, "/", 3)
if len(idParts) != 3 {
return "", "", "", fmt.Errorf("expected ID in format StackName/UserName/AuthenticationType, received: %s", id)
return "", "", "", fmt.Errorf("expected ID in format UserName/StackName/AuthenticationType, received: %s", id)
}
return idParts[0], idParts[1], idParts[2], nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ import (
)

func TestAccAppStreamUserStackAssociation_basic(t *testing.T) {
resourceName := "aws_appstream_stack_user_association.test"
resourceName := "aws_appstream_user_stack_association.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
authType := "USERPOOL"
rEmail := acctest.RandomEmailAddress("hashicorp.com")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckHasIAMRole(t, "AmazonAppStreamServiceAccess")
},
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckUserStackAssociationDestroy,
Expand All @@ -50,15 +49,14 @@ func TestAccAppStreamUserStackAssociation_basic(t *testing.T) {
}

func TestAccAppStreamUserStackAssociation_disappears(t *testing.T) {
resourceName := "aws_appstream_stack_user_association.test"
resourceName := "aws_appstream_user_stack_association.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
authType := "USERPOOL"
rEmail := acctest.RandomEmailAddress("hashicorp.com")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckHasIAMRole(t, "AmazonAppStreamServiceAccess")
},
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckUserStackAssociationDestroy,
Expand All @@ -77,7 +75,7 @@ func TestAccAppStreamUserStackAssociation_disappears(t *testing.T) {
}

func TestAccAppStreamUserStackAssociation_complete(t *testing.T) {
resourceName := "aws_appstream_stack_user_association.test"
resourceName := "aws_appstream_user_stack_association.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
authType := "USERPOOL"
rEmail := acctest.RandomEmailAddress("hashicorp.com")
Expand Down Expand Up @@ -122,7 +120,7 @@ func testAccCheckUserStackAssociationExists(resourceName string) resource.TestCh

conn := acctest.Provider.Meta().(*conns.AWSClient).AppStreamConn

stackName, userName, authType, err := tfappstream.DecodeStackUserID(rs.Primary.ID)
userName, stackName, authType, err := tfappstream.DecodeStackUserID(rs.Primary.ID)
if err != nil {
return fmt.Errorf("error decoding id appstream stack user association (%s): %w", rs.Primary.ID, err)
}
Expand All @@ -149,11 +147,11 @@ func testAccCheckUserStackAssociationDestroy(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).AppStreamConn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_appstream_stack_user_association" {
if rs.Type != "aws_appstream_user_stack_association" {
continue
}

stackName, userName, authType, err := tfappstream.DecodeStackUserID(rs.Primary.ID)
userName, stackName, authType, err := tfappstream.DecodeStackUserID(rs.Primary.ID)
if err != nil {
return fmt.Errorf("error decoding id appstream stack user association (%s): %w", rs.Primary.ID, err)
}
Expand Down Expand Up @@ -191,7 +189,7 @@ resource "aws_appstream_user" "test" {
user_name = %[3]q
}
resource "aws_appstream_stack_user_association" "test" {
resource "aws_appstream_user_stack_association" "test" {
authentication_type = aws_appstream_user.test.authentication_type
stack_name = aws_appstream_stack.test.name
user_name = aws_appstream_user.test.user_name
Expand Down
19 changes: 12 additions & 7 deletions internal/service/appstream/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ func TestAccAppStreamUser_basic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckHasIAMRole(t, "AmazonAppStreamServiceAccess")
},
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckUserDestroy,
Expand All @@ -39,7 +38,6 @@ func TestAccAppStreamUser_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "user_name", rEmail),
acctest.CheckResourceAttrRFC3339(resourceName, "created_time"),
resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "status", "FORCE_CHANGE_PASSWORD"),
),
},
{
Expand All @@ -61,7 +59,6 @@ func TestAccAppStreamUser_disappears(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckHasIAMRole(t, "AmazonAppStreamServiceAccess")
},
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckUserDestroy,
Expand Down Expand Up @@ -98,14 +95,13 @@ func TestAccAppStreamUser_complete(t *testing.T) {
ErrorCheck: acctest.ErrorCheck(t, appstream.EndpointsID),
Steps: []resource.TestStep{
{
Config: testAccUserCompleteConfig(authType, rEmail, firstName, lastName, true),
Config: testAccUserCompleteConfig(authType, rEmail, firstName, lastName, false),
Check: resource.ComposeTestCheckFunc(
testAccCheckUserExists(resourceName, &userOutput),
resource.TestCheckResourceAttr(resourceName, "authentication_type", authType),
resource.TestCheckResourceAttr(resourceName, "user_name", rEmail),
acctest.CheckResourceAttrRFC3339(resourceName, "created_time"),
resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "status", "FORCE_CHANGE_PASSWORD"),
resource.TestCheckResourceAttr(resourceName, "enabled", "false"),
),
},
{
Expand All @@ -116,7 +112,16 @@ func TestAccAppStreamUser_complete(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "user_name", rEmail),
acctest.CheckResourceAttrRFC3339(resourceName, "created_time"),
resource.TestCheckResourceAttr(resourceName, "enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "status", "FORCE_CHANGE_PASSWORD"),
),
},
{
Config: testAccUserCompleteConfig(authType, rEmail, firstName, lastName, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckUserExists(resourceName, &userOutput),
resource.TestCheckResourceAttr(resourceName, "authentication_type", authType),
resource.TestCheckResourceAttr(resourceName, "user_name", rEmail),
acctest.CheckResourceAttrRFC3339(resourceName, "created_time"),
resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
),
},
{
Expand Down
3 changes: 2 additions & 1 deletion internal/service/appstream/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
imageBuilderStateTimeout = 60 * time.Minute
// userOperationTimeout Maximum amount of time to wait for User operation eventual consistency
userOperationTimeout = 4 * time.Minute
userAvailable = "AVAILABLE"
)

// waitStackStateDeleted waits for a deleted stack
Expand Down Expand Up @@ -169,7 +170,7 @@ func waitImageBuilderStateDeleted(ctx context.Context, conn *appstream.AppStream
// waitUserAvailable waits for a user be available
func waitUserAvailable(ctx context.Context, conn *appstream.AppStream, username, authType string) (*appstream.User, error) {
stateConf := &resource.StateChangeConf{
Target: []string{"AVAILABLE"},
Target: []string{userAvailable},
Refresh: statusUserAvailable(ctx, conn, username, authType),
Timeout: userOperationTimeout,
}
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/appstream_user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The following arguments are optional:
* `enabled` - (Optional) Specifies whether the user in the user pool is enabled.
* `first_name` - (Optional) First name, or given name, of the user.
* `last_name` - (Optional) Last name, or surname, of the user.
* `send_email_notification` - (Optional) Send an email notification.

## Attributes Reference

Expand Down
Loading

0 comments on commit 40e7c23

Please sign in to comment.