provider/aws: Add support for alias record to Route53

This commit is contained in:
Radek Simko 2015-05-01 11:02:06 +01:00 committed by Radek Simko
parent bafabf17be
commit 3d665ddfcf
3 changed files with 331 additions and 13 deletions

View File

@ -1,6 +1,7 @@
package aws package aws
import ( import (
"bytes"
"fmt" "fmt"
"log" "log"
"strings" "strings"
@ -42,7 +43,8 @@ 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,
ConflictsWith: []string{"alias"},
Elem: &schema.Schema{Type: schema.TypeString}, Elem: &schema.Schema{Type: schema.TypeString},
Required: true, 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)
@ -323,8 +347,31 @@ func resourceAwsRoute53RecordBuildSet(d *schema.ResourceData, zoneName string) (
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())
}

View File

@ -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
}
}
`

View File

@ -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