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