github.com/paulmey/terraform@v0.5.2-0.20150519145237-046e9b4c884d/builtin/providers/aws/resource_aws_route53_zone.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sort"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  
    13  	"github.com/awslabs/aws-sdk-go/aws"
    14  	"github.com/awslabs/aws-sdk-go/service/route53"
    15  )
    16  
    17  func resourceAwsRoute53Zone() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsRoute53ZoneCreate,
    20  		Read:   resourceAwsRoute53ZoneRead,
    21  		Update: resourceAwsRoute53ZoneUpdate,
    22  		Delete: resourceAwsRoute53ZoneDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"name": &schema.Schema{
    26  				Type:     schema.TypeString,
    27  				Required: true,
    28  				ForceNew: true,
    29  			},
    30  
    31  			"vpc_id": &schema.Schema{
    32  				Type:     schema.TypeString,
    33  				Optional: true,
    34  				ForceNew: true,
    35  			},
    36  
    37  			"vpc_region": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Optional: true,
    40  				ForceNew: true,
    41  				Computed: true,
    42  			},
    43  
    44  			"zone_id": &schema.Schema{
    45  				Type:     schema.TypeString,
    46  				Computed: true,
    47  			},
    48  
    49  			"name_servers": &schema.Schema{
    50  				Type:     schema.TypeList,
    51  				Elem:     &schema.Schema{Type: schema.TypeString},
    52  				Computed: true,
    53  			},
    54  
    55  			"tags": tagsSchema(),
    56  		},
    57  	}
    58  }
    59  
    60  func resourceAwsRoute53ZoneCreate(d *schema.ResourceData, meta interface{}) error {
    61  	r53 := meta.(*AWSClient).r53conn
    62  
    63  	comment := &route53.HostedZoneConfig{Comment: aws.String("Managed by Terraform")}
    64  	req := &route53.CreateHostedZoneInput{
    65  		Name:             aws.String(d.Get("name").(string)),
    66  		HostedZoneConfig: comment,
    67  		CallerReference:  aws.String(time.Now().Format(time.RFC3339Nano)),
    68  	}
    69  	if v := d.Get("vpc_id"); v != "" {
    70  		req.VPC = &route53.VPC{
    71  			VPCID:     aws.String(v.(string)),
    72  			VPCRegion: aws.String(meta.(*AWSClient).region),
    73  		}
    74  		if w := d.Get("vpc_region"); w != "" {
    75  			req.VPC.VPCRegion = aws.String(w.(string))
    76  		}
    77  		d.Set("vpc_region", req.VPC.VPCRegion)
    78  	}
    79  
    80  	log.Printf("[DEBUG] Creating Route53 hosted zone: %s", *req.Name)
    81  	resp, err := r53.CreateHostedZone(req)
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	// Store the zone_id
    87  	zone := cleanZoneID(*resp.HostedZone.ID)
    88  	d.Set("zone_id", zone)
    89  	d.SetId(zone)
    90  
    91  	// Wait until we are done initializing
    92  	wait := resource.StateChangeConf{
    93  		Delay:      30 * time.Second,
    94  		Pending:    []string{"PENDING"},
    95  		Target:     "INSYNC",
    96  		Timeout:    10 * time.Minute,
    97  		MinTimeout: 2 * time.Second,
    98  		Refresh: func() (result interface{}, state string, err error) {
    99  			changeRequest := &route53.GetChangeInput{
   100  				ID: aws.String(cleanChangeID(*resp.ChangeInfo.ID)),
   101  			}
   102  			return resourceAwsGoRoute53Wait(r53, changeRequest)
   103  		},
   104  	}
   105  	_, err = wait.WaitForState()
   106  	if err != nil {
   107  		return err
   108  	}
   109  	return resourceAwsRoute53ZoneUpdate(d, meta)
   110  }
   111  
   112  func resourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) error {
   113  	r53 := meta.(*AWSClient).r53conn
   114  	zone, err := r53.GetHostedZone(&route53.GetHostedZoneInput{ID: aws.String(d.Id())})
   115  	if err != nil {
   116  		// Handle a deleted zone
   117  		if r53err, ok := err.(aws.APIError); ok && r53err.Code == "NoSuchHostedZone" {
   118  			d.SetId("")
   119  			return nil
   120  		}
   121  		return err
   122  	}
   123  
   124  	if !*zone.HostedZone.Config.PrivateZone {
   125  		ns := make([]string, len(zone.DelegationSet.NameServers))
   126  		for i := range zone.DelegationSet.NameServers {
   127  			ns[i] = *zone.DelegationSet.NameServers[i]
   128  		}
   129  		sort.Strings(ns)
   130  		if err := d.Set("name_servers", ns); err != nil {
   131  			return fmt.Errorf("[DEBUG] Error setting name servers for: %s, error: %#v", d.Id(), err)
   132  		}
   133  	} else {
   134  		ns, err := getNameServers(d.Id(), d.Get("name").(string), r53)
   135  		if err != nil {
   136  			return err
   137  		}
   138  		if err := d.Set("name_servers", ns); err != nil {
   139  			return fmt.Errorf("[DEBUG] Error setting name servers for: %s, error: %#v", d.Id(), err)
   140  		}
   141  
   142  		var associatedVPC *route53.VPC
   143  		for _, vpc := range zone.VPCs {
   144  			if *vpc.VPCID == d.Get("vpc_id") {
   145  				associatedVPC = vpc
   146  			}
   147  		}
   148  		if associatedVPC == nil {
   149  			return fmt.Errorf("[DEBUG] VPC: %v is not associated with Zone: %v", d.Get("vpc_id"), d.Id())
   150  		}
   151  	}
   152  
   153  	// get tags
   154  	req := &route53.ListTagsForResourceInput{
   155  		ResourceID:   aws.String(d.Id()),
   156  		ResourceType: aws.String("hostedzone"),
   157  	}
   158  
   159  	resp, err := r53.ListTagsForResource(req)
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	var tags []*route53.Tag
   165  	if resp.ResourceTagSet != nil {
   166  		tags = resp.ResourceTagSet.Tags
   167  	}
   168  
   169  	if err := d.Set("tags", tagsToMapR53(tags)); err != nil {
   170  		return err
   171  	}
   172  
   173  	return nil
   174  }
   175  
   176  func resourceAwsRoute53ZoneUpdate(d *schema.ResourceData, meta interface{}) error {
   177  	conn := meta.(*AWSClient).r53conn
   178  
   179  	if err := setTagsR53(conn, d); err != nil {
   180  		return err
   181  	} else {
   182  		d.SetPartial("tags")
   183  	}
   184  
   185  	return resourceAwsRoute53ZoneRead(d, meta)
   186  }
   187  
   188  func resourceAwsRoute53ZoneDelete(d *schema.ResourceData, meta interface{}) error {
   189  	r53 := meta.(*AWSClient).r53conn
   190  
   191  	log.Printf("[DEBUG] Deleting Route53 hosted zone: %s (ID: %s)",
   192  		d.Get("name").(string), d.Id())
   193  	_, err := r53.DeleteHostedZone(&route53.DeleteHostedZoneInput{ID: aws.String(d.Id())})
   194  	if err != nil {
   195  		return err
   196  	}
   197  
   198  	return nil
   199  }
   200  
   201  func resourceAwsGoRoute53Wait(r53 *route53.Route53, ref *route53.GetChangeInput) (result interface{}, state string, err error) {
   202  
   203  	status, err := r53.GetChange(ref)
   204  	if err != nil {
   205  		return nil, "UNKNOWN", err
   206  	}
   207  	return true, *status.ChangeInfo.Status, nil
   208  }
   209  
   210  // cleanChangeID is used to remove the leading /change/
   211  func cleanChangeID(ID string) string {
   212  	return cleanPrefix(ID, "/change/")
   213  }
   214  
   215  // cleanZoneID is used to remove the leading /hostedzone/
   216  func cleanZoneID(ID string) string {
   217  	return cleanPrefix(ID, "/hostedzone/")
   218  }
   219  
   220  // cleanPrefix removes a string prefix from an ID
   221  func cleanPrefix(ID, prefix string) string {
   222  	if strings.HasPrefix(ID, prefix) {
   223  		ID = strings.TrimPrefix(ID, prefix)
   224  	}
   225  	return ID
   226  }
   227  
   228  func getNameServers(zoneId string, zoneName string, r53 *route53.Route53) ([]string, error) {
   229  	resp, err := r53.ListResourceRecordSets(&route53.ListResourceRecordSetsInput{
   230  		HostedZoneID:    aws.String(zoneId),
   231  		StartRecordName: aws.String(zoneName),
   232  		StartRecordType: aws.String("NS"),
   233  	})
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  	if len(resp.ResourceRecordSets) == 0 {
   238  		return nil, nil
   239  	}
   240  	ns := make([]string, len(resp.ResourceRecordSets[0].ResourceRecords))
   241  	for i := range resp.ResourceRecordSets[0].ResourceRecords {
   242  		ns[i] = *resp.ResourceRecordSets[0].ResourceRecords[i].Value
   243  	}
   244  	sort.Strings(ns)
   245  	return ns, nil
   246  }