diff --git a/internal/service/appstream/find.go b/internal/service/appstream/find.go index ba9ee0e2a618..012f38912ffa 100644 --- a/internal/service/appstream/find.go +++ b/internal/service/appstream/find.go @@ -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" @@ -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 +} diff --git a/internal/service/appstream/stack_fleet_association.go b/internal/service/appstream/fleet_stack_association.go similarity index 58% rename from internal/service/appstream/stack_fleet_association.go rename to internal/service/appstream/fleet_stack_association.go index 0a71ffbcb051..ab592ef97682 100644 --- a/internal/service/appstream/stack_fleet_association.go +++ b/internal/service/appstream/fleet_stack_association.go @@ -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, }, @@ -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)), @@ -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))) - 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) @@ -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{ @@ -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 } diff --git a/internal/service/appstream/stack_fleet_association_test.go b/internal/service/appstream/fleet_stack_association_test.go similarity index 55% rename from internal/service/appstream/stack_fleet_association_test.go rename to internal/service/appstream/fleet_stack_association_test.go index e1dd6dede6f6..6397b0fe6ab0 100644 --- a/internal/service/appstream/stack_fleet_association_test.go +++ b/internal/service/appstream/fleet_stack_association_test.go @@ -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), ), }, { @@ -44,24 +44,23 @@ 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, }, @@ -69,7 +68,7 @@ func TestAccAppStreamStackFleetAssociation_disappears(t *testing.T) { }) } -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 { @@ -78,49 +77,41 @@ 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 } @@ -128,23 +119,15 @@ func testAccCheckStackFleetAssociationDestroy(s *terraform.State) error { 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" { @@ -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 } diff --git a/website/docs/r/appstream_stack_fleet_association.html.markdown b/website/docs/r/appstream_fleet_stack_association.html.markdown similarity index 68% rename from website/docs/r/appstream_stack_fleet_association.html.markdown rename to website/docs/r/appstream_fleet_stack_association.html.markdown index 6f12ea8ae7cf..1545c03f0e9e 100644 --- a/website/docs/r/appstream_stack_fleet_association.html.markdown +++ b/website/docs/r/appstream_fleet_stack_association.html.markdown @@ -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 @@ -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 } @@ -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 ```