From 6928b5bbc739846dfb03f14fe4a44053e82ec7ef Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 8 Jan 2022 19:45:25 +0200 Subject: [PATCH 01/13] appsync domain --- internal/provider/provider.go | 1 + internal/service/appsync/api_association.go | 108 ++++++++++ .../service/appsync/api_association_test.go | 197 +++++++++++++++++ internal/service/appsync/appsync_test.go | 9 + internal/service/appsync/domain_name.go | 131 +++++++++++ internal/service/appsync/domain_name_test.go | 204 ++++++++++++++++++ internal/service/appsync/find.go | 48 +++++ 7 files changed, 698 insertions(+) create mode 100644 internal/service/appsync/api_association.go create mode 100644 internal/service/appsync/api_association_test.go create mode 100644 internal/service/appsync/domain_name.go create mode 100644 internal/service/appsync/domain_name_test.go diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 3ea0cf7fb29..9f16900ff34 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -831,6 +831,7 @@ func Provider() *schema.Provider { "aws_appsync_api_cache": appsync.ResourceAPICache(), "aws_appsync_api_key": appsync.ResourceAPIKey(), "aws_appsync_datasource": appsync.ResourceDataSource(), + "aws_appsync_domain_name": appsync.ResourceDomainName(), "aws_appsync_function": appsync.ResourceFunction(), "aws_appsync_graphql_api": appsync.ResourceGraphQLAPI(), "aws_appsync_resolver": appsync.ResourceResolver(), diff --git a/internal/service/appsync/api_association.go b/internal/service/appsync/api_association.go new file mode 100644 index 00000000000..bbf23bbc2a3 --- /dev/null +++ b/internal/service/appsync/api_association.go @@ -0,0 +1,108 @@ +package appsync + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appsync" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" +) + +func ResourceApiAssociation() *schema.Resource { + + return &schema.Resource{ + Create: resourceApiAssociationCreate, + Read: resourceApiAssociationRead, + Update: resourceApiAssociationUpdate, + Delete: resourceApiAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "api_id": { + Type: schema.TypeString, + Required: true, + }, + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceApiAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + params := &appsync.AssociateApiInput{ + ApiId: aws.String(d.Get("description").(string)), + DomainName: aws.String(d.Get("domain_name").(string)), + } + + resp, err := conn.AssociateApi(params) + if err != nil { + return fmt.Errorf("error creating Appsync API Association: %w", err) + } + + d.SetId(aws.StringValue(resp.ApiAssociation.DomainName)) + + return resourceApiAssociationRead(d, meta) +} + +func resourceApiAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + association, err := FindApiAssociationByID(conn, d.Id()) + if association == nil && !d.IsNewResource() { + log.Printf("[WARN] AppSync API Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error getting Appsync API Association %q: %w", d.Id(), err) + } + + d.Set("domain_name", association.DomainName) + d.Set("api_id", association.ApiId) + + return nil +} + +func resourceApiAssociationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + params := &appsync.AssociateApiInput{ + ApiId: aws.String(d.Get("description").(string)), + DomainName: aws.String(d.Get("domain_name").(string)), + } + + _, err := conn.AssociateApi(params) + if err != nil { + return fmt.Errorf("error creating Appsync API Association: %w", err) + } + + return resourceApiAssociationRead(d, meta) +} + +func resourceApiAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + input := &appsync.DisassociateApiInput{ + DomainName: aws.String(d.Id()), + } + _, err := conn.DisassociateApi(input) + if err != nil { + if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { + return nil + } + return fmt.Errorf("error deleting Appsync API Association: %w", err) + } + + return nil +} diff --git a/internal/service/appsync/api_association_test.go b/internal/service/appsync/api_association_test.go new file mode 100644 index 00000000000..90c4da74587 --- /dev/null +++ b/internal/service/appsync/api_association_test.go @@ -0,0 +1,197 @@ +package appsync_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appsync" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfappsync "github.com/hashicorp/terraform-provider-aws/internal/service/appsync" +) + +func testAccAppSyncApiAssociation_basic(t *testing.T) { + var association appsync.ApiAssociation + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + + resourceName := "aws_appsync_domain_name.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckApiAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppsyncApiAssociationConfig(rootDomain, domain, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckApiAssociationExists(resourceName, &association), + resource.TestCheckResourceAttrPair(resourceName, "domain_name", "aws_appsync_domain_name.test", "domain_name"), + resource.TestCheckResourceAttrPair(resourceName, "api_id", "aws_appsync_graphql_api.test", "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAppsyncApiAssociationUpdatedConfig(rootDomain, domain, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckApiAssociationExists(resourceName, &association), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttrPair(resourceName, "domain_name", "aws_appsync_domain_name.test", "domain_name"), + resource.TestCheckResourceAttrPair(resourceName, "api_id", "aws_appsync_graphql_api.test2", "id"), + ), + }, + }, + }) +} + +func testAccAppSyncApiAssociation_disappears(t *testing.T) { + var association appsync.ApiAssociation + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resourceName := "aws_appsync_domain_name.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckApiAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppsyncApiAssociationConfig(rootDomain, domain, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckApiAssociationExists(resourceName, &association), + acctest.CheckResourceDisappears(acctest.Provider, tfappsync.ResourceApiAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckApiAssociationDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).AppSyncConn + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appsync_domain_name" { + continue + } + + association, err := tfappsync.FindApiAssociationByID(conn, rs.Primary.ID) + if err == nil { + if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { + return nil + } + return err + } + + if association != nil && aws.StringValue(association.DomainName) == rs.Primary.ID { + return fmt.Errorf("Appsync Domain Name ID %q still exists", rs.Primary.ID) + } + + return nil + + } + return nil +} + +func testAccCheckApiAssociationExists(resourceName string, apiAssociation *appsync.ApiAssociation) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Appsync Domain Name Not found in state: %s", resourceName) + } + conn := acctest.Provider.Meta().(*conns.AWSClient).AppSyncConn + + association, err := tfappsync.FindApiAssociationByID(conn, rs.Primary.ID) + if err != nil { + return err + } + + if association == nil || association.DomainName == nil { + return fmt.Errorf("Appsync Domain Name %q not found", rs.Primary.ID) + } + + *apiAssociation = *association + + return nil + } +} + +func testAccAppsyncApiAssociationBaseConfig(rootDomain, domain string) string { + return fmt.Sprintf(` +data "aws_route53_zone" "test" { + name = %[1]q + private_zone = false +} + +resource "aws_acm_certificate" "test" { + domain_name = %[2]q + validation_method = "DNS" +} + +resource "aws_route53_record" "test" { + allow_overwrite = true + name = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_name + records = [tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_value] + ttl = 60 + type = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_type + zone_id = data.aws_route53_zone.test.zone_id +} + +resource "aws_acm_certificate_validation" "test" { + certificate_arn = aws_acm_certificate.test.arn + validation_record_fqdns = [aws_route53_record.test.fqdn] +} + +resource "aws_appsync_domain_name" "test" { + domain_name = aws_acm_certificate.test.domain_name + certificate_arn = aws_acm_certificate_validation.test.certificate_arn +} +`, rootDomain, domain) +} + +func testAccAppsyncApiAssociationConfig(rootDomain, domain, rName string) string { + return testAccAppsyncApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` +resource "aws_appsync_graphql_api" "test" { + authentication_type = "API_KEY" + name = %[1]q +} + +resource "aws_appsync_api_association" "test" { + api_id = aws_appsync_graphql_api.test.id + domain_name = aws_appsync_domain_name.test.domain_name +} +`, rName) +} + +func testAccAppsyncApiAssociationUpdatedConfig(rootDomain, domain, rName string) string { + return testAccAppsyncApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` +resource "aws_appsync_graphql_api" "test" { + authentication_type = "API_KEY" + name = %[1]q +} + +resource "aws_appsync_graphql_api" "test2" { + authentication_type = "API_KEY" + name = "%[1]s-2" +} + +resource "aws_appsync_api_association" "test" { + api_id = aws_appsync_graphql_api.test2.id + domain_name = aws_appsync_domain_name.test.domain_name +} +`, rName) +} diff --git a/internal/service/appsync/appsync_test.go b/internal/service/appsync/appsync_test.go index 423ae1e39fd..4aa79f04def 100644 --- a/internal/service/appsync/appsync_test.go +++ b/internal/service/appsync/appsync_test.go @@ -81,6 +81,15 @@ func TestAccAppSync_serial(t *testing.T) { "basic": testAccAppSyncApiCache_basic, "disappears": testAccAppSyncApiCache_disappears, }, + "DomainName": { + "basic": testAccAppSyncDomainName_basic, + "disappears": testAccAppSyncDomainName_disappears, + "description": testAccAppSyncDomainName_description, + }, + "Association": { + "basic": testAccAppSyncApiAssociation_basic, + "disappears": testAccAppSyncApiAssociation_disappears, + }, } for group, m := range testCases { diff --git a/internal/service/appsync/domain_name.go b/internal/service/appsync/domain_name.go new file mode 100644 index 00000000000..39b8b7a728d --- /dev/null +++ b/internal/service/appsync/domain_name.go @@ -0,0 +1,131 @@ +package appsync + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appsync" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ResourceDomainName() *schema.Resource { + + return &schema.Resource{ + Create: resourceDomainNameCreate, + Read: resourceDomainNameRead, + Update: resourceDomainNameUpdate, + Delete: resourceDomainNameDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "appsync_domain_name": { + Type: schema.TypeString, + Computed: true, + }, + "certificate_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "hosted_zone_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceDomainNameCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + params := &appsync.CreateDomainNameInput{ + CertificateArn: aws.String(d.Get("certificate_arn").(string)), + Description: aws.String(d.Get("description").(string)), + DomainName: aws.String(d.Get("domain_name").(string)), + } + + resp, err := conn.CreateDomainName(params) + if err != nil { + return fmt.Errorf("error creating Appsync Domain Name: %w", err) + } + + d.SetId(aws.StringValue(resp.DomainNameConfig.DomainName)) + + return resourceDomainNameRead(d, meta) +} + +func resourceDomainNameRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + domainName, err := FindDomainNameByID(conn, d.Id()) + if domainName == nil && !d.IsNewResource() { + log.Printf("[WARN] AppSync Domain Name (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error getting Appsync Domain Name %q: %w", d.Id(), err) + } + + d.Set("domain_name", domainName.DomainName) + d.Set("description", domainName.Description) + d.Set("certificate_arn", domainName.CertificateArn) + d.Set("hosted_zone_id", domainName.HostedZoneId) + d.Set("appsync_domain_name", domainName.AppsyncDomainName) + + return nil +} + +func resourceDomainNameUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + params := &appsync.UpdateDomainNameInput{ + DomainName: aws.String(d.Id()), + } + + if d.HasChange("description") { + params.Description = aws.String(d.Get("description").(string)) + } + + _, err := conn.UpdateDomainName(params) + if err != nil { + return fmt.Errorf("error updating Appsync Domain Name %q: %w", d.Id(), err) + } + + return resourceDomainNameRead(d, meta) + +} + +func resourceDomainNameDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppSyncConn + + input := &appsync.DeleteDomainNameInput{ + DomainName: aws.String(d.Id()), + } + _, err := conn.DeleteDomainName(input) + if err != nil { + if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { + return nil + } + return fmt.Errorf("error deleting Appsync Domain Name %q: %w", d.Id(), err) + } + + return nil +} diff --git a/internal/service/appsync/domain_name_test.go b/internal/service/appsync/domain_name_test.go new file mode 100644 index 00000000000..187d85f680c --- /dev/null +++ b/internal/service/appsync/domain_name_test.go @@ -0,0 +1,204 @@ +package appsync_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appsync" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "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" + tfappsync "github.com/hashicorp/terraform-provider-aws/internal/service/appsync" +) + +func testAccAppSyncDomainName_basic(t *testing.T) { + var domainName appsync.DomainNameConfig + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + + acmCertificateResourceName := "aws_acm_certificate.test" + resourceName := "aws_appsync_domain_name.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckDomainNameDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppsyncDomainNameConfig(rootDomain, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainNameExists(resourceName, &domainName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttrPair(resourceName, "domain_name", acmCertificateResourceName, "domain_name"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", acmCertificateResourceName, "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAppSyncDomainName_description(t *testing.T) { + var domainName appsync.DomainNameConfig + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + + resourceName := "aws_appsync_domain_name.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckDomainNameDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppsyncDomainNameDescriptionConfig(rootDomain, domain, "description1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainNameExists(resourceName, &domainName), + resource.TestCheckResourceAttr(resourceName, "description", "description1"), + ), + }, + { + Config: testAccAppsyncDomainNameDescriptionConfig(rootDomain, domain, "description2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainNameExists(resourceName, &domainName), + resource.TestCheckResourceAttr(resourceName, "description", "description2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAppSyncDomainName_disappears(t *testing.T) { + var domainName appsync.DomainNameConfig + rootDomain := acctest.ACMCertificateDomainFromEnv(t) + domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + + resourceName := "aws_appsync_domain_name.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckDomainNameDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppsyncDomainNameConfig(rootDomain, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainNameExists(resourceName, &domainName), + acctest.CheckResourceDisappears(acctest.Provider, tfappsync.ResourceDomainName(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckDomainNameDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).AppSyncConn + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appsync_domain_name" { + continue + } + + domainName, err := tfappsync.FindDomainNameByID(conn, rs.Primary.ID) + if err == nil { + if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { + return nil + } + return err + } + + if domainName != nil && aws.StringValue(domainName.DomainName) == rs.Primary.ID { + return fmt.Errorf("Appsync Domain Name ID %q still exists", rs.Primary.ID) + } + + return nil + + } + return nil +} + +func testAccCheckDomainNameExists(resourceName string, domainName *appsync.DomainNameConfig) resource.TestCheckFunc { + return func(s *terraform.State) error { + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Appsync Domain Name Not found in state: %s", resourceName) + } + conn := acctest.Provider.Meta().(*conns.AWSClient).AppSyncConn + + domain, err := tfappsync.FindDomainNameByID(conn, rs.Primary.ID) + if err != nil { + return err + } + + if domain == nil || domain.DomainName == nil { + return fmt.Errorf("Appsync Domain Name %q not found", rs.Primary.ID) + } + + *domainName = *domain + + return nil + } +} + +func testAccAppsyncDomainNamePublicCertConfig(rootDomain, domain string) string { + return fmt.Sprintf(` +data "aws_route53_zone" "test" { + name = %[1]q + private_zone = false +} + +resource "aws_acm_certificate" "test" { + domain_name = %[2]q + validation_method = "DNS" +} + +resource "aws_route53_record" "test" { + allow_overwrite = true + name = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_name + records = [tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_value] + ttl = 60 + type = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_type + zone_id = data.aws_route53_zone.test.zone_id +} + +resource "aws_acm_certificate_validation" "test" { + certificate_arn = aws_acm_certificate.test.arn + validation_record_fqdns = [aws_route53_record.test.fqdn] +} +`, rootDomain, domain) +} + +func testAccAppsyncDomainNameDescriptionConfig(rootDomain, domain, desc string) string { + return testAccAppsyncDomainNamePublicCertConfig(rootDomain, domain) + fmt.Sprintf(` +resource "aws_appsync_domain_name" "test" { + domain_name = aws_acm_certificate.test.domain_name + certificate_arn = aws_acm_certificate_validation.test.certificate_arn + description = %[1]q +} +`, desc) +} + +func testAccAppsyncDomainNameConfig(rootDomain, domain string) string { + return testAccAppsyncDomainNamePublicCertConfig(rootDomain, domain) + ` +resource "aws_appsync_domain_name" "test" { + domain_name = aws_acm_certificate.test.domain_name + certificate_arn = aws_acm_certificate_validation.test.certificate_arn +} +` +} diff --git a/internal/service/appsync/find.go b/internal/service/appsync/find.go index c4a634b118b..11a83bc4a52 100644 --- a/internal/service/appsync/find.go +++ b/internal/service/appsync/find.go @@ -31,3 +31,51 @@ func FindApiCacheByID(conn *appsync.AppSync, id string) (*appsync.ApiCache, erro return out.ApiCache, nil } + +func FindDomainNameByID(conn *appsync.AppSync, id string) (*appsync.DomainNameConfig, error) { + input := &appsync.GetDomainNameInput{ + DomainName: aws.String(id), + } + out, err := conn.GetDomainName(input) + + if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if out == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return out.DomainNameConfig, nil +} + +func FindDomainNameApiAssociationByID(conn *appsync.AppSync, id string) (*appsync.ApiAssociation, error) { + input := &appsync.GetApiAssociationInput{ + DomainName: aws.String(id), + } + out, err := conn.GetApiAssociation(input) + + if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if out == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return out.ApiAssociation, nil +} From 9725a62e3dcfd62fc38fe96d078d52a3e16203ac Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 8 Jan 2022 19:47:56 +0200 Subject: [PATCH 02/13] appsync association --- internal/provider/provider.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 9f16900ff34..5587b56c6a3 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -828,13 +828,14 @@ func Provider() *schema.Provider { "aws_appstream_user": appstream.ResourceUser(), "aws_appstream_user_stack_association": appstream.ResourceUserStackAssociation(), - "aws_appsync_api_cache": appsync.ResourceAPICache(), - "aws_appsync_api_key": appsync.ResourceAPIKey(), - "aws_appsync_datasource": appsync.ResourceDataSource(), - "aws_appsync_domain_name": appsync.ResourceDomainName(), - "aws_appsync_function": appsync.ResourceFunction(), - "aws_appsync_graphql_api": appsync.ResourceGraphQLAPI(), - "aws_appsync_resolver": appsync.ResourceResolver(), + "aws_appsync_api_cache": appsync.ResourceAPICache(), + "aws_appsync_api_key": appsync.ResourceAPIKey(), + "aws_appsync_datasource": appsync.ResourceDataSource(), + "aws_appsync_domain_name": appsync.ResourceDomainName(), + "aws_appsync_domain_name_api_association": appsync.ResourceDomainNameApiAssociation(), + "aws_appsync_function": appsync.ResourceFunction(), + "aws_appsync_graphql_api": appsync.ResourceGraphQLAPI(), + "aws_appsync_resolver": appsync.ResourceResolver(), "aws_athena_database": athena.ResourceDatabase(), "aws_athena_named_query": athena.ResourceNamedQuery(), From c994351e157366ef666d7422db82797ae3fd9a38 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 8 Jan 2022 19:56:38 +0200 Subject: [PATCH 03/13] docs --- .../r/appsync_api_association.html.markdown | 42 ++++++++++++++++++ .../docs/r/appsync_domain_name.html.markdown | 44 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 website/docs/r/appsync_api_association.html.markdown create mode 100644 website/docs/r/appsync_domain_name.html.markdown diff --git a/website/docs/r/appsync_api_association.html.markdown b/website/docs/r/appsync_api_association.html.markdown new file mode 100644 index 00000000000..1d749f4f8e4 --- /dev/null +++ b/website/docs/r/appsync_api_association.html.markdown @@ -0,0 +1,42 @@ +--- +subcategory: "AppSync" +layout: "aws" +page_title: "AWS: aws_appsync_api_association" +description: |- + Provides an AppSync API Association. +--- + +# Resource: aws_appsync_api_association + +Provides an AppSync API Association. + +## Example Usage + +```terraform +resource "aws_appsync_api_association" "example" { + api_id = aws_acm_certificate.example.api_association + certificate_arn = aws_acm_certificate.example.arn +} +``` + +## Argument Reference + +The following arguments are supported: + +* `api_id` - (Required) The API ID. +* `domain_name` - (Required) The Appsync domain name. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The Appsync domain name. + + +## Import + +`aws_appsync_api_association` can be imported using the AppSync domain name, e.g., + +``` +$ terraform import aws_appsync_api_association.example example.com +``` diff --git a/website/docs/r/appsync_domain_name.html.markdown b/website/docs/r/appsync_domain_name.html.markdown new file mode 100644 index 00000000000..9f80a41c0ee --- /dev/null +++ b/website/docs/r/appsync_domain_name.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "AppSync" +layout: "aws" +page_title: "AWS: aws_appsync_domain_name" +description: |- + Provides an AppSync Domain Name. +--- + +# Resource: aws_appsync_domain_name + +Provides an AppSync Domain Name. + +## Example Usage + +```terraform +resource "aws_appsync_domain_name" "example" { + domain_name = aws_acm_certificate.example.domain_name + certificate_arn = aws_acm_certificate.example.arn +} +``` + +## Argument Reference + +The following arguments are supported: + +* `certificate_arn` - (Required) The Amazon Resource Name (ARN) of the certificate. This can be an Certificate Manager (ACM) certificate or an Identity and Access Management (IAM) server certificate. +* `description` - (Optional) A description of the Domain Name. +* `domain_name` - (Required) The domain name. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The Appsync Domain Name. +* `appsync_domain_name` - The domain name that AppSync provides. +* `hosted_zone_id` - The ID of your Amazon Route 53 hosted zone. + +## Import + +`aws_appsync_domain_name` can be imported using the AppSync domain name, e.g., + +``` +$ terraform import aws_appsync_domain_name.example example.com +``` From a2a654c19425af5315edf7644f57168e9e51bb02 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 14 Jan 2022 01:02:08 +0200 Subject: [PATCH 04/13] appsync domain name tests --- internal/service/appsync/appsync_test.go | 13 +++ internal/service/appsync/domain_name.go | 22 ++++- internal/service/appsync/domain_name_test.go | 88 ++++++++------------ 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/internal/service/appsync/appsync_test.go b/internal/service/appsync/appsync_test.go index 4aa79f04def..73fb2267d97 100644 --- a/internal/service/appsync/appsync_test.go +++ b/internal/service/appsync/appsync_test.go @@ -1,6 +1,7 @@ package appsync_test import ( + "os" "testing" ) @@ -104,3 +105,15 @@ func TestAccAppSync_serial(t *testing.T) { }) } } + +func getAppsyncCertDomain(t *testing.T) string { + value := os.Getenv("AWS_APPSYNC_DOMAIN_NAME_CERTIFICATE_DOMAIN") + if value == "" { + t.Skip( + "Environment variable AWS_APPSYNC_DOMAIN_NAME_CERTIFICATE_DOMAIN is not set. " + + "This environment variable must be set to any non-empty value " + + "to enable the test.") + } + + return value +} diff --git a/internal/service/appsync/domain_name.go b/internal/service/appsync/domain_name.go index 39b8b7a728d..3a9487e5a29 100644 --- a/internal/service/appsync/domain_name.go +++ b/internal/service/appsync/domain_name.go @@ -3,12 +3,15 @@ package appsync import ( "fmt" "log" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appsync" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -119,11 +122,22 @@ func resourceDomainNameDelete(d *schema.ResourceData, meta interface{}) error { input := &appsync.DeleteDomainNameInput{ DomainName: aws.String(d.Id()), } - _, err := conn.DeleteDomainName(input) - if err != nil { - if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { - return nil + + err := resource.Retry(5*time.Minute, func() *resource.RetryError { + _, err := conn.DeleteDomainName(input) + if tfawserr.ErrCodeEquals(err, appsync.ErrCodeConcurrentModificationException) { + return resource.RetryableError(fmt.Errorf("deleting Appsync Domain Name %q: %w", d.Id(), err)) } + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + if tfresource.TimedOut(err) { + _, err = conn.DeleteDomainName(input) + } + if err != nil { return fmt.Errorf("error deleting Appsync Domain Name %q: %w", d.Id(), err) } diff --git a/internal/service/appsync/domain_name_test.go b/internal/service/appsync/domain_name_test.go index 187d85f680c..1c58154ae48 100644 --- a/internal/service/appsync/domain_name_test.go +++ b/internal/service/appsync/domain_name_test.go @@ -7,7 +7,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appsync" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/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/conns" @@ -15,25 +17,25 @@ import ( ) func testAccAppSyncDomainName_basic(t *testing.T) { + var providers []*schema.Provider var domainName appsync.DomainNameConfig - rootDomain := acctest.ACMCertificateDomainFromEnv(t) - domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + appsyncCertDomain := getAppsyncCertDomain(t) - acmCertificateResourceName := "aws_acm_certificate.test" + rName := sdkacctest.RandString(8) + acmCertificateResourceName := "data.aws_acm_certificate.test" resourceName := "aws_appsync_domain_name.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, - ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckDomainNameDestroy, + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckDomainNameDestroy, Steps: []resource.TestStep{ { - Config: testAccAppsyncDomainNameConfig(rootDomain, domain), + Config: testAccAppsyncDomainNameBasicConfig(rName, appsyncCertDomain), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameExists(resourceName, &domainName), resource.TestCheckResourceAttr(resourceName, "description", ""), - resource.TestCheckResourceAttrPair(resourceName, "domain_name", acmCertificateResourceName, "domain_name"), resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", acmCertificateResourceName, "arn"), ), }, @@ -48,9 +50,9 @@ func testAccAppSyncDomainName_basic(t *testing.T) { func testAccAppSyncDomainName_description(t *testing.T) { var domainName appsync.DomainNameConfig - rootDomain := acctest.ACMCertificateDomainFromEnv(t) - domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + appsyncCertDomain := getAppsyncCertDomain(t) + rName := sdkacctest.RandString(8) resourceName := "aws_appsync_domain_name.test" resource.Test(t, resource.TestCase{ @@ -60,14 +62,14 @@ func testAccAppSyncDomainName_description(t *testing.T) { CheckDestroy: testAccCheckDomainNameDestroy, Steps: []resource.TestStep{ { - Config: testAccAppsyncDomainNameDescriptionConfig(rootDomain, domain, "description1"), + Config: testAccAppsyncDomainNameDescriptionConfig(rName, appsyncCertDomain, "description1"), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameExists(resourceName, &domainName), resource.TestCheckResourceAttr(resourceName, "description", "description1"), ), }, { - Config: testAccAppsyncDomainNameDescriptionConfig(rootDomain, domain, "description2"), + Config: testAccAppsyncDomainNameDescriptionConfig(rName, appsyncCertDomain, "description2"), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameExists(resourceName, &domainName), resource.TestCheckResourceAttr(resourceName, "description", "description2"), @@ -84,9 +86,9 @@ func testAccAppSyncDomainName_description(t *testing.T) { func testAccAppSyncDomainName_disappears(t *testing.T) { var domainName appsync.DomainNameConfig - rootDomain := acctest.ACMCertificateDomainFromEnv(t) - domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + appsyncCertDomain := getAppsyncCertDomain(t) + rName := sdkacctest.RandString(8) resourceName := "aws_appsync_domain_name.test" resource.Test(t, resource.TestCase{ @@ -96,7 +98,7 @@ func testAccAppSyncDomainName_disappears(t *testing.T) { CheckDestroy: testAccCheckDomainNameDestroy, Steps: []resource.TestStep{ { - Config: testAccAppsyncDomainNameConfig(rootDomain, domain), + Config: testAccAppsyncDomainNameBasicConfig(rName, appsyncCertDomain), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameExists(resourceName, &domainName), acctest.CheckResourceDisappears(acctest.Provider, tfappsync.ResourceDomainName(), resourceName), @@ -156,49 +158,31 @@ func testAccCheckDomainNameExists(resourceName string, domainName *appsync.Domai } } -func testAccAppsyncDomainNamePublicCertConfig(rootDomain, domain string) string { - return fmt.Sprintf(` -data "aws_route53_zone" "test" { - name = %[1]q - private_zone = false -} - -resource "aws_acm_certificate" "test" { - domain_name = %[2]q - validation_method = "DNS" -} - -resource "aws_route53_record" "test" { - allow_overwrite = true - name = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_name - records = [tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_value] - ttl = 60 - type = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_type - zone_id = data.aws_route53_zone.test.zone_id -} - -resource "aws_acm_certificate_validation" "test" { - certificate_arn = aws_acm_certificate.test.arn - validation_record_fqdns = [aws_route53_record.test.fqdn] +func testAccAppsyncDomainNameBaseConfig(domain string) string { + return acctest.ConfigAlternateRegionProvider() + fmt.Sprintf(` +data "aws_acm_certificate" "test" { + provider = "awsalternate" + domain = "*.%[1]s" + most_recent = true } -`, rootDomain, domain) +`, domain) } -func testAccAppsyncDomainNameDescriptionConfig(rootDomain, domain, desc string) string { - return testAccAppsyncDomainNamePublicCertConfig(rootDomain, domain) + fmt.Sprintf(` +func testAccAppsyncDomainNameDescriptionConfig(rName, domain, desc string) string { + return testAccAppsyncDomainNameBaseConfig(domain) + fmt.Sprintf(` resource "aws_appsync_domain_name" "test" { - domain_name = aws_acm_certificate.test.domain_name - certificate_arn = aws_acm_certificate_validation.test.certificate_arn - description = %[1]q + domain_name = "%[2]s.%[1]s" + certificate_arn = data.aws_acm_certificate.test.arn + description = %[3]q } -`, desc) +`, rName, domain, desc) } -func testAccAppsyncDomainNameConfig(rootDomain, domain string) string { - return testAccAppsyncDomainNamePublicCertConfig(rootDomain, domain) + ` +func testAccAppsyncDomainNameBasicConfig(rName, domain string) string { + return testAccAppsyncDomainNameBaseConfig(domain) + fmt.Sprintf(` resource "aws_appsync_domain_name" "test" { - domain_name = aws_acm_certificate.test.domain_name - certificate_arn = aws_acm_certificate_validation.test.certificate_arn + domain_name = "%[2]s.%[1]s" + certificate_arn = data.aws_acm_certificate.test.arn } -` +`, domain, rName) } From d5ce90cb72641b114aa84cafc682a6a560606f06 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 14 Jan 2022 13:07:36 +0200 Subject: [PATCH 05/13] sweep --- internal/service/appsync/sweep.go | 92 +++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/internal/service/appsync/sweep.go b/internal/service/appsync/sweep.go index 0fe60919fba..be0ed5ae6d7 100644 --- a/internal/service/appsync/sweep.go +++ b/internal/service/appsync/sweep.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appsync" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/sweep" @@ -19,6 +20,11 @@ func init() { Name: "aws_appsync_graphql_api", F: sweepGraphQLAPIs, }) + + resource.AddTestSweepers("aws_appsync_domain_name", &resource.Sweeper{ + Name: "aws_appsync_domain_name", + F: sweepDomainNames, + }) } func sweepGraphQLAPIs(region string) error { @@ -27,6 +33,8 @@ func sweepGraphQLAPIs(region string) error { return fmt.Errorf("Error getting client: %s", err) } conn := client.(*conns.AWSClient).AppSyncConn + sweepResources := make([]*sweep.SweepResource, 0) + var errs *multierror.Error input := &appsync.ListGraphqlApisInput{} @@ -38,21 +46,76 @@ func sweepGraphQLAPIs(region string) error { } if err != nil { - return fmt.Errorf("Error retrieving AppSync GraphQL APIs: %s", err) + err := fmt.Errorf("error reading AppSync GraphQL API: %w", err) + log.Printf("[ERROR] %s", err) + errs = multierror.Append(errs, err) + break } for _, graphAPI := range output.GraphqlApis { + + r := ResourceGraphQLAPI() + d := r.Data(nil) + id := aws.StringValue(graphAPI.ApiId) - input := &appsync.DeleteGraphqlApiInput{ - ApiId: graphAPI.ApiId, - } + d.SetId(id) + + sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + if err := sweep.SweepOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping AppSync GraphQL API %s: %w", region, err)) + } + + if sweep.SkipSweepError(err) { + log.Printf("[WARN] Skipping AppSync GraphQL API sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + +func sweepDomainNames(region string) error { + client, err := sweep.SharedRegionalSweepClient(region) + if err != nil { + return fmt.Errorf("Error getting client: %s", err) + } + conn := client.(*conns.AWSClient).AppSyncConn + sweepResources := make([]*sweep.SweepResource, 0) + var errs *multierror.Error - log.Printf("[INFO] Deleting AppSync GraphQL API %s", id) - _, err := conn.DeleteGraphqlApi(input) + input := &appsync.ListDomainNamesInput{} - if err != nil { - return fmt.Errorf("error deleting AppSync GraphQL API (%s): %s", id, err) - } + for { + output, err := conn.ListDomainNames(input) + if sweep.SkipSweepError(err) { + log.Printf("[WARN] Skipping AppSync Domain Name sweep for %s: %s", region, err) + return nil + } + + if err != nil { + err := fmt.Errorf("error reading AppSync Domain Name: %w", err) + log.Printf("[ERROR] %s", err) + errs = multierror.Append(errs, err) + break + } + + for _, dm := range output.DomainNameConfigs { + + r := ResourceDomainName() + d := r.Data(nil) + + id := aws.StringValue(dm.DomainName) + d.SetId(id) + + sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) } if aws.StringValue(output.NextToken) == "" { @@ -62,5 +125,14 @@ func sweepGraphQLAPIs(region string) error { input.NextToken = output.NextToken } - return nil + if err := sweep.SweepOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping AppSync Domain Name %s: %w", region, err)) + } + + if sweep.SkipSweepError(err) { + log.Printf("[WARN] Skipping AppSync Domain Name sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() } From 656ad77a4679d86645eda8dcf0c01b7c0397e123 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 14 Jan 2022 13:19:16 +0200 Subject: [PATCH 06/13] domain name full tests --- internal/service/appsync/domain_name_test.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/service/appsync/domain_name_test.go b/internal/service/appsync/domain_name_test.go index 1c58154ae48..a102a3c109c 100644 --- a/internal/service/appsync/domain_name_test.go +++ b/internal/service/appsync/domain_name_test.go @@ -49,6 +49,7 @@ func testAccAppSyncDomainName_basic(t *testing.T) { } func testAccAppSyncDomainName_description(t *testing.T) { + var providers []*schema.Provider var domainName appsync.DomainNameConfig appsyncCertDomain := getAppsyncCertDomain(t) @@ -56,10 +57,10 @@ func testAccAppSyncDomainName_description(t *testing.T) { resourceName := "aws_appsync_domain_name.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, - ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckDomainNameDestroy, + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckDomainNameDestroy, Steps: []resource.TestStep{ { Config: testAccAppsyncDomainNameDescriptionConfig(rName, appsyncCertDomain, "description1"), @@ -85,6 +86,7 @@ func testAccAppSyncDomainName_description(t *testing.T) { } func testAccAppSyncDomainName_disappears(t *testing.T) { + var providers []*schema.Provider var domainName appsync.DomainNameConfig appsyncCertDomain := getAppsyncCertDomain(t) @@ -92,10 +94,10 @@ func testAccAppSyncDomainName_disappears(t *testing.T) { resourceName := "aws_appsync_domain_name.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, - ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckDomainNameDestroy, + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckDomainNameDestroy, Steps: []resource.TestStep{ { Config: testAccAppsyncDomainNameBasicConfig(rName, appsyncCertDomain), From 1f05b107501bf199510f91a405e7929c213c62c3 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 14 Jan 2022 13:24:58 +0200 Subject: [PATCH 07/13] rename --- ...tion.go => domain_name_api_association.go} | 24 +++++----- ...go => domain_name_api_association_test.go} | 46 +++++++++---------- .../docs/r/appsync_domain_name.html.markdown | 4 +- ...domain_name_api_association.html.markdown} | 14 +++--- 4 files changed, 44 insertions(+), 44 deletions(-) rename internal/service/appsync/{api_association.go => domain_name_api_association.go} (72%) rename internal/service/appsync/{api_association_test.go => domain_name_api_association_test.go} (73%) rename website/docs/r/{appsync_api_association.html.markdown => appsync_domain_name_api_association.html.markdown} (51%) diff --git a/internal/service/appsync/api_association.go b/internal/service/appsync/domain_name_api_association.go similarity index 72% rename from internal/service/appsync/api_association.go rename to internal/service/appsync/domain_name_api_association.go index bbf23bbc2a3..8f70e54a6fc 100644 --- a/internal/service/appsync/api_association.go +++ b/internal/service/appsync/domain_name_api_association.go @@ -11,13 +11,13 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" ) -func ResourceApiAssociation() *schema.Resource { +func ResourceDomainNameApiAssociation() *schema.Resource { return &schema.Resource{ - Create: resourceApiAssociationCreate, - Read: resourceApiAssociationRead, - Update: resourceApiAssociationUpdate, - Delete: resourceApiAssociationDelete, + Create: resourceDomainNameApiAssociationCreate, + Read: resourceDomainNameApiAssociationRead, + Update: resourceDomainNameApiAssociationUpdate, + Delete: resourceDomainNameApiAssociationDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -36,7 +36,7 @@ func ResourceApiAssociation() *schema.Resource { } } -func resourceApiAssociationCreate(d *schema.ResourceData, meta interface{}) error { +func resourceDomainNameApiAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppSyncConn params := &appsync.AssociateApiInput{ @@ -51,13 +51,13 @@ func resourceApiAssociationCreate(d *schema.ResourceData, meta interface{}) erro d.SetId(aws.StringValue(resp.ApiAssociation.DomainName)) - return resourceApiAssociationRead(d, meta) + return resourceDomainNameApiAssociationRead(d, meta) } -func resourceApiAssociationRead(d *schema.ResourceData, meta interface{}) error { +func resourceDomainNameApiAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppSyncConn - association, err := FindApiAssociationByID(conn, d.Id()) + association, err := FindDomainNameApiAssociationByID(conn, d.Id()) if association == nil && !d.IsNewResource() { log.Printf("[WARN] AppSync API Association (%s) not found, removing from state", d.Id()) d.SetId("") @@ -74,7 +74,7 @@ func resourceApiAssociationRead(d *schema.ResourceData, meta interface{}) error return nil } -func resourceApiAssociationUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceDomainNameApiAssociationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppSyncConn params := &appsync.AssociateApiInput{ @@ -87,10 +87,10 @@ func resourceApiAssociationUpdate(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("error creating Appsync API Association: %w", err) } - return resourceApiAssociationRead(d, meta) + return resourceDomainNameApiAssociationRead(d, meta) } -func resourceApiAssociationDelete(d *schema.ResourceData, meta interface{}) error { +func resourceDomainNameApiAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AppSyncConn input := &appsync.DisassociateApiInput{ diff --git a/internal/service/appsync/api_association_test.go b/internal/service/appsync/domain_name_api_association_test.go similarity index 73% rename from internal/service/appsync/api_association_test.go rename to internal/service/appsync/domain_name_api_association_test.go index 90c4da74587..615c7eb4152 100644 --- a/internal/service/appsync/api_association_test.go +++ b/internal/service/appsync/domain_name_api_association_test.go @@ -15,8 +15,8 @@ import ( tfappsync "github.com/hashicorp/terraform-provider-aws/internal/service/appsync" ) -func testAccAppSyncApiAssociation_basic(t *testing.T) { - var association appsync.ApiAssociation +func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { + var association appsync.DomainNameApiAssociation rootDomain := acctest.ACMCertificateDomainFromEnv(t) domain := acctest.ACMCertificateRandomSubDomain(rootDomain) @@ -27,12 +27,12 @@ func testAccAppSyncApiAssociation_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), Providers: acctest.Providers, - CheckDestroy: testAccCheckApiAssociationDestroy, + CheckDestroy: testAccCheckDomainNameApiAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAppsyncApiAssociationConfig(rootDomain, domain, rName), + Config: testAccAppsyncDomainNameApiAssociationConfig(rootDomain, domain, rName), Check: resource.ComposeTestCheckFunc( - testAccCheckApiAssociationExists(resourceName, &association), + testAccCheckDomainNameApiAssociationExists(resourceName, &association), resource.TestCheckResourceAttrPair(resourceName, "domain_name", "aws_appsync_domain_name.test", "domain_name"), resource.TestCheckResourceAttrPair(resourceName, "api_id", "aws_appsync_graphql_api.test", "id"), ), @@ -43,9 +43,9 @@ func testAccAppSyncApiAssociation_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAppsyncApiAssociationUpdatedConfig(rootDomain, domain, rName), + Config: testAccAppsyncDomainNameApiAssociationUpdatedConfig(rootDomain, domain, rName), Check: resource.ComposeTestCheckFunc( - testAccCheckApiAssociationExists(resourceName, &association), + testAccCheckDomainNameApiAssociationExists(resourceName, &association), resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttrPair(resourceName, "domain_name", "aws_appsync_domain_name.test", "domain_name"), resource.TestCheckResourceAttrPair(resourceName, "api_id", "aws_appsync_graphql_api.test2", "id"), @@ -55,8 +55,8 @@ func testAccAppSyncApiAssociation_basic(t *testing.T) { }) } -func testAccAppSyncApiAssociation_disappears(t *testing.T) { - var association appsync.ApiAssociation +func testAccAppSyncDomainNameApiAssociation_disappears(t *testing.T) { + var association appsync.DomainNameApiAssociation rootDomain := acctest.ACMCertificateDomainFromEnv(t) domain := acctest.ACMCertificateRandomSubDomain(rootDomain) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -67,13 +67,13 @@ func testAccAppSyncApiAssociation_disappears(t *testing.T) { PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), Providers: acctest.Providers, - CheckDestroy: testAccCheckApiAssociationDestroy, + CheckDestroy: testAccCheckDomainNameApiAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAppsyncApiAssociationConfig(rootDomain, domain, rName), + Config: testAccAppsyncDomainNameApiAssociationConfig(rootDomain, domain, rName), Check: resource.ComposeTestCheckFunc( - testAccCheckApiAssociationExists(resourceName, &association), - acctest.CheckResourceDisappears(acctest.Provider, tfappsync.ResourceApiAssociation(), resourceName), + testAccCheckDomainNameApiAssociationExists(resourceName, &association), + acctest.CheckResourceDisappears(acctest.Provider, tfappsync.ResourceDomainNameApiAssociation(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -81,14 +81,14 @@ func testAccAppSyncApiAssociation_disappears(t *testing.T) { }) } -func testAccCheckApiAssociationDestroy(s *terraform.State) error { +func testAccCheckDomainNameApiAssociationDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppSyncConn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_appsync_domain_name" { continue } - association, err := tfappsync.FindApiAssociationByID(conn, rs.Primary.ID) + association, err := tfappsync.FindDomainNameApiAssociationByID(conn, rs.Primary.ID) if err == nil { if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { return nil @@ -106,7 +106,7 @@ func testAccCheckApiAssociationDestroy(s *terraform.State) error { return nil } -func testAccCheckApiAssociationExists(resourceName string, apiAssociation *appsync.ApiAssociation) resource.TestCheckFunc { +func testAccCheckDomainNameApiAssociationExists(resourceName string, DomainNameApiAssociation *appsync.DomainNameApiAssociation) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -115,7 +115,7 @@ func testAccCheckApiAssociationExists(resourceName string, apiAssociation *appsy } conn := acctest.Provider.Meta().(*conns.AWSClient).AppSyncConn - association, err := tfappsync.FindApiAssociationByID(conn, rs.Primary.ID) + association, err := tfappsync.FindDomainNameApiAssociationByID(conn, rs.Primary.ID) if err != nil { return err } @@ -124,13 +124,13 @@ func testAccCheckApiAssociationExists(resourceName string, apiAssociation *appsy return fmt.Errorf("Appsync Domain Name %q not found", rs.Primary.ID) } - *apiAssociation = *association + *DomainNameApiAssociation = *association return nil } } -func testAccAppsyncApiAssociationBaseConfig(rootDomain, domain string) string { +func testAccAppsyncDomainNameApiAssociationBaseConfig(rootDomain, domain string) string { return fmt.Sprintf(` data "aws_route53_zone" "test" { name = %[1]q @@ -163,8 +163,8 @@ resource "aws_appsync_domain_name" "test" { `, rootDomain, domain) } -func testAccAppsyncApiAssociationConfig(rootDomain, domain, rName string) string { - return testAccAppsyncApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` +func testAccAppsyncDomainNameApiAssociationConfig(rootDomain, domain, rName string) string { + return testAccAppsyncDomainNameApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` resource "aws_appsync_graphql_api" "test" { authentication_type = "API_KEY" name = %[1]q @@ -177,8 +177,8 @@ resource "aws_appsync_api_association" "test" { `, rName) } -func testAccAppsyncApiAssociationUpdatedConfig(rootDomain, domain, rName string) string { - return testAccAppsyncApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` +func testAccAppsyncDomainNameApiAssociationUpdatedConfig(rootDomain, domain, rName string) string { + return testAccAppsyncDomainNameApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` resource "aws_appsync_graphql_api" "test" { authentication_type = "API_KEY" name = %[1]q diff --git a/website/docs/r/appsync_domain_name.html.markdown b/website/docs/r/appsync_domain_name.html.markdown index 9f80a41c0ee..ea07a00c934 100644 --- a/website/docs/r/appsync_domain_name.html.markdown +++ b/website/docs/r/appsync_domain_name.html.markdown @@ -14,7 +14,7 @@ Provides an AppSync Domain Name. ```terraform resource "aws_appsync_domain_name" "example" { - domain_name = aws_acm_certificate.example.domain_name + domain_name = "api.example.com" certificate_arn = aws_acm_certificate.example.arn } ``` @@ -23,7 +23,7 @@ resource "aws_appsync_domain_name" "example" { The following arguments are supported: -* `certificate_arn` - (Required) The Amazon Resource Name (ARN) of the certificate. This can be an Certificate Manager (ACM) certificate or an Identity and Access Management (IAM) server certificate. +* `certificate_arn` - (Required) The Amazon Resource Name (ARN) of the certificate. This can be an Certificate Manager (ACM) certificate or an Identity and Access Management (IAM) server certificate. The certifiacte must reside in us-east-1. * `description` - (Optional) A description of the Domain Name. * `domain_name` - (Required) The domain name. diff --git a/website/docs/r/appsync_api_association.html.markdown b/website/docs/r/appsync_domain_name_api_association.html.markdown similarity index 51% rename from website/docs/r/appsync_api_association.html.markdown rename to website/docs/r/appsync_domain_name_api_association.html.markdown index 1d749f4f8e4..9c93a902159 100644 --- a/website/docs/r/appsync_api_association.html.markdown +++ b/website/docs/r/appsync_domain_name_api_association.html.markdown @@ -1,21 +1,21 @@ --- subcategory: "AppSync" layout: "aws" -page_title: "AWS: aws_appsync_api_association" +page_title: "AWS: aws_appsync_domain_name_api_association" description: |- Provides an AppSync API Association. --- -# Resource: aws_appsync_api_association +# Resource: aws_appsync_domain_name_api_association Provides an AppSync API Association. ## Example Usage ```terraform -resource "aws_appsync_api_association" "example" { - api_id = aws_acm_certificate.example.api_association - certificate_arn = aws_acm_certificate.example.arn +resource "aws_appsync_domain_name_api_association" "example" { + api_id = aws_appsync_graphql_api.example.id + domain_name = aws_appsync_domain_name.example.domain_name } ``` @@ -35,8 +35,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -`aws_appsync_api_association` can be imported using the AppSync domain name, e.g., +`aws_appsync_domain_name_api_association` can be imported using the AppSync domain name, e.g., ``` -$ terraform import aws_appsync_api_association.example example.com +$ terraform import aws_appsync_domain_name_api_association.example example.com ``` From 5fe3e10015e63725403d85392b58a59d1a91e3be Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 14 Jan 2022 13:59:36 +0200 Subject: [PATCH 08/13] domain name tests --- internal/service/appsync/appsync_test.go | 4 ++-- .../service/appsync/domain_name_api_association_test.go | 6 +++--- internal/service/appsync/domain_name_test.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/appsync/appsync_test.go b/internal/service/appsync/appsync_test.go index 73fb2267d97..121285f9f43 100644 --- a/internal/service/appsync/appsync_test.go +++ b/internal/service/appsync/appsync_test.go @@ -88,8 +88,8 @@ func TestAccAppSync_serial(t *testing.T) { "description": testAccAppSyncDomainName_description, }, "Association": { - "basic": testAccAppSyncApiAssociation_basic, - "disappears": testAccAppSyncApiAssociation_disappears, + "basic": testAccAppSyncDomainNameApiAssociation_basic, + "disappears": testAccAppSyncDomainNameApiAssociation_disappears, }, } diff --git a/internal/service/appsync/domain_name_api_association_test.go b/internal/service/appsync/domain_name_api_association_test.go index 615c7eb4152..31a20b415ce 100644 --- a/internal/service/appsync/domain_name_api_association_test.go +++ b/internal/service/appsync/domain_name_api_association_test.go @@ -16,7 +16,7 @@ import ( ) func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { - var association appsync.DomainNameApiAssociation + var association appsync.ApiAssociation rootDomain := acctest.ACMCertificateDomainFromEnv(t) domain := acctest.ACMCertificateRandomSubDomain(rootDomain) @@ -56,7 +56,7 @@ func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { } func testAccAppSyncDomainNameApiAssociation_disappears(t *testing.T) { - var association appsync.DomainNameApiAssociation + var association appsync.ApiAssociation rootDomain := acctest.ACMCertificateDomainFromEnv(t) domain := acctest.ACMCertificateRandomSubDomain(rootDomain) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -106,7 +106,7 @@ func testAccCheckDomainNameApiAssociationDestroy(s *terraform.State) error { return nil } -func testAccCheckDomainNameApiAssociationExists(resourceName string, DomainNameApiAssociation *appsync.DomainNameApiAssociation) resource.TestCheckFunc { +func testAccCheckDomainNameApiAssociationExists(resourceName string, DomainNameApiAssociation *appsync.ApiAssociation) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] diff --git a/internal/service/appsync/domain_name_test.go b/internal/service/appsync/domain_name_test.go index a102a3c109c..c2b78024d01 100644 --- a/internal/service/appsync/domain_name_test.go +++ b/internal/service/appsync/domain_name_test.go @@ -177,7 +177,7 @@ resource "aws_appsync_domain_name" "test" { certificate_arn = data.aws_acm_certificate.test.arn description = %[3]q } -`, rName, domain, desc) +`, domain, rName, desc) } func testAccAppsyncDomainNameBasicConfig(rName, domain string) string { From f18919c04a2517b68b9e0bb942ca8388455ecefd Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 14 Jan 2022 14:16:08 +0200 Subject: [PATCH 09/13] rename --- internal/service/appsync/appsync_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appsync/appsync_test.go b/internal/service/appsync/appsync_test.go index 121285f9f43..4b89788ea00 100644 --- a/internal/service/appsync/appsync_test.go +++ b/internal/service/appsync/appsync_test.go @@ -87,7 +87,7 @@ func TestAccAppSync_serial(t *testing.T) { "disappears": testAccAppSyncDomainName_disappears, "description": testAccAppSyncDomainName_description, }, - "Association": { + "DomainNameAssociation": { "basic": testAccAppSyncDomainNameApiAssociation_basic, "disappears": testAccAppSyncDomainNameApiAssociation_disappears, }, From 68ce9679d1ece2c4e55ce30fba3597ec545fbc16 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 14 Jan 2022 21:22:57 +0200 Subject: [PATCH 10/13] assoication waiter + tests --- .../appsync/domain_name_api_association.go | 26 +++-- .../domain_name_api_association_test.go | 94 +++++++------------ internal/service/appsync/status.go | 16 ++++ internal/service/appsync/wait.go | 36 ++++++- 4 files changed, 103 insertions(+), 69 deletions(-) diff --git a/internal/service/appsync/domain_name_api_association.go b/internal/service/appsync/domain_name_api_association.go index 8f70e54a6fc..a8e378ca060 100644 --- a/internal/service/appsync/domain_name_api_association.go +++ b/internal/service/appsync/domain_name_api_association.go @@ -40,17 +40,21 @@ func resourceDomainNameApiAssociationCreate(d *schema.ResourceData, meta interfa conn := meta.(*conns.AWSClient).AppSyncConn params := &appsync.AssociateApiInput{ - ApiId: aws.String(d.Get("description").(string)), + ApiId: aws.String(d.Get("api_id").(string)), DomainName: aws.String(d.Get("domain_name").(string)), } resp, err := conn.AssociateApi(params) if err != nil { - return fmt.Errorf("error creating Appsync API Association: %w", err) + return fmt.Errorf("error creating Appsync Domain Name API Association: %w", err) } d.SetId(aws.StringValue(resp.ApiAssociation.DomainName)) + if _, err := waitDomainNameApiAssociation(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Association: %w", d.Id(), err) + } + return resourceDomainNameApiAssociationRead(d, meta) } @@ -59,13 +63,13 @@ func resourceDomainNameApiAssociationRead(d *schema.ResourceData, meta interface association, err := FindDomainNameApiAssociationByID(conn, d.Id()) if association == nil && !d.IsNewResource() { - log.Printf("[WARN] AppSync API Association (%s) not found, removing from state", d.Id()) + log.Printf("[WARN] Appsync Domain Name API Association (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error getting Appsync API Association %q: %w", d.Id(), err) + return fmt.Errorf("error getting Appsync Domain Name API Association %q: %w", d.Id(), err) } d.Set("domain_name", association.DomainName) @@ -78,13 +82,17 @@ func resourceDomainNameApiAssociationUpdate(d *schema.ResourceData, meta interfa conn := meta.(*conns.AWSClient).AppSyncConn params := &appsync.AssociateApiInput{ - ApiId: aws.String(d.Get("description").(string)), + ApiId: aws.String(d.Get("api_id").(string)), DomainName: aws.String(d.Get("domain_name").(string)), } _, err := conn.AssociateApi(params) if err != nil { - return fmt.Errorf("error creating Appsync API Association: %w", err) + return fmt.Errorf("error creating Appsync Domain Name API Association: %w", err) + } + + if _, err := waitDomainNameApiAssociation(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Association: %w", d.Id(), err) } return resourceDomainNameApiAssociationRead(d, meta) @@ -101,7 +109,11 @@ func resourceDomainNameApiAssociationDelete(d *schema.ResourceData, meta interfa if tfawserr.ErrCodeEquals(err, appsync.ErrCodeNotFoundException) { return nil } - return fmt.Errorf("error deleting Appsync API Association: %w", err) + return fmt.Errorf("error deleting Appsync Domain Name API Association: %w", err) + } + + if _, err := waitDomainNameApiDisassociation(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Disassociation: %w", d.Id(), err) } return nil diff --git a/internal/service/appsync/domain_name_api_association_test.go b/internal/service/appsync/domain_name_api_association_test.go index 31a20b415ce..2dba47165a1 100644 --- a/internal/service/appsync/domain_name_api_association_test.go +++ b/internal/service/appsync/domain_name_api_association_test.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/aws-sdk-go-base/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/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/conns" @@ -16,21 +17,21 @@ import ( ) func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { + var providers []*schema.Provider var association appsync.ApiAssociation - rootDomain := acctest.ACMCertificateDomainFromEnv(t) - domain := acctest.ACMCertificateRandomSubDomain(rootDomain) + appsyncCertDomain := getAppsyncCertDomain(t) + rName := sdkacctest.RandString(8) resourceName := "aws_appsync_domain_name.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, - ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckDomainNameApiAssociationDestroy, + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckDomainNameApiAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAppsyncDomainNameApiAssociationConfig(rootDomain, domain, rName), + Config: testAccAppsyncDomainNameApiAssociationConfig(appsyncCertDomain, rName), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameApiAssociationExists(resourceName, &association), resource.TestCheckResourceAttrPair(resourceName, "domain_name", "aws_appsync_domain_name.test", "domain_name"), @@ -43,7 +44,7 @@ func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAppsyncDomainNameApiAssociationUpdatedConfig(rootDomain, domain, rName), + Config: testAccAppsyncDomainNameApiAssociationUpdatedConfig(appsyncCertDomain, rName), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameApiAssociationExists(resourceName, &association), resource.TestCheckResourceAttr(resourceName, "description", ""), @@ -57,20 +58,20 @@ func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { func testAccAppSyncDomainNameApiAssociation_disappears(t *testing.T) { var association appsync.ApiAssociation - rootDomain := acctest.ACMCertificateDomainFromEnv(t) - domain := acctest.ACMCertificateRandomSubDomain(rootDomain) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var providers []*schema.Provider + appsyncCertDomain := getAppsyncCertDomain(t) + rName := sdkacctest.RandString(8) resourceName := "aws_appsync_domain_name.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, - ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), - Providers: acctest.Providers, - CheckDestroy: testAccCheckDomainNameApiAssociationDestroy, + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appsync.EndpointsID), + ProviderFactories: acctest.FactoriesAlternate(&providers), + CheckDestroy: testAccCheckDomainNameApiAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAppsyncDomainNameApiAssociationConfig(rootDomain, domain, rName), + Config: testAccAppsyncDomainNameApiAssociationConfig(appsyncCertDomain, rName), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameApiAssociationExists(resourceName, &association), acctest.CheckResourceDisappears(acctest.Provider, tfappsync.ResourceDomainNameApiAssociation(), resourceName), @@ -130,66 +131,43 @@ func testAccCheckDomainNameApiAssociationExists(resourceName string, DomainNameA } } -func testAccAppsyncDomainNameApiAssociationBaseConfig(rootDomain, domain string) string { - return fmt.Sprintf(` -data "aws_route53_zone" "test" { - name = %[1]q - private_zone = false -} - -resource "aws_acm_certificate" "test" { - domain_name = %[2]q - validation_method = "DNS" -} - -resource "aws_route53_record" "test" { - allow_overwrite = true - name = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_name - records = [tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_value] - ttl = 60 - type = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_type - zone_id = data.aws_route53_zone.test.zone_id -} - -resource "aws_acm_certificate_validation" "test" { - certificate_arn = aws_acm_certificate.test.arn - validation_record_fqdns = [aws_route53_record.test.fqdn] +func testAccAppsyncDomainNameApiAssociationBaseConfig(domain, rName string) string { + return acctest.ConfigAlternateRegionProvider() + fmt.Sprintf(` +data "aws_acm_certificate" "test" { + provider = "awsalternate" + domain = "*.%[1]s" + most_recent = true } resource "aws_appsync_domain_name" "test" { - domain_name = aws_acm_certificate.test.domain_name - certificate_arn = aws_acm_certificate_validation.test.certificate_arn -} -`, rootDomain, domain) + domain_name = "%[2]s.%[1]s" + certificate_arn = data.aws_acm_certificate.test.arn } -func testAccAppsyncDomainNameApiAssociationConfig(rootDomain, domain, rName string) string { - return testAccAppsyncDomainNameApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` resource "aws_appsync_graphql_api" "test" { authentication_type = "API_KEY" - name = %[1]q + name = %[2]q +} +`, domain, rName) } -resource "aws_appsync_api_association" "test" { +func testAccAppsyncDomainNameApiAssociationConfig(domain, rName string) string { + return testAccAppsyncDomainNameApiAssociationBaseConfig(domain, rName) + ` +resource "aws_appsync_domain_name_api_association" "test" { api_id = aws_appsync_graphql_api.test.id domain_name = aws_appsync_domain_name.test.domain_name } -`, rName) -} - -func testAccAppsyncDomainNameApiAssociationUpdatedConfig(rootDomain, domain, rName string) string { - return testAccAppsyncDomainNameApiAssociationBaseConfig(rootDomain, domain) + fmt.Sprintf(` -resource "aws_appsync_graphql_api" "test" { - authentication_type = "API_KEY" - name = %[1]q +` } +func testAccAppsyncDomainNameApiAssociationUpdatedConfig(domain, rName string) string { + return testAccAppsyncDomainNameApiAssociationBaseConfig(domain, rName) + fmt.Sprintf(` resource "aws_appsync_graphql_api" "test2" { authentication_type = "API_KEY" name = "%[1]s-2" } -resource "aws_appsync_api_association" "test" { +resource "aws_appsync_domain_name_api_association" "test" { api_id = aws_appsync_graphql_api.test2.id domain_name = aws_appsync_domain_name.test.domain_name } diff --git a/internal/service/appsync/status.go b/internal/service/appsync/status.go index f539fcf56db..be0633493c2 100644 --- a/internal/service/appsync/status.go +++ b/internal/service/appsync/status.go @@ -22,3 +22,19 @@ func StatusApiCache(conn *appsync.AppSync, name string) resource.StateRefreshFun return output, aws.StringValue(output.Status), nil } } + +func statusDomainNameApiAssociation(conn *appsync.AppSync, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindDomainNameApiAssociationByID(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.AssociationStatus), nil + } +} diff --git a/internal/service/appsync/wait.go b/internal/service/appsync/wait.go index ebc30da495f..4046655042c 100644 --- a/internal/service/appsync/wait.go +++ b/internal/service/appsync/wait.go @@ -8,8 +8,10 @@ import ( ) const ( - ApiCacheAvailableTimeout = 60 * time.Minute - ApiCacheDeletedTimeout = 60 * time.Minute + apiCacheAvailableTimeout = 60 * time.Minute + apiCacheDeletedTimeout = 60 * time.Minute + domainNameApiAssociationTimeout = 60 * time.Minute + domainNameApiDisassociationTimeout = 60 * time.Minute ) func waitApiCacheAvailable(conn *appsync.AppSync, id string) error { @@ -17,7 +19,7 @@ func waitApiCacheAvailable(conn *appsync.AppSync, id string) error { Pending: []string{appsync.ApiCacheStatusCreating, appsync.ApiCacheStatusModifying}, Target: []string{appsync.ApiCacheStatusAvailable}, Refresh: StatusApiCache(conn, id), - Timeout: ApiCacheAvailableTimeout, + Timeout: apiCacheAvailableTimeout, } _, err := stateConf.WaitForState() @@ -30,7 +32,33 @@ func waitApiCacheDeleted(conn *appsync.AppSync, id string) error { Pending: []string{appsync.ApiCacheStatusDeleting}, Target: []string{}, Refresh: StatusApiCache(conn, id), - Timeout: ApiCacheDeletedTimeout, + Timeout: apiCacheDeletedTimeout, + } + + _, err := stateConf.WaitForState() + + return err +} + +func waitDomainNameApiAssociation(conn *appsync.AppSync, id string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{appsync.AssociationStatusProcessing}, + Target: []string{appsync.AssociationStatusSuccess}, + Refresh: statusDomainNameApiAssociation(conn, id), + Timeout: domainNameApiAssociationTimeout, + } + + _, err := stateConf.WaitForState() + + return err +} + +func waitDomainNameApiDisassociation(conn *appsync.AppSync, id string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{appsync.AssociationStatusProcessing}, + Target: []string{}, + Refresh: statusDomainNameApiAssociation(conn, id), + Timeout: domainNameApiDisassociationTimeout, } _, err := stateConf.WaitForState() From ebb425057071b10982e5368baf00a3e4241c722b Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 14 Jan 2022 21:51:30 +0200 Subject: [PATCH 11/13] sweeper --- .../domain_name_api_association_test.go | 4 +- internal/service/appsync/sweep.go | 63 +++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/internal/service/appsync/domain_name_api_association_test.go b/internal/service/appsync/domain_name_api_association_test.go index 2dba47165a1..aa5f806c335 100644 --- a/internal/service/appsync/domain_name_api_association_test.go +++ b/internal/service/appsync/domain_name_api_association_test.go @@ -22,7 +22,7 @@ func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { appsyncCertDomain := getAppsyncCertDomain(t) rName := sdkacctest.RandString(8) - resourceName := "aws_appsync_domain_name.test" + resourceName := "aws_appsync_domain_name_api_association.test" resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, @@ -62,7 +62,7 @@ func testAccAppSyncDomainNameApiAssociation_disappears(t *testing.T) { appsyncCertDomain := getAppsyncCertDomain(t) rName := sdkacctest.RandString(8) - resourceName := "aws_appsync_domain_name.test" + resourceName := "aws_appsync_domain_name_api_association.test" resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appsync.EndpointsID, t) }, diff --git a/internal/service/appsync/sweep.go b/internal/service/appsync/sweep.go index be0ed5ae6d7..8a1bb342bd6 100644 --- a/internal/service/appsync/sweep.go +++ b/internal/service/appsync/sweep.go @@ -24,6 +24,14 @@ func init() { resource.AddTestSweepers("aws_appsync_domain_name", &resource.Sweeper{ Name: "aws_appsync_domain_name", F: sweepDomainNames, + Dependencies: []string{ + "aws_appsync_domain_name_api_association", + }, + }) + + resource.AddTestSweepers("aws_appsync_domain_name_api_association", &resource.Sweeper{ + Name: "aws_appsync_domain_name_api_association", + F: sweepDomainNameAssociations, }) } @@ -136,3 +144,58 @@ func sweepDomainNames(region string) error { return errs.ErrorOrNil() } + +func sweepDomainNameAssociations(region string) error { + client, err := sweep.SharedRegionalSweepClient(region) + if err != nil { + return fmt.Errorf("Error getting client: %s", err) + } + conn := client.(*conns.AWSClient).AppSyncConn + sweepResources := make([]*sweep.SweepResource, 0) + var errs *multierror.Error + + input := &appsync.ListDomainNamesInput{} + + for { + output, err := conn.ListDomainNames(input) + if sweep.SkipSweepError(err) { + log.Printf("[WARN] Skipping AppSync Domain Name Association sweep for %s: %s", region, err) + return nil + } + + if err != nil { + err := fmt.Errorf("error reading AppSync Domain Name Association: %w", err) + log.Printf("[ERROR] %s", err) + errs = multierror.Append(errs, err) + break + } + + for _, dm := range output.DomainNameConfigs { + + r := ResourceDomainNameApiAssociation() + d := r.Data(nil) + + id := aws.StringValue(dm.DomainName) + d.SetId(id) + + sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + if err := sweep.SweepOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping AppSync Domain Name Association %s: %w", region, err)) + } + + if sweep.SkipSweepError(err) { + log.Printf("[WARN] Skipping AppSync Domain Name Association sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} From 4c474bea7ec1b279f2c46433351f1ac65d8a1a42 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 15 Jan 2022 00:22:50 +0200 Subject: [PATCH 12/13] waiter --- .../service/appsync/domain_name_api_association.go | 12 ++++++------ .../appsync/domain_name_api_association_test.go | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/service/appsync/domain_name_api_association.go b/internal/service/appsync/domain_name_api_association.go index a8e378ca060..f70d7a22e9a 100644 --- a/internal/service/appsync/domain_name_api_association.go +++ b/internal/service/appsync/domain_name_api_association.go @@ -51,8 +51,8 @@ func resourceDomainNameApiAssociationCreate(d *schema.ResourceData, meta interfa d.SetId(aws.StringValue(resp.ApiAssociation.DomainName)) - if _, err := waitDomainNameApiAssociation(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Association: %w", d.Id(), err) + if err := waitDomainNameApiAssociation(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Association: %w", d.Id(), err) } return resourceDomainNameApiAssociationRead(d, meta) @@ -91,8 +91,8 @@ func resourceDomainNameApiAssociationUpdate(d *schema.ResourceData, meta interfa return fmt.Errorf("error creating Appsync Domain Name API Association: %w", err) } - if _, err := waitDomainNameApiAssociation(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Association: %w", d.Id(), err) + if err := waitDomainNameApiAssociation(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Association: %w", d.Id(), err) } return resourceDomainNameApiAssociationRead(d, meta) @@ -112,8 +112,8 @@ func resourceDomainNameApiAssociationDelete(d *schema.ResourceData, meta interfa return fmt.Errorf("error deleting Appsync Domain Name API Association: %w", err) } - if _, err := waitDomainNameApiDisassociation(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Disassociation: %w", d.Id(), err) + if err := waitDomainNameApiDisassociation(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Appsync Domain Name API (%s) Disassociation: %w", d.Id(), err) } return nil diff --git a/internal/service/appsync/domain_name_api_association_test.go b/internal/service/appsync/domain_name_api_association_test.go index aa5f806c335..b60048772ad 100644 --- a/internal/service/appsync/domain_name_api_association_test.go +++ b/internal/service/appsync/domain_name_api_association_test.go @@ -47,7 +47,6 @@ func testAccAppSyncDomainNameApiAssociation_basic(t *testing.T) { Config: testAccAppsyncDomainNameApiAssociationUpdatedConfig(appsyncCertDomain, rName), Check: resource.ComposeTestCheckFunc( testAccCheckDomainNameApiAssociationExists(resourceName, &association), - resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttrPair(resourceName, "domain_name", "aws_appsync_domain_name.test", "domain_name"), resource.TestCheckResourceAttrPair(resourceName, "api_id", "aws_appsync_graphql_api.test2", "id"), ), From 4cbc7cc74f8def76fd4e1d1b4aaabb452ab9ce45 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 18 Jan 2022 18:18:59 +0200 Subject: [PATCH 13/13] changelog --- .changelog/22487.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/22487.txt diff --git a/.changelog/22487.txt b/.changelog/22487.txt new file mode 100644 index 00000000000..c0e7fbdf287 --- /dev/null +++ b/.changelog/22487.txt @@ -0,0 +1,7 @@ +```release-note:new-resource +aws_appsync_domain_name +``` + +```release-note:new-resource +aws_appsync_domain_name_api_association +```