diff --git a/aws/internal/service/cognitoidentityprovider/waiter/status.go b/aws/internal/service/cognitoidentityprovider/waiter/status.go new file mode 100644 index 00000000000..54c071f2d97 --- /dev/null +++ b/aws/internal/service/cognitoidentityprovider/waiter/status.go @@ -0,0 +1,33 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + userPoolDomainStatusNotFound = "NotFound" + userPoolDomainStatusUnknown = "Unknown" +) + +// UserPoolDomainStatus fetches the Operation and its Status +func UserPoolDomainStatus(conn *cognitoidentityprovider.CognitoIdentityProvider, domain string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &cognitoidentityprovider.DescribeUserPoolDomainInput{ + Domain: aws.String(domain), + } + + output, err := conn.DescribeUserPoolDomain(input) + + if err != nil { + return nil, userPoolDomainStatusUnknown, err + } + + if output == nil { + return nil, userPoolDomainStatusNotFound, nil + } + + return output, aws.StringValue(output.DomainDescription.Status), nil + } +} diff --git a/aws/internal/service/cognitoidentityprovider/waiter/waiter.go b/aws/internal/service/cognitoidentityprovider/waiter/waiter.go new file mode 100644 index 00000000000..345e8de5624 --- /dev/null +++ b/aws/internal/service/cognitoidentityprovider/waiter/waiter.go @@ -0,0 +1,56 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + // Maximum amount of time to wait for an Operation to return Success + UserPoolDomainDeleteTimeout = 1 * time.Minute +) + +// UserPoolDomainDeleted waits for an Operation to return Success +func UserPoolDomainDeleted(conn *cognitoidentityprovider.CognitoIdentityProvider, domain string) (*cognitoidentityprovider.DescribeUserPoolDomainOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + cognitoidentityprovider.DomainStatusTypeUpdating, + cognitoidentityprovider.DomainStatusTypeDeleting, + }, + Target: []string{""}, + Refresh: UserPoolDomainStatus(conn, domain), + Timeout: UserPoolDomainDeleteTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*cognitoidentityprovider.DescribeUserPoolDomainOutput); ok { + return output, err + } + + return nil, err +} + +func UserPoolDomainCreated(conn *cognitoidentityprovider.CognitoIdentityProvider, domain string, timeout time.Duration) (*cognitoidentityprovider.DescribeUserPoolDomainOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + cognitoidentityprovider.DomainStatusTypeCreating, + cognitoidentityprovider.DomainStatusTypeUpdating, + }, + Target: []string{ + cognitoidentityprovider.DomainStatusTypeActive, + }, + Refresh: UserPoolDomainStatus(conn, domain), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*cognitoidentityprovider.DescribeUserPoolDomainOutput); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_cognito_user_pool_domain.go b/aws/resource_aws_cognito_user_pool_domain.go index e4e74aef7d4..1caecad6ed6 100644 --- a/aws/resource_aws_cognito_user_pool_domain.go +++ b/aws/resource_aws_cognito_user_pool_domain.go @@ -7,9 +7,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" - "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/terraform-providers/terraform-provider-aws/aws/internal/service/cognitoidentityprovider/waiter" ) func resourceAwsCognitoUserPoolDomain() *schema.Resource { @@ -83,37 +83,13 @@ func resourceAwsCognitoUserPoolDomainCreate(d *schema.ResourceData, meta interfa _, err := conn.CreateUserPoolDomain(params) if err != nil { - return fmt.Errorf("Error creating Cognito User Pool Domain: %s", err) + return fmt.Errorf("Error creating Cognito User Pool Domain: %w", err) } d.SetId(domain) - stateConf := resource.StateChangeConf{ - Pending: []string{ - cognitoidentityprovider.DomainStatusTypeCreating, - cognitoidentityprovider.DomainStatusTypeUpdating, - }, - Target: []string{ - cognitoidentityprovider.DomainStatusTypeActive, - }, - MinTimeout: 1 * time.Minute, - Timeout: timeout, - Refresh: func() (interface{}, string, error) { - domain, err := conn.DescribeUserPoolDomain(&cognitoidentityprovider.DescribeUserPoolDomainInput{ - Domain: aws.String(d.Get("domain").(string)), - }) - if err != nil { - return 42, "", err - } - - desc := domain.DomainDescription - - return domain, *desc.Status, nil - }, - } - _, err = stateConf.WaitForState() - if err != nil { - return err + if _, err := waiter.UserPoolDomainCreated(conn, d.Id(), timeout); err != nil { + return fmt.Errorf("error waiting for User Pool Domain (%s) creation: %w", d.Id(), err) } return resourceAwsCognitoUserPoolDomainRead(d, meta) @@ -127,7 +103,7 @@ func resourceAwsCognitoUserPoolDomainRead(d *schema.ResourceData, meta interface Domain: aws.String(d.Id()), }) if err != nil { - if isAWSErr(err, "ResourceNotFoundException", "") { + if isAWSErr(err, cognitoidentityprovider.ErrCodeResourceNotFoundException, "") { log.Printf("[WARN] Cognito User Pool Domain %q not found, removing from state", d.Id()) d.SetId("") return nil @@ -137,6 +113,12 @@ func resourceAwsCognitoUserPoolDomainRead(d *schema.ResourceData, meta interface desc := domain.DomainDescription + if desc.Status == nil { + log.Printf("[WARN] Cognito User Pool Domain %q not found, removing from state", d.Id()) + d.SetId("") + return nil + } + d.Set("domain", d.Id()) d.Set("certificate_arn", "") if desc.CustomDomainConfig != nil { @@ -160,35 +142,16 @@ func resourceAwsCognitoUserPoolDomainDelete(d *schema.ResourceData, meta interfa UserPoolId: aws.String(d.Get("user_pool_id").(string)), }) if err != nil { - return err + return fmt.Errorf("Error deleting User Pool Domain: %w", err) } - stateConf := resource.StateChangeConf{ - Pending: []string{ - cognitoidentityprovider.DomainStatusTypeUpdating, - cognitoidentityprovider.DomainStatusTypeDeleting, - }, - Target: []string{""}, - Timeout: 1 * time.Minute, - Refresh: func() (interface{}, string, error) { - domain, err := conn.DescribeUserPoolDomain(&cognitoidentityprovider.DescribeUserPoolDomainInput{ - Domain: aws.String(d.Id()), - }) - if err != nil { - if isAWSErr(err, "ResourceNotFoundException", "") { - return 42, "", nil - } - return 42, "", err - } - - desc := domain.DomainDescription - if desc.Status == nil { - return 42, "", nil - } - - return domain, *desc.Status, nil - }, + if _, err := waiter.UserPoolDomainDeleted(conn, d.Id()); err != nil { + if isAWSErr(err, cognitoidentityprovider.ErrCodeResourceNotFoundException, "") { + return nil + } + return fmt.Errorf("error waiting for User Pool Domain (%s) deletion: %w", d.Id(), err) } - _, err = stateConf.WaitForState() - return err + + return nil + } diff --git a/aws/resource_aws_cognito_user_pool_domain_test.go b/aws/resource_aws_cognito_user_pool_domain_test.go index 7cc62b3aa63..4163094871a 100644 --- a/aws/resource_aws_cognito_user_pool_domain_test.go +++ b/aws/resource_aws_cognito_user_pool_domain_test.go @@ -151,6 +151,28 @@ func TestAccAWSCognitoUserPoolDomain_custom(t *testing.T) { }) } +func TestAccAWSCognitoUserPoolDomain_disappears(t *testing.T) { + domainName := fmt.Sprintf("tf-acc-test-domain-%d", acctest.RandInt()) + poolName := fmt.Sprintf("tf-acc-test-pool-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) + resourceName := "aws_cognito_user_pool_domain.main" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolDomainDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolDomainConfig_basic(domainName, poolName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolDomainExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCognitoUserPoolDomain(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSCognitoUserPoolDomainExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -185,7 +207,7 @@ func testAccCheckAWSCognitoUserPoolDomainDestroy(s *terraform.State) error { }) if err != nil { - if isAWSErr(err, "ResourceNotFoundException", "") { + if isAWSErr(err, cognitoidentityprovider.ErrCodeResourceNotFoundException, "") { return nil } return err