Skip to content

Commit

Permalink
provider/aws: aws_route53_vpc_association_authorization resource
Browse files Browse the repository at this point in the history
Adds the aws_route53_vpc_association_authorization resource which allows
you to create cross account route53 zone associations.
  • Loading branch information
RyanJarv committed Mar 9, 2017
1 parent 6affc2e commit d6869f6
Show file tree
Hide file tree
Showing 3 changed files with 372 additions and 0 deletions.
1 change: 1 addition & 0 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ func Provider() terraform.ResourceProvider {
"aws_redshift_subnet_group": resourceAwsRedshiftSubnetGroup(),
"aws_route53_delegation_set": resourceAwsRoute53DelegationSet(),
"aws_route53_record": resourceAwsRoute53Record(),
"aws_route53_vpc_association_authorization": resourceAwsRoute53VPCAssociationAuthorization(),
"aws_route53_zone_association": resourceAwsRoute53ZoneAssociation(),
"aws_route53_zone": resourceAwsRoute53Zone(),
"aws_route53_health_check": resourceAwsRoute53HealthCheck(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package aws

import (
"fmt"
"log"
"strings"

"github.com/hashicorp/terraform/helper/schema"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/route53"
)

func resourceAwsRoute53VPCAssociationAuthorization() *schema.Resource {
return &schema.Resource{
Create: resourceAwsRoute53VPCAssociationAuthorizationCreate,
Read: resourceAwsRoute53VPCAssociationAuthorizationRead,
Update: resourceAwsRoute53VPCAssociationAuthorizationUpdate,
Delete: resourceAwsRoute53VPCAssociationAuthorizationDelete,

Schema: map[string]*schema.Schema{
"zone_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
},

"vpc_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
},

"vpc_region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
},
}
}

func resourceAwsRoute53VPCAssociationAuthorizationCreate(d *schema.ResourceData, meta interface{}) error {
r53 := meta.(*AWSClient).r53conn

req := &route53.CreateVPCAssociationAuthorizationInput{
HostedZoneId: aws.String(d.Get("zone_id").(string)),
VPC: &route53.VPC{
VPCId: aws.String(d.Get("vpc_id").(string)),
VPCRegion: aws.String(meta.(*AWSClient).region),
},
}
if w := d.Get("vpc_region"); w != "" {
req.VPC.VPCRegion = aws.String(w.(string))
}

log.Printf("[DEBUG] Creating Route53 VPC Association Authorization for hosted zone %s with VPC %s and region %s", *req.HostedZoneId, *req.VPC.VPCId, *req.VPC.VPCRegion)
var err error
_, err = r53.CreateVPCAssociationAuthorization(req)
if err != nil {
return err
}

// Store association id
d.SetId(fmt.Sprintf("%s:%s", *req.HostedZoneId, *req.VPC.VPCId))
d.Set("vpc_region", req.VPC.VPCRegion)

return resourceAwsRoute53VPCAssociationAuthorizationUpdate(d, meta)
}

func resourceAwsRoute53VPCAssociationAuthorizationRead(d *schema.ResourceData, meta interface{}) error {
r53 := meta.(*AWSClient).r53conn
zone_id, vpc_id := resourceAwsRoute53VPCAssociationAuthorizationParseId(d.Id())
req := route53.ListVPCAssociationAuthorizationsInput{HostedZoneId: aws.String(zone_id)}
for {
res, err := r53.ListVPCAssociationAuthorizations(&req)
if err != nil {
return err
}

for _, vpc := range res.VPCs {
if vpc_id == *vpc.VPCId {
return nil
}
}

// Loop till we find our authorization or we reach the end
if res.NextToken != nil {
req.NextToken = res.NextToken
} else {
break
}
}

// no association found
d.SetId("")
return nil
}

func resourceAwsRoute53VPCAssociationAuthorizationUpdate(d *schema.ResourceData, meta interface{}) error {
return resourceAwsRoute53VPCAssociationAuthorizationRead(d, meta)
}

func resourceAwsRoute53VPCAssociationAuthorizationDelete(d *schema.ResourceData, meta interface{}) error {
r53 := meta.(*AWSClient).r53conn
zone_id, vpc_id := resourceAwsRoute53VPCAssociationAuthorizationParseId(d.Id())
log.Printf("[DEBUG] Deleting Route53 Assocatiation Authorization for (%s) from vpc %s)",
zone_id, vpc_id)

req := route53.DeleteVPCAssociationAuthorizationInput{
HostedZoneId: aws.String(zone_id),
VPC: &route53.VPC{
VPCId: aws.String(vpc_id),
VPCRegion: aws.String(d.Get("vpc_region").(string)),
},
}

_, err := r53.DeleteVPCAssociationAuthorization(&req)
if err != nil {
return err
}

return nil
}

func resourceAwsRoute53VPCAssociationAuthorizationParseId(id string) (zone_id, vpc_id string) {
parts := strings.SplitN(id, ":", 2)
zone_id = parts[0]
vpc_id = parts[1]
return
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package aws

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/route53"
)

