github.com/bendemaree/terraform@v0.5.4-0.20150613200311-f50d97d6eee6/builtin/providers/azure/resource_azure_data_disk.go (about) 1 package azure 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/Azure/azure-sdk-for-go/management" 9 "github.com/Azure/azure-sdk-for-go/management/virtualmachinedisk" 10 "github.com/hashicorp/terraform/helper/schema" 11 ) 12 13 const dataDiskBlobStorageURL = "http://%s.blob.core.windows.net/disks/%s.vhd" 14 15 func resourceAzureDataDisk() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceAzureDataDiskCreate, 18 Read: resourceAzureDataDiskRead, 19 Update: resourceAzureDataDiskUpdate, 20 Delete: resourceAzureDataDiskDelete, 21 22 Schema: map[string]*schema.Schema{ 23 "name": &schema.Schema{ 24 Type: schema.TypeString, 25 Optional: true, 26 Computed: true, 27 ForceNew: true, 28 }, 29 30 "label": &schema.Schema{ 31 Type: schema.TypeString, 32 Optional: true, 33 Computed: true, 34 ForceNew: true, 35 }, 36 37 "lun": &schema.Schema{ 38 Type: schema.TypeInt, 39 Required: true, 40 }, 41 42 "size": &schema.Schema{ 43 Type: schema.TypeInt, 44 Optional: true, 45 }, 46 47 "caching": &schema.Schema{ 48 Type: schema.TypeString, 49 Optional: true, 50 Default: "None", 51 }, 52 53 "storage_service_name": &schema.Schema{ 54 Type: schema.TypeString, 55 Optional: true, 56 ForceNew: true, 57 }, 58 59 "media_link": &schema.Schema{ 60 Type: schema.TypeString, 61 Optional: true, 62 Computed: true, 63 ForceNew: true, 64 }, 65 66 "source_media_link": &schema.Schema{ 67 Type: schema.TypeString, 68 Optional: true, 69 ForceNew: true, 70 }, 71 72 "virtual_machine": &schema.Schema{ 73 Type: schema.TypeString, 74 Required: true, 75 }, 76 }, 77 } 78 } 79 80 func resourceAzureDataDiskCreate(d *schema.ResourceData, meta interface{}) error { 81 mc := meta.(*Client).mgmtClient 82 83 if err := verifyDataDiskParameters(d); err != nil { 84 return err 85 } 86 87 lun := d.Get("lun").(int) 88 vm := d.Get("virtual_machine").(string) 89 90 label := d.Get("label").(string) 91 if label == "" { 92 label = fmt.Sprintf("%s-%d", vm, lun) 93 } 94 95 p := virtualmachinedisk.CreateDataDiskParameters{ 96 DiskLabel: label, 97 Lun: lun, 98 LogicalDiskSizeInGB: d.Get("size").(int), 99 HostCaching: hostCaching(d), 100 MediaLink: mediaLink(d), 101 SourceMediaLink: d.Get("source_media_link").(string), 102 } 103 104 if name, ok := d.GetOk("name"); ok { 105 p.DiskName = name.(string) 106 } 107 108 log.Printf("[DEBUG] Adding data disk %d to instance: %s", lun, vm) 109 req, err := virtualmachinedisk.NewClient(mc).AddDataDisk(vm, vm, vm, p) 110 if err != nil { 111 return fmt.Errorf("Error adding data disk %d to instance %s: %s", lun, vm, err) 112 } 113 114 // Wait until the data disk is added 115 if err := mc.WaitForOperation(req, nil); err != nil { 116 return fmt.Errorf( 117 "Error waiting for data disk %d to be added to instance %s: %s", lun, vm, err) 118 } 119 120 log.Printf("[DEBUG] Retrieving data disk %d from instance %s", lun, vm) 121 disk, err := virtualmachinedisk.NewClient(mc).GetDataDisk(vm, vm, vm, lun) 122 if err != nil { 123 return fmt.Errorf("Error retrieving data disk %d from instance %s: %s", lun, vm, err) 124 } 125 126 d.SetId(disk.DiskName) 127 128 return resourceAzureDataDiskRead(d, meta) 129 } 130 131 func resourceAzureDataDiskRead(d *schema.ResourceData, meta interface{}) error { 132 mc := meta.(*Client).mgmtClient 133 134 lun := d.Get("lun").(int) 135 vm := d.Get("virtual_machine").(string) 136 137 log.Printf("[DEBUG] Retrieving data disk: %s", d.Id()) 138 datadisk, err := virtualmachinedisk.NewClient(mc).GetDataDisk(vm, vm, vm, lun) 139 if err != nil { 140 if management.IsResourceNotFoundError(err) { 141 d.SetId("") 142 return nil 143 } 144 return fmt.Errorf("Error retrieving data disk %s: %s", d.Id(), err) 145 } 146 147 d.Set("name", datadisk.DiskName) 148 d.Set("label", datadisk.DiskLabel) 149 d.Set("lun", datadisk.Lun) 150 d.Set("size", datadisk.LogicalDiskSizeInGB) 151 d.Set("caching", datadisk.HostCaching) 152 d.Set("media_link", datadisk.MediaLink) 153 154 log.Printf("[DEBUG] Retrieving disk: %s", d.Id()) 155 disk, err := virtualmachinedisk.NewClient(mc).GetDisk(d.Id()) 156 if err != nil { 157 return fmt.Errorf("Error retrieving disk %s: %s", d.Id(), err) 158 } 159 160 d.Set("virtual_machine", disk.AttachedTo.RoleName) 161 162 return nil 163 } 164 165 func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error { 166 mc := meta.(*Client).mgmtClient 167 diskClient := virtualmachinedisk.NewClient(mc) 168 169 lun := d.Get("lun").(int) 170 vm := d.Get("virtual_machine").(string) 171 172 if d.HasChange("lun") || d.HasChange("size") || d.HasChange("virtual_machine") { 173 olun, _ := d.GetChange("lun") 174 ovm, _ := d.GetChange("virtual_machine") 175 176 log.Printf("[DEBUG] Detaching data disk: %s", d.Id()) 177 req, err := diskClient. 178 DeleteDataDisk(ovm.(string), ovm.(string), ovm.(string), olun.(int), false) 179 if err != nil { 180 return fmt.Errorf("Error detaching data disk %s: %s", d.Id(), err) 181 } 182 183 // Wait until the data disk is detached 184 if err := mc.WaitForOperation(req, nil); err != nil { 185 return fmt.Errorf( 186 "Error waiting for data disk %s to be detached: %s", d.Id(), err) 187 } 188 189 log.Printf("[DEBUG] Verifying data disk %s is properly detached...", d.Id()) 190 for i := 0; i < 6; i++ { 191 disk, err := diskClient.GetDisk(d.Id()) 192 if err != nil { 193 return fmt.Errorf("Error retrieving disk %s: %s", d.Id(), err) 194 } 195 196 // Check if the disk is really detached 197 if disk.AttachedTo.RoleName == "" { 198 break 199 } 200 201 // If not, wait 30 seconds and try it again... 202 time.Sleep(time.Duration(30 * time.Second)) 203 } 204 205 if d.HasChange("size") { 206 p := virtualmachinedisk.UpdateDiskParameters{ 207 Name: d.Id(), 208 Label: d.Get("label").(string), 209 ResizedSizeInGB: d.Get("size").(int), 210 } 211 212 log.Printf("[DEBUG] Updating disk: %s", d.Id()) 213 req, err := diskClient.UpdateDisk(d.Id(), p) 214 if err != nil { 215 return fmt.Errorf("Error updating disk %s: %s", d.Id(), err) 216 } 217 218 // Wait until the disk is updated 219 if err := mc.WaitForOperation(req, nil); err != nil { 220 return fmt.Errorf( 221 "Error waiting for disk %s to be updated: %s", d.Id(), err) 222 } 223 } 224 225 p := virtualmachinedisk.CreateDataDiskParameters{ 226 DiskName: d.Id(), 227 Lun: lun, 228 HostCaching: hostCaching(d), 229 MediaLink: mediaLink(d), 230 } 231 232 log.Printf("[DEBUG] Attaching data disk: %s", d.Id()) 233 req, err = diskClient.AddDataDisk(vm, vm, vm, p) 234 if err != nil { 235 return fmt.Errorf("Error attaching data disk %s to instance %s: %s", d.Id(), vm, err) 236 } 237 238 // Wait until the data disk is attached 239 if err := mc.WaitForOperation(req, nil); err != nil { 240 return fmt.Errorf( 241 "Error waiting for data disk %s to be attached to instance %s: %s", d.Id(), vm, err) 242 } 243 244 // Make sure we return here since all possible changes are 245 // already updated if we reach this point 246 return nil 247 } 248 249 if d.HasChange("caching") { 250 p := virtualmachinedisk.UpdateDataDiskParameters{ 251 DiskName: d.Id(), 252 Lun: lun, 253 HostCaching: hostCaching(d), 254 MediaLink: mediaLink(d), 255 } 256 257 log.Printf("[DEBUG] Updating data disk: %s", d.Id()) 258 req, err := diskClient.UpdateDataDisk(vm, vm, vm, lun, p) 259 if err != nil { 260 return fmt.Errorf("Error updating data disk %s: %s", d.Id(), err) 261 } 262 263 // Wait until the data disk is updated 264 if err := mc.WaitForOperation(req, nil); err != nil { 265 return fmt.Errorf( 266 "Error waiting for data disk %s to be updated: %s", d.Id(), err) 267 } 268 } 269 270 return resourceAzureDataDiskRead(d, meta) 271 } 272 273 func resourceAzureDataDiskDelete(d *schema.ResourceData, meta interface{}) error { 274 mc := meta.(*Client).mgmtClient 275 276 lun := d.Get("lun").(int) 277 vm := d.Get("virtual_machine").(string) 278 279 // If a name was not supplied, it means we created a new emtpy disk and we now want to 280 // delete that disk again. Otherwise we only want to detach the disk and keep the blob. 281 _, removeBlob := d.GetOk("name") 282 283 log.Printf("[DEBUG] Detaching data disk %s with removeBlob = %t", d.Id(), removeBlob) 284 req, err := virtualmachinedisk.NewClient(mc).DeleteDataDisk(vm, vm, vm, lun, removeBlob) 285 if err != nil { 286 return fmt.Errorf( 287 "Error detaching data disk %s with removeBlob = %t: %s", d.Id(), removeBlob, err) 288 } 289 290 // Wait until the data disk is detached and optionally deleted 291 if err := mc.WaitForOperation(req, nil); err != nil { 292 return fmt.Errorf( 293 "Error waiting for data disk %s to be detached with removeBlob = %t: %s", 294 d.Id(), removeBlob, err) 295 } 296 297 d.SetId("") 298 299 return nil 300 } 301 302 func hostCaching(d *schema.ResourceData) virtualmachinedisk.HostCachingType { 303 switch d.Get("caching").(string) { 304 case "ReadOnly": 305 return virtualmachinedisk.HostCachingTypeReadOnly 306 case "ReadWrite": 307 return virtualmachinedisk.HostCachingTypeReadWrite 308 default: 309 return virtualmachinedisk.HostCachingTypeNone 310 } 311 } 312 313 func mediaLink(d *schema.ResourceData) string { 314 mediaLink, ok := d.GetOk("media_link") 315 if ok { 316 return mediaLink.(string) 317 } 318 319 name, ok := d.GetOk("name") 320 if !ok { 321 name = fmt.Sprintf("%s-%d", d.Get("virtual_machine").(string), d.Get("lun").(int)) 322 } 323 324 return fmt.Sprintf(dataDiskBlobStorageURL, d.Get("storage_service_name").(string), name.(string)) 325 } 326 327 func verifyDataDiskParameters(d *schema.ResourceData) error { 328 caching := d.Get("caching").(string) 329 if caching != "None" && caching != "ReadOnly" && caching != "ReadWrite" { 330 return fmt.Errorf( 331 "Invalid caching type %s! Valid options are 'None', 'ReadOnly' and 'ReadWrite'.", caching) 332 } 333 334 if _, ok := d.GetOk("media_link"); !ok { 335 if _, ok := d.GetOk("storage_service_name"); !ok { 336 return fmt.Errorf("If not supplying 'media_link', you must supply 'storage'.") 337 } 338 } 339 340 return nil 341 }