Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
coderGo93 authored and gdavison committed Nov 24, 2021
1 parent a81c41b commit 86cabd3
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 86 deletions.
38 changes: 38 additions & 0 deletions internal/service/appstream/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package appstream
import (
"context"
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/appstream"
Expand Down Expand Up @@ -150,3 +151,40 @@ func FindUserByUserNameAndAuthType(ctx context.Context, conn *appstream.AppStrea

return result, nil
}

// FindAssociatedFleetStack Retrieve an associated fleet with a stack by fleet and stack name
func FindAssociatedFleetStack(ctx context.Context, conn *appstream.AppStream, fleetName, stackName string) (*string, error) {
input := &appstream.ListAssociatedStacksInput{
FleetName: aws.String(fleetName),
}

resp, err := conn.ListAssociatedStacksWithContext(ctx, &appstream.ListAssociatedStacksInput{FleetName: aws.String(fleetName)})

if tfawserr.ErrCodeEquals(err, appstream.ErrCodeResourceNotFoundException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}
if err != nil {
return nil, err
}

var sName string
for _, name := range resp.Names {
log.Printf("[DEBIG] name : %v", name)
if aws.StringValue(name) == stackName {
log.Printf("[DEBIG] name : %v found", name)
sName = aws.StringValue(name)
}
}

if len(sName) == 0 {
return nil, &resource.NotFoundError{
Message: "Empty result",
LastRequest: input,
}
}

return aws.String(sName), nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func ResourceStackFleetAssociation() *schema.Resource {
func ResourceFleetStackAssociation() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceStackFleetAssociationCreate,
ReadWithoutTimeout: resourceStackFleetAssociationRead,
DeleteWithoutTimeout: resourceStackFleetAssociationDelete,
CreateWithoutTimeout: resourceFleetStackAssociationCreate,
ReadWithoutTimeout: resourceFleetStackAssociationRead,
DeleteWithoutTimeout: resourceFleetStackAssociationDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Expand All @@ -39,7 +39,7 @@ func ResourceStackFleetAssociation() *schema.Resource {
}
}

func resourceStackFleetAssociationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
func resourceFleetStackAssociationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).AppStreamConn
input := &appstream.AssociateFleetInput{
FleetName: aws.String(d.Get("fleet_name").(string)),
Expand All @@ -63,44 +63,33 @@ func resourceStackFleetAssociationCreate(ctx context.Context, d *schema.Resource
_, err = conn.AssociateFleetWithContext(ctx, input)
}
if err != nil {
return diag.FromErr(fmt.Errorf("error creating Appstream Stack Fleet Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error creating Appstream Fleet Stack Association (%s): %w", d.Id(), err))
}

d.SetId(fmt.Sprintf("%s/%s", d.Get("stack_name").(string), d.Get("fleet_name").(string)))
d.SetId(EncodeStackFleetID(d.Get("stack_name").(string), d.Get("fleet_name").(string)))

This comment has been minimized.

Copy link
@rednevals

rednevals Apr 14, 2022

The arguments to EncodeStackFleetID are reversed. See this issue for details. Please correct...


return resourceStackFleetAssociationRead(ctx, d, meta)
return resourceFleetStackAssociationRead(ctx, d, meta)
}

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

stackName, fleetName, err := DecodeStackFleetID(d.Id())
fleetName, stackName, err := DecodeStackFleetID(d.Id())
if err != nil {
return diag.FromErr(fmt.Errorf("error decoding id Appstream Stack Fleet Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error decoding id Appstream Fleet Stack Association (%s): %w", d.Id(), err))
}

resp, err := conn.ListAssociatedStacksWithContext(ctx, &appstream.ListAssociatedStacksInput{FleetName: aws.String(fleetName)})
sName, err := FindAssociatedFleetStack(ctx, conn, fleetName, stackName)

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

var sName string
for _, name := range resp.Names {
if aws.StringValue(name) == stackName {
sName = aws.StringValue(name)
}
}

if err != nil {
return diag.FromErr(fmt.Errorf("error reading Appstream Stack Fleet Association (%s): %w", d.Id(), err))
}
if len(sName) == 0 {
log.Printf("[WARN] Appstream Stack Fleet Association (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
return diag.FromErr(fmt.Errorf("error reading Appstream Fleet Stack Association (%s): %w", d.Id(), err))
}

d.Set("fleet_name", fleetName)
Expand All @@ -109,12 +98,12 @@ func resourceStackFleetAssociationRead(ctx context.Context, d *schema.ResourceDa
return nil
}

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

stackName, fleetName, err := DecodeStackFleetID(d.Id())
fleetName, stackName, err := DecodeStackFleetID(d.Id())
if err != nil {
return diag.FromErr(fmt.Errorf("error decoding id Appstream Stack Fleet Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error decoding id Appstream Fleet Stack Association (%s): %w", d.Id(), err))
}

_, err = conn.DisassociateFleetWithContext(ctx, &appstream.DisassociateFleetInput{
Expand All @@ -126,15 +115,19 @@ func resourceStackFleetAssociationDelete(ctx context.Context, d *schema.Resource
if tfawserr.ErrCodeEquals(err, appstream.ErrCodeResourceNotFoundException) {
return nil
}
return diag.FromErr(fmt.Errorf("error deleting Appstream Stack Fleet Association (%s): %w", d.Id(), err))
return diag.FromErr(fmt.Errorf("error deleting Appstream Fleet Stack Association (%s): %w", d.Id(), err))
}
return nil
}

func EncodeStackFleetID(fleetName, stackName string) string {
return fmt.Sprintf("%s/%s", fleetName, stackName)
}

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

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/appstream"
"github.com/hashicorp/aws-sdk-go-base/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/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tfappstream "github.com/hashicorp/terraform-provider-aws/internal/service/appstream"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func TestAccAppStreamStackFleetAssociation_basic(t *testing.T) {
resourceName := "aws_appstream_stack_fleet_association.test"
func TestAccAppStreamFleetStackAssociation_basic(t *testing.T) {
resourceName := "aws_appstream_fleet_stack_association.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckHasIAMRole(t, "AmazonAppStreamServiceAccess")
},
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckStackFleetAssociationDestroy,
CheckDestroy: testAccCheckFleetStackAssociationDestroy,
ErrorCheck: acctest.ErrorCheck(t, appstream.EndpointsID),
Steps: []resource.TestStep{
{
Config: testAccStackFleetAssociationConfig(rName),
Config: testAccFleetStackAssociationConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckStackFleetAssociationExists(resourceName),
testAccCheckFleetStackAssociationExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "fleet_name", rName),
resource.TestCheckResourceAttr(resourceName, "stack_name", rName),
),
},
{
Expand All @@ -44,32 +44,31 @@ func TestAccAppStreamStackFleetAssociation_basic(t *testing.T) {
})
}

func TestAccAppStreamStackFleetAssociation_disappears(t *testing.T) {
resourceName := "aws_appstream_stack_fleet_association.test"
func TestAccAppStreamFleetStackAssociation_disappears(t *testing.T) {
resourceName := "aws_appstream_fleet_stack_association.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
acctest.PreCheckHasIAMRole(t, "AmazonAppStreamServiceAccess")
},
ProviderFactories: acctest.ProviderFactories,
CheckDestroy: testAccCheckStackFleetAssociationDestroy,
CheckDestroy: testAccCheckFleetStackAssociationDestroy,
ErrorCheck: acctest.ErrorCheck(t, appstream.EndpointsID),
Steps: []resource.TestStep{
{
Config: testAccStackFleetAssociationConfig(rName),
Config: testAccFleetStackAssociationConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckStackFleetAssociationExists(resourceName),
acctest.CheckResourceDisappears(acctest.Provider, tfappstream.ResourceStackFleetAssociation(), resourceName),
testAccCheckFleetStackAssociationExists(resourceName),
acctest.CheckResourceDisappears(acctest.Provider, tfappstream.ResourceFleetStackAssociation(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckStackFleetAssociationExists(resourceName string) resource.TestCheckFunc {
func testAccCheckFleetStackAssociationExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
Expand All @@ -78,73 +77,57 @@ func testAccCheckStackFleetAssociationExists(resourceName string) resource.TestC

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

stackName, fleetName, err := tfappstream.DecodeStackFleetID(rs.Primary.ID)
fleetName, stackName, err := tfappstream.DecodeStackFleetID(rs.Primary.ID)
if err != nil {
return fmt.Errorf("error decoding id appstream stack fleet association (%s): %w", rs.Primary.ID, err)
return fmt.Errorf("error decoding id appstream fleet stack association (%s): %w", rs.Primary.ID, err)
}

resp, err := conn.ListAssociatedStacksWithContext(context.Background(), &appstream.ListAssociatedStacksInput{FleetName: aws.String(fleetName)})
sName, err := tfappstream.FindAssociatedFleetStack(context.TODO(), conn, fleetName, stackName)

if err != nil {
return err
}

found := false

for _, name := range resp.Names {
if aws.StringValue(name) == stackName {
found = true
}
}

if !found {
return fmt.Errorf("appstream stack fleet association %q does not exist", rs.Primary.ID)
if sName == nil {
return fmt.Errorf("appstream fleet stack association %q does not exist", rs.Primary.ID)
}

return nil
}
}

func testAccCheckStackFleetAssociationDestroy(s *terraform.State) error {
func testAccCheckFleetStackAssociationDestroy(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).AppStreamConn

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

stackName, fleetName, err := tfappstream.DecodeStackFleetID(rs.Primary.ID)
fleetName, stackName, err := tfappstream.DecodeStackFleetID(rs.Primary.ID)
if err != nil {
return fmt.Errorf("error decoding id appstream stack fleet association (%s): %w", rs.Primary.ID, err)
return fmt.Errorf("error decoding id appstream fleet stack association (%s): %w", rs.Primary.ID, err)
}

resp, err := conn.ListAssociatedStacksWithContext(context.Background(), &appstream.ListAssociatedStacksInput{FleetName: aws.String(fleetName)})
sName, err := tfappstream.FindAssociatedFleetStack(context.TODO(), conn, fleetName, stackName)

if tfawserr.ErrCodeEquals(err, appstream.ErrCodeResourceNotFoundException) {
if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

found := false

for _, name := range resp.Names {
if aws.StringValue(name) == stackName {
found = true
}
}

if found {
return fmt.Errorf("appstream stack fleet association %q still exists", rs.Primary.ID)
if sName != nil {
return fmt.Errorf("appstream fleet stack association %q still exists", rs.Primary.ID)
}
}

return nil
}

func testAccStackFleetAssociationConfig(name string) string {
func testAccFleetStackAssociationConfig(name string) string {
// "Amazon-AppStream2-Sample-Image-02-04-2019" is not available in GovCloud
return fmt.Sprintf(`
resource "aws_appstream_fleet" "test" {
Expand All @@ -161,7 +144,7 @@ resource "aws_appstream_stack" "test" {
name = %[1]q
}
resource "aws_appstream_stack_fleet_association" "test" {
resource "aws_appstream_fleet_stack_association" "test" {
fleet_name = aws_appstream_fleet.test.name
stack_name = aws_appstream_stack.test.name
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
subcategory: "AppStream"
layout: "aws"
page_title: "AWS: aws_appstream_stack_fleet_association"
page_title: "AWS: aws_appstream_fleet_stack_association"
description: |-
Manages an AppStream Stack Fleet association.
Manages an AppStream Fleet Stack association.
---

# Resource: aws_appstream_stack_fleet_association
# Resource: aws_appstream_fleet_stack_association

Manages an AppStream Stack Fleet association.
Manages an AppStream Fleet Stack association.

## Example Usage

Expand All @@ -27,7 +27,7 @@ resource "aws_appstream_stack" "example" {
name = "STACK NAME"
}
resource "aws_appstream_stack_fleet_association" "example" {
resource "aws_appstream_fleet_stack_association" "example" {
fleet_name = aws_appstream_fleet.example.name
stack_name = aws_appstream_stack.example.name
}
Expand All @@ -49,8 +49,8 @@ In addition to all arguments above, the following attributes are exported:

## Import

AppStream Stack Fleet Association can be imported by using the `stack_name` and `fleet_name` separated by a slash (`/`), e.g.,
AppStream Stack Fleet Association can be imported by using the `fleet_name` and `stack_name` separated by a slash (`/`), e.g.,

```
$ terraform import aws_appstream_stack_fleet_association.example stackName/fleetName
$ terraform import aws_appstream_fleet_stack_association.example fleetName/stackName
```

0 comments on commit 86cabd3

Please sign in to comment.