From 766aead4a540d4236058ce0058266d8db39886ac Mon Sep 17 00:00:00 2001 From: John Engelman Date: Fri, 8 May 2015 14:47:42 -0500 Subject: [PATCH] Add tests for cross region VPC associations. --- .../aws/resource_aws_route53_zone.go | 2 + .../resource_aws_route53_zone_association.go | 3 +- ...ource_aws_route53_zone_association_test.go | 175 +++++++++++++++--- .../aws/resource_aws_route53_zone_test.go | 150 ++++++++++++--- 4 files changed, 272 insertions(+), 58 deletions(-) diff --git a/builtin/providers/aws/resource_aws_route53_zone.go b/builtin/providers/aws/resource_aws_route53_zone.go index f9ad99f4c..fd74ed167 100644 --- a/builtin/providers/aws/resource_aws_route53_zone.go +++ b/builtin/providers/aws/resource_aws_route53_zone.go @@ -38,6 +38,7 @@ func resourceAwsRoute53Zone() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, }, "zone_id": &schema.Schema{ @@ -85,6 +86,7 @@ func resourceAwsRoute53ZoneCreate(d *schema.ResourceData, meta interface{}) erro zone := cleanZoneID(*resp.HostedZone.ID) d.Set("zone_id", zone) d.SetId(zone) + d.Set("vpc_region", req.VPC.VPCRegion) // Wait until we are done initializing wait := resource.StateChangeConf{ diff --git a/builtin/providers/aws/resource_aws_route53_zone_association.go b/builtin/providers/aws/resource_aws_route53_zone_association.go index 9b174985c..6d53d937f 100644 --- a/builtin/providers/aws/resource_aws_route53_zone_association.go +++ b/builtin/providers/aws/resource_aws_route53_zone_association.go @@ -34,6 +34,7 @@ func resourceAwsRoute53ZoneAssociation() *schema.Resource { "vpc_region": &schema.Schema{ Type: schema.TypeString, Optional: true, + Computed: true, }, }, @@ -55,7 +56,7 @@ func resourceAwsRoute53ZoneAssociationCreate(d *schema.ResourceData, meta interf req.VPC.VPCRegion = aws.String(w.(string)) } - log.Printf("[DEBUG] Associating Route53 Private Zone %s with VPC %s", *req.HostedZoneID, *req.VPC.VPCID) + log.Printf("[DEBUG] Associating Route53 Private Zone %s with VPC %s with region %s", *req.HostedZoneID, *req.VPC.VPCID, *req.VPC.VPCRegion) resp, err := r53.AssociateVPCWithHostedZone(req) if err != nil { return err diff --git a/builtin/providers/aws/resource_aws_route53_zone_association_test.go b/builtin/providers/aws/resource_aws_route53_zone_association_test.go index 4addc5357..d8389e35d 100644 --- a/builtin/providers/aws/resource_aws_route53_zone_association_test.go +++ b/builtin/providers/aws/resource_aws_route53_zone_association_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" "github.com/awslabs/aws-sdk-go/aws" @@ -22,7 +23,36 @@ func TestAccRoute53ZoneAssociation(t *testing.T) { resource.TestStep{ Config: testAccRoute53ZoneAssociationConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53ZoneAssociationExists("aws_route53_zone_association.main", &zone), + testAccCheckRoute53ZoneAssociationExists("aws_route53_zone_association.foobar", &zone), + ), + }, + }, + }) +} + +func TestAccRoute53ZoneAssociationWithRegion(t *testing.T) { + var zone route53.HostedZone + + // record the initialized providers so that we can use them to + // check for the instances in each region + var providers []*schema.Provider + providerFactories := map[string]terraform.ResourceProviderFactory{ + "aws": func() (terraform.ResourceProvider, error) { + p := Provider() + providers = append(providers, p.(*schema.Provider)) + return p, nil + }, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckRoute53ZoneAssociationDestroyWithProviders(&providers), + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccRoute53ZoneAssociationRegionConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ZoneAssociationExistsWithProviders("aws_route53_zone_association.foobar", &zone, &providers), ), }, }, @@ -30,15 +60,43 @@ func TestAccRoute53ZoneAssociation(t *testing.T) { } func testAccCheckRoute53ZoneAssociationDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).r53conn + return testAccCheckRoute53ZoneAssociationDestroyWithProvider(s, testAccProvider) +} + +func testAccCheckRoute53ZoneAssociationDestroyWithProviders(providers *[]*schema.Provider) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, provider := range *providers { + if provider.Meta() == nil { + continue + } + if err := testAccCheckRoute53ZoneAssociationDestroyWithProvider(s, provider); err != nil { + return err + } + } + return nil + } +} + +func testAccCheckRoute53ZoneAssociationDestroyWithProvider(s *terraform.State, provider *schema.Provider) error { + conn := provider.Meta().(*AWSClient).r53conn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_route53_zone" { + if rs.Type != "aws_route53_zone_association" { continue } - _, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(rs.Primary.ID)}) - if err == nil { - return fmt.Errorf("Hosted zone still exists") + zone_id, vpc_id := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) + + resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(zone_id)}) + if err != nil { + exists := false + for _, vpc := range resp.VPCs { + if vpc_id == *vpc.VPCID { + exists = true + } + } + if exists { + return fmt.Errorf("VPC: %v is still associated to HostedZone: %v", vpc_id, zone_id) + } } } return nil @@ -46,36 +104,56 @@ func testAccCheckRoute53ZoneAssociationDestroy(s *terraform.State) error { func testAccCheckRoute53ZoneAssociationExists(n string, zone *route53.HostedZone) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } + return testAccCheckRoute53ZoneAssociationExistsWithProvider(s, n, zone, testAccProvider) + } +} - if rs.Primary.ID == "" { - return fmt.Errorf("No hosted zone ID is set") - } - - conn := testAccProvider.Meta().(*AWSClient).r53conn - resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(rs.Primary.ID)}) - if err != nil { - return fmt.Errorf("Hosted zone err: %v", err) - } - - exists := false - for _, vpc := range resp.VPCs { - if rs.Primary.Meta["vpc_id"] == *vpc.VPCID { - exists = true +func testAccCheckRoute53ZoneAssociationExistsWithProviders(n string, zone *route53.HostedZone, providers *[]*schema.Provider) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, provider := range *providers { + if provider.Meta() == nil { + continue + } + if err := testAccCheckRoute53ZoneAssociationExistsWithProvider(s, n, zone, provider); err != nil { + return err } } - if !exists { - return fmt.Errorf("Hosted zone association not found") - } - - *zone = *resp.HostedZone return nil } } +func testAccCheckRoute53ZoneAssociationExistsWithProvider(s *terraform.State, n string, zone *route53.HostedZone, provider *schema.Provider) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No zone association ID is set") + } + + zone_id, vpc_id := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID) + + conn := provider.Meta().(*AWSClient).r53conn + resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(zone_id)}) + if err != nil { + return fmt.Errorf("Hosted zone err: %v", err) + } + + exists := false + for _, vpc := range resp.VPCs { + if vpc_id == *vpc.VPCID { + exists = true + } + } + if !exists { + return fmt.Errorf("Hosted zone association not found") + } + + *zone = *resp.HostedZone + return nil +} + const testAccRoute53ZoneAssociationConfig = ` resource "aws_vpc" "foo" { cidr_block = "10.6.0.0/16" @@ -99,3 +177,42 @@ resource "aws_route53_zone_association" "foobar" { vpc_id = "${aws_vpc.bar.id}" } ` + +const testAccRoute53ZoneAssociationRegionConfig = ` +provider "aws" { + alias = "west" + region = "us-west-2" +} + +provider "aws" { + alias = "east" + region = "us-east-1" +} + +resource "aws_vpc" "foo" { + provider = "aws.west" + cidr_block = "10.6.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true +} + +resource "aws_vpc" "bar" { + provider = "aws.east" + cidr_block = "10.7.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true +} + +resource "aws_route53_zone" "foo" { + provider = "aws.west" + name = "foo.com" + vpc_id = "${aws_vpc.foo.id}" +} + +resource "aws_route53_zone_association" "foobar" { + provider = "aws.west" + zone_id = "${aws_route53_zone.foo.id}" + vpc_id = "${aws_vpc.bar.id}" + vpc_region = "us-east-1" +} +` diff --git a/builtin/providers/aws/resource_aws_route53_zone_test.go b/builtin/providers/aws/resource_aws_route53_zone_test.go index ecb285374..1ca3927ec 100644 --- a/builtin/providers/aws/resource_aws_route53_zone_test.go +++ b/builtin/providers/aws/resource_aws_route53_zone_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" "github.com/awslabs/aws-sdk-go/aws" @@ -103,8 +104,56 @@ func TestAccRoute53PrivateZone(t *testing.T) { }) } +func TestAccRoute53PrivateZoneWithRegion(t *testing.T) { + var zone route53.GetHostedZoneOutput + + // record the initialized providers so that we can use them to + // check for the instances in each region + var providers []*schema.Provider + providerFactories := map[string]terraform.ResourceProviderFactory{ + "aws": func() (terraform.ResourceProvider, error) { + p := Provider() + providers = append(providers, p.(*schema.Provider)) + return p, nil + }, + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckRoute53ZoneDestroyWithProviders(&providers), + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccRoute53PrivateZoneRegionConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ZoneExistsWithProviders("aws_route53_zone.main", &zone, &providers), + testAccCheckRoute53ZoneAssociatesWithVpc("aws_vpc.main", &zone), + ), + }, + }, + }) +} + func testAccCheckRoute53ZoneDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).r53conn + return testAccCheckRoute53ZoneDestroyWithProvider(s, testAccProvider) +} + +func testAccCheckRoute53ZoneDestroyWithProviders(providers *[]*schema.Provider) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, provider := range *providers { + if provider.Meta() == nil { + continue + } + if err := testAccCheckRoute53ZoneDestroyWithProvider(s, provider); err != nil { + return err + } + } + return nil + } +} + +func testAccCheckRoute53ZoneDestroyWithProvider(s *terraform.State, provider *schema.Provider) error { + conn := provider.Meta().(*AWSClient).r53conn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_route53_zone" { continue @@ -120,41 +169,59 @@ func testAccCheckRoute53ZoneDestroy(s *terraform.State) error { func testAccCheckRoute53ZoneExists(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } + return testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, testAccProvider) + } +} - if rs.Primary.ID == "" { - return fmt.Errorf("No hosted zone ID is set") - } - - conn := testAccProvider.Meta().(*AWSClient).r53conn - resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(rs.Primary.ID)}) - if err != nil { - return fmt.Errorf("Hosted zone err: %v", err) - } - - if ! *resp.HostedZone.Config.PrivateZone { - sorted_ns := make([]string, len(resp.DelegationSet.NameServers)) - for i, ns := range resp.DelegationSet.NameServers { - sorted_ns[i] = *ns +func testAccCheckRoute53ZoneExistsWithProviders(n string, zone *route53.GetHostedZoneOutput, providers *[]*schema.Provider) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, provider := range *providers { + if provider.Meta() == nil { + continue } - sort.Strings(sorted_ns) - for idx, ns := range sorted_ns { - attribute := fmt.Sprintf("name_servers.%d", idx) - dsns := rs.Primary.Attributes[attribute] - if dsns != ns { - return fmt.Errorf("Got: %v for %v, Expected: %v", dsns, attribute, ns) - } + if err := testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, provider); err != nil { + return err } } - - *zone = *resp return nil } } +func testAccCheckRoute53ZoneExistsWithProvider(s *terraform.State, n string, zone *route53.GetHostedZoneOutput, provider *schema.Provider) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No hosted zone ID is set") + } + + conn := provider.Meta().(*AWSClient).r53conn + resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(rs.Primary.ID)}) + if err != nil { + return fmt.Errorf("Hosted zone err: %v", err) + } + + if ! *resp.HostedZone.Config.PrivateZone { + sorted_ns := make([]string, len(resp.DelegationSet.NameServers)) + for i, ns := range resp.DelegationSet.NameServers { + sorted_ns[i] = *ns + } + sort.Strings(sorted_ns) + for idx, ns := range sorted_ns { + attribute := fmt.Sprintf("name_servers.%d", idx) + dsns := rs.Primary.Attributes[attribute] + if dsns != ns { + return fmt.Errorf("Got: %v for %v, Expected: %v", dsns, attribute, ns) + } + } + } + + *zone = *resp + return nil +} + func testAccCheckRoute53ZoneAssociatesWithVpc(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -226,3 +293,30 @@ resource "aws_route53_zone" "main" { vpc_id = "${aws_vpc.main.id}" } ` + +const testAccRoute53PrivateZoneRegionConfig = ` +provider "aws" { + alias = "west" + region = "us-west-2" +} + +provider "aws" { + alias = "east" + region = "us-east-1" +} + +resource "aws_vpc" "main" { + provider = "aws.east" + cidr_block = "172.29.0.0/24" + instance_tenancy = "default" + enable_dns_support = true + enable_dns_hostnames = true +} + +resource "aws_route53_zone" "main" { + provider = "aws.west" + name = "hashicorp.com" + vpc_id = "${aws_vpc.main.id}" + vpc_region = "us-east-1" +} +`