provider/aws: Allow force_destroying records in R53 hosted zone
This commit is contained in:
parent
cc239439fc
commit
079e0c5b86
|
@ -19,9 +19,10 @@ func TestAccAWSRoute53Zone_importBasic(t *testing.T) {
|
|||
},
|
||||
|
||||
resource.TestStep{
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ResourceName: resourceName,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportStateVerifyIgnore: []string{"force_destroy"},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -71,6 +71,12 @@ func resourceAwsRoute53Zone() *schema.Resource {
|
|||
},
|
||||
|
||||
"tags": tagsSchema(),
|
||||
|
||||
"force_destroy": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -258,6 +264,10 @@ func resourceAwsRoute53ZoneUpdate(d *schema.ResourceData, meta interface{}) erro
|
|||
func resourceAwsRoute53ZoneDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
r53 := meta.(*AWSClient).r53conn
|
||||
|
||||
if d.Get("force_destroy").(bool) {
|
||||
deleteAllRecordsInHostedZoneId(d.Id(), d.Get("name").(string), r53)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Deleting Route53 hosted zone: %s (ID: %s)",
|
||||
d.Get("name").(string), d.Id())
|
||||
_, err := r53.DeleteHostedZone(&route53.DeleteHostedZoneInput{Id: aws.String(d.Id())})
|
||||
|
@ -273,6 +283,59 @@ func resourceAwsRoute53ZoneDelete(d *schema.ResourceData, meta interface{}) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *route53.Route53) error {
|
||||
input := &route53.ListResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String(hostedZoneId),
|
||||
}
|
||||
|
||||
var lastDeleteErr, lastErrorFromWaiter error
|
||||
var pageNum = 0
|
||||
err := conn.ListResourceRecordSetsPages(input, func(page *route53.ListResourceRecordSetsOutput, isLastPage bool) bool {
|
||||
sets := page.ResourceRecordSets
|
||||
pageNum += 1
|
||||
|
||||
changes := make([]*route53.Change, 0)
|
||||
// 100 items per page returned by default
|
||||
for _, set := range sets {
|
||||
if *set.Name == hostedZoneName+"." && (*set.Type == "NS" || *set.Type == "SOA") {
|
||||
// Zone NS & SOA records cannot be deleted
|
||||
continue
|
||||
}
|
||||
changes = append(changes, &route53.Change{
|
||||
Action: aws.String("DELETE"),
|
||||
ResourceRecordSet: set,
|
||||
})
|
||||
}
|
||||
log.Printf("[DEBUG] Deleting %d records (page %d) from %s",
|
||||
len(changes), pageNum, hostedZoneId)
|
||||
|
||||
req := &route53.ChangeResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String(hostedZoneId),
|
||||
ChangeBatch: &route53.ChangeBatch{
|
||||
Comment: aws.String("Deleted by Terraform"),
|
||||
Changes: changes,
|
||||
},
|
||||
}
|
||||
|
||||
var resp interface{}
|
||||
resp, lastDeleteErr = deleteRoute53RecordSet(conn, req)
|
||||
if out, ok := resp.(*route53.ChangeResourceRecordSetsOutput); ok {
|
||||
log.Printf("[DEBUG] Waiting for change batch to become INSYNC: %#v", out)
|
||||
lastErrorFromWaiter = waitForRoute53RecordSetToSync(conn, cleanChangeID(*out.ChangeInfo.Id))
|
||||
} else {
|
||||
log.Printf("[DEBUG] Unable to wait for change batch because of an error: %s", lastDeleteErr)
|
||||
}
|
||||
|
||||
return !isLastPage
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed listing/deleting record sets: %s\nLast error from deletion: %s\nLast error from waiter: %s",
|
||||
err, lastDeleteErr, lastErrorFromWaiter)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsGoRoute53Wait(r53 *route53.Route53, ref *route53.GetChangeInput) (result interface{}, state string, err error) {
|
||||
|
||||
status, err := r53.GetChange(ref)
|
||||
|
|
|
@ -2,9 +2,11 @@ package aws
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -86,6 +88,39 @@ func TestAccAWSRoute53Zone_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRoute53Zone_forceDestroy(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) },
|
||||
IDRefreshName: "aws_route53_zone.destroyable",
|
||||
ProviderFactories: providerFactories,
|
||||
CheckDestroy: testAccCheckRoute53ZoneDestroyWithProviders(&providers),
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccRoute53ZoneConfig_forceDestroy,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckRoute53ZoneExistsWithProviders("aws_route53_zone.destroyable", &zone, &providers),
|
||||
// Add >100 records to verify pagination works ok
|
||||
testAccCreateRandomRoute53RecordsInZoneIdWithProviders(&providers, &zone, 100),
|
||||
testAccCreateRandomRoute53RecordsInZoneIdWithProviders(&providers, &zone, 5),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRoute53Zone_updateComment(t *testing.T) {
|
||||
var zone route53.GetHostedZoneOutput
|
||||
var td route53.ResourceTagSet
|
||||
|
@ -204,6 +239,59 @@ func testAccCheckRoute53ZoneDestroyWithProvider(s *terraform.State, provider *sc
|
|||
return nil
|
||||
}
|
||||
|
||||
func testAccCreateRandomRoute53RecordsInZoneIdWithProviders(providers *[]*schema.Provider,
|
||||
zone *route53.GetHostedZoneOutput, recordsCount int) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
for _, provider := range *providers {
|
||||
if provider.Meta() == nil {
|
||||
continue
|
||||
}
|
||||
if err := testAccCreateRandomRoute53RecordsInZoneId(provider, zone, recordsCount); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCreateRandomRoute53RecordsInZoneId(provider *schema.Provider, zone *route53.GetHostedZoneOutput, recordsCount int) error {
|
||||
conn := provider.Meta().(*AWSClient).r53conn
|
||||
|
||||
var changes []*route53.Change
|
||||
if recordsCount > 100 {
|
||||
return fmt.Errorf("Route53 API only allows 100 record sets in a single batch")
|
||||
}
|
||||
for i := 0; i < recordsCount; i++ {
|
||||
changes = append(changes, &route53.Change{
|
||||
Action: aws.String("UPSERT"),
|
||||
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||
Name: aws.String(fmt.Sprintf("%d-tf-acc-random.%s", acctest.RandInt(), *zone.HostedZone.Name)),
|
||||
Type: aws.String("CNAME"),
|
||||
ResourceRecords: []*route53.ResourceRecord{
|
||||
&route53.ResourceRecord{Value: aws.String(fmt.Sprintf("random.%s", *zone.HostedZone.Name))},
|
||||
},
|
||||
TTL: aws.Int64(int64(30)),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
req := &route53.ChangeResourceRecordSetsInput{
|
||||
HostedZoneId: zone.HostedZone.Id,
|
||||
ChangeBatch: &route53.ChangeBatch{
|
||||
Comment: aws.String("Generated by Terraform"),
|
||||
Changes: changes,
|
||||
},
|
||||
}
|
||||
log.Printf("[DEBUG] Change set: %s\n", *req)
|
||||
resp, err := changeRoute53RecordSet(conn, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
changeInfo := resp.(*route53.ChangeResourceRecordSetsOutput).ChangeInfo
|
||||
err = waitForRoute53RecordSetToSync(conn, cleanChangeID(*changeInfo.Id))
|
||||
return err
|
||||
}
|
||||
|
||||
func testAccCheckRoute53ZoneExists(n string, zone *route53.GetHostedZoneOutput) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
return testAccCheckRoute53ZoneExistsWithProvider(s, n, zone, testAccProvider)
|
||||
|
@ -324,6 +412,13 @@ resource "aws_route53_zone" "main" {
|
|||
}
|
||||
`
|
||||
|
||||
const testAccRoute53ZoneConfig_forceDestroy = `
|
||||
resource "aws_route53_zone" "destroyable" {
|
||||
name = "terraform.io"
|
||||
force_destroy = true
|
||||
}
|
||||
`
|
||||
|
||||
const testAccRoute53ZoneConfigUpdateComment = `
|
||||
resource "aws_route53_zone" "main" {
|
||||
name = "hashicorp.com."
|
||||
|
|
|
@ -61,6 +61,8 @@ The following arguments are supported:
|
|||
* `vpc_region` - (Optional) The VPC's region. Defaults to the region of the AWS provider.
|
||||
* `delegation_set_id` - (Optional) The ID of the reusable delgation set whose NS records you want to assign to the hosted zone.
|
||||
Conflicts w/ `vpc_id` as delegation sets can only be used for public zones.
|
||||
* `force_destroy` - (Optional) Whether to destroy all records (possibly managed outside of Terraform)
|
||||
in the zone when destroying the zone.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
|
|
Loading…
Reference in New Issue