diff --git a/adapters/route53-resource-record-set.go b/adapters/route53-resource-record-set.go index 129d4c3d..c3fe7511 100644 --- a/adapters/route53-resource-record-set.go +++ b/adapters/route53-resource-record-set.go @@ -3,6 +3,7 @@ package adapters import ( "context" "errors" + "fmt" "strings" "github.com/aws/aws-sdk-go-v2/service/route53" @@ -17,21 +18,46 @@ func resourceRecordSetGetFunc(ctx context.Context, client *route53.Client, scope } // ResourceRecordSetSearchFunc Search func that accepts a hosted zone or a -// terraform ID in the format {hostedZone}_{recordName}_{type} +// terraform ID in the format {hostedZone}_{recordName}_{type}. Unfortunately +// the "name" means the record name within the scope of the hosted zone, not the +// full FQDN. This is something that Terraform does to match the AWS GUI, where +// you specify a name like "foo" and then you end up with a record like +// "foo.example.com.". That record has a "name" attribute, but it's set to +// "foo.example.com.". +// +// Because of this behaviour we need to construct the full name, rather than +// just the half-name. You can see that the terraform provider itself also does +// this in `findResourceRecordSetByFourPartKey`: +// https://github.com/hashicorp/terraform-provider-aws/blob/main/internal/service/route53/record.go#L786-L825 func resourceRecordSetSearchFunc(ctx context.Context, client *route53.Client, scope, query string) ([]*types.ResourceRecordSet, error) { splits := strings.Split(query, "_") var out *route53.ListResourceRecordSetsOutput var err error if len(splits) == 3 { - // In this case we have a terraform ID + var zoneResp *route53.GetHostedZoneOutput + // In this case we have a terraform ID. We have to get the details of the hosted zone first + zoneResp, err = client.GetHostedZone(ctx, &route53.GetHostedZoneInput{ + Id: &splits[0], + }) + if err != nil { + return nil, err + } + if zoneResp.HostedZone == nil { + return nil, fmt.Errorf("hosted zone %s not found", splits[0]) + } + + // Calculate the full FQDN based on the hosted zone name and the record name + fullName := splits[1] + "." + *zoneResp.HostedZone.Name + var max int32 = 1 - out, err = client.ListResourceRecordSets(ctx, &route53.ListResourceRecordSetsInput{ + req := route53.ListResourceRecordSetsInput{ HostedZoneId: &splits[0], - StartRecordName: &splits[1], + StartRecordName: &fullName, StartRecordType: types.RRType(splits[2]), MaxItems: &max, - }) + } + out, err = client.ListResourceRecordSets(ctx, &req) } else { // In this case we have a hosted zone ID out, err = client.ListResourceRecordSets(ctx, &route53.ListResourceRecordSetsInput{