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  }