Merge pull request #1526 from PeopleNet/route53_private_hosted_zone

AWS/Route53Zone - create private hosted zone associated with VPC.
This commit is contained in:
Clint 2015-05-14 16:23:12 -05:00
commit b3a4965f84
9 changed files with 674 additions and 26 deletions

View File

@ -9,12 +9,14 @@ IMPROVEMENTS:
* **New config function: `formatlist`** - Format lists in a similar way to `format`. * **New config function: `formatlist`** - Format lists in a similar way to `format`.
Useful for creating URLs from a list of IPs. [GH-1829] Useful for creating URLs from a list of IPs. [GH-1829]
* **New resource: `aws_route53_zone_association`**
* provider/aws: `aws_autoscaling_group` can wait for capacity in ELB * provider/aws: `aws_autoscaling_group` can wait for capacity in ELB
via `min_elb_capacity` [GH-1970] via `min_elb_capacity` [GH-1970]
* provider/aws: `aws_db_instances` supports `license_model` [GH-1966] * provider/aws: `aws_db_instances` supports `license_model` [GH-1966]
* provider/aws: `aws_elasticache_cluster` add support for Tags [GH-1965] * provider/aws: `aws_elasticache_cluster` add support for Tags [GH-1965]
* provider/aws: `aws_s3_bucket` exports `hosted_zone_id` and `region` [GH-1865] * provider/aws: `aws_s3_bucket` exports `hosted_zone_id` and `region` [GH-1865]
* provider/aws: `aws_route53_record` exports `fqdn` [GH-1847] * provider/aws: `aws_route53_record` exports `fqdn` [GH-1847]
* provider/aws: `aws_route53_zone` can create private hosted zones [GH-1526]
* provider/google: `google_compute_instance` `scratch` attribute added [GH-1920] * provider/google: `google_compute_instance` `scratch` attribute added [GH-1920]
BUG FIXES: BUG FIXES:

View File

@ -115,6 +115,7 @@ func Provider() terraform.ResourceProvider {
"aws_network_interface": resourceAwsNetworkInterface(), "aws_network_interface": resourceAwsNetworkInterface(),
"aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(), "aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(),
"aws_route53_record": resourceAwsRoute53Record(), "aws_route53_record": resourceAwsRoute53Record(),
"aws_route53_zone_association": resourceAwsRoute53ZoneAssociation(),
"aws_route53_zone": resourceAwsRoute53Zone(), "aws_route53_zone": resourceAwsRoute53Zone(),
"aws_route_table_association": resourceAwsRouteTableAssociation(), "aws_route_table_association": resourceAwsRouteTableAssociation(),
"aws_route_table": resourceAwsRouteTable(), "aws_route_table": resourceAwsRouteTable(),

View File

@ -28,6 +28,19 @@ func resourceAwsRoute53Zone() *schema.Resource {
ForceNew: true, ForceNew: true,
}, },
"vpc_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"vpc_region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},
"zone_id": &schema.Schema{ "zone_id": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
@ -53,6 +66,16 @@ func resourceAwsRoute53ZoneCreate(d *schema.ResourceData, meta interface{}) erro
HostedZoneConfig: comment, HostedZoneConfig: comment,
CallerReference: aws.String(time.Now().Format(time.RFC3339Nano)), CallerReference: aws.String(time.Now().Format(time.RFC3339Nano)),
} }
if v := d.Get("vpc_id"); v != "" {
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))
}
d.Set("vpc_region", req.VPC.VPCRegion)
}
log.Printf("[DEBUG] Creating Route53 hosted zone: %s", *req.Name) log.Printf("[DEBUG] Creating Route53 hosted zone: %s", *req.Name)
resp, err := r53.CreateHostedZone(req) resp, err := r53.CreateHostedZone(req)
@ -98,13 +121,33 @@ func resourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) error
return err return err
} }
ns := make([]string, len(zone.DelegationSet.NameServers)) if !*zone.HostedZone.Config.PrivateZone {
for i := range zone.DelegationSet.NameServers { ns := make([]string, len(zone.DelegationSet.NameServers))
ns[i] = *zone.DelegationSet.NameServers[i] for i := range zone.DelegationSet.NameServers {
} ns[i] = *zone.DelegationSet.NameServers[i]
sort.Strings(ns) }
if err := d.Set("name_servers", ns); err != nil { sort.Strings(ns)
return fmt.Errorf("[DEBUG] Error setting name servers for: %s, error: %#v", d.Id(), err) if err := d.Set("name_servers", ns); err != nil {
return fmt.Errorf("[DEBUG] Error setting name servers for: %s, error: %#v", d.Id(), err)
}
} else {
ns, err := getNameServers(d.Id(), d.Get("name").(string), r53)
if err != nil {
return err
}
if err := d.Set("name_servers", ns); err != nil {
return fmt.Errorf("[DEBUG] Error setting name servers for: %s, error: %#v", d.Id(), err)
}
var associatedVPC *route53.VPC
for _, vpc := range zone.VPCs {
if *vpc.VPCID == d.Get("vpc_id") {
associatedVPC = vpc
}
}
if associatedVPC == nil {
return fmt.Errorf("[DEBUG] VPC: %v is not associated with Zone: %v", d.Get("vpc_id"), d.Id())
}
} }
// get tags // get tags
@ -181,3 +224,23 @@ func cleanPrefix(ID, prefix string) string {
} }
return ID return ID
} }
func getNameServers(zoneId string, zoneName string, r53 *route53.Route53) ([]string, error) {
resp, err := r53.ListResourceRecordSets(&route53.ListResourceRecordSetsInput{
HostedZoneID: aws.String(zoneId),
StartRecordName: aws.String(zoneName),
StartRecordType: aws.String("NS"),
})
if err != nil {
return nil, err
}
if len(resp.ResourceRecordSets) == 0 {
return nil, nil
}
ns := make([]string, len(resp.ResourceRecordSets[0].ResourceRecords))
for i := range resp.ResourceRecordSets[0].ResourceRecords {
ns[i] = *resp.ResourceRecordSets[0].ResourceRecords[i].Value
}
sort.Strings(ns)
return ns, nil
}

