Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

providers/aws: resource aws_route53_zone_association #1827

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func Provider() terraform.ResourceProvider {
"aws_network_interface": resourceAwsNetworkInterface(),
"aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(),
"aws_route53_record": resourceAwsRoute53Record(),
"aws_route53_zone_association": resourceAwsRoute53ZoneAssociation(),
"aws_route53_zone": resourceAwsRoute53Zone(),
"aws_route_table_association": resourceAwsRouteTableAssociation(),
"aws_route_table": resourceAwsRouteTable(),
Expand Down
22 changes: 22 additions & 0 deletions builtin/providers/aws/resource_aws_route53_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ func resourceAwsRoute53Zone() *schema.Resource {
ForceNew: true,
},

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

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

"zone_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
Expand All @@ -53,6 +65,16 @@ func resourceAwsRoute53ZoneCreate(d *schema.ResourceData, meta interface{}) erro
HostedZoneConfig: comment,
CallerReference: aws.String(time.Now().Format(time.RFC3339Nano)),
}
if v := d.Get("vpc_id"); v != nil {

req.VPC = &route53.VPC{
VPCID: aws.String(v.(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 hosted zone: %s", *req.Name)
resp, err := r53.CreateHostedZone(req)
Expand Down
126 changes: 126 additions & 0 deletions builtin/providers/aws/resource_aws_route53_zone_association.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package aws

import (
"log"

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

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

func resourceAwsRoute53ZoneAssociation() *schema.Resource {
return &schema.Resource{
Create: resourceAwsRoute53ZoneAssociationCreate,
Read: resourceAwsRoute53ZoneAssociationRead,
Update: resourceAwsRoute53ZoneAssociationUpdate,
Delete: resourceAwsRoute53ZoneAssociationDelete,

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,
},

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

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

req := &route53.AssociateVPCWithHostedZoneInput{
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),
},
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", *req.HostedZoneID, *req.VPC.VPCID)
resp, err := r53.AssociateVPCWithHostedZone(req)
if err != nil {
return err
}

// Store association id
association_id := cleanChangeID(*resp.ChangeInfo.ID)
d.Set("association_id", association_id)
d.SetId(association_id)

return resourceAwsRoute53ZoneAssociationUpdate(d, meta)
}

func resourceAwsRoute53ZoneAssociationRead(d *schema.ResourceData, meta interface{}) error {
r53 := meta.(*AWSClient).r53conn
zone, err := r53.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(d.Id())})
if err != nil {
// Handle a deleted zone
if r53err, ok := err.(aws.APIError); ok && r53err.Code == "NoSuchHostedZone" {
d.SetId("")
return nil
}
return err
}

vpc_id := d.Get("vpc_id")

for i := range zone.VPCs {
if vpc_id == *zone.VPCs[i].VPCID {
// association is there, return
return nil
}
}

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

func resourceAwsRoute53ZoneAssociationUpdate(d *schema.ResourceData, meta interface{}) error {
return resourceAwsRoute53ZoneAssociationRead(d, meta)
}

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

log.Printf("[DEBUG] Deleting Route53 Private Zone (%s) association (ID: %s)",
d.Get("zone_id").(string), d.Id())

req := &route53.DisassociateVPCFromHostedZoneInput{
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),
},
Comment: aws.String("Managed by Terraform"),
}
if w := d.Get("vpc_region"); w != "" {
req.VPC.VPCRegion = aws.String(w.(string))
}

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

return nil
}
101 changes: 101 additions & 0 deletions builtin/providers/aws/resource_aws_route53_zone_association_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package aws

import (
"fmt"
"testing"

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

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

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

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRoute53ZoneAssociationConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53ZoneAssociationExists("aws_route53_zone_association.main", &zone),
),
},
},
})
}

func testAccCheckRoute53ZoneAssociationDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).r53conn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route53_zone" {
continue
}

_, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(rs.Primary.ID)})
if err == nil {
return fmt.Errorf("Hosted zone still exists")
}
}
return nil
}

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)
}

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 i := range resp.VPCs {
if rs.Primary.Meta["vpc_id"] == *resp.VPCs[i].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"
enable_dns_hostnames = true
enable_dns_support = true
}

resource "aws_vpc" "bar" {
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_zone_association" "foobar" {
zone_id = "${aws_route53_zone.foo.id}"
vpc_id = "${aws_vpc.bar.id}"
}
`
32 changes: 32 additions & 0 deletions builtin/providers/aws/resource_aws_route53_zone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ func TestAccRoute53Zone(t *testing.T) {
})
}

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

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckRoute53ZoneDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRoute53PrivateZoneConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53ZoneExists("aws_route53_zone.main", &zone),
),
},
},
})
}

func testAccCheckRoute53ZoneDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).r53conn
for _, rs := range s.RootModule().Resources {
Expand Down Expand Up @@ -167,3 +185,17 @@ resource "aws_route53_zone" "main" {
}
}
`

const testAccRoute53PrivateZoneConfig = `
resource "aws_vpc" "main" {
cidr_block = "172.29.0.0/24"
instance_tenancy = "default"
enable_dns_support = true
enable_dns_hostnames = true
}

resource "aws_route53_zone" "main" {
name = "hashicorp.com"
vpc_id = "${aws_vpc.main.id}"
}
`
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ The following arguments are supported:

* `name` - (Required) This is the name of the hosted zone.
* `tags` - (Optional) A mapping of tags to assign to the zone.
* `vpc_id` - (Optional) The VPC to associate with a private hosted zone. Specifying `vpc_id` will create a private hosted zone.
* `vpc_region` - (Optional) The VPC's region. Defaults to the region of the AWS provider.

## Attributes Reference

Expand All @@ -63,3 +65,4 @@ The following attributes are exported:
* `zone_id` - The Hosted Zone ID. This can be referenced by zone records.
* `name_servers` - A list of name servers in a default delegation set.
Find more about delegation sets in [AWS docs](http://docs.aws.amazon.com/Route53/latest/APIReference/actions-on-reusable-delegation-sets.html).
=======