Merge pull request #1775 from TimeIncOSS/r53-alias-record
aws: Add support for Alias records into AWS Route 53
This commit is contained in:
commit
8633c88723
|
@ -177,6 +177,11 @@ func resourceAwsElb() *schema.Resource {
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"zone_id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
"tags": tagsSchema(),
|
"tags": tagsSchema(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -281,6 +286,7 @@ func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
|
||||||
d.Set("name", *lb.LoadBalancerName)
|
d.Set("name", *lb.LoadBalancerName)
|
||||||
d.Set("dns_name", *lb.DNSName)
|
d.Set("dns_name", *lb.DNSName)
|
||||||
|
d.Set("zone_id", *lb.CanonicalHostedZoneNameID)
|
||||||
d.Set("internal", *lb.Scheme == "internal")
|
d.Set("internal", *lb.Scheme == "internal")
|
||||||
d.Set("availability_zones", lb.AvailabilityZones)
|
d.Set("availability_zones", lb.AvailabilityZones)
|
||||||
d.Set("instances", flattenInstances(lb.Instances))
|
d.Set("instances", flattenInstances(lb.Instances))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -41,8 +42,9 @@ func resourceAwsRoute53Record() *schema.Resource {
|
||||||
},
|
},
|
||||||
|
|
||||||
"ttl": &schema.Schema{
|
"ttl": &schema.Schema{
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Required: true,
|
Optional: true,
|
||||||
|
ConflictsWith: []string{"alias"},
|
||||||
},
|
},
|
||||||
|
|
||||||
"weight": &schema.Schema{
|
"weight": &schema.Schema{
|
||||||
|
@ -56,10 +58,36 @@ func resourceAwsRoute53Record() *schema.Resource {
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"alias": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
ConflictsWith: []string{"records", "ttl"},
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"zone_id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"evaluate_target_health": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: resourceAwsRoute53AliasRecordHash,
|
||||||
|
},
|
||||||
|
|
||||||
"records": &schema.Schema{
|
"records": &schema.Schema{
|
||||||
Type: schema.TypeSet,
|
Type: schema.TypeSet,
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
ConflictsWith: []string{"alias"},
|
||||||
Required: true,
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Optional: true,
|
||||||
Set: func(v interface{}) int {
|
Set: func(v interface{}) int {
|
||||||
return hashcode.String(v.(string))
|
return hashcode.String(v.(string))
|
||||||
},
|
},
|
||||||
|
@ -309,10 +337,6 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceAwsRoute53RecordBuildSet(d *schema.ResourceData, zoneName string) (*route53.ResourceRecordSet, error) {
|
func resourceAwsRoute53RecordBuildSet(d *schema.ResourceData, zoneName string) (*route53.ResourceRecordSet, error) {
|
||||||
recs := d.Get("records").(*schema.Set).List()
|
|
||||||
|
|
||||||
records := expandResourceRecords(recs, d.Get("type").(string))
|
|
||||||
|
|
||||||
// get expanded name
|
// get expanded name
|
||||||
en := expandRecordName(d.Get("name").(string), zoneName)
|
en := expandRecordName(d.Get("name").(string), zoneName)
|
||||||
|
|
||||||
|
@ -321,10 +345,33 @@ func resourceAwsRoute53RecordBuildSet(d *schema.ResourceData, zoneName string) (
|
||||||
// not require the trailing ".", which it will itself, so we don't call FQDN
|
// not require the trailing ".", which it will itself, so we don't call FQDN
|
||||||
// here.
|
// here.
|
||||||
rec := &route53.ResourceRecordSet{
|
rec := &route53.ResourceRecordSet{
|
||||||
Name: aws.String(en),
|
Name: aws.String(en),
|
||||||
Type: aws.String(d.Get("type").(string)),
|
Type: aws.String(d.Get("type").(string)),
|
||||||
TTL: aws.Long(int64(d.Get("ttl").(int))),
|
}
|
||||||
ResourceRecords: records,
|
|
||||||
|
if v, ok := d.GetOk("ttl"); ok {
|
||||||
|
rec.TTL = aws.Long(int64(v.(int)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resource records
|
||||||
|
if v, ok := d.GetOk("records"); ok {
|
||||||
|
recs := v.(*schema.Set).List()
|
||||||
|
rec.ResourceRecords = expandResourceRecords(recs, d.Get("type").(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alias record
|
||||||
|
if v, ok := d.GetOk("alias"); ok {
|
||||||
|
aliases := v.(*schema.Set).List()
|
||||||
|
if len(aliases) > 1 {
|
||||||
|
return nil, fmt.Errorf("You can only define a single alias target per record")
|
||||||
|
}
|
||||||
|
alias := aliases[0].(map[string]interface{})
|
||||||
|
rec.AliasTarget = &route53.AliasTarget{
|
||||||
|
DNSName: aws.String(alias["name"].(string)),
|
||||||
|
EvaluateTargetHealth: aws.Boolean(alias["evaluate_target_health"].(bool)),
|
||||||
|
HostedZoneID: aws.String(alias["zone_id"].(string)),
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] Creating alias: %#v", alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := d.GetOk("weight"); ok {
|
if v, ok := d.GetOk("weight"); ok {
|
||||||
|
@ -370,3 +417,13 @@ func expandRecordName(name, zone string) string {
|
||||||
}
|
}
|
||||||
return rn
|
return rn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resourceAwsRoute53AliasRecordHash(v interface{}) int {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
m := v.(map[string]interface{})
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-", m["zone_id"].(string)))
|
||||||
|
buf.WriteString(fmt.Sprintf("%t-", m["evaluate_target_health"].(bool)))
|
||||||
|
|
||||||
|
return hashcode.String(buf.String())
|
||||||
|
}
|
||||||
|
|
|
@ -139,6 +139,57 @@ func TestAccRoute53Record_weighted(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccRoute53Record_alias(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckRoute53RecordDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccRoute53ElbAliasRecord,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.elb_alias"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccRoute53AliasRecord,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.origin"),
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.alias"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccRoute53Record_weighted_alias(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckRoute53RecordDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccRoute53WeightedElbAliasRecord,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.elb_weighted_alias_live"),
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.elb_weighted_alias_dev"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccRoute53WeightedR53AliasRecord,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.green_origin"),
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.r53_weighted_alias_live"),
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.blue_origin"),
|
||||||
|
testAccCheckRoute53RecordExists("aws_route53_record.r53_weighted_alias_dev"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
|
func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
|
||||||
conn := testAccProvider.Meta().(*AWSClient).r53conn
|
conn := testAccProvider.Meta().(*AWSClient).r53conn
|
||||||
for _, rs := range s.RootModule().Resources {
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
@ -325,3 +376,171 @@ resource "aws_route53_record" "www-live" {
|
||||||
records = ["dev.notexample.com"]
|
records = ["dev.notexample.com"]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testAccRoute53ElbAliasRecord = `
|
||||||
|
resource "aws_route53_zone" "main" {
|
||||||
|
name = "notexample.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "alias" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "www"
|
||||||
|
type = "A"
|
||||||
|
|
||||||
|
alias {
|
||||||
|
zone_id = "${aws_elb.main.zone_id}"
|
||||||
|
name = "${aws_elb.main.dns_name}"
|
||||||
|
evaluate_target_health = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_elb" "main" {
|
||||||
|
name = "foobar-terraform-elb"
|
||||||
|
availability_zones = ["us-west-2a"]
|
||||||
|
|
||||||
|
listener {
|
||||||
|
instance_port = 80
|
||||||
|
instance_protocol = "http"
|
||||||
|
lb_port = 80
|
||||||
|
lb_protocol = "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const testAccRoute53AliasRecord = `
|
||||||
|
resource "aws_route53_zone" "main" {
|
||||||
|
name = "notexample.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "origin" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "origin"
|
||||||
|
type = "A"
|
||||||
|
ttl = 5
|
||||||
|
records = ["127.0.0.1"]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "alias" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "www"
|
||||||
|
type = "A"
|
||||||
|
|
||||||
|
alias {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "${aws_route53_record.origin.name}.${aws_route53_zone.main.name}"
|
||||||
|
evaluate_target_health = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const testAccRoute53WeightedElbAliasRecord = `
|
||||||
|
resource "aws_route53_zone" "main" {
|
||||||
|
name = "notexample.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_elb" "live" {
|
||||||
|
name = "foobar-terraform-elb-live"
|
||||||
|
availability_zones = ["us-west-2a"]
|
||||||
|
|
||||||
|
listener {
|
||||||
|
instance_port = 80
|
||||||
|
instance_protocol = "http"
|
||||||
|
lb_port = 80
|
||||||
|
lb_protocol = "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "elb_weighted_alias_live" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "www"
|
||||||
|
type = "A"
|
||||||
|
|
||||||
|
weight = 90
|
||||||
|
set_identifier = "live"
|
||||||
|
|
||||||
|
alias {
|
||||||
|
zone_id = "${aws_elb.live.zone_id}"
|
||||||
|
name = "${aws_elb.live.dns_name}"
|
||||||
|
evaluate_target_health = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_elb" "dev" {
|
||||||
|
name = "foobar-terraform-elb-dev"
|
||||||
|
availability_zones = ["us-west-2a"]
|
||||||
|
|
||||||
|
listener {
|
||||||
|
instance_port = 80
|
||||||
|
instance_protocol = "http"
|
||||||
|
lb_port = 80
|
||||||
|
lb_protocol = "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "elb_weighted_alias_dev" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "www"
|
||||||
|
type = "A"
|
||||||
|
|
||||||
|
weight = 10
|
||||||
|
set_identifier = "dev"
|
||||||
|
|
||||||
|
alias {
|
||||||
|
zone_id = "${aws_elb.dev.zone_id}"
|
||||||
|
name = "${aws_elb.dev.dns_name}"
|
||||||
|
evaluate_target_health = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const testAccRoute53WeightedR53AliasRecord = `
|
||||||
|
resource "aws_route53_zone" "main" {
|
||||||
|
name = "notexample.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "blue_origin" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "blue-origin"
|
||||||
|
type = "CNAME"
|
||||||
|
ttl = 5
|
||||||
|
records = ["v1.terraform.io"]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "r53_weighted_alias_live" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "www"
|
||||||
|
type = "CNAME"
|
||||||
|
|
||||||
|
weight = 90
|
||||||
|
set_identifier = "blue"
|
||||||
|
|
||||||
|
alias {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "${aws_route53_record.blue_origin.name}.${aws_route53_zone.main.name}"
|
||||||
|
evaluate_target_health = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "green_origin" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "green-origin"
|
||||||
|
type = "CNAME"
|
||||||
|
ttl = 5
|
||||||
|
records = ["v2.terraform.io"]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "r53_weighted_alias_dev" {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "www"
|
||||||
|
type = "CNAME"
|
||||||
|
|
||||||
|
weight = 10
|
||||||
|
set_identifier = "green"
|
||||||
|
|
||||||
|
alias {
|
||||||
|
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||||
|
name = "${aws_route53_record.green_origin.name}.${aws_route53_zone.main.name}"
|
||||||
|
evaluate_target_health = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
|
@ -96,3 +96,4 @@ The following attributes are exported:
|
||||||
* `source_security_group` - The name of the security group that you can use as
|
* `source_security_group` - The name of the security group that you can use as
|
||||||
part of your inbound rules for your load balancer's back-end application
|
part of your inbound rules for your load balancer's back-end application
|
||||||
instances.
|
instances.
|
||||||
|
* `zone_id` - The canonical hosted zone ID of the ELB (to be used in a Route 53 Alias record)
|
||||||
|
|
|
@ -49,6 +49,39 @@ resource "aws_route53_record" "www-live" {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Alias record
|
||||||
|
See [related part of AWS Route53 Developer Guide](http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-choosing-alias-non-alias.html)
|
||||||
|
to understand differences between alias and non-alias records.
|
||||||
|
|
||||||
|
TTL for all alias records is [60 seconds](http://aws.amazon.com/route53/faqs/#dns_failover_do_i_need_to_adjust),
|
||||||
|
you cannot change this, therefore `ttl` has to be ommitted in alias records.
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_elb" "main" {
|
||||||
|
name = "foobar-terraform-elb"
|
||||||
|
availability_zones = ["us-east-1c"]
|
||||||
|
|
||||||
|
listener {
|
||||||
|
instance_port = 80
|
||||||
|
instance_protocol = "http"
|
||||||
|
lb_port = 80
|
||||||
|
lb_protocol = "http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route53_record" "www" {
|
||||||
|
zone_id = "${aws_route53_zone.primary.zone_id}"
|
||||||
|
name = "example.com"
|
||||||
|
type = "A"
|
||||||
|
|
||||||
|
alias {
|
||||||
|
name = "${aws_elb.main.dns_name}"
|
||||||
|
zone_id = "${aws_elb.main.zone_id}"
|
||||||
|
evaluate_target_health = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Argument Reference
|
## Argument Reference
|
||||||
|
|
||||||
The following arguments are supported:
|
The following arguments are supported:
|
||||||
|
@ -61,6 +94,15 @@ The following arguments are supported:
|
||||||
* `weight` - (Optional) The weight of weighted record (0-255).
|
* `weight` - (Optional) The weight of weighted record (0-255).
|
||||||
* `set_identifier` - (Optional) Unique identifier to differentiate weighted
|
* `set_identifier` - (Optional) Unique identifier to differentiate weighted
|
||||||
record from one another. Required for each weighted record.
|
record from one another. Required for each weighted record.
|
||||||
|
* `alias` - (Optional) An alias block. Alias record documented below.
|
||||||
|
|
||||||
|
Exactly one of `records` or `alias` must be specified: this determines whether it's an alias record.
|
||||||
|
|
||||||
|
Alias records support the following:
|
||||||
|
|
||||||
|
* `name` - (Required) DNS domain name for a CloudFront distribution, S3 bucket, ELB, or another resource record set in this hosted zone.
|
||||||
|
* `zone_id` - (Required) Hosted zone ID for a CloudFront distribution, S3 bucket, ELB, or Route 53 hosted zone. See [`resource_elb.zone_id`](/docs/providers/aws/r/elb.html#zone_id) for example.
|
||||||
|
* `evaluate_target_health` - (Required) Set to `true` if you want Route 53 to determine whether to respond to DNS queries using this resource record set by checking the health of the resource record set. Some resources have special requirements, see [related part of documentation](http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-values.html#rrsets-values-alias-evaluate-target-health).
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue