github.com/GoogleCloudPlatform/terraformer@v0.8.18/providers/aws/route53.go (about) 1 // Copyright 2018 The Terraformer Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package aws 16 17 import ( 18 "context" 19 "fmt" 20 "log" 21 "strings" 22 23 "github.com/GoogleCloudPlatform/terraformer/terraformutils" 24 25 "github.com/aws/aws-sdk-go-v2/aws" 26 "github.com/aws/aws-sdk-go-v2/service/route53" 27 ) 28 29 var route53AllowEmptyValues = []string{} 30 31 var route53AdditionalFields = map[string]interface{}{} 32 33 type Route53Generator struct { 34 AWSService 35 } 36 37 func (g *Route53Generator) createZonesResources(svc *route53.Client) []terraformutils.Resource { 38 var resources []terraformutils.Resource 39 p := route53.NewListHostedZonesPaginator(svc, &route53.ListHostedZonesInput{}) 40 for p.HasMorePages() { 41 page, err := p.NextPage(context.TODO()) 42 if err != nil { 43 log.Println(err) 44 return resources 45 } 46 for _, zone := range page.HostedZones { 47 zoneID := cleanZoneID(StringValue(zone.Id)) 48 resources = append(resources, terraformutils.NewResource( 49 zoneID, 50 zoneID+"_"+strings.TrimSuffix(StringValue(zone.Name), "."), 51 "aws_route53_zone", 52 "aws", 53 map[string]string{ 54 "name": StringValue(zone.Name), 55 "force_destroy": "false", 56 }, 57 route53AllowEmptyValues, 58 route53AdditionalFields, 59 )) 60 records := g.createRecordsResources(svc, zoneID) 61 resources = append(resources, records...) 62 } 63 } 64 return resources 65 } 66 67 func (Route53Generator) createRecordsResources(svc *route53.Client, zoneID string) []terraformutils.Resource { 68 var resources []terraformutils.Resource 69 var sets *route53.ListResourceRecordSetsOutput 70 var err error 71 listParams := &route53.ListResourceRecordSetsInput{ 72 HostedZoneId: aws.String(zoneID), 73 } 74 75 for { 76 sets, err = svc.ListResourceRecordSets(context.TODO(), listParams) 77 if err != nil { 78 log.Println(err) 79 return resources 80 } 81 for _, record := range sets.ResourceRecordSets { 82 recordName := wildcardUnescape(StringValue(record.Name)) 83 typeString := string(record.Type) 84 resources = append(resources, terraformutils.NewResource( 85 fmt.Sprintf("%s_%s_%s_%s", zoneID, recordName, typeString, StringValue(record.SetIdentifier)), 86 fmt.Sprintf("%s_%s_%s_%s", zoneID, recordName, typeString, StringValue(record.SetIdentifier)), 87 "aws_route53_record", 88 "aws", 89 map[string]string{ 90 "name": strings.TrimSuffix(recordName, "."), 91 "zone_id": zoneID, 92 "type": typeString, 93 "set_identifier": StringValue(record.SetIdentifier), 94 }, 95 route53AllowEmptyValues, 96 route53AdditionalFields, 97 )) 98 } 99 100 if sets.IsTruncated { 101 listParams.StartRecordName = sets.NextRecordName 102 listParams.StartRecordType = sets.NextRecordType 103 listParams.StartRecordIdentifier = sets.NextRecordIdentifier 104 } else { 105 break 106 } 107 } 108 return resources 109 } 110 111 // Generate TerraformResources from AWS API, 112 // create terraform resource for each zone + each record 113 func (g *Route53Generator) InitResources() error { 114 config, e := g.generateConfig() 115 if e != nil { 116 return e 117 } 118 svc := route53.NewFromConfig(config) 119 120 g.Resources = g.createZonesResources(svc) 121 return nil 122 } 123 124 func (g *Route53Generator) PostConvertHook() error { 125 for i, resourceRecord := range g.Resources { 126 if resourceRecord.InstanceInfo.Type == "aws_route53_zone" { 127 continue 128 } 129 item := resourceRecord.Item 130 zoneID := item["zone_id"].(string) 131 for _, resourceZone := range g.Resources { 132 if resourceZone.InstanceInfo.Type != "aws_route53_zone" { 133 continue 134 } 135 if zoneID == resourceZone.InstanceState.ID { 136 g.Resources[i].Item["zone_id"] = "${aws_route53_zone." + resourceZone.ResourceName + ".zone_id}" 137 } 138 } 139 if _, aliasExist := resourceRecord.Item["alias"]; aliasExist { 140 if _, ttlExist := resourceRecord.Item["ttl"]; ttlExist { 141 delete(g.Resources[i].Item, "ttl") 142 } 143 } 144 } 145 return nil 146 } 147 148 func wildcardUnescape(s string) string { 149 if strings.Contains(s, "\\052") { 150 s = strings.Replace(s, "\\052", "*", 1) 151 } 152 return s 153 } 154 155 // cleanZoneID is used to remove the leading /hostedzone/ 156 func cleanZoneID(id string) string { 157 return cleanPrefix(id, "/hostedzone/") 158 } 159 160 // cleanPrefix removes a string prefix from an ID 161 func cleanPrefix(id, prefix string) string { 162 return strings.TrimPrefix(id, prefix) 163 }