View File

@ -0,0 +1,147 @@
package aws
import (
"fmt"
"log"
"strings"
"time"
"github.com/hashicorp/terraform/helper/resource"
"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,
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 with region %s", *req.HostedZoneID, *req.VPC.VPCID, *req.VPC.VPCRegion)
resp, err := r53.AssociateVPCWithHostedZone(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)
// Wait until we are done initializing
wait := resource.StateChangeConf{
Delay: 30 * time.Second,
Pending: []string{"PENDING"},
Target: "INSYNC",
Timeout: 10 * time.Minute,
MinTimeout: 2 * time.Second,
Refresh: func() (result interface{}, state string, err error) {
changeRequest := &route53.GetChangeInput{
ID: aws.String(cleanChangeID(*resp.ChangeInfo.ID)),
}
return resourceAwsGoRoute53Wait(r53, changeRequest)
},
}
_, err = wait.WaitForState()
if err != nil {
return err
}
return resourceAwsRoute53ZoneAssociationUpdate(d, meta)
}
func resourceAwsRoute53ZoneAssociationRead(d *schema.ResourceData, meta interface{}) error {
r53 := meta.(*AWSClient).r53conn
zone_id, vpc_id := resourceAwsRoute53ZoneAssociationParseId(d.Id())
zone, err := r53.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(zone_id)})
if err != nil {
// Handle a deleted zone
if r53err, ok := err.(aws.APIError); ok && r53err.Code == "NoSuchHostedZone" {
d.SetId("")
return nil
}
return err
}
for _, vpc := range zone.VPCs {
if vpc_id == *vpc.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
zone_id, vpc_id := resourceAwsRoute53ZoneAssociationParseId(d.Id())
log.Printf("[DEBUG] Deleting Route53 Private Zone (%s) association (VPC: %s)",
zone_id, vpc_id)
req := &route53.DisassociateVPCFromHostedZoneInput{
HostedZoneID: aws.String(zone_id),
VPC: &route53.VPC{
VPCID: aws.String(vpc_id),
VPCRegion: aws.String(d.Get("vpc_region").(string)),
},
Comment: aws.String("Managed by Terraform"),
}
_, err := r53.DisassociateVPCFromHostedZone(req)
if err != nil {
return err
}
return nil
}
func resourceAwsRoute53ZoneAssociationParseId(id string) (zone_id, vpc_id string) {
parts := strings.SplitN(id, ":", 2)
zone_id = parts[0]
vpc_id = parts[1]
return
}

