Merge pull request #1526 from PeopleNet/route53_private_hosted_zone
AWS/Route53Zone - create private hosted zone associated with VPC.
This commit is contained in:
commit
b3a4965f84
|
@ -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:
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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"
|
||||||
|
}
|
||||||
|
`
|
|
@ -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"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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.
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue