Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resource: aws_cognito_user_pool_domain #2325

Merged
merged 1 commit into from
Jan 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ func Provider() terraform.ResourceProvider {
"aws_cognito_identity_pool": resourceAwsCognitoIdentityPool(),
"aws_cognito_identity_pool_roles_attachment": resourceAwsCognitoIdentityPoolRolesAttachment(),
"aws_cognito_user_pool": resourceAwsCognitoUserPool(),
"aws_cognito_user_pool_domain": resourceAwsCognitoUserPoolDomain(),
"aws_autoscaling_lifecycle_hook": resourceAwsAutoscalingLifecycleHook(),
"aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(),
"aws_cloudwatch_dashboard": resourceAwsCloudWatchDashboard(),
Expand Down
171 changes: 171 additions & 0 deletions aws/resource_aws_cognito_user_pool_domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package aws

import (
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsCognitoUserPoolDomain() *schema.Resource {
return &schema.Resource{
Create: resourceAwsCognitoUserPoolDomainCreate,
Read: resourceAwsCognitoUserPoolDomainRead,
Delete: resourceAwsCognitoUserPoolDomainDelete,
Importer: &schema.ResourceImporter{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of adding a test for the import?

State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"domain": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateCognitoUserPoolDomain,
},
"user_pool_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"aws_account_id": {
Type: schema.TypeString,
Computed: true,
},
"cloudfront_distribution_arn": {
Type: schema.TypeString,
Computed: true,
},
"s3_bucket": {
Type: schema.TypeString,
Computed: true,
},
"version": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAwsCognitoUserPoolDomainCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cognitoidpconn

domain := d.Get("domain").(string)

params := &cognitoidentityprovider.CreateUserPoolDomainInput{
Domain: aws.String(domain),
UserPoolId: aws.String(d.Get("user_pool_id").(string)),
}
log.Printf("[DEBUG] Creating Cognito User Pool Domain: %s", params)

_, err := conn.CreateUserPoolDomain(params)
if err != nil {
return fmt.Errorf("Error creating Cognito User Pool Domain: %s", err)
}

d.SetId(domain)

stateConf := resource.StateChangeConf{
Pending: []string{
cognitoidentityprovider.DomainStatusTypeCreating,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

cognitoidentityprovider.DomainStatusTypeUpdating,
},
Target: []string{
cognitoidentityprovider.DomainStatusTypeActive,
},
Timeout: 1 * time.Minute,
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
}

return resourceAwsCognitoUserPoolDomainRead(d, meta)
}

func resourceAwsCognitoUserPoolDomainRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cognitoidpconn
log.Printf("[DEBUG] Reading Cognito User Pool Domain: %s", d.Id())

domain, err := conn.DescribeUserPoolDomain(&cognitoidentityprovider.DescribeUserPoolDomainInput{
Domain: aws.String(d.Id()),
})
if err != nil {
if isAWSErr(err, "ResourceNotFoundException", "") {
log.Printf("[WARN] Cognito User Pool Domain %q not found, removing from state", d.Id())
d.SetId("")
return nil
}
return err
}

desc := domain.DomainDescription

d.Set("domain", d.Id())
d.Set("aws_account_id", desc.AWSAccountId)
d.Set("cloudfront_distribution_arn", desc.CloudFrontDistribution)
d.Set("s3_bucket", desc.S3Bucket)
d.Set("user_pool_id", desc.UserPoolId)
d.Set("version", desc.Version)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: What do you think of checking that these attributes are actually set, in the related test?


return nil
}

func resourceAwsCognitoUserPoolDomainDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).cognitoidpconn
log.Printf("[DEBUG] Deleting Cognito User Pool Domain: %s", d.Id())

_, err := conn.DeleteUserPoolDomain(&cognitoidentityprovider.DeleteUserPoolDomainInput{
Domain: aws.String(d.Id()),
UserPoolId: aws.String(d.Get("user_pool_id").(string)),
})
if err != nil {
return 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
},
}
_, err = stateConf.WaitForState()
return err
}
120 changes: 120 additions & 0 deletions aws/resource_aws_cognito_user_pool_domain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package aws

import (
"errors"
"fmt"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSCognitoUserPoolDomain_basic(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))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCognitoUserPoolDomainDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCognitoUserPoolDomainConfig_basic(domainName, poolName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSCognitoUserPoolDomainExists("aws_cognito_user_pool_domain.main"),
resource.TestCheckResourceAttr("aws_cognito_user_pool_domain.main", "domain", domainName),
resource.TestCheckResourceAttr("aws_cognito_user_pool.main", "name", poolName),
resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "aws_account_id"),
resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "cloudfront_distribution_arn"),
resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "s3_bucket"),
resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "version"),
),
},
},
})
}