View File

@ -0,0 +1,218 @@
package aws
import (
"fmt"
"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"
"github.com/awslabs/aws-sdk-go/service/route53"
)
func TestAccRoute53ZoneAssociation_basic(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.foobar", &zone),
),
},
},
})
}
func TestAccRoute53ZoneAssociation_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: testAccCheckRoute53ZoneAssociationDestroyWithProviders(&providers),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRoute53ZoneAssociationRegionConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53ZoneAssociationExistsWithProviders("aws_route53_zone_association.foobar", &zone, &providers),
),
},
},
})
}
func testAccCheckRoute53ZoneAssociationDestroy(s *terraform.State) error {
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_association" {
continue
}
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
}
func testAccCheckRoute53ZoneAssociationExists(n string, zone *route53.HostedZone) resource.TestCheckFunc {
return func(s *terraform.State) error {
return testAccCheckRoute53ZoneAssociationExistsWithProvider(s, n, zone, testAccProvider)
}
}
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
}
}
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"
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}"
}
`
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"
}
`

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/awslabs/aws-sdk-go/aws" "github.com/awslabs/aws-sdk-go/aws"
@ -63,8 +64,8 @@ func TestCleanChangeID(t *testing.T) {
} }
} }
func TestAccRoute53Zone(t *testing.T) { func TestAccRoute53Zone_basic(t *testing.T) {
var zone route53.HostedZone var zone route53.GetHostedZoneOutput
var td route53.ResourceTagSet var td route53.ResourceTagSet
resource.Test(t, resource.TestCase{ resource.Test(t, resource.TestCase{
@ -84,8 +85,75 @@ func TestAccRoute53Zone(t *testing.T) {
}) })
} }
func TestAccRoute53Zone_private_basic(t *testing.T) {
var zone route53.GetHostedZoneOutput
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),
testAccCheckRoute53ZoneAssociatesWithVpc("aws_vpc.main", &zone),
),
},
},
})
}
func TestAccRoute53Zone_private_region(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 { 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 { for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route53_zone" { if rs.Type != "aws_route53_zone" {
continue continue
@ -99,23 +167,43 @@ func testAccCheckRoute53ZoneDestroy(s *terraform.State) error {
return nil return nil
} }
func testAccCheckRoute53ZoneExists(n string, zone *route53.HostedZone) resource.TestCheckFunc { func testAccCheckRoute53ZoneExists(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n] return testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, testAccProvider)
if !ok { }
return fmt.Errorf("Not found: %s", n) }
}
if rs.Primary.ID == "" { func testAccCheckRoute53ZoneExistsWithProviders(n string, zone *route53.GetHostedZoneOutput, providers *[]*schema.Provider) resource.TestCheckFunc {
return fmt.Errorf("No hosted zone ID is set") return func(s *terraform.State) error {
for _, provider := range *providers {
if provider.Meta() == nil {
continue
}
if err := testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, provider); err != nil {
return err
}
} }
return nil
}
}
conn := testAccProvider.Meta().(*AWSClient).r53conn func testAccCheckRoute53ZoneExistsWithProvider(s *terraform.State, n string, zone *route53.GetHostedZoneOutput, provider *schema.Provider) error {
resp, err := conn.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(rs.Primary.ID)}) rs, ok := s.RootModule().Resources[n]
if err != nil { if !ok {
return fmt.Errorf("Hosted zone err: %v", err) 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)) sorted_ns := make([]string, len(resp.DelegationSet.NameServers))
for i, ns := range resp.DelegationSet.NameServers { for i, ns := range resp.DelegationSet.NameServers {
sorted_ns[i] = *ns sorted_ns[i] = *ns
@ -128,17 +216,41 @@ func testAccCheckRoute53ZoneExists(n string, zone *route53.HostedZone) resource.
return fmt.Errorf("Got: %v for %v, Expected: %v", dsns, attribute, ns) return fmt.Errorf("Got: %v for %v, Expected: %v", dsns, attribute, ns)
} }
} }
}
*zone = *resp.HostedZone *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]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No VPC ID is set")
}
var associatedVPC *route53.VPC
for _, vpc := range zone.VPCs {
if *vpc.VPCID == rs.Primary.ID {
associatedVPC = vpc
}
}
if associatedVPC == nil {
return fmt.Errorf("VPC: %v is not associated to Zone: %v", n, cleanZoneID(*zone.HostedZone.ID))
}
return nil return nil
} }
} }
func testAccLoadTagsR53(zone *route53.HostedZone, td *route53.ResourceTagSet) resource.TestCheckFunc { func testAccLoadTagsR53(zone *route53.GetHostedZoneOutput, td *route53.ResourceTagSet) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).r53conn conn := testAccProvider.Meta().(*AWSClient).r53conn
zone := cleanZoneID(*zone.ID) zone := cleanZoneID(*zone.HostedZone.ID)
req := &route53.ListTagsForResourceInput{ req := &route53.ListTagsForResourceInput{
ResourceID: aws.String(zone), ResourceID: aws.String(zone),
ResourceType: aws.String("hostedzone"), ResourceType: aws.String("hostedzone"),
@ -167,3 +279,44 @@ 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}"
}
`
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"
}
`

