diff --git a/.changelog/27790.txt b/.changelog/27790.txt new file mode 100644 index 000000000000..f87daa007ff6 --- /dev/null +++ b/.changelog/27790.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cognito_user_pool_domain: Add `cloudfront_distribution` and `cloudfront_distribution_zone_id` attributes +``` \ No newline at end of file diff --git a/internal/conns/awsclient.go b/internal/conns/awsclient.go index 4f001a37d14d..a3bdc0d7269e 100644 --- a/internal/conns/awsclient.go +++ b/internal/conns/awsclient.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" + "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/s3" ) @@ -43,3 +44,12 @@ func (client *AWSClient) SetHTTPClient(httpClient *http.Client) { func (client *AWSClient) HTTPClient() *http.Client { return client.httpClient } + +// CloudFrontDistributionHostedZoneIDForPartition returns for the Route 53 hosted zone ID +// for Amazon CloudFront distributions in the configured AWS partition. +func (client *AWSClient) CloudFrontDistributionHostedZoneID() string { + if client.Partition == endpoints.AwsCnPartitionID { + return "Z3RFFRIM2A3IF5" // See https://docs.amazonaws.cn/en_us/aws/latest/userguide/route53.html + } + return "Z2FDTNDATAQYW2" // See https://docs.aws.amazon.com/Route53/latest/APIReference/API_AliasTarget.html#Route53-Type-AliasTarget-HostedZoneId +} diff --git a/internal/service/apigateway/acc_test.go b/internal/service/apigateway/acc_test.go deleted file mode 100644 index 565c25a88f62..000000000000 --- a/internal/service/apigateway/acc_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package apigateway_test - -import ( - "context" - "fmt" - "sync" - "testing" - - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/service/apigateway" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "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/terraform" - "github.com/hashicorp/terraform-provider-aws/internal/acctest" - "github.com/hashicorp/terraform-provider-aws/internal/provider" -) - -// API Gateway Edge-Optimized Domain Name can only be created with ACM Certificates in specific regions. - -// testAccEdgeDomainNameRegion is the chosen API Gateway Domain Name testing region -// -// Cached to prevent issues should multiple regions become available. -var testAccEdgeDomainNameRegion string - -// testAccProviderEdgeDomainName is the API Gateway Domain Name provider instance -// -// This Provider can be used in testing code for API calls without requiring -// the use of saving and referencing specific ProviderFactories instances. -// -// testAccPreCheckEdgeDomainName(t) must be called before using this provider instance. -var testAccProviderEdgeDomainName *schema.Provider - -// testAccProviderEdgeDomainNameConfigure ensures the provider is only configured once -var testAccProviderEdgeDomainNameConfigure sync.Once - -// testAccPreCheckEdgeDomainName verifies AWS credentials and that API Gateway Domain Name is supported -func testAccPreCheckEdgeDomainName(ctx context.Context, t *testing.T) { - acctest.PreCheckPartitionHasService(t, apigateway.EndpointsID) - - region := testAccGetEdgeDomainNameRegion() - - if region == "" { - t.Skip("API Gateway Domain Name not available in this AWS Partition") - } - - // Since we are outside the scope of the Terraform configuration we must - // call Configure() to properly initialize the provider configuration. - testAccProviderEdgeDomainNameConfigure.Do(func() { - var err error - testAccProviderEdgeDomainName, err = provider.New(ctx) - - if err != nil { - t.Fatal(err) - } - - config := map[string]interface{}{ - "region": region, - } - - diags := testAccProviderEdgeDomainName.Configure(ctx, terraform.NewResourceConfigRaw(config)) - - if diags != nil && diags.HasError() { - for _, d := range diags { - if d.Severity == diag.Error { - t.Fatalf("error configuring API Gateway Domain Name provider: %s", d.Summary) - } - } - } - }) -} - -// testAccEdgeDomainNameRegionProviderConfig is the Terraform provider configuration for API Gateway Domain Name region testing -// -// Testing API Gateway Domain Name assumes no other provider configurations -// are necessary and overwrites the "aws" provider configuration. -func testAccEdgeDomainNameRegionProviderConfig() string { - return acctest.ConfigRegionalProvider(testAccGetEdgeDomainNameRegion()) -} - -// testAccEdgeDomainNameRegion returns the API Gateway Domain Name region for testing -func testAccGetEdgeDomainNameRegion() string { - if testAccEdgeDomainNameRegion != "" { - return testAccEdgeDomainNameRegion - } - - // AWS Commercial: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-custom-domains.html - // AWS GovCloud (US) - edge custom domain names not supported: https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-abp.html - // AWS China - edge custom domain names not supported: https://docs.amazonaws.cn/en_us/aws/latest/userguide/api-gateway.html - switch acctest.Partition() { - case endpoints.AwsPartitionID: - testAccEdgeDomainNameRegion = endpoints.UsEast1RegionID - } - - return testAccEdgeDomainNameRegion -} - -// testAccCheckResourceAttrRegionalARNEdgeDomainName ensures the Terraform state exactly matches the expected API Gateway Edge Domain Name format -func testAccCheckResourceAttrRegionalARNEdgeDomainName(resourceName, attributeName, arnService string, domain string) resource.TestCheckFunc { - return func(s *terraform.State) error { - attributeValue := arn.ARN{ - Partition: acctest.Partition(), - Region: testAccGetEdgeDomainNameRegion(), - Resource: fmt.Sprintf("/domainnames/%s", domain), - Service: arnService, - }.String() - - return resource.TestCheckResourceAttr(resourceName, attributeName, attributeValue)(s) - } -} - -// testAccCheckResourceAttrRegionalARNRegionalDomainName ensures the Terraform state exactly matches the expected API Gateway Regional Domain Name format -func testAccCheckResourceAttrRegionalARNRegionalDomainName(resourceName, attributeName, arnService string, domain string) resource.TestCheckFunc { - return func(s *terraform.State) error { - attributeValue := arn.ARN{ - Partition: acctest.Partition(), - Region: acctest.Region(), - Resource: fmt.Sprintf("/domainnames/%s", domain), - Service: arnService, - }.String() - - return resource.TestCheckResourceAttr(resourceName, attributeName, attributeValue)(s) - } -} diff --git a/internal/service/apigateway/domain_name.go b/internal/service/apigateway/domain_name.go index e2c9255357e8..f8aea787248f 100644 --- a/internal/service/apigateway/domain_name.go +++ b/internal/service/apigateway/domain_name.go @@ -11,11 +11,13 @@ import ( "github.com/aws/aws-sdk-go/service/apigateway" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "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/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -26,35 +28,41 @@ func ResourceDomainName() *schema.Resource { ReadWithoutTimeout: resourceDomainNameRead, UpdateWithoutTimeout: resourceDomainNameUpdate, DeleteWithoutTimeout: resourceDomainNameDelete, + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, Schema: map[string]*schema.Schema{ - + "arn": { + Type: schema.TypeString, + Computed: true, + }, //According to AWS Documentation, ACM will be the only way to add certificates //to ApiGateway DomainNames. When this happens, we will be deprecating all certificate methods //except certificate_arn. We are not quite sure when this will happen. + "certificate_arn": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"certificate_body", "certificate_chain", "certificate_name", "certificate_private_key", "regional_certificate_arn", "regional_certificate_name"}, + }, "certificate_body": { Type: schema.TypeString, ForceNew: true, Optional: true, ConflictsWith: []string{"certificate_arn", "regional_certificate_arn"}, }, - "certificate_chain": { Type: schema.TypeString, ForceNew: true, Optional: true, ConflictsWith: []string{"certificate_arn", "regional_certificate_arn"}, }, - "certificate_name": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"certificate_arn", "regional_certificate_arn", "regional_certificate_name"}, }, - "certificate_private_key": { Type: schema.TypeString, ForceNew: true, @@ -62,44 +70,23 @@ func ResourceDomainName() *schema.Resource { Sensitive: true, ConflictsWith: []string{"certificate_arn", "regional_certificate_arn"}, }, - - "domain_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "security_policy": { + "certificate_upload_date": { Type: schema.TypeString, - Optional: true, Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - apigateway.SecurityPolicyTls10, - apigateway.SecurityPolicyTls12, - }, true), - }, - - "certificate_arn": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"certificate_body", "certificate_chain", "certificate_name", "certificate_private_key", "regional_certificate_arn", "regional_certificate_name"}, }, - "cloudfront_domain_name": { Type: schema.TypeString, Computed: true, }, - - "certificate_upload_date": { + "cloudfront_zone_id": { Type: schema.TypeString, Computed: true, }, - - "cloudfront_zone_id": { + "domain_name": { Type: schema.TypeString, - Computed: true, + Required: true, + ForceNew: true, }, - "endpoint_configuration": { Type: schema.TypeList, Optional: true, @@ -125,7 +112,6 @@ func ResourceDomainName() *schema.Resource { }, }, }, - "mutual_tls_authentication": { Type: schema.TypeList, Optional: true, @@ -144,38 +130,35 @@ func ResourceDomainName() *schema.Resource { }, }, }, - "ownership_verification_certificate_arn": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: verify.ValidARN, }, - "regional_certificate_arn": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"certificate_arn", "certificate_body", "certificate_chain", "certificate_name", "certificate_private_key", "regional_certificate_name"}, }, - "regional_certificate_name": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"certificate_arn", "certificate_name", "regional_certificate_arn"}, }, - "regional_domain_name": { Type: schema.TypeString, Computed: true, }, - "regional_zone_id": { Type: schema.TypeString, Computed: true, }, - "arn": { - Type: schema.TypeString, - Computed: true, + "security_policy": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(apigateway.SecurityPolicy_Values(), true), }, "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), @@ -190,63 +173,64 @@ func resourceDomainNameCreate(ctx context.Context, d *schema.ResourceData, meta conn := meta.(*conns.AWSClient).APIGatewayConn() defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) - log.Printf("[DEBUG] Creating API Gateway Domain Name") - params := &apigateway.CreateDomainNameInput{ - DomainName: aws.String(d.Get("domain_name").(string)), + domainName := d.Get("domain_name").(string) + input := &apigateway.CreateDomainNameInput{ + DomainName: aws.String(domainName), MutualTlsAuthentication: expandMutualTLSAuthentication(d.Get("mutual_tls_authentication").([]interface{})), } if v, ok := d.GetOk("certificate_arn"); ok { - params.CertificateArn = aws.String(v.(string)) - } - - if v, ok := d.GetOk("certificate_name"); ok { - params.CertificateName = aws.String(v.(string)) + input.CertificateArn = aws.String(v.(string)) } if v, ok := d.GetOk("certificate_body"); ok { - params.CertificateBody = aws.String(v.(string)) + input.CertificateBody = aws.String(v.(string)) } if v, ok := d.GetOk("certificate_chain"); ok { - params.CertificateChain = aws.String(v.(string)) + input.CertificateChain = aws.String(v.(string)) + } + + if v, ok := d.GetOk("certificate_name"); ok { + input.CertificateName = aws.String(v.(string)) } if v, ok := d.GetOk("certificate_private_key"); ok { - params.CertificatePrivateKey = aws.String(v.(string)) + input.CertificatePrivateKey = aws.String(v.(string)) } if v, ok := d.GetOk("endpoint_configuration"); ok { - params.EndpointConfiguration = expandEndpointConfiguration(v.([]interface{})) + input.EndpointConfiguration = expandEndpointConfiguration(v.([]interface{})) + } + + if v, ok := d.GetOk("ownership_verification_certificate_arn"); ok { + input.OwnershipVerificationCertificateArn = aws.String(v.(string)) } if v, ok := d.GetOk("regional_certificate_arn"); ok { - params.RegionalCertificateArn = aws.String(v.(string)) + input.RegionalCertificateArn = aws.String(v.(string)) } if v, ok := d.GetOk("regional_certificate_name"); ok { - params.RegionalCertificateName = aws.String(v.(string)) + input.RegionalCertificateName = aws.String(v.(string)) } if v, ok := d.GetOk("security_policy"); ok { - params.SecurityPolicy = aws.String(v.(string)) - } - - if v, ok := d.GetOk("ownership_verification_certificate_arn"); ok { - params.OwnershipVerificationCertificateArn = aws.String(v.(string)) + input.SecurityPolicy = aws.String(v.(string)) } if len(tags) > 0 { - params.Tags = Tags(tags.IgnoreAWS()) + input.Tags = Tags(tags.IgnoreAWS()) } - domainName, err := conn.CreateDomainNameWithContext(ctx, params) + output, err := conn.CreateDomainNameWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "creating API Gateway Domain Name: %s", err) + return sdkdiag.AppendErrorf(diags, "creating API Gateway Domain Name (%s): %s", domainName, err) } - d.SetId(aws.StringValue(domainName.DomainName)) + d.SetId(aws.StringValue(output.DomainName)) return append(diags, resourceDomainNameRead(ctx, d, meta)...) } @@ -257,29 +241,16 @@ func resourceDomainNameRead(ctx context.Context, d *schema.ResourceData, meta in defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - log.Printf("[DEBUG] Reading API Gateway Domain Name %s", d.Id()) + domainName, err := FindDomainName(ctx, conn, d.Id()) - domainName, err := conn.GetDomainNameWithContext(ctx, &apigateway.GetDomainNameInput{ - DomainName: aws.String(d.Id()), - }) - if err != nil { - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, apigateway.ErrCodeNotFoundException) { - log.Printf("[WARN] API Gateway Domain Name (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags - } - return sdkdiag.AppendErrorf(diags, "reading API Gateway Domain Name (%s): %s", d.Id(), err) - } - - tags := KeyValueTags(ctx, domainName.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) - - //lintignore:AWSR002 - if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] API Gateway Domain Name (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags } - if err := d.Set("tags_all", tags.Map()); err != nil { - return sdkdiag.AppendErrorf(diags, "setting tags_all: %s", err) + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading API Gateway Domain Name (%s): %s", d.Id(), err) } arn := arn.ARN{ @@ -291,129 +262,137 @@ func resourceDomainNameRead(ctx context.Context, d *schema.ResourceData, meta in d.Set("arn", arn) d.Set("certificate_arn", domainName.CertificateArn) d.Set("certificate_name", domainName.CertificateName) - if err := d.Set("certificate_upload_date", domainName.CertificateUploadDate.Format(time.RFC3339)); err != nil { - log.Printf("[DEBUG] Error setting certificate_upload_date: %s", err) + if domainName.CertificateUploadDate != nil { + d.Set("certificate_upload_date", domainName.CertificateUploadDate.Format(time.RFC3339)) + } else { + d.Set("certificate_upload_date", nil) } d.Set("cloudfront_domain_name", domainName.DistributionDomainName) - d.Set("cloudfront_zone_id", cloudFrontRoute53ZoneID) + d.Set("cloudfront_zone_id", meta.(*conns.AWSClient).CloudFrontDistributionHostedZoneID()) d.Set("domain_name", domainName.DomainName) - d.Set("security_policy", domainName.SecurityPolicy) - d.Set("ownership_verification_certificate_arn", domainName.OwnershipVerificationCertificateArn) - if err := d.Set("endpoint_configuration", flattenEndpointConfiguration(domainName.EndpointConfiguration)); err != nil { return sdkdiag.AppendErrorf(diags, "setting endpoint_configuration: %s", err) } - if err = d.Set("mutual_tls_authentication", flattenMutualTLSAuthentication(domainName.MutualTlsAuthentication)); err != nil { return sdkdiag.AppendErrorf(diags, "setting mutual_tls_authentication: %s", err) } - + d.Set("ownership_verification_certificate_arn", domainName.OwnershipVerificationCertificateArn) d.Set("regional_certificate_arn", domainName.RegionalCertificateArn) d.Set("regional_certificate_name", domainName.RegionalCertificateName) d.Set("regional_domain_name", domainName.RegionalDomainName) d.Set("regional_zone_id", domainName.RegionalHostedZoneId) + d.Set("security_policy", domainName.SecurityPolicy) - return diags -} - -func resourceDomainNameUpdateOperations(d *schema.ResourceData) []*apigateway.PatchOperation { - operations := make([]*apigateway.PatchOperation, 0) + tags := KeyValueTags(ctx, domainName.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) - if d.HasChange("certificate_name") { - operations = append(operations, &apigateway.PatchOperation{ - Op: aws.String(apigateway.OpReplace), - Path: aws.String("/certificateName"), - Value: aws.String(d.Get("certificate_name").(string)), - }) + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) } - if d.HasChange("certificate_arn") { - operations = append(operations, &apigateway.PatchOperation{ - Op: aws.String(apigateway.OpReplace), - Path: aws.String("/certificateArn"), - Value: aws.String(d.Get("certificate_arn").(string)), - }) + if err := d.Set("tags_all", tags.Map()); err != nil { + return sdkdiag.AppendErrorf(diags, "setting tags_all: %s", err) } - if d.HasChange("regional_certificate_name") { - operations = append(operations, &apigateway.PatchOperation{ - Op: aws.String(apigateway.OpReplace), - Path: aws.String("/regionalCertificateName"), - Value: aws.String(d.Get("regional_certificate_name").(string)), - }) - } + return diags +} - if d.HasChange("regional_certificate_arn") { - operations = append(operations, &apigateway.PatchOperation{ - Op: aws.String(apigateway.OpReplace), - Path: aws.String("/regionalCertificateArn"), - Value: aws.String(d.Get("regional_certificate_arn").(string)), - }) - } +func resourceDomainNameUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).APIGatewayConn() - if d.HasChange("security_policy") { - operations = append(operations, &apigateway.PatchOperation{ - Op: aws.String(apigateway.OpReplace), - Path: aws.String("/securityPolicy"), - Value: aws.String(d.Get("security_policy").(string)), - }) - } + if d.HasChangesExcept("tags", "tags_all") { + var operations []*apigateway.PatchOperation - if d.HasChange("endpoint_configuration.0.types") { - // The domain name must have an endpoint type. - // If attempting to remove the configuration, do nothing. - if v, ok := d.GetOk("endpoint_configuration"); ok && len(v.([]interface{})) > 0 { - m := v.([]interface{})[0].(map[string]interface{}) + if d.HasChange("certificate_arn") { + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String(apigateway.OpReplace), + Path: aws.String("/certificateArn"), + Value: aws.String(d.Get("certificate_arn").(string)), + }) + } + if d.HasChange("certificate_name") { operations = append(operations, &apigateway.PatchOperation{ Op: aws.String(apigateway.OpReplace), - Path: aws.String("/endpointConfiguration/types/0"), - Value: aws.String(m["types"].([]interface{})[0].(string)), + Path: aws.String("/certificateName"), + Value: aws.String(d.Get("certificate_name").(string)), }) } - } - if d.HasChange("mutual_tls_authentication") { - mutTLSAuth := d.Get("mutual_tls_authentication").([]interface{}) + if d.HasChange("endpoint_configuration.0.types") { + // The domain name must have an endpoint type. + // If attempting to remove the configuration, do nothing. + if v, ok := d.GetOk("endpoint_configuration"); ok && len(v.([]interface{})) > 0 { + m := v.([]interface{})[0].(map[string]interface{}) + + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String(apigateway.OpReplace), + Path: aws.String("/endpointConfiguration/types/0"), + Value: aws.String(m["types"].([]interface{})[0].(string)), + }) + } + } - if len(mutTLSAuth) == 0 || mutTLSAuth[0] == nil { - // To disable mutual TLS for a custom domain name, remove the truststore from your custom domain name. + if d.HasChange("mutual_tls_authentication") { + mutTLSAuth := d.Get("mutual_tls_authentication").([]interface{}) + + if len(mutTLSAuth) == 0 || mutTLSAuth[0] == nil { + // To disable mutual TLS for a custom domain name, remove the truststore from your custom domain name. + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String(apigateway.OpReplace), + Path: aws.String("/mutualTlsAuthentication/truststoreUri"), + Value: aws.String(""), + }) + } else { + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String(apigateway.OpReplace), + Path: aws.String("/mutualTlsAuthentication/truststoreVersion"), + Value: aws.String(mutTLSAuth[0].(map[string]interface{})["truststore_version"].(string)), + }) + } + } + + if d.HasChange("regional_certificate_arn") { operations = append(operations, &apigateway.PatchOperation{ Op: aws.String(apigateway.OpReplace), - Path: aws.String("/mutualTlsAuthentication/truststoreUri"), - Value: aws.String(""), + Path: aws.String("/regionalCertificateArn"), + Value: aws.String(d.Get("regional_certificate_arn").(string)), }) - } else { + } + + if d.HasChange("regional_certificate_name") { operations = append(operations, &apigateway.PatchOperation{ Op: aws.String(apigateway.OpReplace), - Path: aws.String("/mutualTlsAuthentication/truststoreVersion"), - Value: aws.String(mutTLSAuth[0].(map[string]interface{})["truststore_version"].(string)), + Path: aws.String("/regionalCertificateName"), + Value: aws.String(d.Get("regional_certificate_name").(string)), }) } - } - return operations -} + if d.HasChange("security_policy") { + operations = append(operations, &apigateway.PatchOperation{ + Op: aws.String(apigateway.OpReplace), + Path: aws.String("/securityPolicy"), + Value: aws.String(d.Get("security_policy").(string)), + }) + } -func resourceDomainNameUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).APIGatewayConn() - log.Printf("[DEBUG] Updating API Gateway Domain Name %s", d.Id()) + _, err := conn.UpdateDomainNameWithContext(ctx, &apigateway.UpdateDomainNameInput{ + DomainName: aws.String(d.Id()), + PatchOperations: operations, + }) - if d.HasChange("tags_all") { - o, n := d.GetChange("tags_all") - if err := UpdateTags(ctx, conn, d.Get("arn").(string), o, n); err != nil { - return sdkdiag.AppendErrorf(diags, "updating tags: %s", err) + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating API Gateway Domain Name (%s): %s", d.Id(), err) } } - _, err := conn.UpdateDomainNameWithContext(ctx, &apigateway.UpdateDomainNameInput{ - DomainName: aws.String(d.Id()), - PatchOperations: resourceDomainNameUpdateOperations(d), - }) + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") - if err != nil { - return sdkdiag.AppendErrorf(diags, "updating API Gateway Domain Name (%s): %s", d.Id(), err) + if err := UpdateTags(ctx, conn, d.Get("arn").(string), o, n); err != nil { + return sdkdiag.AppendErrorf(diags, "updating API Gateway Domain Name (%s) tags: %s", d.Id(), err) + } } return append(diags, resourceDomainNameRead(ctx, d, meta)...) @@ -422,8 +401,8 @@ func resourceDomainNameUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceDomainNameDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).APIGatewayConn() - log.Printf("[DEBUG] Deleting API Gateway Domain Name: %s", d.Id()) + log.Printf("[DEBUG] Deleting API Gateway Domain Name: %s", d.Id()) _, err := conn.DeleteDomainNameWithContext(ctx, &apigateway.DeleteDomainNameInput{ DomainName: aws.String(d.Id()), }) @@ -439,6 +418,31 @@ func resourceDomainNameDelete(ctx context.Context, d *schema.ResourceData, meta return diags } +func FindDomainName(ctx context.Context, conn *apigateway.APIGateway, domainName string) (*apigateway.DomainName, error) { + input := &apigateway.GetDomainNameInput{ + DomainName: aws.String(domainName), + } + + output, err := conn.GetDomainNameWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, apigateway.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + func expandMutualTLSAuthentication(tfList []interface{}) *apigateway.MutualTlsAuthenticationInput { if len(tfList) == 0 || tfList[0] == nil { return nil diff --git a/internal/service/apigateway/domain_name_data_source.go b/internal/service/apigateway/domain_name_data_source.go index 7a0fba115dd7..10ec4ef08a03 100644 --- a/internal/service/apigateway/domain_name_data_source.go +++ b/internal/service/apigateway/domain_name_data_source.go @@ -7,7 +7,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/apigateway" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -15,14 +14,11 @@ import ( tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" ) -// cloudFrontRoute53ZoneID defines the route 53 zone ID for CloudFront. This -// is used to set the zone_id attribute. -const cloudFrontRoute53ZoneID = "Z2FDTNDATAQYW2" - // @SDKDataSource("aws_api_gateway_domain_name") func DataSourceDomainName() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceDomainNameRead, + Schema: map[string]*schema.Schema{ "arn": { Type: schema.TypeString, @@ -95,19 +91,14 @@ func dataSourceDomainNameRead(ctx context.Context, d *schema.ResourceData, meta conn := meta.(*conns.AWSClient).APIGatewayConn() ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - input := &apigateway.GetDomainNameInput{} - - if v, ok := d.GetOk("domain_name"); ok { - input.DomainName = aws.String(v.(string)) - } - - domainName, err := conn.GetDomainNameWithContext(ctx, input) + domainName := d.Get("domain_name").(string) + output, err := FindDomainName(ctx, conn, domainName) if err != nil { - return sdkdiag.AppendErrorf(diags, "getting API Gateway Domain Name: %s", err) + return sdkdiag.AppendErrorf(diags, "reading API Gateway Domain Name (%s): %s", domainName, err) } - d.SetId(aws.StringValue(domainName.DomainName)) + d.SetId(aws.StringValue(output.DomainName)) arn := arn.ARN{ Partition: meta.(*conns.AWSClient).Partition, @@ -116,28 +107,24 @@ func dataSourceDomainNameRead(ctx context.Context, d *schema.ResourceData, meta Resource: fmt.Sprintf("/domainnames/%s", d.Id()), }.String() d.Set("arn", arn) - d.Set("certificate_arn", domainName.CertificateArn) - d.Set("certificate_name", domainName.CertificateName) - - if domainName.CertificateUploadDate != nil { - d.Set("certificate_upload_date", domainName.CertificateUploadDate.Format(time.RFC3339)) + d.Set("certificate_arn", output.CertificateArn) + d.Set("certificate_name", output.CertificateName) + if output.CertificateUploadDate != nil { + d.Set("certificate_upload_date", output.CertificateUploadDate.Format(time.RFC3339)) } - - d.Set("cloudfront_domain_name", domainName.DistributionDomainName) - d.Set("cloudfront_zone_id", cloudFrontRoute53ZoneID) - d.Set("domain_name", domainName.DomainName) - - if err := d.Set("endpoint_configuration", flattenEndpointConfiguration(domainName.EndpointConfiguration)); err != nil { + d.Set("cloudfront_domain_name", output.DistributionDomainName) + d.Set("cloudfront_zone_id", meta.(*conns.AWSClient).CloudFrontDistributionHostedZoneID()) + d.Set("domain_name", output.DomainName) + if err := d.Set("endpoint_configuration", flattenEndpointConfiguration(output.EndpointConfiguration)); err != nil { return sdkdiag.AppendErrorf(diags, "setting endpoint_configuration: %s", err) } + d.Set("regional_certificate_arn", output.RegionalCertificateArn) + d.Set("regional_certificate_name", output.RegionalCertificateName) + d.Set("regional_domain_name", output.RegionalDomainName) + d.Set("regional_zone_id", output.RegionalHostedZoneId) + d.Set("security_policy", output.SecurityPolicy) - d.Set("regional_certificate_arn", domainName.RegionalCertificateArn) - d.Set("regional_certificate_name", domainName.RegionalCertificateName) - d.Set("regional_domain_name", domainName.RegionalDomainName) - d.Set("regional_zone_id", domainName.RegionalHostedZoneId) - d.Set("security_policy", domainName.SecurityPolicy) - - if err := d.Set("tags", KeyValueTags(ctx, domainName.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + if err := d.Set("tags", KeyValueTags(ctx, output.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) } diff --git a/internal/service/apigateway/domain_name_data_source_test.go b/internal/service/apigateway/domain_name_data_source_test.go index c090086843e6..02c151e3a05a 100644 --- a/internal/service/apigateway/domain_name_data_source_test.go +++ b/internal/service/apigateway/domain_name_data_source_test.go @@ -14,7 +14,6 @@ func TestAccAPIGatewayDomainNameDataSource_basic(t *testing.T) { resourceName := "aws_api_gateway_domain_name.test" dataSourceName := "data.aws_api_gateway_domain_name.test" rName := acctest.RandomSubdomain() - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, rName) diff --git a/internal/service/apigateway/domain_name_test.go b/internal/service/apigateway/domain_name_test.go index a2a4270689fc..2f6e1a63e059 100644 --- a/internal/service/apigateway/domain_name_test.go +++ b/internal/service/apigateway/domain_name_test.go @@ -7,36 +7,36 @@ import ( "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/apigateway" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/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" tfapigateway "github.com/hashicorp/terraform-provider-aws/internal/service/apigateway" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccAPIGatewayDomainName_certificateARN(t *testing.T) { ctx := acctest.Context(t) rootDomain := acctest.ACMCertificateDomainFromEnv(t) domain := acctest.ACMCertificateRandomSubDomain(rootDomain) - var domainName apigateway.DomainName acmCertificateResourceName := "aws_acm_certificate.test" resourceName := "aws_api_gateway_domain_name.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); testAccPreCheckEdgeDomainName(ctx, t) }, + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckRegion(t, endpoints.UsEast1RegionID) }, ErrorCheck: acctest.ErrorCheck(t, apigateway.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckEdgeDomainNameDestroy(ctx), + CheckDestroy: testAccCheckDomainNameDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDomainNameConfig_certificateARN(rootDomain, domain), Check: resource.ComposeTestCheckFunc( - testAccCheckEdgeDomainNameExists(ctx, resourceName, &domainName), + testAccCheckDomainNameExists(ctx, resourceName, &domainName), testAccCheckResourceAttrRegionalARNEdgeDomainName(resourceName, "arn", "apigateway", domain), resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", acmCertificateResourceName, "arn"), resource.TestMatchResourceAttr(resourceName, "cloudfront_domain_name", regexp.MustCompile(`[a-z0-9]+.cloudfront.net`)), @@ -86,7 +86,6 @@ func TestAccAPIGatewayDomainName_certificateName(t *testing.T) { "This environment variable must be set to any non-empty value " + "with a domain name acceptable for the certificate to enable the test.") } - var conf apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" @@ -123,7 +122,6 @@ func TestAccAPIGatewayDomainName_regionalCertificateARN(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" rName := acctest.RandomSubdomain() - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, rName) @@ -149,7 +147,6 @@ func TestAccAPIGatewayDomainName_regionalCertificateARN(t *testing.T) { func TestAccAPIGatewayDomainName_regionalCertificateName(t *testing.T) { ctx := acctest.Context(t) - // For now, use an environment variable to limit running this test // BadRequestException: Uploading certificates is not supported for REGIONAL. // See Remarks section of https://docs.aws.amazon.com/apigateway/api-reference/link-relation/domainname-create/ @@ -162,14 +159,11 @@ func TestAccAPIGatewayDomainName_regionalCertificateName(t *testing.T) { "in a region where uploading REGIONAL certificates is allowed " + "to enable the test.") } - var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" - domain := acctest.RandomDomainName() domainWildcard := fmt.Sprintf("*.%s", domain) rName := fmt.Sprintf("%s.%s", sdkacctest.RandString(8), domain) - caKey := acctest.TLSRSAPrivateKeyPEM(t, 2048) caCertificate := acctest.TLSRSAX509SelfSignedCACertificatePEM(t, caKey) key := acctest.TLSRSAPrivateKeyPEM(t, 2048) @@ -205,7 +199,6 @@ func TestAccAPIGatewayDomainName_securityPolicy(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" rName := acctest.RandomSubdomain() - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, rName) @@ -236,7 +229,6 @@ func TestAccAPIGatewayDomainName_tags(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" rName := acctest.RandomSubdomain() - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, rName) @@ -285,7 +277,6 @@ func TestAccAPIGatewayDomainName_disappears(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" rName := acctest.RandomSubdomain() - key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, rName) @@ -311,7 +302,6 @@ func TestAccAPIGatewayDomainName_MutualTLSAuthentication_basic(t *testing.T) { ctx := acctest.Context(t) rootDomain := acctest.ACMCertificateDomainFromEnv(t) domain := fmt.Sprintf("%s.%s", acctest.RandomSubdomain(), rootDomain) - var v apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" acmCertificateResourceName := "aws_acm_certificate.test" @@ -359,7 +349,6 @@ func TestAccAPIGatewayDomainName_MutualTLSAuthentication_ownership(t *testing.T) domain := fmt.Sprintf("%s.%s", acctest.RandomSubdomain(), rootDomain) key := acctest.TLSRSAPrivateKeyPEM(t, 2048) certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, domain) - var v apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" publicAcmCertificateResourceName := "aws_acm_certificate.test" @@ -393,7 +382,7 @@ func TestAccAPIGatewayDomainName_MutualTLSAuthentication_ownership(t *testing.T) }) } -func testAccCheckDomainNameExists(ctx context.Context, n string, res *apigateway.DomainName) resource.TestCheckFunc { +func testAccCheckDomainNameExists(ctx context.Context, n string, v *apigateway.DomainName) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -401,24 +390,18 @@ func testAccCheckDomainNameExists(ctx context.Context, n string, res *apigateway } if rs.Primary.ID == "" { - return fmt.Errorf("No API Gateway DomainName ID is set") + return fmt.Errorf("No API Gateway Domain Name ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).APIGatewayConn() - req := &apigateway.GetDomainNameInput{ - DomainName: aws.String(rs.Primary.ID), - } - describe, err := conn.GetDomainNameWithContext(ctx, req) + output, err := tfapigateway.FindDomainName(ctx, conn, rs.Primary.ID) + if err != nil { return err } - if *describe.DomainName != rs.Primary.ID { - return fmt.Errorf("APIGateway DomainName not found") - } - - *res = *describe + *v = *output return nil } @@ -433,87 +416,52 @@ func testAccCheckDomainNameDestroy(ctx context.Context) resource.TestCheckFunc { continue } - _, err := conn.GetDomainNameWithContext(ctx, &apigateway.GetDomainNameInput{ - DomainName: aws.String(rs.Primary.ID), - }) + _, err := tfapigateway.FindDomainName(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } if err != nil { - if tfawserr.ErrCodeEquals(err, apigateway.ErrCodeNotFoundException) { - return nil - } return err } - return fmt.Errorf("API Gateway Domain Name still exists: %s", rs.Primary.ID) + return fmt.Errorf("API Gateway Domain Name %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckEdgeDomainNameExists(ctx context.Context, resourceName string, domainName *apigateway.DomainName) resource.TestCheckFunc { +// testAccCheckResourceAttrRegionalARNEdgeDomainName ensures the Terraform state exactly matches the expected API Gateway Edge Domain Name format. +func testAccCheckResourceAttrRegionalARNEdgeDomainName(resourceName, attributeName, arnService string, domain string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] - - if !ok { - return fmt.Errorf("not found: %s", resourceName) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("resource ID not set") - } - - conn := testAccProviderEdgeDomainName.Meta().(*conns.AWSClient).APIGatewayConn() - - input := &apigateway.GetDomainNameInput{ - DomainName: aws.String(rs.Primary.ID), - } - - output, err := conn.GetDomainNameWithContext(ctx, input) - - if err != nil { - return fmt.Errorf("error reading API Gateway Domain Name (%s): %w", rs.Primary.ID, err) - } - - *domainName = *output - - return nil + attributeValue := arn.ARN{ + Partition: acctest.Partition(), + Region: acctest.Region(), + Resource: fmt.Sprintf("/domainnames/%s", domain), + Service: arnService, + }.String() + + return resource.TestCheckResourceAttr(resourceName, attributeName, attributeValue)(s) } } -func testAccCheckEdgeDomainNameDestroy(ctx context.Context) resource.TestCheckFunc { +// testAccCheckResourceAttrRegionalARNRegionalDomainName ensures the Terraform state exactly matches the expected API Gateway Regional Domain Name format. +func testAccCheckResourceAttrRegionalARNRegionalDomainName(resourceName, attributeName, arnService string, domain string) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := testAccProviderEdgeDomainName.Meta().(*conns.AWSClient).APIGatewayConn() - - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_api_gateway_domain_name" { - continue - } - - input := &apigateway.GetDomainNameInput{ - DomainName: aws.String(rs.Primary.ID), - } - - output, err := conn.GetDomainNameWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, apigateway.ErrCodeNotFoundException) { - continue - } - - if err != nil { - return fmt.Errorf("error reading API Gateway Domain Name (%s): %w", rs.Primary.ID, err) - } - - if output != nil && aws.StringValue(output.DomainName) == rs.Primary.ID { - return fmt.Errorf("API Gateway Domain Name (%s) still exists", rs.Primary.ID) - } - } - - return nil + attributeValue := arn.ARN{ + Partition: acctest.Partition(), + Region: acctest.Region(), + Resource: fmt.Sprintf("/domainnames/%s", domain), + Service: arnService, + }.String() + + return resource.TestCheckResourceAttr(resourceName, attributeName, attributeValue)(s) } } -func testAccDomainNamePublicCertConfig(rootDomain, domain string) string { +func testAccDomainNameConfig_basePublicCert(rootDomain, domain string) string { return fmt.Sprintf(` data "aws_route53_zone" "test" { name = %[1]q @@ -525,26 +473,6 @@ resource "aws_acm_certificate" "test" { validation_method = "DNS" } -# -# for_each acceptance testing requires: -# https://github.com/hashicorp/terraform-plugin-sdk/issues/536 -# -# resource "aws_route53_record" "test" { -# for_each = { -# for dvo in aws_acm_certificate.test.domain_validation_options: dvo.domain_name => { -# name = dvo.resource_record_name -# record = dvo.resource_record_value -# type = dvo.resource_record_type -# } -# } -# allow_overwrite = true -# name = each.value.name -# records = [each.value.record] -# ttl = 60 -# type = each.value.type -# zone_id = data.aws_route53_zone.test.zone_id -# } - resource "aws_route53_record" "test" { allow_overwrite = true name = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_name @@ -562,10 +490,7 @@ resource "aws_acm_certificate_validation" "test" { } func testAccDomainNameConfig_certificateARN(rootDomain string, domain string) string { - return acctest.ConfigCompose( - testAccEdgeDomainNameRegionProviderConfig(), - testAccDomainNamePublicCertConfig(rootDomain, domain), - ` + return acctest.ConfigCompose(testAccDomainNameConfig_basePublicCert(rootDomain, domain), ` resource "aws_api_gateway_domain_name" "test" { domain_name = aws_acm_certificate.test.domain_name certificate_arn = aws_acm_certificate_validation.test.certificate_arn @@ -580,7 +505,7 @@ resource "aws_api_gateway_domain_name" "test" { func testAccDomainNameConfig_certificate(domainName, key, certificate, chainCertificate string) string { return fmt.Sprintf(` resource "aws_api_gateway_domain_name" "test" { - domain_name = "%[1]s" + domain_name = %[1]q certificate_body = "%[2]s" certificate_chain = "%[3]s" certificate_name = "tf-acc-apigateway-domain-name" @@ -613,7 +538,7 @@ resource "aws_api_gateway_domain_name" "test" { certificate_body = "%[2]s" certificate_chain = "%[3]s" certificate_private_key = "%[4]s" - domain_name = "%[1]s" + domain_name = %[1]q regional_certificate_name = "tf-acc-apigateway-domain-name" endpoint_configuration { @@ -689,7 +614,7 @@ resource "aws_api_gateway_domain_name" "test" { func testAccDomainNameConfig_mutualTLSAuthentication(rName, rootDomain, domain string) string { return acctest.ConfigCompose( - testAccDomainNamePublicCertConfig(rootDomain, domain), + testAccDomainNameConfig_basePublicCert(rootDomain, domain), fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q @@ -729,7 +654,7 @@ resource "aws_api_gateway_domain_name" "test" { func testAccDomainNameConfig_mutualTLSAuthenticationMissing(rootDomain, domain string) string { return acctest.ConfigCompose( - testAccDomainNamePublicCertConfig(rootDomain, domain), + testAccDomainNameConfig_basePublicCert(rootDomain, domain), ` resource "aws_api_gateway_domain_name" "test" { domain_name = aws_acm_certificate.test.domain_name @@ -745,7 +670,7 @@ resource "aws_api_gateway_domain_name" "test" { func testAccDomainNameConfig_mutualTLSOwnership(rName, rootDomain, domain, certificate, key string) string { return acctest.ConfigCompose( - testAccDomainNamePublicCertConfig(rootDomain, domain), + testAccDomainNameConfig_basePublicCert(rootDomain, domain), fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q diff --git a/internal/service/cloudfront/distribution.go b/internal/service/cloudfront/distribution.go index 1bf26cab450c..d84d94f2f5e6 100644 --- a/internal/service/cloudfront/distribution.go +++ b/internal/service/cloudfront/distribution.go @@ -6,7 +6,6 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/cloudfront" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -887,12 +886,9 @@ func resourceDistributionRead(ctx context.Context, d *schema.ResourceData, meta defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - params := &cloudfront.GetDistributionInput{ - Id: aws.String(d.Id()), - } + output, err := FindDistributionByID(ctx, conn, d.Id()) - resp, err := conn.GetDistributionWithContext(ctx, params) - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { + if !d.IsNewResource() && tfresource.NotFound(err) { create.LogNotFoundRemoveState(names.CloudFront, create.ErrActionReading, ResNameDistribution, d.Id()) d.SetId("") return diags @@ -903,32 +899,25 @@ func resourceDistributionRead(ctx context.Context, d *schema.ResourceData, meta } // Update attributes from DistributionConfig - err = flattenDistributionConfig(d, resp.Distribution.DistributionConfig) + err = flattenDistributionConfig(d, output.Distribution.DistributionConfig) if err != nil { return sdkdiag.AppendErrorf(diags, "reading CloudFront Distribution (%s): %s", d.Id(), err) } // Update other attributes outside of DistributionConfig - if err := d.Set("trusted_key_groups", flattenActiveTrustedKeyGroups(resp.Distribution.ActiveTrustedKeyGroups)); err != nil { + if err := d.Set("trusted_key_groups", flattenActiveTrustedKeyGroups(output.Distribution.ActiveTrustedKeyGroups)); err != nil { return sdkdiag.AppendErrorf(diags, "setting trusted_key_groups: %s", err) } - if err := d.Set("trusted_signers", flattenActiveTrustedSigners(resp.Distribution.ActiveTrustedSigners)); err != nil { + if err := d.Set("trusted_signers", flattenActiveTrustedSigners(output.Distribution.ActiveTrustedSigners)); err != nil { return sdkdiag.AppendErrorf(diags, "setting trusted_signers: %s", err) } - d.Set("status", resp.Distribution.Status) - d.Set("domain_name", resp.Distribution.DomainName) - d.Set("last_modified_time", aws.String(resp.Distribution.LastModifiedTime.String())) - d.Set("in_progress_validation_batches", resp.Distribution.InProgressInvalidationBatches) - d.Set("etag", resp.ETag) - d.Set("arn", resp.Distribution.ARN) - - // override hosted_zone_id from flattenDistributionConfig - region := meta.(*conns.AWSClient).Region - if v, ok := endpoints.PartitionForRegion(endpoints.DefaultPartitions(), region); ok && v.ID() == endpoints.AwsCnPartitionID { - d.Set("hosted_zone_id", cnRoute53ZoneID) - } else { - d.Set("hosted_zone_id", route53ZoneID) - } + d.Set("status", output.Distribution.Status) + d.Set("domain_name", output.Distribution.DomainName) + d.Set("last_modified_time", aws.String(output.Distribution.LastModifiedTime.String())) + d.Set("in_progress_validation_batches", output.Distribution.InProgressInvalidationBatches) + d.Set("etag", output.ETag) + d.Set("arn", output.Distribution.ARN) + d.Set("hosted_zone_id", meta.(*conns.AWSClient).CloudFrontDistributionHostedZoneID()) tags, err := ListTags(ctx, conn, d.Get("arn").(string)) if err != nil { @@ -1028,36 +1017,26 @@ func resourceDistributionDelete(ctx context.Context, d *schema.ResourceData, met conn := meta.(*conns.AWSClient).CloudFrontConn() if d.Get("retain_on_delete").(bool) { - // Check if we need to disable first - getDistributionInput := &cloudfront.GetDistributionInput{ - Id: aws.String(d.Id()), - } - - log.Printf("[DEBUG] Refreshing CloudFront Distribution (%s) to check if disable is necessary", d.Id()) - getDistributionOutput, err := conn.GetDistributionWithContext(ctx, getDistributionInput) + // Check if we need to disable first. + output, err := FindDistributionByID(ctx, conn, d.Id()) if err != nil { - return sdkdiag.AppendErrorf(diags, "refreshing CloudFront Distribution (%s) to check if disable is necessary: %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "reading CloudFront Distribution (%s): %s", d.Id(), err) } - if getDistributionOutput == nil || getDistributionOutput.Distribution == nil || getDistributionOutput.Distribution.DistributionConfig == nil { - return sdkdiag.AppendErrorf(diags, "refreshing CloudFront Distribution (%s) to check if disable is necessary: empty response", d.Id()) - } - - if !aws.BoolValue(getDistributionOutput.Distribution.DistributionConfig.Enabled) { + if !aws.BoolValue(output.Distribution.DistributionConfig.Enabled) { log.Printf("[WARN] Removing CloudFront Distribution ID %q with `retain_on_delete` set. Please delete this distribution manually.", d.Id()) return diags } - updateDistributionInput := &cloudfront.UpdateDistributionInput{ - DistributionConfig: getDistributionOutput.Distribution.DistributionConfig, - Id: getDistributionInput.Id, - IfMatch: getDistributionOutput.ETag, + input := &cloudfront.UpdateDistributionInput{ + DistributionConfig: output.Distribution.DistributionConfig, + Id: aws.String(d.Id()), + IfMatch: output.ETag, } - updateDistributionInput.DistributionConfig.Enabled = aws.Bool(false) + input.DistributionConfig.Enabled = aws.Bool(false) - log.Printf("[DEBUG] Disabling CloudFront Distribution: %s", d.Id()) - _, err = conn.UpdateDistributionWithContext(ctx, updateDistributionInput) + _, err = conn.UpdateDistributionWithContext(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "disabling CloudFront Distribution (%s): %s", d.Id(), err) @@ -1067,13 +1046,13 @@ func resourceDistributionDelete(ctx context.Context, d *schema.ResourceData, met return diags } - deleteDistributionInput := &cloudfront.DeleteDistributionInput{ + deleteDistroInput := &cloudfront.DeleteDistributionInput{ Id: aws.String(d.Id()), IfMatch: aws.String(d.Get("etag").(string)), } log.Printf("[DEBUG] Deleting CloudFront Distribution: %s", d.Id()) - _, err := conn.DeleteDistributionWithContext(ctx, deleteDistributionInput) + _, err := conn.DeleteDistributionWithContext(ctx, deleteDistroInput) if err == nil || tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { return diags @@ -1081,113 +1060,95 @@ func resourceDistributionDelete(ctx context.Context, d *schema.ResourceData, met // Refresh our ETag if it is out of date and attempt deletion again. if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeInvalidIfMatchVersion) { - getDistributionInput := &cloudfront.GetDistributionInput{ - Id: aws.String(d.Id()), - } - var getDistributionOutput *cloudfront.GetDistributionOutput - - log.Printf("[DEBUG] Refreshing CloudFront Distribution (%s) ETag", d.Id()) - getDistributionOutput, err = conn.GetDistributionWithContext(ctx, getDistributionInput) + var output *cloudfront.GetDistributionOutput + output, err = FindDistributionByID(ctx, conn, d.Id()) if err != nil { - return sdkdiag.AppendErrorf(diags, "refreshing CloudFront Distribution (%s) ETag: %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "reading CloudFront Distribution (%s): %s", d.Id(), err) } - if getDistributionOutput == nil { - return sdkdiag.AppendErrorf(diags, "refreshing CloudFront Distribution (%s) ETag: empty response", d.Id()) - } - - deleteDistributionInput.IfMatch = getDistributionOutput.ETag + deleteDistroInput.IfMatch = output.ETag - _, err = conn.DeleteDistributionWithContext(ctx, deleteDistributionInput) + _, err = conn.DeleteDistributionWithContext(ctx, deleteDistroInput) } // Disable distribution if it is not yet disabled and attempt deletion again. // Here we update via the deployed configuration to ensure we are not submitting an out of date // configuration from the Terraform configuration, should other changes have occurred manually. if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeDistributionNotDisabled) { - getDistributionInput := &cloudfront.GetDistributionInput{ - Id: aws.String(d.Id()), - } - var getDistributionOutput *cloudfront.GetDistributionOutput - - log.Printf("[DEBUG] Refreshing CloudFront Distribution (%s) to disable", d.Id()) - getDistributionOutput, err = conn.GetDistributionWithContext(ctx, getDistributionInput) + var output *cloudfront.GetDistributionOutput + output, err = FindDistributionByID(ctx, conn, d.Id()) if err != nil { - return sdkdiag.AppendErrorf(diags, "refreshing CloudFront Distribution (%s) to disable: %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "reading CloudFront Distribution (%s): %s", d.Id(), err) } - if getDistributionOutput == nil || getDistributionOutput.Distribution == nil { - return sdkdiag.AppendErrorf(diags, "refreshing CloudFront Distribution (%s) to disable: empty response", d.Id()) + updateDistroInput := &cloudfront.UpdateDistributionInput{ + DistributionConfig: output.Distribution.DistributionConfig, + Id: aws.String(d.Id()), + IfMatch: output.ETag, } + updateDistroInput.DistributionConfig.Enabled = aws.Bool(false) + var updateDistroOutput *cloudfront.UpdateDistributionOutput - updateDistributionInput := &cloudfront.UpdateDistributionInput{ - DistributionConfig: getDistributionOutput.Distribution.DistributionConfig, - Id: deleteDistributionInput.Id, - IfMatch: getDistributionOutput.ETag, - } - updateDistributionInput.DistributionConfig.Enabled = aws.Bool(false) - var updateDistributionOutput *cloudfront.UpdateDistributionOutput - - log.Printf("[DEBUG] Disabling CloudFront Distribution: %s", d.Id()) - updateDistributionOutput, err = conn.UpdateDistributionWithContext(ctx, updateDistributionInput) + updateDistroOutput, err = conn.UpdateDistributionWithContext(ctx, updateDistroInput) if err != nil { return sdkdiag.AppendErrorf(diags, "disabling CloudFront Distribution (%s): %s", d.Id(), err) } - log.Printf("[DEBUG] Waiting until CloudFront Distribution (%s) is deployed", d.Id()) if err := DistributionWaitUntilDeployed(ctx, d.Id(), meta); err != nil { return sdkdiag.AppendErrorf(diags, "waiting until CloudFront Distribution (%s) is deployed: %s", d.Id(), err) } - deleteDistributionInput.IfMatch = updateDistributionOutput.ETag + deleteDistroInput.IfMatch = updateDistroOutput.ETag - _, err = conn.DeleteDistributionWithContext(ctx, deleteDistributionInput) + _, err = conn.DeleteDistributionWithContext(ctx, deleteDistroInput) // CloudFront has eventual consistency issues even for "deployed" state. // Occasionally the DeleteDistribution call will return this error as well, in which retries will succeed: // * PreconditionFailed: The request failed because it didn't meet the preconditions in one or more request-header fields - if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeDistributionNotDisabled) || tfawserr.ErrCodeEquals(err, cloudfront.ErrCodePreconditionFailed) { - err = resource.RetryContext(ctx, 2*time.Minute, func() *resource.RetryError { - _, err := conn.DeleteDistributionWithContext(ctx, deleteDistributionInput) + if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeDistributionNotDisabled, cloudfront.ErrCodePreconditionFailed) { + _, err = tfresource.RetryWhenAWSErrCodeEquals(ctx, 2*time.Minute, func() (interface{}, error) { + return conn.DeleteDistributionWithContext(ctx, deleteDistroInput) + }, cloudfront.ErrCodeDistributionNotDisabled, cloudfront.ErrCodePreconditionFailed) + } + } - if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeDistributionNotDisabled) { - return resource.RetryableError(err) - } + if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { + return diags + } - if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { - return nil - } + if err != nil { + return sdkdiag.AppendErrorf(diags, "deleting CloudFront Distribution (%s): %s", d.Id(), err) + } - if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodePreconditionFailed) { - return resource.RetryableError(err) - } + return diags +} - if err != nil { - return resource.NonRetryableError(err) - } +func FindDistributionByID(ctx context.Context, conn *cloudfront.CloudFront, id string) (*cloudfront.GetDistributionOutput, error) { + input := &cloudfront.GetDistributionInput{ + Id: aws.String(id), + } - return nil - }) + output, err := conn.GetDistributionWithContext(ctx, input) - // Propagate AWS Go SDK retried error, if any - if tfresource.TimedOut(err) { - _, err = conn.DeleteDistributionWithContext(ctx, deleteDistributionInput) - } + if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, } } - if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { - return diags + if err != nil { + return nil, err } - if err != nil { - return sdkdiag.AppendErrorf(diags, "CloudFront Distribution %s cannot be deleted: %s", d.Id(), err) + if output == nil || output.Distribution == nil || output.Distribution.DistributionConfig == nil { + return nil, tfresource.NewEmptyResultError(input) } - return diags + return output, nil } // resourceAwsCloudFrontWebDistributionWaitUntilDeployed blocks until the diff --git a/internal/service/cloudfront/distribution_configuration_structure.go b/internal/service/cloudfront/distribution_configuration_structure.go index ea633d811424..4e47611c30aa 100644 --- a/internal/service/cloudfront/distribution_configuration_structure.go +++ b/internal/service/cloudfront/distribution_configuration_structure.go @@ -20,15 +20,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" ) -// route53ZoneID defines the route 53 zone ID for CloudFront. This -// is used to set the zone_id attribute. -const route53ZoneID = "Z2FDTNDATAQYW2" - -// cnRoute53ZoneID defines the route 53 zone ID for CloudFront in AWS CN. -// This is used to set the zone_id attribute. -// ref: https://docs.amazonaws.cn/en_us/aws/latest/userguide/route53.html -const cnRoute53ZoneID = "Z3RFFRIM2A3IF5" - // Assemble the *cloudfront.DistributionConfig variable. Calls out to various // expander functions to convert attributes and sub-attributes to the various // complex structures which are necessary to properly build the @@ -90,7 +81,6 @@ func flattenDistributionConfig(d *schema.ResourceData, distributionConfig *cloud d.Set("enabled", distributionConfig.Enabled) d.Set("is_ipv6_enabled", distributionConfig.IsIPV6Enabled) d.Set("price_class", distributionConfig.PriceClass) - d.Set("hosted_zone_id", route53ZoneID) err = d.Set("default_cache_behavior", []interface{}{flattenDefaultCacheBehavior(distributionConfig.DefaultCacheBehavior)}) if err != nil { diff --git a/internal/service/cloudfront/distribution_data_source.go b/internal/service/cloudfront/distribution_data_source.go index 1ac8589cf992..a8f088c3e43d 100644 --- a/internal/service/cloudfront/distribution_data_source.go +++ b/internal/service/cloudfront/distribution_data_source.go @@ -4,8 +4,6 @@ import ( "context" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/service/cloudfront" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -68,21 +66,16 @@ func DataSourceDistribution() *schema.Resource { func dataSourceDistributionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - d.SetId(d.Get("id").(string)) conn := meta.(*conns.AWSClient).CloudFrontConn() ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - input := &cloudfront.GetDistributionInput{ - Id: aws.String(d.Id()), - } + output, err := FindDistributionByID(ctx, conn, d.Get("id").(string)) - output, err := conn.GetDistributionWithContext(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "getting CloudFront Distribution (%s): %s", d.Id(), err) } - if output == nil { - return sdkdiag.AppendErrorf(diags, "getting CloudFront Distribution (%s): empty response", d.Id()) - } + + d.SetId(aws.StringValue(output.Distribution.Id)) d.Set("etag", output.ETag) if distribution := output.Distribution; distribution != nil { d.Set("arn", distribution.ARN) @@ -90,12 +83,7 @@ func dataSourceDistributionRead(ctx context.Context, d *schema.ResourceData, met d.Set("in_progress_validation_batches", distribution.InProgressInvalidationBatches) d.Set("last_modified_time", aws.String(distribution.LastModifiedTime.String())) d.Set("status", distribution.Status) - region := meta.(*conns.AWSClient).Region - if v, ok := endpoints.PartitionForRegion(endpoints.DefaultPartitions(), region); ok && v.ID() == endpoints.AwsCnPartitionID { - d.Set("hosted_zone_id", cnRoute53ZoneID) - } else { - d.Set("hosted_zone_id", route53ZoneID) - } + d.Set("hosted_zone_id", meta.(*conns.AWSClient).CloudFrontDistributionHostedZoneID()) if distributionConfig := distribution.DistributionConfig; distributionConfig != nil { d.Set("enabled", distributionConfig.Enabled) if aliases := distributionConfig.Aliases; aliases != nil { diff --git a/internal/service/cloudfront/distribution_data_source_test.go b/internal/service/cloudfront/distribution_data_source_test.go index d2caabc6105a..16c1bfa292bf 100644 --- a/internal/service/cloudfront/distribution_data_source_test.go +++ b/internal/service/cloudfront/distribution_data_source_test.go @@ -37,8 +37,7 @@ func TestAccCloudFrontDistributionDataSource_basic(t *testing.T) { } func testAccDistributionDataSourceConfig_basic(rName string) string { - return acctest.ConfigCompose( - testAccDistributionConfig_s3Tags(rName), ` + return acctest.ConfigCompose(testAccDistributionConfig_s3Tags(rName), ` data "aws_cloudfront_distribution" "test" { id = aws_cloudfront_distribution.s3_distribution.id } diff --git a/internal/service/cloudfront/find.go b/internal/service/cloudfront/find.go index 79244a741845..c5a8df9d9e96 100644 --- a/internal/service/cloudfront/find.go +++ b/internal/service/cloudfront/find.go @@ -35,31 +35,6 @@ func FindCachePolicyByID(ctx context.Context, conn *cloudfront.CloudFront, id st return output, nil } -func FindDistributionByID(ctx context.Context, conn *cloudfront.CloudFront, id string) (*cloudfront.GetDistributionOutput, error) { - input := &cloudfront.GetDistributionInput{ - Id: aws.String(id), - } - - output, err := conn.GetDistributionWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { - return nil, &resource.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err - } - - if output == nil || output.Distribution == nil || output.Distribution.DistributionConfig == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output, nil -} - func FindFieldLevelEncryptionConfigByID(ctx context.Context, conn *cloudfront.CloudFront, id string) (*cloudfront.GetFieldLevelEncryptionConfigOutput, error) { input := &cloudfront.GetFieldLevelEncryptionConfigInput{ Id: aws.String(id), diff --git a/internal/service/cognitoidp/acc_test.go b/internal/service/cognitoidp/acc_test.go deleted file mode 100644 index 3b6d7ac7553b..000000000000 --- a/internal/service/cognitoidp/acc_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package cognitoidp_test - -import ( - "context" - "sync" - "testing" - - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/hashicorp/terraform-provider-aws/internal/acctest" - "github.com/hashicorp/terraform-provider-aws/internal/provider" -) - -// Cognito User Pool Custom Domains can only be created with ACM Certificates in specific regions. - -// testAccCognitoUserPoolCustomDomainRegion is the chosen Cognito User Pool Custom Domains testing region -// -// Cached to prevent issues should multiple regions become available. -var testAccCognitoUserPoolCustomDomainRegion string - -// testAccProviderCognitoUserPoolCustomDomain is the Cognito User Pool Custom Domains provider instance -// -// This Provider can be used in testing code for API calls without requiring -// the use of saving and referencing specific ProviderFactories instances. -// -// testAccPreCheckUserPoolCustomDomain(t) must be called before using this provider instance. -var testAccProviderCognitoUserPoolCustomDomain *schema.Provider - -// testAccProviderCognitoUserPoolCustomDomainConfigure ensures the provider is only configured once -var testAccProviderCognitoUserPoolCustomDomainConfigure sync.Once - -// testAccPreCheckUserPoolCustomDomain verifies AWS credentials and that Cognito User Pool Custom Domains is supported -func testAccPreCheckUserPoolCustomDomain(ctx context.Context, t *testing.T) { - acctest.PreCheckPartitionHasService(t, cognitoidentityprovider.EndpointsID) - - region := testAccGetUserPoolCustomDomainRegion() - - if region == "" { - t.Skip("Cognito User Pool Custom Domains not available in this AWS Partition") - } - - // Since we are outside the scope of the Terraform configuration we must - // call Configure() to properly initialize the provider configuration. - testAccProviderCognitoUserPoolCustomDomainConfigure.Do(func() { - var err error - testAccProviderCognitoUserPoolCustomDomain, err = provider.New(ctx) - - if err != nil { - t.Fatal(err) - } - - config := map[string]interface{}{ - "region": region, - } - - diags := testAccProviderCognitoUserPoolCustomDomain.Configure(ctx, terraform.NewResourceConfigRaw(config)) - - if diags != nil && diags.HasError() { - for _, d := range diags { - if d.Severity == diag.Error { - t.Fatalf("error configuring Cognito User Pool Custom Domains provider: %s", d.Summary) - } - } - } - }) -} - -// testAccUserPoolCustomDomainRegionProviderConfig is the Terraform provider configuration for Cognito User Pool Custom Domains region testing -// -// Testing Cognito User Pool Custom Domains assumes no other provider configurations -// are necessary and overwrites the "aws" provider configuration. -func testAccUserPoolCustomDomainRegionProviderConfig() string { - return acctest.ConfigRegionalProvider(testAccGetUserPoolCustomDomainRegion()) -} - -// testAccGetUserPoolCustomDomainRegion returns the Cognito User Pool Custom Domains region for testing -func testAccGetUserPoolCustomDomainRegion() string { - if testAccCognitoUserPoolCustomDomainRegion != "" { - return testAccCognitoUserPoolCustomDomainRegion - } - - // AWS Commercial: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html - // AWS GovCloud (US) - not supported: https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-cog.html - // AWS China - not supported: https://docs.amazonaws.cn/en_us/aws/latest/userguide/cognito.html - switch acctest.Partition() { - case endpoints.AwsPartitionID: - testAccCognitoUserPoolCustomDomainRegion = endpoints.UsEast1RegionID - } - - return testAccCognitoUserPoolCustomDomainRegion -} diff --git a/internal/service/cognitoidp/status.go b/internal/service/cognitoidp/status.go deleted file mode 100644 index b72f319e142f..000000000000 --- a/internal/service/cognitoidp/status.go +++ /dev/null @@ -1,35 +0,0 @@ -package cognitoidp - -import ( - "context" - - "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" -) - -// statusUserPoolDomain fetches the Operation and its Status -func statusUserPoolDomain(ctx context.Context, conn *cognitoidentityprovider.CognitoIdentityProvider, domain string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - input := &cognitoidentityprovider.DescribeUserPoolDomainInput{ - Domain: aws.String(domain), - } - - output, err := conn.DescribeUserPoolDomainWithContext(ctx, 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/internal/service/cognitoidp/user_pool_domain.go b/internal/service/cognitoidp/user_pool_domain.go index 4cbfc93d3787..524833dd0017 100644 --- a/internal/service/cognitoidp/user_pool_domain.go +++ b/internal/service/cognitoidp/user_pool_domain.go @@ -2,7 +2,6 @@ package cognitoidp import ( "context" - "errors" "log" "time" @@ -10,11 +9,13 @@ import ( "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "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/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -25,16 +26,15 @@ func ResourceUserPoolDomain() *schema.Resource { CreateWithoutTimeout: resourceUserPoolDomainCreate, ReadWithoutTimeout: resourceUserPoolDomainRead, DeleteWithoutTimeout: resourceUserPoolDomainDelete, + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, Schema: map[string]*schema.Schema{ - "domain": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 63), + "aws_account_id": { + Type: schema.TypeString, + Computed: true, }, "certificate_arn": { Type: schema.TypeString, @@ -42,23 +42,33 @@ func ResourceUserPoolDomain() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidARN, }, - "user_pool_id": { + "cloudfront_distribution": { Type: schema.TypeString, - Required: true, - ForceNew: true, + Computed: true, }, - "aws_account_id": { + "cloudfront_distribution_arn": { Type: schema.TypeString, Computed: true, }, - "cloudfront_distribution_arn": { + "cloudfront_distribution_zone_id": { Type: schema.TypeString, Computed: true, }, + "domain": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 63), + }, "s3_bucket": { Type: schema.TypeString, Computed: true, }, + "user_pool_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, "version": { Type: schema.TypeString, Computed: true, @@ -72,33 +82,29 @@ func resourceUserPoolDomainCreate(ctx context.Context, d *schema.ResourceData, m conn := meta.(*conns.AWSClient).CognitoIDPConn() domain := d.Get("domain").(string) - - timeout := 1 * time.Minute //Default timeout for a basic domain - - params := &cognitoidentityprovider.CreateUserPoolDomainInput{ + timeout := 1 * time.Minute + input := &cognitoidentityprovider.CreateUserPoolDomainInput{ Domain: aws.String(domain), UserPoolId: aws.String(d.Get("user_pool_id").(string)), } if v, ok := d.GetOk("certificate_arn"); ok { - customDomainConfig := &cognitoidentityprovider.CustomDomainConfigType{ + input.CustomDomainConfig = &cognitoidentityprovider.CustomDomainConfigType{ CertificateArn: aws.String(v.(string)), } - params.CustomDomainConfig = customDomainConfig - timeout = 60 * time.Minute //Custom domains take more time to become active + timeout = 60 * time.Minute // Custom domains take more time to become active. } - log.Printf("[DEBUG] Creating Cognito User Pool Domain: %s", params) + _, err := conn.CreateUserPoolDomainWithContext(ctx, input) - _, err := conn.CreateUserPoolDomainWithContext(ctx, params) if err != nil { - return sdkdiag.AppendErrorf(diags, "Error creating Cognito User Pool Domain: %s", err) + return sdkdiag.AppendErrorf(diags, "creating Cognito User Pool Domain (%s): %s", domain, err) } d.SetId(domain) if _, err := waitUserPoolDomainCreated(ctx, conn, d.Id(), timeout); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for User Pool Domain (%s) creation: %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "waiting for Cognito User Pool Domain (%s) create: %s", d.Id(), err) } return append(diags, resourceUserPoolDomainRead(ctx, d, meta)...) @@ -107,40 +113,28 @@ func resourceUserPoolDomainCreate(ctx context.Context, d *schema.ResourceData, m func resourceUserPoolDomainRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).CognitoIDPConn() - log.Printf("[DEBUG] Reading Cognito User Pool Domain: %s", d.Id()) - domain, err := conn.DescribeUserPoolDomainWithContext(ctx, &cognitoidentityprovider.DescribeUserPoolDomainInput{ - Domain: aws.String(d.Id()), - }) - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, cognitoidentityprovider.ErrCodeResourceNotFoundException) { - create.LogNotFoundRemoveState(names.CognitoIDP, create.ErrActionReading, ResNameUserPoolDomain, d.Id()) - d.SetId("") - return diags - } - - if err != nil { - return create.DiagError(names.CognitoIDP, create.ErrActionReading, ResNameUserPoolDomain, d.Id(), err) - } - - desc := domain.DomainDescription + desc, err := FindUserPoolDomain(ctx, conn, d.Id()) - if !d.IsNewResource() && desc.Status == nil { + if !d.IsNewResource() && tfresource.NotFound(err) { create.LogNotFoundRemoveState(names.CognitoIDP, create.ErrActionReading, ResNameUserPoolDomain, d.Id()) d.SetId("") return diags } - if d.IsNewResource() && desc.Status == nil { - return create.DiagError(names.CognitoIDP, create.ErrActionReading, ResNameUserPoolDomain, d.Id(), errors.New("not found after creation")) + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading Cognito User Pool Domain (%s): %s", d.Id(), err) } - d.Set("domain", d.Id()) + d.Set("aws_account_id", desc.AWSAccountId) d.Set("certificate_arn", "") if desc.CustomDomainConfig != nil { d.Set("certificate_arn", desc.CustomDomainConfig.CertificateArn) } - d.Set("aws_account_id", desc.AWSAccountId) + d.Set("cloudfront_distribution", desc.CloudFrontDistribution) d.Set("cloudfront_distribution_arn", desc.CloudFrontDistribution) + d.Set("cloudfront_distribution_zone_id", meta.(*conns.AWSClient).CloudFrontDistributionHostedZoneID()) + d.Set("domain", d.Id()) d.Set("s3_bucket", desc.S3Bucket) d.Set("user_pool_id", desc.UserPoolId) d.Set("version", desc.Version) @@ -151,22 +145,103 @@ func resourceUserPoolDomainRead(ctx context.Context, d *schema.ResourceData, met func resourceUserPoolDomainDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).CognitoIDPConn() - log.Printf("[DEBUG] Deleting Cognito User Pool Domain: %s", d.Id()) + log.Printf("[DEBUG] Deleting Cognito User Pool Domain: %s", d.Id()) _, err := conn.DeleteUserPoolDomainWithContext(ctx, &cognitoidentityprovider.DeleteUserPoolDomainInput{ Domain: aws.String(d.Id()), UserPoolId: aws.String(d.Get("user_pool_id").(string)), }) + + if tfawserr.ErrMessageContains(err, cognitoidentityprovider.ErrCodeInvalidParameterException, "No such domain") { + return diags + } + if err != nil { - return sdkdiag.AppendErrorf(diags, "Error deleting User Pool Domain: %s", err) + return sdkdiag.AppendErrorf(diags, "deleting Cognito User Pool Domain (%s): %s", d.Id(), err) } - if _, err := waitUserPoolDomainDeleted(ctx, conn, d.Id()); err != nil { - if tfawserr.ErrCodeEquals(err, cognitoidentityprovider.ErrCodeResourceNotFoundException) { - return diags - } - return sdkdiag.AppendErrorf(diags, "waiting for User Pool Domain (%s) deletion: %s", d.Id(), err) + if _, err := waitUserPoolDomainDeleted(ctx, conn, d.Id(), 1*time.Minute); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for Cognito User Pool Domain (%s) delete: %s", d.Id(), err) } return diags } + +func FindUserPoolDomain(ctx context.Context, conn *cognitoidentityprovider.CognitoIdentityProvider, domain string) (*cognitoidentityprovider.DomainDescriptionType, error) { + input := &cognitoidentityprovider.DescribeUserPoolDomainInput{ + Domain: aws.String(domain), + } + + output, err := conn.DescribeUserPoolDomainWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, cognitoidentityprovider.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + // e.g. + // { + // "DomainDescription": {} + // } + if output == nil || output.DomainDescription == nil || output.DomainDescription.Status == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.DomainDescription, nil +} + +func statusUserPoolDomain(ctx context.Context, conn *cognitoidentityprovider.CognitoIdentityProvider, domain string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindUserPoolDomain(ctx, conn, domain) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + +func waitUserPoolDomainCreated(ctx context.Context, conn *cognitoidentityprovider.CognitoIdentityProvider, domain string, timeout time.Duration) (*cognitoidentityprovider.DomainDescriptionType, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{cognitoidentityprovider.DomainStatusTypeCreating, cognitoidentityprovider.DomainStatusTypeUpdating}, + Target: []string{cognitoidentityprovider.DomainStatusTypeActive}, + Refresh: statusUserPoolDomain(ctx, conn, domain), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*cognitoidentityprovider.DomainDescriptionType); ok { + return output, err + } + + return nil, err +} + +func waitUserPoolDomainDeleted(ctx context.Context, conn *cognitoidentityprovider.CognitoIdentityProvider, domain string, timeout time.Duration) (*cognitoidentityprovider.DomainDescriptionType, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{cognitoidentityprovider.DomainStatusTypeUpdating, cognitoidentityprovider.DomainStatusTypeDeleting}, + Target: []string{}, + Refresh: statusUserPoolDomain(ctx, conn, domain), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*cognitoidentityprovider.DomainDescriptionType); ok { + return output, err + } + + return nil, err +} diff --git a/internal/service/cognitoidp/user_pool_domain_test.go b/internal/service/cognitoidp/user_pool_domain_test.go index 965491a669a7..02f48eb7ede8 100644 --- a/internal/service/cognitoidp/user_pool_domain_test.go +++ b/internal/service/cognitoidp/user_pool_domain_test.go @@ -4,24 +4,23 @@ import ( "context" "errors" "fmt" - "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/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" tfcognitoidp "github.com/hashicorp/terraform-provider-aws/internal/service/cognitoidp" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccCognitoIDPUserPoolDomain_basic(t *testing.T) { ctx := acctest.Context(t) - domainName := fmt.Sprintf("tf-acc-test-domain-%d", sdkacctest.RandInt()) - poolName := fmt.Sprintf("tf-acc-test-pool-%s", sdkacctest.RandString(10)) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_cognito_user_pool_domain.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t); testAccPreCheckIdentityProvider(ctx, t) }, @@ -30,19 +29,20 @@ func TestAccCognitoIDPUserPoolDomain_basic(t *testing.T) { CheckDestroy: testAccCheckUserPoolDomainDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccUserPoolDomainConfig_basic(domainName, poolName), + Config: testAccUserPoolDomainConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckUserPoolDomainExists(ctx, "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"), + testAccCheckUserPoolDomainExists(ctx, resourceName), + acctest.CheckResourceAttrAccountID(resourceName, "aws_account_id"), + resource.TestCheckResourceAttrSet(resourceName, "cloudfront_distribution"), + resource.TestCheckResourceAttrSet(resourceName, "cloudfront_distribution_arn"), + resource.TestCheckResourceAttr(resourceName, "cloudfront_distribution_zone_id", "Z2FDTNDATAQYW2"), + resource.TestCheckResourceAttr(resourceName, "domain", rName), + resource.TestCheckResourceAttrSet(resourceName, "s3_bucket"), + resource.TestCheckResourceAttrSet(resourceName, "version"), ), }, { - ResourceName: "aws_cognito_user_pool_domain.main", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -50,64 +50,64 @@ func TestAccCognitoIDPUserPoolDomain_basic(t *testing.T) { }) } -func TestAccCognitoIDPUserPoolDomain_custom(t *testing.T) { +func TestAccCognitoIDPUserPoolDomain_disappears(t *testing.T) { ctx := acctest.Context(t) - rootDomain := acctest.ACMCertificateDomainFromEnv(t) - domain := acctest.ACMCertificateRandomSubDomain(rootDomain) - poolName := fmt.Sprintf("tf-acc-test-pool-%s", sdkacctest.RandString(10)) - - acmCertificateResourceName := "aws_acm_certificate.test" - cognitoUserPoolResourceName := "aws_cognito_user_pool.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_cognito_user_pool_domain.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); testAccPreCheckUserPoolCustomDomain(ctx, t) }, + PreCheck: func() { acctest.PreCheck(t); testAccPreCheckIdentityProvider(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, cognitoidentityprovider.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckUserPoolDomainDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccUserPoolDomainConfig_custom(rootDomain, domain, poolName), + Config: testAccUserPoolDomainConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckUserPoolDomainExists(ctx, resourceName), - acctest.CheckResourceAttrAccountID(resourceName, "aws_account_id"), - resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", acmCertificateResourceName, "arn"), - //lintignore:AWSAT001 // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/11666 - resource.TestMatchResourceAttr(resourceName, "cloudfront_distribution_arn", regexp.MustCompile(`[a-z0-9]+.cloudfront.net$`)), - resource.TestCheckResourceAttrPair(resourceName, "domain", acmCertificateResourceName, "domain_name"), - resource.TestMatchResourceAttr(resourceName, "s3_bucket", regexp.MustCompile(`^.+$`)), - resource.TestCheckResourceAttrPair(resourceName, "user_pool_id", cognitoUserPoolResourceName, "id"), - resource.TestMatchResourceAttr(resourceName, "version", regexp.MustCompile(`^.+$`)), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfcognitoidp.ResourceUserPoolDomain(), resourceName), ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccCognitoIDPUserPoolDomain_disappears(t *testing.T) { +func TestAccCognitoIDPUserPoolDomain_custom(t *testing.T) { ctx := acctest.Context(t) - domainName := fmt.Sprintf("tf-acc-test-domain-%d", sdkacctest.RandInt()) - poolName := fmt.Sprintf("tf-acc-test-pool-%s", sdkacctest.RandString(10)) - resourceName := "aws_cognito_user_pool_domain.main" + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + poolName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + acmCertificateResourceName := "aws_acm_certificate.test" + resourceName := "aws_cognito_user_pool_domain.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); testAccPreCheckIdentityProvider(ctx, t) }, + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckRegion(t, endpoints.UsEast1RegionID) }, ErrorCheck: acctest.ErrorCheck(t, cognitoidentityprovider.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckUserPoolDomainDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccUserPoolDomainConfig_basic(domainName, poolName), + Config: testAccUserPoolDomainConfig_custom(rootDomain, domain, poolName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckUserPoolDomainExists(ctx, resourceName), - acctest.CheckResourceDisappears(ctx, acctest.Provider, tfcognitoidp.ResourceUserPoolDomain(), resourceName), + acctest.CheckResourceAttrAccountID(resourceName, "aws_account_id"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", acmCertificateResourceName, "arn"), + resource.TestCheckResourceAttrSet(resourceName, "cloudfront_distribution"), + resource.TestCheckResourceAttr(resourceName, "cloudfront_distribution_zone_id", "Z2FDTNDATAQYW2"), + resource.TestCheckResourceAttrPair(resourceName, "domain", acmCertificateResourceName, "domain_name"), + resource.TestCheckResourceAttrSet(resourceName, "s3_bucket"), + resource.TestCheckResourceAttrSet(resourceName, "version"), ), - ExpectNonEmptyPlan: true, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -126,9 +126,7 @@ func testAccCheckUserPoolDomainExists(ctx context.Context, n string) resource.Te conn := acctest.Provider.Meta().(*conns.AWSClient).CognitoIDPConn() - _, err := conn.DescribeUserPoolDomainWithContext(ctx, &cognitoidentityprovider.DescribeUserPoolDomainInput{ - Domain: aws.String(rs.Primary.ID), - }) + _, err := tfcognitoidp.FindUserPoolDomain(ctx, conn, rs.Primary.ID) return err } @@ -143,39 +141,38 @@ func testAccCheckUserPoolDomainDestroy(ctx context.Context) resource.TestCheckFu continue } - _, err := conn.DescribeUserPoolDomainWithContext(ctx, &cognitoidentityprovider.DescribeUserPoolDomainInput{ - Domain: aws.String(rs.Primary.ID), - }) + _, err := tfcognitoidp.FindUserPoolDomain(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } if err != nil { - if tfawserr.ErrCodeEquals(err, cognitoidentityprovider.ErrCodeResourceNotFoundException) { - return nil - } return err } + + return fmt.Errorf("Cognito User Pool Domain %s still exists", rs.Primary.ID) } return nil } } -func testAccUserPoolDomainConfig_basic(domainName, poolName string) string { +func testAccUserPoolDomainConfig_basic(rName 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_domain" "test" { + domain = %[1]q + user_pool_id = aws_cognito_user_pool.test.id } -resource "aws_cognito_user_pool" "main" { - name = "%s" +resource "aws_cognito_user_pool" "test" { + name = %[1]q } -`, domainName, poolName) +`, rName) } func testAccUserPoolDomainConfig_custom(rootDomain string, domain string, poolName string) string { - return acctest.ConfigCompose( - testAccUserPoolCustomDomainRegionProviderConfig(), - fmt.Sprintf(` + return fmt.Sprintf(` data "aws_route53_zone" "test" { name = %[1]q private_zone = false @@ -186,27 +183,6 @@ resource "aws_acm_certificate" "test" { validation_method = "DNS" } -# -# for_each acceptance testing requires: -# https://github.com/hashicorp/terraform-plugin-sdk/issues/536 -# -# resource "aws_route53_record" "test" { -# for_each = { -# for dvo in aws_acm_certificate.test.domain_validation_options: dvo.domain_name => { -# name = dvo.resource_record_name -# record = dvo.resource_record_value -# type = dvo.resource_record_type -# } -# } - -# allow_overwrite = true -# name = each.value.name -# records = [each.value.record] -# ttl = 60 -# type = each.value.type -# zone_id = data.aws_route53_zone.test.zone_id -# } - resource "aws_route53_record" "test" { allow_overwrite = true name = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_name @@ -230,5 +206,5 @@ resource "aws_cognito_user_pool_domain" "test" { domain = aws_acm_certificate.test.domain_name user_pool_id = aws_cognito_user_pool.test.id } -`, rootDomain, domain, poolName)) +`, rootDomain, domain, poolName) } diff --git a/internal/service/cognitoidp/wait.go b/internal/service/cognitoidp/wait.go deleted file mode 100644 index 1f03522b094d..000000000000 --- a/internal/service/cognitoidp/wait.go +++ /dev/null @@ -1,57 +0,0 @@ -package cognitoidp - -import ( - "context" - "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 -) - -// waitUserPoolDomainDeleted waits for an Operation to return Success -func waitUserPoolDomainDeleted(ctx context.Context, conn *cognitoidentityprovider.CognitoIdentityProvider, domain string) (*cognitoidentityprovider.DescribeUserPoolDomainOutput, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - cognitoidentityprovider.DomainStatusTypeUpdating, - cognitoidentityprovider.DomainStatusTypeDeleting, - }, - Target: []string{""}, - Refresh: statusUserPoolDomain(ctx, conn, domain), - Timeout: userPoolDomainDeleteTimeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - - if output, ok := outputRaw.(*cognitoidentityprovider.DescribeUserPoolDomainOutput); ok { - return output, err - } - - return nil, err -} - -func waitUserPoolDomainCreated(ctx context.Context, 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: statusUserPoolDomain(ctx, conn, domain), - Timeout: timeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - - if output, ok := outputRaw.(*cognitoidentityprovider.DescribeUserPoolDomainOutput); ok { - return output, err - } - - return nil, err -} diff --git a/website/docs/r/cognito_user_pool_domain.markdown b/website/docs/r/cognito_user_pool_domain.markdown index da3149666050..9211cb3bef6b 100644 --- a/website/docs/r/cognito_user_pool_domain.markdown +++ b/website/docs/r/cognito_user_pool_domain.markdown @@ -48,9 +48,9 @@ resource "aws_route53_record" "auth-cognito-A" { zone_id = data.aws_route53_zone.example.zone_id alias { evaluate_target_health = false - name = aws_cognito_user_pool_domain.main.cloudfront_distribution_arn - # This zone_id is fixed - zone_id = "Z2FDTNDATAQYW2" + + name = aws_cognito_user_pool_domain.main.cloudfront_distribution + zone_id = aws_cognito_user_pool_domain.main.cloudfront_distribution_zone_id } } ``` @@ -68,7 +68,9 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `aws_account_id` - The AWS account ID for the user pool owner. +* `cloudfront_distribution` - The Amazon CloudFront endpoint (e.g. `dpp0gtxikpq3y.cloudfront.net`) that you use as the target of the alias that you set up with your Domain Name Service (DNS) provider. * `cloudfront_distribution_arn` - The URL of the CloudFront distribution. This is required to generate the ALIAS `aws_route53_record` +* `cloudfront_distribution_zone_id` - The Route 53 hosted zone ID of the CloudFront distribution. * `s3_bucket` - The S3 bucket where the static files for this domain are stored. * `version` - The app version.