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

aws: Add support for Alias records into AWS Route 53 #1775

Merged
merged 2 commits into from
May 4, 2015
Merged
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
6 changes: 6 additions & 0 deletions builtin/providers/aws/resource_aws_elb.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ func resourceAwsElb() *schema.Resource {
Computed: true,
},

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

"tags": tagsSchema(),
},
}
Expand Down Expand Up @@ -281,6 +286,7 @@ func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error {

d.Set("name", *lb.LoadBalancerName)
d.Set("dns_name", *lb.DNSName)
d.Set("zone_id", *lb.CanonicalHostedZoneNameID)
d.Set("internal", *lb.Scheme == "internal")
d.Set("availability_zones", lb.AvailabilityZones)
d.Set("instances", flattenInstances(lb.Instances))
Expand Down
83 changes: 70 additions & 13 deletions builtin/providers/aws/resource_aws_route53_record.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package aws

import (
"bytes"
"fmt"
"log"
"strings"
Expand Down Expand Up @@ -41,8 +42,9 @@ func resourceAwsRoute53Record() *schema.Resource {
},

"ttl": &schema.Schema{
Type: schema.TypeInt,
Required: true,
Type: schema.TypeInt,
Optional: true,
ConflictsWith: []string{"alias"},
},

"weight": &schema.Schema{
Expand All @@ -56,10 +58,36 @@ func resourceAwsRoute53Record() *schema.Resource {
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{
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Required: true,
Type: schema.TypeSet,
ConflictsWith: []string{"alias"},
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
Set: func(v interface{}) int {
return hashcode.String(v.(string))
},
Expand Down Expand Up @@ -309,10 +337,6 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er
}

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
en := expandRecordName(d.Get("name").(string), zoneName)

Expand All @@ -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
// here.
rec := &route53.ResourceRecordSet{
Name: aws.String(en),
Type: aws.String(d.Get("type").(string)),
TTL: aws.Long(int64(d.Get("ttl").(int))),
ResourceRecords: records,
Name: aws.String(en),
Type: aws.String(d.Get("type").(string)),
}

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 {
Expand Down Expand Up @@ -370,3 +417,13 @@ func expandRecordName(name, zone string) string {
}
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())
}
219 changes: 219 additions & 0 deletions builtin/providers/aws/resource_aws_route53_record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
conn := testAccProvider.Meta().(*AWSClient).r53conn
for _, rs := range s.RootModule().Resources {
Expand Down Expand Up @@ -325,3 +376,171 @@ resource "aws_route53_record" "www-live" {
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
}
}
`
1 change: 1 addition & 0 deletions website/source/docs/providers/aws/r/elb.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,4 @@ The following attributes are exported:
* `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
instances.
* `zone_id` - The canonical hosted zone ID of the ELB (to be used in a Route 53 Alias record)
Loading