diff --git a/.changelog/21556.txt b/.changelog/21556.txt new file mode 100644 index 00000000000..1bcb9678090 --- /dev/null +++ b/.changelog/21556.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_route53_record: Fix import with underscores in names +``` diff --git a/internal/service/route53/record.go b/internal/service/route53/record.go index 2e46ab820ec..e808a1acd57 100644 --- a/internal/service/route53/record.go +++ b/internal/service/route53/record.go @@ -6,7 +6,6 @@ import ( "fmt" "log" "math/rand" - "regexp" "strconv" "strings" "time" @@ -30,7 +29,6 @@ const ( var ( r53NoRecordsFound = errors.New("No matching records found") r53NoHostedZoneFound = errors.New("No matching Hosted Zone found") - r53ValidRecordTypes = regexp.MustCompile("^(A|AAAA|CAA|CNAME|MX|NAPTR|NS|PTR|SOA|SPF|SRV|TXT|DS)$") ) func ResourceRecord() *schema.Resource { @@ -65,23 +63,9 @@ func ResourceRecord() *schema.Resource { }, "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - route53.RRTypeSoa, - route53.RRTypeA, - route53.RRTypeTxt, - route53.RRTypeNs, - route53.RRTypeCname, - route53.RRTypeMx, - route53.RRTypeNaptr, - route53.RRTypePtr, - route53.RRTypeSrv, - route53.RRTypeSpf, - route53.RRTypeAaaa, - route53.RRTypeCaa, - route53.RRTypeDs, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(route53.RRType_Values(), false), }, "zone_id": { @@ -975,24 +959,33 @@ func NormalizeAliasName(alias interface{}) string { func ParseRecordID(id string) [4]string { var recZone, recType, recName, recSet string - parts := strings.SplitN(id, "_", 2) - if len(parts) == 2 { + parts := strings.Split(id, "_") + if len(parts) > 1 { recZone = parts[0] - firstUnderscore := strings.Index(parts[1][:], "_") - // Handles the case of having a DNS name that starts with _ - if firstUnderscore == 0 { - firstUnderscore = strings.Index(parts[1][1:], "_") + 1 - } - if firstUnderscore != -1 { - recName, recType = parts[1][0:firstUnderscore], parts[1][firstUnderscore+1:] - } - if !r53ValidRecordTypes.MatchString(recType) { - firstUnderscore = strings.Index(recType, "_") - if firstUnderscore != -1 { - recType, recSet = recType[0:firstUnderscore], recType[firstUnderscore+1:] + } + if len(parts) >= 3 { + var recTypeIndex int = -1 + for i, maybeRecType := range parts[1:] { + if validRecordType(maybeRecType) { + recTypeIndex = i + 1 + break } } + if recTypeIndex > 1 { + recName = strings.Join(parts[1:recTypeIndex], "_") + recName = strings.TrimSuffix(recName, ".") + recType = parts[recTypeIndex] + recSet = strings.Join(parts[recTypeIndex+1:], "_") + } } - recName = strings.TrimSuffix(recName, ".") return [4]string{recZone, recName, recType, recSet} } + +func validRecordType(s string) bool { + for _, v := range route53.RRType_Values() { + if v == s { + return true + } + } + return false +} diff --git a/internal/service/route53/record_test.go b/internal/service/route53/record_test.go index e1fff390a47..5fa9ccd1bc9 100644 --- a/internal/service/route53/record_test.go +++ b/internal/service/route53/record_test.go @@ -96,22 +96,27 @@ func TestParseRecordId(t *testing.T) { {"ABCDEF__underscore.example.com_A_set1", "ABCDEF", "_underscore.example.com", "A", "set1"}, {"ABCDEF__underscore.example.com_A_set_with1", "ABCDEF", "_underscore.example.com", "A", "set_with1"}, {"ABCDEF__underscore.example.com_A_set_with_1", "ABCDEF", "_underscore.example.com", "A", "set_with_1"}, + {"ABCDEF_prefix._underscore.example.com_A", "ABCDEF", "prefix._underscore.example.com", "A", ""}, + {"ABCDEF_prefix._underscore.example.com_A_set", "ABCDEF", "prefix._underscore.example.com", "A", "set"}, + {"ABCDEF_prefix._underscore.example.com_A_set_underscore", "ABCDEF", "prefix._underscore.example.com", "A", "set_underscore"}, } for _, tc := range cases { - parts := tfroute53.ParseRecordID(tc.Input) - if parts[0] != tc.Zone { - t.Fatalf("input: %s\noutput: %s\nexpected:%s", tc.Input, parts[0], tc.Zone) - } - if parts[1] != tc.Name { - t.Fatalf("input: %s\noutput: %s\nexpected:%s", tc.Input, parts[1], tc.Name) - } - if parts[2] != tc.Type { - t.Fatalf("input: %s\noutput: %s\nexpected:%s", tc.Input, parts[2], tc.Type) - } - if parts[3] != tc.Set { - t.Fatalf("input: %s\noutput: %s\nexpected:%s", tc.Input, parts[3], tc.Set) - } + t.Run(tc.Input, func(t *testing.T) { + parts := tfroute53.ParseRecordID(tc.Input) + if parts[0] != tc.Zone { + t.Fatalf("input: %s\nzone: %s\nexpected:%s", tc.Input, parts[0], tc.Zone) + } + if parts[1] != tc.Name { + t.Fatalf("input: %s\nname: %s\nexpected:%s", tc.Input, parts[1], tc.Name) + } + if parts[2] != tc.Type { + t.Fatalf("input: %s\ntype: %s\nexpected:%s", tc.Input, parts[2], tc.Type) + } + if parts[3] != tc.Set { + t.Fatalf("input: %s\nset: %s\nexpected:%s", tc.Input, parts[3], tc.Set) + } + }) } }