provider/aws: Fix wildcard support in Route53 record
Fixes a bug in Route53 and wildcard entries. Refs #501. Also fixes: - an issue in the library where we don't fully wait for the results, because the error code/condition changed with the migration to aws-sdk-go - a limitation in the test, where we only consider the first record returned
This commit is contained in:
parent
dc4abb48fa
commit
49e6c8fd87
|
@ -173,7 +173,8 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro
|
|||
// Scan for a matching record
|
||||
found := false
|
||||
for _, record := range resp.ResourceRecordSets {
|
||||
if FQDN(*record.Name) != FQDN(*lopts.StartRecordName) {
|
||||
name := cleanRecordName(*record.Name)
|
||||
if FQDN(name) != FQDN(*lopts.StartRecordName) {
|
||||
continue
|
||||
}
|
||||
if strings.ToUpper(*record.Type) != strings.ToUpper(*lopts.StartRecordType) {
|
||||
|
@ -232,15 +233,17 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er
|
|||
Refresh: func() (interface{}, string, error) {
|
||||
_, err := conn.ChangeResourceRecordSets(req)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "PriorRequestNotComplete") {
|
||||
// There is some pending operation, so just retry
|
||||
// in a bit.
|
||||
return 42, "rejected", nil
|
||||
}
|
||||
if r53err, ok := err.(aws.APIError); ok {
|
||||
if r53err.Code == "PriorRequestNotComplete" {
|
||||
// There is some pending operation, so just retry
|
||||
// in a bit.
|
||||
return 42, "rejected", nil
|
||||
}
|
||||
|
||||
if strings.Contains(err.Error(), "InvalidChangeBatch") {
|
||||
// This means that the record is already gone.
|
||||
return 42, "accepted", nil
|
||||
if r53err.Code == "InvalidChangeBatch" {
|
||||
// This means that the record is already gone.
|
||||
return 42, "accepted", nil
|
||||
}
|
||||
}
|
||||
|
||||
return 42, "failure", err
|
||||
|
@ -282,3 +285,15 @@ func FQDN(name string) string {
|
|||
return name + "."
|
||||
}
|
||||
}
|
||||
|
||||
// Route 53 stores the "*" wildcard indicator as ASCII 42 and returns the
|
||||
// octal equivalent, "\\052". Here we look for that, and convert back to "*"
|
||||
// as needed.
|
||||
func cleanRecordName(name string) string {
|
||||
str := name
|
||||
if strings.HasPrefix(name, "\\052") {
|
||||
str = strings.Replace(name, "\\052", "*", 1)
|
||||
log.Printf("[DEBUG] Replacing octal \\052 for * in: %s", name)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
|
|
@ -9,9 +9,26 @@ import (
|
|||
"github.com/hashicorp/terraform/terraform"
|
||||
|
||||
"github.com/hashicorp/aws-sdk-go/aws"
|
||||
awsr53 "github.com/hashicorp/aws-sdk-go/gen/route53"
|
||||
route53 "github.com/hashicorp/aws-sdk-go/gen/route53"
|
||||
)
|
||||
|
||||
func TestCleanRecordName(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input, Output string
|
||||
}{
|
||||
{"www.nonexample.com", "www.nonexample.com"},
|
||||
{"\\052.nonexample.com", "*.nonexample.com"},
|
||||
{"nonexample.com", "nonexample.com"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
actual := cleanRecordName(tc.Input)
|
||||
if actual != tc.Output {
|
||||
t.Fatalf("input: %s\noutput: %s", tc.Input, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccRoute53Record(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -44,6 +61,30 @@ func TestAccRoute53Record_generatesSuffix(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccRoute53Record_wildcard(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckRoute53RecordDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccRoute53WildCardRecordConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckRoute53RecordExists("aws_route53_record.wildcard"),
|
||||
),
|
||||
},
|
||||
|
||||
// Cause a change, which will trigger a refresh
|
||||
resource.TestStep{
|
||||
Config: testAccRoute53WildCardRecordConfigUpdate,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckRoute53RecordExists("aws_route53_record.wildcard"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).r53conn
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
|
@ -56,7 +97,7 @@ func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
|
|||
name := parts[1]
|
||||
rType := parts[2]
|
||||
|
||||
lopts := &awsr53.ListResourceRecordSetsRequest{
|
||||
lopts := &route53.ListResourceRecordSetsRequest{
|
||||
HostedZoneID: aws.String(cleanZoneID(zone)),
|
||||
StartRecordName: aws.String(name),
|
||||
StartRecordType: aws.String(rType),
|
||||
|
@ -94,7 +135,7 @@ func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
|
|||
name := parts[1]
|
||||
rType := parts[2]
|
||||
|
||||
lopts := &awsr53.ListResourceRecordSetsRequest{
|
||||
lopts := &route53.ListResourceRecordSetsRequest{
|
||||
HostedZoneID: aws.String(cleanZoneID(zone)),
|
||||
StartRecordName: aws.String(name),
|
||||
StartRecordType: aws.String(rType),
|
||||
|
@ -107,11 +148,14 @@ func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
|
|||
if len(resp.ResourceRecordSets) == 0 {
|
||||
return fmt.Errorf("Record does not exist")
|
||||
}
|
||||
rec := resp.ResourceRecordSets[0]
|
||||
if FQDN(*rec.Name) == FQDN(name) && *rec.Type == rType {
|
||||
return nil
|
||||
// rec := resp.ResourceRecordSets[0]
|
||||
for _, rec := range resp.ResourceRecordSets {
|
||||
recName := cleanRecordName(*rec.Name)
|
||||
if FQDN(recName) == FQDN(name) && *rec.Type == rType {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Record does not exist: %#v", rec)
|
||||
return fmt.Errorf("Record does not exist: %#v", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,3 +186,47 @@ resource "aws_route53_record" "default" {
|
|||
records = ["127.0.0.1", "127.0.0.27"]
|
||||
}
|
||||
`
|
||||
|
||||
const testAccRoute53WildCardRecordConfig = `
|
||||
resource "aws_route53_zone" "main" {
|
||||
name = "notexample.com"
|
||||
}
|
||||
|
||||
resource "aws_route53_record" "default" {
|
||||
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||
name = "subdomain"
|
||||
type = "A"
|
||||
ttl = "30"
|
||||
records = ["127.0.0.1", "127.0.0.27"]
|
||||
}
|
||||
|
||||
resource "aws_route53_record" "wildcard" {
|
||||
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||
name = "*.notexample.com"
|
||||
type = "A"
|
||||
ttl = "30"
|
||||
records = ["127.0.0.1"]
|
||||
}
|
||||
`
|
||||
|
||||
const testAccRoute53WildCardRecordConfigUpdate = `
|
||||
resource "aws_route53_zone" "main" {
|
||||
name = "notexample.com"
|
||||
}
|
||||
|
||||
resource "aws_route53_record" "default" {
|
||||
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||
name = "subdomain"
|
||||
type = "A"
|
||||
ttl = "30"
|
||||
records = ["127.0.0.1", "127.0.0.27"]
|
||||
}
|
||||
|
||||
resource "aws_route53_record" "wildcard" {
|
||||
zone_id = "${aws_route53_zone.main.zone_id}"
|
||||
name = "*.notexample.com"
|
||||
type = "A"
|
||||
ttl = "60"
|
||||
records = ["127.0.0.1"]
|
||||
}
|
||||
`
|
||||
|
|
Loading…
Reference in New Issue