View File

@ -49,17 +49,23 @@ resource "aws_route53_record" "dev-ns" {
} }
``` ```
~> **NOTE:** The `name_servers` set is populated only for public Hosted Zones.
Private Zones will contain any empty set since AWS does not return a `DelegationSet`
for private Hosted Zones.
## Argument Reference ## Argument Reference
The following arguments are supported: The following arguments are supported:
* `name` - (Required) This is the name of the hosted zone. * `name` - (Required) This is the name of the hosted zone.
* `tags` - (Optional) A mapping of tags to assign to the 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 ## Attributes Reference
The following attributes are exported: The following attributes are exported:
* `zone_id` - The Hosted Zone ID. This can be referenced by zone records. * `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. * `name_servers` - A list of name servers in a default delegation set. Supported only for Public Hosted Zones.
Find more about delegation sets in [AWS docs](http://docs.aws.amazon.com/Route53/latest/APIReference/actions-on-reusable-delegation-sets.html). Find more about delegation sets in [AWS docs](http://docs.aws.amazon.com/Route53/latest/APIReference/actions-on-reusable-delegation-sets.html).

View File

@ -0,0 +1,54 @@
---
layout: "aws"
page_title: "AWS: aws_route53_zone_association"
sidebar_current: "docs-aws-resource-route53-zone-association"
description: |-
Provides a Route53 private Hosted Zone to VPC association resource.
---
# aws\_route53\_zone\_association
Provides a Route53 private Hosted Zone to VPC association resource.
## Example Usage
```
resource "aws_vpc" "primary" {
cidr_block = "10.6.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_vpc" "secondary" {
cidr_block = "10.7.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_route53_zone" "example" {
name = "example.com"
vpc_id = "${aws_vpc.primary.id}"
}
resource "aws_route53_zone_assocation" "secondary" {
zone_id = "${aws_route53_zone.example.id}"
vpc_id = "${aws_vpc.secondary.id}"
}
```
## Argument Reference
The following arguments are supported:
* `zone_id` - (Required) The private hosted zone to associate.
* `vpc_id` - (Required) The VPC to associate with the private hosted zone.
* `vpc_region` - (Optional) The VPC's region. Defaults to the region of the AWS provider.
## Attributes Reference
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.

View File

@ -144,6 +144,10 @@
<a href="/docs/providers/aws/r/route53_zone.html">aws_route53_zone</a> <a href="/docs/providers/aws/r/route53_zone.html">aws_route53_zone</a>
</li> </li>
<li<%= sidebar_current("docs-aws-resource-route53-zone-association") %>>
<a href="/docs/providers/aws/r/route53_zone_association.html">aws_route53_zone_association</a>
</li>
<li<%= sidebar_current("docs-aws-resource-s3-bucket") %>> <li<%= sidebar_current("docs-aws-resource-s3-bucket") %>>
<a href="/docs/providers/aws/r/s3_bucket.html">aws_s3_bucket</a> <a href="/docs/providers/aws/r/s3_bucket.html">aws_s3_bucket</a>
</li> </li>