From fb151fe8c58adea3399055e5c17833102b0b9633 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 6 Aug 2020 16:41:15 -0400 Subject: [PATCH] service/route53: Finalize cross-account VPC association handling Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/10333 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13527 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13826 Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/14215 Changes: * Add disappears testing to aws_route53_vpc_association_authorization. * Ensure aws_route53_vpc_association_authorization example shows implicit ordering for downstream aws_route53_zone_association usage * Fix aws_route53_zone_association VPC Region handling by including it in the ID, falling back to the attribute state, or falling back to the provider region. Document additional import handling. * Add aws_route53_zone_association error handling to remove resource from state. * Standardize aws_route53_zone_association disappears testing. Output from acceptance testing: ``` --- PASS: TestAccAWSRoute53VpcAssociationAuthorization_disappears (110.26s) --- PASS: TestAccAWSRoute53VpcAssociationAuthorization_basic (113.19s) --- PASS: TestAccAWSRoute53ZoneAssociation_CrossAccount (211.48s) --- PASS: TestAccAWSRoute53ZoneAssociation_CrossRegion (275.34s) --- PASS: TestAccAWSRoute53ZoneAssociation_disappears_Zone (280.22s) --- PASS: TestAccAWSRoute53ZoneAssociation_disappears (281.72s) --- PASS: TestAccAWSRoute53ZoneAssociation_disappears_VPC (281.85s) --- PASS: TestAccAWSRoute53ZoneAssociation_basic (283.83s) ``` --- ...te53_vpc_association_authorization_test.go | 28 ++- aws/resource_aws_route53_zone_association.go | 109 ++++++++---- ...ource_aws_route53_zone_association_test.go | 163 +++++++++++------- ...pc_association_authorization.html.markdown | 13 +- .../r/route53_zone_association.html.markdown | 11 +- 5 files changed, 215 insertions(+), 109 deletions(-) diff --git a/aws/resource_aws_route53_vpc_association_authorization_test.go b/aws/resource_aws_route53_vpc_association_authorization_test.go index 9b0ce6e3c48..ff74560d572 100644 --- a/aws/resource_aws_route53_vpc_association_authorization_test.go +++ b/aws/resource_aws_route53_vpc_association_authorization_test.go @@ -40,6 +40,30 @@ func TestAccAWSRoute53VpcAssociationAuthorization_basic(t *testing.T) { }) } +func TestAccAWSRoute53VpcAssociationAuthorization_disappears(t *testing.T) { + var providers []*schema.Provider + resourceName := "aws_route53_vpc_association_authorization.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckRoute53VPCAssociationAuthorizationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53VPCAssociationAuthorizationConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53VPCAssociationAuthorizationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53VPCAssociationAuthorization(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckRoute53VPCAssociationAuthorizationDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).r53conn @@ -48,7 +72,7 @@ func testAccCheckRoute53VPCAssociationAuthorizationDestroy(s *terraform.State) e continue } - zone_id, vpc_id, err := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) + zone_id, vpc_id, err := resourceAwsRoute53VPCAssociationAuthorizationParseId(rs.Primary.ID) if err != nil { return err } @@ -85,7 +109,7 @@ func testAccCheckRoute53VPCAssociationAuthorizationExists(n string) resource.Tes return fmt.Errorf("No VPC association authorization ID is set") } - zone_id, vpc_id, err := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) + zone_id, vpc_id, err := resourceAwsRoute53VPCAssociationAuthorizationParseId(rs.Primary.ID) if err != nil { return err } diff --git a/aws/resource_aws_route53_zone_association.go b/aws/resource_aws_route53_zone_association.go index 6fac23346a1..bde22bfaa58 100644 --- a/aws/resource_aws_route53_zone_association.go +++ b/aws/resource_aws_route53_zone_association.go @@ -51,42 +51,46 @@ func resourceAwsRoute53ZoneAssociation() *schema.Resource { } func resourceAwsRoute53ZoneAssociationCreate(d *schema.ResourceData, meta interface{}) error { - r53 := meta.(*AWSClient).r53conn + conn := meta.(*AWSClient).r53conn + + vpcRegion := meta.(*AWSClient).region + vpcID := d.Get("vpc_id").(string) + zoneID := d.Get("zone_id").(string) + + if v, ok := d.GetOk("vpc_region"); ok { + vpcRegion = v.(string) + } - req := &route53.AssociateVPCWithHostedZoneInput{ - HostedZoneId: aws.String(d.Get("zone_id").(string)), + input := &route53.AssociateVPCWithHostedZoneInput{ + HostedZoneId: aws.String(zoneID), VPC: &route53.VPC{ - VPCId: aws.String(d.Get("vpc_id").(string)), - VPCRegion: aws.String(meta.(*AWSClient).region), + VPCId: aws.String(vpcID), + VPCRegion: aws.String(vpcRegion), }, Comment: aws.String("Managed by Terraform"), } - if w := d.Get("vpc_region"); w != "" { - req.VPC.VPCRegion = aws.String(w.(string)) - } - log.Printf("[DEBUG] Associating Route53 Private Zone %s with VPC %s with region %s", *req.HostedZoneId, *req.VPC.VPCId, *req.VPC.VPCRegion) + output, err := conn.AssociateVPCWithHostedZone(input) - resp, err := r53.AssociateVPCWithHostedZone(req) if err != nil { - return err + return fmt.Errorf("error associating Route 53 Hosted Zone (%s) to EC2 VPC (%s): %w", zoneID, vpcID, err) } - // Store association id - d.SetId(fmt.Sprintf("%s:%s", *req.HostedZoneId, *req.VPC.VPCId)) + d.SetId(fmt.Sprintf("%s:%s:%s", zoneID, vpcID, vpcRegion)) - // Wait until we are done initializing - wait := resource.StateChangeConf{ - Delay: 30 * time.Second, - Pending: []string{route53.ChangeStatusPending}, - Target: []string{route53.ChangeStatusInsync}, - Timeout: 10 * time.Minute, - MinTimeout: 2 * time.Second, - Refresh: resourceAwsRoute53ZoneAssociationRefreshFunc(r53, cleanChangeID(*resp.ChangeInfo.Id), d.Id()), - } - _, err = wait.WaitForState() - if err != nil { - return err + if output != nil && output.ChangeInfo != nil && output.ChangeInfo.Id != nil { + wait := resource.StateChangeConf{ + Delay: 30 * time.Second, + Pending: []string{route53.ChangeStatusPending}, + Target: []string{route53.ChangeStatusInsync}, + Timeout: 10 * time.Minute, + MinTimeout: 2 * time.Second, + Refresh: resourceAwsRoute53ZoneAssociationRefreshFunc(conn, cleanChangeID(aws.StringValue(output.ChangeInfo.Id)), d.Id()), + } + + if _, err := wait.WaitForState(); err != nil { + return fmt.Errorf("error waiting for Route 53 Zone Association (%s) synchronization: %w", d.Id(), err) + } } return resourceAwsRoute53ZoneAssociationRead(d, meta) @@ -95,20 +99,38 @@ func resourceAwsRoute53ZoneAssociationCreate(d *schema.ResourceData, meta interf func resourceAwsRoute53ZoneAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).r53conn - zoneID, vpcID, err := resourceAwsRoute53ZoneAssociationParseId(d.Id()) - vpcRegion := meta.(*AWSClient).region + zoneID, vpcID, vpcRegion, err := resourceAwsRoute53ZoneAssociationParseId(d.Id()) if err != nil { return err } + // Continue supporting older resources without VPC Region in ID + if vpcRegion == "" { + vpcRegion = d.Get("vpc_region").(string) + } + + if vpcRegion == "" { + vpcRegion = meta.(*AWSClient).region + } + hostedZoneSummary, err := route53GetZoneAssociation(conn, zoneID, vpcID, vpcRegion) + if isAWSErr(err, "AccessDenied", "is not owned by you") && !d.IsNewResource() { + log.Printf("[WARN] Route 53 Zone Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { - return fmt.Errorf("error getting Route 53 Hosted Zone (%s): %s", zoneID, err) + return fmt.Errorf("error getting Route 53 Zone Association (%s): %w", d.Id(), err) } if hostedZoneSummary == nil { + if d.IsNewResource() { + return fmt.Errorf("error getting Route 53 Zone Association (%s): missing after creation", d.Id()) + } + log.Printf("[WARN] Route 53 Hosted Zone (%s) Association (%s) not found, removing from state", zoneID, vpcID) d.SetId("") return nil @@ -125,38 +147,51 @@ func resourceAwsRoute53ZoneAssociationRead(d *schema.ResourceData, meta interfac func resourceAwsRoute53ZoneAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).r53conn - zoneID, vpcID, err := resourceAwsRoute53ZoneAssociationParseId(d.Id()) + zoneID, vpcID, vpcRegion, err := resourceAwsRoute53ZoneAssociationParseId(d.Id()) if err != nil { return err } - log.Printf("[DEBUG] Disassociating Route 53 Hosted Zone (%s) Association: %s", zoneID, vpcID) + // Continue supporting older resources without VPC Region in ID + if vpcRegion == "" { + vpcRegion = d.Get("vpc_region").(string) + } + + if vpcRegion == "" { + vpcRegion = meta.(*AWSClient).region + } - req := &route53.DisassociateVPCFromHostedZoneInput{ + input := &route53.DisassociateVPCFromHostedZoneInput{ HostedZoneId: aws.String(zoneID), VPC: &route53.VPC{ VPCId: aws.String(vpcID), - VPCRegion: aws.String(d.Get("vpc_region").(string)), + VPCRegion: aws.String(vpcRegion), }, Comment: aws.String("Managed by Terraform"), } - _, err = conn.DisassociateVPCFromHostedZone(req) + _, err = conn.DisassociateVPCFromHostedZone(input) if err != nil { - return fmt.Errorf("error disassociating Route 53 Hosted Zone (%s) Association (%s): %s", zoneID, vpcID, err) + return fmt.Errorf("error disassociating Route 53 Hosted Zone (%s) from EC2 VPC (%s): %w", zoneID, vpcID, err) } return nil } -func resourceAwsRoute53ZoneAssociationParseId(id string) (string, string, error) { +func resourceAwsRoute53ZoneAssociationParseId(id string) (string, string, string, error) { parts := strings.Split(id, ":") + + if len(parts) == 3 && parts[0] != "" && parts[1] != "" && parts[2] != "" { + return parts[0], parts[1], parts[2], nil + } + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", "", fmt.Errorf("Unexpected format of ID (%q), expected ZONEID:VPCID", id) + return "", "", "", fmt.Errorf("Unexpected format of ID (%q), expected ZONEID:VPCID or ZONEID:VPCID:VPCREGION", id) } - return parts[0], parts[1], nil + + return parts[0], parts[1], "", nil } func resourceAwsRoute53ZoneAssociationRefreshFunc(conn *route53.Route53, changeId, id string) resource.StateRefreshFunc { diff --git a/aws/resource_aws_route53_zone_association_test.go b/aws/resource_aws_route53_zone_association_test.go index eff4b0c4405..554047099de 100644 --- a/aws/resource_aws_route53_zone_association_test.go +++ b/aws/resource_aws_route53_zone_association_test.go @@ -9,12 +9,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/route53" ) func TestAccAWSRoute53ZoneAssociation_basic(t *testing.T) { - var vpc route53.VPC resourceName := "aws_route53_zone_association.foobar" resource.ParallelTest(t, resource.TestCase{ @@ -25,7 +23,7 @@ func TestAccAWSRoute53ZoneAssociation_basic(t *testing.T) { { Config: testAccRoute53ZoneAssociationConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53ZoneAssociationExists(resourceName, &vpc), + testAccCheckRoute53ZoneAssociationExists(resourceName), ), }, { @@ -38,10 +36,7 @@ func TestAccAWSRoute53ZoneAssociation_basic(t *testing.T) { } func TestAccAWSRoute53ZoneAssociation_disappears(t *testing.T) { - var vpc route53.VPC - var zone route53.GetHostedZoneOutput resourceName := "aws_route53_zone_association.foobar" - route53ZoneResourceName := "aws_route53_zone.foo" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -51,9 +46,8 @@ func TestAccAWSRoute53ZoneAssociation_disappears(t *testing.T) { { Config: testAccRoute53ZoneAssociationConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53ZoneExists(route53ZoneResourceName, &zone), - testAccCheckRoute53ZoneAssociationExists(resourceName, &vpc), - testAccCheckRoute53ZoneAssociationDisappears(&zone, &vpc), + testAccCheckRoute53ZoneAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53ZoneAssociation(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -62,8 +56,6 @@ func TestAccAWSRoute53ZoneAssociation_disappears(t *testing.T) { } func TestAccAWSRoute53ZoneAssociation_disappears_VPC(t *testing.T) { - var ec2Vpc ec2.Vpc - var route53Vpc route53.VPC resourceName := "aws_route53_zone_association.foobar" vpcResourceName := "aws_vpc.bar" @@ -75,9 +67,8 @@ func TestAccAWSRoute53ZoneAssociation_disappears_VPC(t *testing.T) { { Config: testAccRoute53ZoneAssociationConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53ZoneAssociationExists(resourceName, &route53Vpc), - testAccCheckVpcExists(vpcResourceName, &ec2Vpc), - testAccCheckVpcDisappears(&ec2Vpc), + testAccCheckRoute53ZoneAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsVpc(), vpcResourceName), ), ExpectNonEmptyPlan: true, }, @@ -86,8 +77,6 @@ func TestAccAWSRoute53ZoneAssociation_disappears_VPC(t *testing.T) { } func TestAccAWSRoute53ZoneAssociation_disappears_Zone(t *testing.T) { - var vpc route53.VPC - var zone route53.GetHostedZoneOutput resourceName := "aws_route53_zone_association.foobar" route53ZoneResourceName := "aws_route53_zone.foo" @@ -99,9 +88,8 @@ func TestAccAWSRoute53ZoneAssociation_disappears_Zone(t *testing.T) { { Config: testAccRoute53ZoneAssociationConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53ZoneExists(route53ZoneResourceName, &zone), - testAccCheckRoute53ZoneAssociationExists(resourceName, &vpc), - testAccCheckRoute53ZoneDisappears(&zone), + testAccCheckRoute53ZoneAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53Zone(), route53ZoneResourceName), ), ExpectNonEmptyPlan: true, }, @@ -109,8 +97,7 @@ func TestAccAWSRoute53ZoneAssociation_disappears_Zone(t *testing.T) { }) } -func TestAccAWSRoute53ZoneAssociation_region(t *testing.T) { - var vpc route53.VPC +func TestAccAWSRoute53ZoneAssociation_CrossAccount(t *testing.T) { resourceName := "aws_route53_zone_association.test" // record the initialized providers so that we can use them to @@ -120,8 +107,38 @@ func TestAccAWSRoute53ZoneAssociation_region(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccMultipleRegionsPreCheck(t) - testAccAlternateRegionPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ZoneAssociationCrossAccountConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ZoneAssociationExists(resourceName), + ), + }, + { + Config: testAccRoute53ZoneAssociationCrossAccountConfig(), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSRoute53ZoneAssociation_CrossRegion(t *testing.T) { + resourceName := "aws_route53_zone_association.test" + + // record the initialized providers so that we can use them to + // check for the instances in each region + var providers []*schema.Provider + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionPreCheck(t, 2) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, @@ -129,7 +146,7 @@ func TestAccAWSRoute53ZoneAssociation_region(t *testing.T) { { Config: testAccRoute53ZoneAssociationRegionConfig(), Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53ZoneAssociationExists(resourceName, &vpc), + testAccCheckRoute53ZoneAssociationExists(resourceName), ), }, { @@ -149,15 +166,15 @@ func testAccCheckRoute53ZoneAssociationDestroy(s *terraform.State) error { continue } - zoneID, vpcID, err := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) + zoneID, vpcID, vpcRegion, err := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) if err != nil { return err } - vpc, err := testAccCheckRoute53ZoneAssociationGet(conn, zoneID, vpcID) + hostedZoneSummary, err := route53GetZoneAssociation(conn, zoneID, vpcID, vpcRegion) - if isAWSErr(err, route53.ErrCodeNoSuchHostedZone, "") { + if isAWSErr(err, "AccessDenied", "is not owned by you") { continue } @@ -165,25 +182,25 @@ func testAccCheckRoute53ZoneAssociationDestroy(s *terraform.State) error { return err } - if vpc != nil { - return fmt.Errorf("Route 53 Hosted Zone (%s) Association (%s) still exists", zoneID, vpcID) + if hostedZoneSummary != nil { + return fmt.Errorf("Route 53 Zone Association (%s) still exists", rs.Primary.ID) } } return nil } -func testAccCheckRoute53ZoneAssociationExists(n string, vpc *route53.VPC) resource.TestCheckFunc { +func testAccCheckRoute53ZoneAssociationExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] + rs, ok := s.RootModule().Resources[resourceName] if !ok { - return fmt.Errorf("Not found: %s", n) + return fmt.Errorf("Not found: %s", resourceName) } if rs.Primary.ID == "" { return fmt.Errorf("No zone association ID is set") } - zoneID, vpcID, err := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) + zoneID, vpcID, vpcRegion, err := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) if err != nil { return err @@ -191,18 +208,16 @@ func testAccCheckRoute53ZoneAssociationExists(n string, vpc *route53.VPC) resour conn := testAccProvider.Meta().(*AWSClient).r53conn - associationVPC, err := testAccCheckRoute53ZoneAssociationGet(conn, zoneID, vpcID) + hostedZoneSummary, err := route53GetZoneAssociation(conn, zoneID, vpcID, vpcRegion) if err != nil { return err } - if associationVPC == nil { + if hostedZoneSummary == nil { return fmt.Errorf("Route 53 Hosted Zone (%s) Association (%s) not found", zoneID, vpcID) } - *vpc = *associationVPC - return nil } } @@ -223,28 +238,6 @@ func testAccCheckRoute53ZoneAssociationDisappears(zone *route53.GetHostedZoneOut } } -func testAccCheckRoute53ZoneAssociationGet(conn *route53.Route53, zoneID, vpcID string) (*route53.VPC, error) { - input := &route53.GetHostedZoneInput{ - Id: aws.String(zoneID), - } - - output, err := conn.GetHostedZone(input) - - if err != nil { - return nil, err - } - - var vpc *route53.VPC - for _, zoneVPC := range output.VPCs { - if vpcID == aws.StringValue(zoneVPC.VPCId) { - vpc = zoneVPC - break - } - } - - return vpc, nil -} - const testAccRoute53ZoneAssociationConfig = ` resource "aws_vpc" "foo" { cidr_block = "10.6.0.0/16" @@ -280,8 +273,56 @@ resource "aws_route53_zone_association" "foobar" { } ` +func testAccRoute53ZoneAssociationCrossAccountConfig() string { + return composeConfig( + testAccAlternateAccountProviderConfig(), + ` +resource "aws_vpc" "alternate" { + provider = "awsalternate" + + cidr_block = "10.7.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true +} + +resource "aws_vpc" "test" { + cidr_block = "10.6.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true +} + +resource "aws_route53_zone" "test" { + provider = "awsalternate" + + name = "foo.com" + + vpc { + vpc_id = aws_vpc.alternate.id + } + + lifecycle { + ignore_changes = [vpc] + } +} + +resource "aws_route53_vpc_association_authorization" "test" { + provider = "awsalternate" + + vpc_id = aws_vpc.test.id + zone_id = aws_route53_zone.test.id +} + +resource "aws_route53_zone_association" "test" { + vpc_id = aws_route53_vpc_association_authorization.test.vpc_id + zone_id = aws_route53_vpc_association_authorization.test.zone_id +} +`) +} + func testAccRoute53ZoneAssociationRegionConfig() string { - return testAccAlternateRegionProviderConfig() + ` + return composeConfig( + testAccMultipleRegionProviderConfig(2), + ` data "aws_region" "alternate" { provider = "awsalternate" } @@ -328,5 +369,5 @@ resource "aws_route53_zone_association" "test" { vpc_region = data.aws_region.alternate.name zone_id = aws_route53_zone.test.id } -` +`) } diff --git a/website/docs/r/route53_vpc_association_authorization.html.markdown b/website/docs/r/route53_vpc_association_authorization.html.markdown index cf88ccf5437..85dcdcbba03 100644 --- a/website/docs/r/route53_vpc_association_authorization.html.markdown +++ b/website/docs/r/route53_vpc_association_authorization.html.markdown @@ -28,27 +28,30 @@ resource "aws_vpc" "example" { resource "aws_route53_zone" "example" { name = "example.com" + vpc { vpc_id = aws_vpc.example.id } } resource "aws_vpc" "alternate" { - provider = "aws.alternate" + provider = "aws.alternate" + cidr_block = "10.7.0.0/16" enable_dns_hostnames = true enable_dns_support = true } resource "aws_route53_vpc_association_authorization" "example" { - zone_id = aws_route53_zone.example.id vpc_id = aws_vpc.alternate.id + zone_id = aws_route53_zone.example.id } -resource "aws_route53_zone_association" "alternate" { +resource "aws_route53_zone_association" "example" { provider = "aws.alternate" - zone_id = aws_route53_zone.example.zone_id - vpc_id = aws_vpc.alternate.id + + vpc_id = aws_route53_vpc_association_authorization.example.vpc_id + zone_id = aws_route53_vpc_association_authorization.example.zone_id } ``` diff --git a/website/docs/r/route53_zone_association.html.markdown b/website/docs/r/route53_zone_association.html.markdown index aeffc4234a8..dde709ee8e6 100644 --- a/website/docs/r/route53_zone_association.html.markdown +++ b/website/docs/r/route53_zone_association.html.markdown @@ -8,7 +8,7 @@ description: |- # Resource: aws_route53_zone_association -Manages a Route53 Hosted Zone VPC association. VPC associations can only be made on private zones. +Manages a Route53 Hosted Zone VPC association. VPC associations can only be made on private zones. See the [`aws_route53_vpc_association_authorization` resource](route53_vpc_association_authorization.html) for setting up cross-account associations. ~> **NOTE:** Unless explicit association ordering is required (e.g. a separate cross-account association authorization), usage of this resource is not recommended. Use the `vpc` configuration blocks available within the [`aws_route53_zone` resource](/docs/providers/aws/r/route53_zone.html) instead. @@ -65,9 +65,6 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The calculated unique identifier for the association. -* `zone_id` - The ID of the hosted zone for the association. -* `vpc_id` - The ID of the VPC for the association. -* `vpc_region` - The region in which the VPC identified by `vpc_id` was created. * `owning_account` - The account ID of the account that created the hosted zone. ## Import @@ -77,3 +74,9 @@ Route 53 Hosted Zone Associations can be imported via the Hosted Zone ID and VPC ``` $ terraform import aws_route53_zone_association.example Z123456ABCDEFG:vpc-12345678 ``` + +If the VPC is in a different region than the Terraform AWS Provider region configuration, the VPC Region can be added to the end. e.g. + +``` +$ terraform import aws_route53_zone_association.example Z123456ABCDEFG:vpc-12345678:us-east-2 +```