github.com/richardbowden/terraform@v0.6.12-0.20160901200758-30ea22c25211/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  }