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

provider/aws: Refactor Route53 record to fix regression in deleting #4892

Merged
merged 3 commits into from
Jan 29, 2016
Merged
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
118 changes: 68 additions & 50 deletions builtin/providers/aws/resource_aws_route53_record.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package aws

import (
"bytes"
"errors"
"fmt"
"log"
"strings"
Expand All @@ -16,6 +17,9 @@ import (
"github.com/aws/aws-sdk-go/service/route53"
)

var r53NoRecordsFound = errors.New("No matching Hosted Zone found")
var r53NoHostedZoneFound = errors.New("No matching records found")

func resourceAwsRoute53Record() *schema.Resource {
return &schema.Resource{
Create: resourceAwsRoute53RecordCreate,
Expand Down Expand Up @@ -151,7 +155,7 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("[WARN] No Route53 Zone found for id (%s)", zone)
}

// Get the record
// Build the record
rec, err := resourceAwsRoute53RecordBuildSet(d, *zoneRecord.HostedZone.Name)
if err != nil {
return err
Expand Down Expand Up @@ -242,19 +246,64 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er
}

func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).r53conn
record, err := findRecord(d, meta)
if err != nil {
switch err {
case r53NoHostedZoneFound, r53NoRecordsFound:
log.Printf("[DEBUG] %s for: %s, removing from state file", err, d.Id())
d.SetId("")
return nil
default:
return err
}
}

err = d.Set("records", flattenResourceRecords(record.ResourceRecords))
if err != nil {
return fmt.Errorf("[DEBUG] Error setting records for: %s, error: %#v", d.Id(), err)
}

d.Set("ttl", record.TTL)
// Only set the weight if it's non-nil, otherwise we end up with a 0 weight
// which has actual contextual meaning with Route 53 records
// See http://docs.aws.amazon.com/fr_fr/Route53/latest/APIReference/API_ChangeResourceRecordSets_Examples.html
if record.Weight != nil {
d.Set("weight", record.Weight)
}
d.Set("set_identifier", record.SetIdentifier)
d.Set("failover", record.Failover)
d.Set("health_check_id", record.HealthCheckId)

return nil
}

// findRecord takes a ResourceData struct for aws_resource_route53_record. It
// uses the referenced zone_id to query Route53 and find information on it's
// records.
//
// If records are found, it returns the matching
// route53.ResourceRecordSet and nil for the error.
//
// If no hosted zone is found, it returns a nil recordset and r53NoHostedZoneFound
// error.
//
// If no matching recordset is found, it returns nil and a r53NoRecordsFound
// error
//
// If there are other errors, it returns nil a nil recordset and passes on the
// error.
func findRecord(d *schema.ResourceData, meta interface{}) (*route53.ResourceRecordSet, error) {
conn := meta.(*AWSClient).r53conn
// Scan for a
zone := cleanZoneID(d.Get("zone_id").(string))

// get expanded name
zoneRecord, err := conn.GetHostedZone(&route53.GetHostedZoneInput{Id: aws.String(zone)})
if err != nil {
if r53err, ok := err.(awserr.Error); ok && r53err.Code() == "NoSuchHostedZone" {
log.Printf("[DEBUG] No matching Route 53 Record found for: %s, removing from state file", d.Id())
d.SetId("")
return nil
return nil, r53NoHostedZoneFound
}
return err
return nil, err
}
en := expandRecordName(d.Get("name").(string), *zoneRecord.HostedZone.Name)
log.Printf("[DEBUG] Expanded record name: %s", en)
Expand All @@ -270,11 +319,9 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro
zone, lopts)
resp, err := conn.ListResourceRecordSets(lopts)
if err != nil {
return err
return nil, err
}

// Scan for a matching record
found := false
for _, record := range resp.ResourceRecordSets {
name := cleanRecordName(*record.Name)
if FQDN(strings.ToLower(name)) != FQDN(strings.ToLower(*lopts.StartRecordName)) {
Expand All @@ -287,56 +334,25 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro
if record.SetIdentifier != nil && *record.SetIdentifier != d.Get("set_identifier") {
continue
}

found = true

err := d.Set("records", flattenResourceRecords(record.ResourceRecords))
if err != nil {
return fmt.Errorf("[DEBUG] Error setting records for: %s, error: %#v", en, err)
}

d.Set("ttl", record.TTL)
// Only set the weight if it's non-nil, otherwise we end up with a 0 weight
// which has actual contextual meaning with Route 53 records
// See http://docs.aws.amazon.com/fr_fr/Route53/latest/APIReference/API_ChangeResourceRecordSets_Examples.html
if record.Weight != nil {
d.Set("weight", record.Weight)
}
d.Set("set_identifier", record.SetIdentifier)
d.Set("failover", record.Failover)
d.Set("health_check_id", record.HealthCheckId)

break
}

if !found {
log.Printf("[DEBUG] No matching record found for: %s, removing from state file", en)
d.SetId("")
// The only safe return where a record is found
return record, nil
}

return nil
return nil, r53NoRecordsFound
}

func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).r53conn

zone := cleanZoneID(d.Get("zone_id").(string))
log.Printf("[DEBUG] Deleting resource records for zone: %s, name: %s",
zone, d.Get("name").(string))
var err error
zoneRecord, err := conn.GetHostedZone(&route53.GetHostedZoneInput{Id: aws.String(zone)})
// Get the records
rec, err := findRecord(d, meta)
if err != nil {
if r53err, ok := err.(awserr.Error); ok && r53err.Code() == "NoSuchHostedZone" {
log.Printf("[DEBUG] No matching Route 53 Record found for: %s, removing from state file", d.Id())
switch err {
case r53NoHostedZoneFound, r53NoRecordsFound:
log.Printf("[DEBUG] %s for: %s, removing from state file", err, d.Id())
d.SetId("")
return nil
default:
return err
}
return err
}
// Get the records
rec, err := resourceAwsRoute53RecordBuildSet(d, *zoneRecord.HostedZone.Name)
if err != nil {
return err
}

// Create the new records
Expand All @@ -350,6 +366,8 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er
},
}

zone := cleanZoneID(d.Get("zone_id").(string))

req := &route53.ChangeResourceRecordSetsInput{
HostedZoneId: aws.String(cleanZoneID(zone)),
ChangeBatch: changeBatch,
Expand Down