func TestAccAWSCognitoUserPoolDomain_import(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))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCognitoUserPoolDomainDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCognitoUserPoolDomainConfig_basic(domainName, poolName),
},
{
ResourceName: "aws_cognito_user_pool_domain.main",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckAWSCognitoUserPoolDomainExists(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return errors.New("No Cognito User Pool Domain ID is set")
}

conn := testAccProvider.Meta().(*AWSClient).cognitoidpconn

_, err := conn.DescribeUserPoolDomain(&cognitoidentityprovider.DescribeUserPoolDomainInput{
Domain: aws.String(rs.Primary.ID),
})

if err != nil {
return err
}

return nil
}
}

func testAccCheckAWSCognitoUserPoolDomainDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).cognitoidpconn

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

_, err := conn.DescribeUserPoolDomain(&cognitoidentityprovider.DescribeUserPoolDomainInput{
Domain: aws.String(rs.Primary.ID),
})

if err != nil {
if isAWSErr(err, "ResourceNotFoundException", "") {
return nil
}
return err
}
}

return nil
}

func testAccAWSCognitoUserPoolDomainConfig_basic(domainName, poolName string) string {
return fmt.Sprintf(`
resource "aws_cognito_user_pool_domain" "main" {
domain = "%s"
user_pool_id = "${aws_cognito_user_pool.main.id}"
}

resource "aws_cognito_user_pool" "main" {
name = "%s"
}
`, domainName, poolName)
}
9 changes: 9 additions & 0 deletions aws/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -1986,6 +1986,15 @@ func validateCognitoRoles(v map[string]interface{}, k string) (errors []error) {
return
}

func validateCognitoUserPoolDomain(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only lowercase alphanumeric characters and hyphens (max length 63 chars) allowed in %q", k))
}
return
}

func validateDxConnectionBandWidth(v interface{}, k string) (ws []string, errors []error) {
val, ok := v.(string)
if !ok {
Expand Down
27 changes: 27 additions & 0 deletions aws/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2863,3 +2863,30 @@ func TestResourceAWSElastiCacheReplicationGroupAuthTokenValidation(t *testing.T)
}
}
}

func TestValidateCognitoUserPoolDomain(t *testing.T) {
validTypes := []string{
"valid-domain",
"validdomain",
"val1d-d0main",
}
for _, v := range validTypes {
_, errors := validateCognitoUserPoolDomain(v, "name")
if len(errors) != 0 {
t.Fatalf("%q should be a valid Cognito User Pool Domain: %q", v, errors)
}
}

invalidTypes := []string{
"UpperCase",
"-invalid",
"invalid-",
strings.Repeat("i", 64), // > 63
}
for _, v := range invalidTypes {
_, errors := validateCognitoUserPoolDomain(v, "name")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid Cognito User Pool Domain", v)
}
}
}
3 changes: 3 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@
<li<%= sidebar_current("docs-aws-resource-cognito-user-pool") %>>
<a href="/docs/providers/aws/r/cognito_user_pool.html">aws_cognito_user_pool</a>
</li>
<li<%= sidebar_current("docs-aws-resource-cognito-user-pool-domain") %>>
<a href="/docs/providers/aws/r/cognito_user_pool_domain.html">aws_cognito_user_pool_domain</a>
</li>
</ul>
</li>

Expand Down
40 changes: 40 additions & 0 deletions website/docs/r/cognito_user_pool_domain.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--
layout: "aws"
page_title: "AWS: aws_cognito_user_pool_domain"
side_bar_current: "docs-aws-resource-cognito-user-pool-domain"
description: |-
Provides a Cognito User Pool Domain resource.
---

# aws_cognito_user_pool_domain

Provides a Cognito User Pool Domain resource.

## Example Usage

```hcl
resource "aws_cognito_user_pool_domain" "main" {
domain = "example-domain"
user_pool_id = "${aws_cognito_user_pool.example.id}"
}

resource "aws_cognito_user_pool" "example" {
name = "example-pool"
}
```

## Argument Reference

The following arguments are supported:

* `domain` - (Required) The domain string.
* `user_pool_id` - (Required) The user pool ID.

## Attribute Reference

The following attributes are exported:

* `aws_account_id` - The AWS account ID for the user pool owner.
* `cloudfront_distribution_arn` - The ARN of the CloudFront distribution.
* `s3_bucket` - The S3 bucket where the static files for this domain are stored.
* `version` - The app version.