github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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 vmDiskClient := meta.(*Client).vmDiskClient 83 84 if err := verifyDataDiskParameters(d); err != nil { 85 return err 86 } 87 88 lun := d.Get("lun").(int) 89 vm := d.Get("virtual_machine").(string) 90 91 label := d.Get("label").(string) 92 if label == "" { 93 label = fmt.Sprintf("%s-%d", vm, lun) 94 } 95 96 p := virtualmachinedisk.CreateDataDiskParameters{ 97 DiskLabel: label, 98 Lun: lun, 99 LogicalDiskSizeInGB: d.Get("size").(int), 100 HostCaching: hostCaching(d), 101 MediaLink: mediaLink(d), 102 SourceMediaLink: d.Get("source_media_link").(string), 103 } 104 105 if name, ok := d.GetOk("name"); ok { 106 p.DiskName = name.(string) 107 } 108 109 log.Printf("[DEBUG] Adding data disk %d to instance: %s", lun, vm) 110 req, err := vmDiskClient.AddDataDisk(vm, vm, vm, p) 111 if err != nil { 112 return fmt.Errorf("Error adding data disk %d to instance %s: %s", lun, vm, err) 113 } 114 115 // Wait until the data disk is added 116 if err := mc.WaitForOperation(req, nil); err != nil { 117 return fmt.Errorf( 118 "Error waiting for data disk %d to be added to instance %s: %s", lun, vm, err) 119 } 120 121 log.Printf("[DEBUG] Retrieving data disk %d from instance %s", lun, vm) 122 disk, err := vmDiskClient.GetDataDisk(vm, vm, vm, lun) 123 if err != nil { 124 return fmt.Errorf("Error retrieving data disk %d from instance %s: %s", lun, vm, err) 125 } 126 127 d.SetId(disk.DiskName) 128 129 return resourceAzureDataDiskRead(d, meta) 130 } 131 132 func resourceAzureDataDiskRead(d *schema.ResourceData, meta interface{}) error { 133 vmDiskClient := meta.(*Client).vmDiskClient 134 135 lun := d.Get("lun").(int) 136 vm := d.Get("virtual_machine").(string) 137 138 log.Printf("[DEBUG] Retrieving data disk: %s", d.Id()) 139 datadisk, err := vmDiskClient.GetDataDisk(vm, vm, vm, lun) 140 if err != nil { 141 if management.IsResourceNotFoundError(err) { 142 d.SetId("") 143 return nil 144 } 145 return fmt.Errorf("Error retrieving data disk %s: %s", d.Id(), err) 146 } 147 148 d.Set("name", datadisk.DiskName) 149 d.Set("label", datadisk.DiskLabel) 150 d.Set("lun", datadisk.Lun) 151 d.Set("size", datadisk.LogicalDiskSizeInGB) 152 d.Set("caching", datadisk.HostCaching) 153 d.Set("media_link", datadisk.MediaLink) 154 155 log.Printf("[DEBUG] Retrieving disk: %s", d.Id()) 156 disk, err := vmDiskClient.GetDisk(d.Id()) 157 if err != nil { 158 return fmt.Errorf("Error retrieving disk %s: %s", d.Id(), err) 159 } 160 161 d.Set("virtual_machine", disk.AttachedTo.RoleName) 162 163 return nil 164 } 165 166 func resourceAzureDataDiskUpdate(d *schema.ResourceData, meta interface{}) error { 167 mc := meta.(*Client).mgmtClient 168 vmDiskClient := meta.(*Client).vmDiskClient 169 170 lun := d.Get("lun").(int) 171 vm := d.Get("virtual_machine").(string) 172 173 if d.HasChange("lun") || d.HasChange("size") || d.HasChange("virtual_machine") { 174 olun, _ := d.GetChange("lun") 175 ovm, _ := d.GetChange("virtual_machine") 176 177 log.Printf("[DEBUG] Detaching data disk: %s", d.Id()) 178 req, err := vmDiskClient. 179 DeleteDataDisk(ovm.(string), ovm.(string), ovm.(string), olun.(int), false) 180 if err != nil { 181 return fmt.Errorf("Error detaching data disk %s: %s", d.Id(), err) 182 } 183 184 // Wait until the data disk is detached 185 if err := mc.WaitForOperation(req, nil); err != nil { 186 return fmt.Errorf( 187 "Error waiting for data disk %s to be detached: %s", d.Id(), err) 188 } 189 190 log.Printf("[DEBUG] Verifying data disk %s is properly detached...", d.Id()) 191 for i := 0; i < 6; i++ { 192 disk, err := vmDiskClient.GetDisk(d.Id()) 193 if err != nil { 194 return fmt.Errorf("Error retrieving disk %s: %s", d.Id(), err) 195 } 196 197 // Check if the disk is really detached 198 if disk.AttachedTo.RoleName == "" { 199 break 200 } 201 202 // If not, wait 30 seconds and try it again... 203 time.Sleep(time.Duration(30 * time.Second)) 204 } 205 206 if d.HasChange("size") { 207 p := virtualmachinedisk.UpdateDiskParameters{ 208 Name: d.Id(), 209 Label: d.Get("label").(string), 210 ResizedSizeInGB: d.Get("size").(int), 211 } 212 213 log.Printf("[DEBUG] Updating disk: %s", d.Id()) 214 req, err := vmDiskClient.UpdateDisk(d.Id(), p) 215 if err != nil { 216 return fmt.Errorf("Error updating disk %s: %s", d.Id(), err) 217 } 218 219 // Wait until the disk is updated 220 if err := mc.WaitForOperation(req, nil); err != nil { 221 return fmt.Errorf( 222 "Error waiting for disk %s to be updated: %s", d.Id(), err) 223 } 224 } 225 226 p := virtualmachinedisk.CreateDataDiskParameters{ 227 DiskName: d.Id(), 228 Lun: lun, 229 HostCaching: hostCaching(d), 230 MediaLink: mediaLink(d), 231 } 232 233 log.Printf("[DEBUG] Attaching data disk: %s", d.Id()) 234 req, err = vmDiskClient.AddDataDisk(vm, vm, vm, p) 235 if err != nil { 236 return fmt.Errorf("Error attaching data disk %s to instance %s: %s", d.Id(), vm, err) 237 } 238 239 // Wait until the data disk is attached 240 if err := mc.WaitForOperation(req, nil); err != nil { 241 return fmt.Errorf( 242 "Error waiting for data disk %s to be attached to instance %s: %s", d.Id(), vm, err) 243 } 244 245 // Make sure we return here since all possible changes are 246 // already updated if we reach this point 247 return nil 248 } 249 250 if d.HasChange("caching") { 251 p := virtualmachinedisk.UpdateDataDiskParameters{ 252 DiskName: d.Id(), 253 Lun: lun, 254 HostCaching: hostCaching(d), 255 MediaLink: mediaLink(d), 256 } 257 258 log.Printf("[DEBUG] Updating data disk: %s", d.Id()) 259 req, err := vmDiskClient.UpdateDataDisk(vm, vm, vm, lun, p) 260 if err != nil { 261 return fmt.Errorf("Error updating data disk %s: %s", d.Id(), err) 262 } 263 264 // Wait until the data disk is updated 265 if err := mc.WaitForOperation(req, nil); err != nil { 266 return fmt.Errorf( 267 "Error waiting for data disk %s to be updated: %s", d.Id(), err) 268 } 269 } 270 271 return resourceAzureDataDiskRead(d, meta) 272 } 273 274 func resourceAzureDataDiskDelete(d *schema.ResourceData, meta interface{}) error { 275 mc := meta.(*Client).mgmtClient 276 vmDiskClient := meta.(*Client).vmDiskClient 277 278 lun := d.Get("lun").(int) 279 vm := d.Get("virtual_machine").(string) 280 281 // If a name was not supplied, it means we created a new emtpy disk and we now want to 282 // delete that disk again. Otherwise we only want to detach the disk and keep the blob. 283 _, removeBlob := d.GetOk("name") 284 285 log.Printf("[DEBUG] Detaching data disk %s with removeBlob = %t", d.Id(), removeBlob) 286 req, err := vmDiskClient.DeleteDataDisk(vm, vm, vm, lun, removeBlob) 287 if err != nil { 288 return fmt.Errorf( 289 "Error detaching data disk %s with removeBlob = %t: %s", d.Id(), removeBlob, err) 290 } 291 292 // Wait until the data disk is detached and optionally deleted 293 if err := mc.WaitForOperation(req, nil); err != nil { 294 return fmt.Errorf( 295 "Error waiting for data disk %s to be detached with removeBlob = %t: %s", 296 d.Id(), removeBlob, err) 297 } 298 299 d.SetId("") 300 301 return nil 302 } 303 304 func hostCaching(d *schema.ResourceData) virtualmachinedisk.HostCachingType { 305 switch d.Get("caching").(string) { 306 case "ReadOnly": 307 return virtualmachinedisk.HostCachingTypeReadOnly 308 case "ReadWrite": 309 return virtualmachinedisk.HostCachingTypeReadWrite 310 default: 311 return virtualmachinedisk.HostCachingTypeNone 312 } 313 } 314 315 func mediaLink(d *schema.ResourceData) string { 316 mediaLink, ok := d.GetOk("media_link") 317 if ok { 318 return mediaLink.(string) 319 } 320 321 name, ok := d.GetOk("name") 322 if !ok { 323 name = fmt.Sprintf("%s-%d", d.Get("virtual_machine").(string), d.Get("lun").(int)) 324 } 325 326 return fmt.Sprintf(dataDiskBlobStorageURL, d.Get("storage_service_name").(string), name.(string)) 327 } 328 329 func verifyDataDiskParameters(d *schema.ResourceData) error { 330 caching := d.Get("caching").(string) 331 if caching != "None" && caching != "ReadOnly" && caching != "ReadWrite" { 332 return fmt.Errorf( 333 "Invalid caching type %s! Valid options are 'None', 'ReadOnly' and 'ReadWrite'.", caching) 334 } 335 336 if _, ok := d.GetOk("media_link"); !ok { 337 if _, ok := d.GetOk("storage_service_name"); !ok { 338 return fmt.Errorf("If not supplying 'media_link', you must supply 'storage'.") 339 } 340 } 341 342 return nil 343 }