func TestAccAWSRoute53VpcAssociationAuthorization_basic(t *testing.T) {
var zone route53.HostedZone

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckRoute53VPCAssociationAuthorizationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRoute53VPCAssociationAuthorizationConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53VPCAssociationAuthorizationExists("aws_route53_vpc_association_authorization.peer", &zone),
),
},
},
})
}

func TestAccAWSRoute53VPCAssociationAuthorization_region(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: testAccCheckRoute53VPCAssociationAuthorizationDestroyWithProviders(&providers),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRoute53ZoneAssociationRegionConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53VPCAssociationAuthorizationExistsWithProviders("aws_route53_vpc_association_authorization.peer", &zone, &providers),
),
},
},
})
}

func testAccCheckRoute53VPCAssociationAuthorizationDestroy(s *terraform.State) error {
return testAccCheckRoute53VPCAssociationAuthorizationDestroyWithProvider(s, testAccProvider)
}

func testAccCheckRoute53VPCAssociationAuthorizationDestroyWithProviders(providers *[]*schema.Provider) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, provider := range *providers {
if provider.Meta() == nil {
continue
}
if err := testAccCheckRoute53VPCAssociationAuthorizationDestroyWithProvider(s, provider); err != nil {
return err
}
}
return nil
}
}

func testAccCheckRoute53VPCAssociationAuthorizationDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
conn := provider.Meta().(*AWSClient).r53conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route53_vpc_association_authorization" {
continue
}

zone_id, vpc_id := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID)

req := route53.ListVPCAssociationAuthorizationsInput{HostedZoneId: aws.String(zone_id)}
res, err := conn.ListVPCAssociationAuthorizations(&req)
if err != nil {
return err
}

exists := false
for _, vpc := range res.VPCs {
if vpc_id == *vpc.VPCId {
exists = true
}
}

if exists {
return fmt.Errorf("VPC association authorization for zone %v with %v still exists", zone_id, vpc_id)
}
}
return nil
}

func testAccCheckRoute53VPCAssociationAuthorizationExists(n string, zone *route53.HostedZone) resource.TestCheckFunc {
return func(s *terraform.State) error {
return testAccCheckRoute53VPCAssociationAuthorizationExistsWithProvider(s, n, zone, testAccProvider)
}
}

func testAccCheckRoute53VPCAssociationAuthorizationExistsWithProviders(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 := testAccCheckRoute53VPCAssociationAuthorizationExistsWithProvider(s, n, zone, provider); err != nil {
return err
}
}
return nil
}
}

func testAccCheckRoute53VPCAssociationAuthorizationExistsWithProvider(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 VPC association authorization ID is set")
}

zone_id, vpc_id := resourceAwsRoute53ZoneAssociationParseId(rs.Primary.ID)
conn := provider.Meta().(*AWSClient).r53conn

req := route53.ListVPCAssociationAuthorizationsInput{HostedZoneId: aws.String(zone_id)}
res, err := conn.ListVPCAssociationAuthorizations(&req)
if err != nil {
return err
}

exists := false
for _, vpc := range res.VPCs {
if vpc_id == *vpc.VPCId {
exists = true
}
}

if !exists {
return fmt.Errorf("VPC association authorization not found")
}

return nil
}

const testAccRoute53VPCAssociationAuthorizationConfig = `
provider "aws" {
region = "us-west-2"
// Requester's credentials.
}
provider "aws" {
alias = "peer"
region = "us-west-2"
}
resource "aws_vpc" "foo" {
cidr_block = "10.6.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_vpc" "peer" {
provider = "aws.peer"
cidr_block = "10.7.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_route53_zone" "foo" {
name = "foo.com"
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_route53_vpc_association_authorization" "peer" {
zone_id = "${aws_route53_zone.foo.id}"
vpc_id = "${aws_vpc.peer.id}"
}
resource "aws_route53_zone_association" "foobar" {
zone_id = "${aws_route53_zone.foo.id}"
vpc_id = "${aws_vpc.peer.id}"
}
`

const testAccRoute53VPCAssociationAuthorizationRegionConfig = `
provider "aws" {
region = "us-west-2"
// Requester's credentials.
}
provider "aws" {
alias = "peer"
region = "us-east-2"
}
resource "aws_vpc" "foo" {
cidr_block = "10.6.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_vpc" "peer" {
provider = "aws.peer"
cidr_block = "10.7.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_route53_zone" "foo" {
name = "foo.com"
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_route53_vpc_association_authorization" "peer" {
zone_id = "${aws_route53_zone.foo.id}"
vpc_id = "${aws_vpc.peer.id}"
region = "us-east-2"
}
resource "aws_route53_zone_association" "foobar" {
zone_id = "${aws_route53_zone.foo.id}"
vpc_id = "${aws_vpc.peer.id}"
region = "us-east-2"
}
`

0 comments on commit d6869f6

Please sign in to comment.