diff --git a/vsphere/resource_vsphere_virtual_disk.go b/vsphere/resource_vsphere_virtual_disk.go index ca90f1181..dc50a52f5 100644 --- a/vsphere/resource_vsphere_virtual_disk.go +++ b/vsphere/resource_vsphere_virtual_disk.go @@ -38,6 +38,7 @@ func resourceVSphereVirtualDisk() *schema.Resource { return &schema.Resource{ Create: resourceVSphereVirtualDiskCreate, Read: resourceVSphereVirtualDiskRead, + Update: resourceVSphereVirtualDiskUpdate, Delete: resourceVSphereVirtualDiskDelete, Importer: &schema.ResourceImporter{ State: resourceVSphereVirtualDiskImport, @@ -48,7 +49,6 @@ func resourceVSphereVirtualDisk() *schema.Resource { "size": { Type: schema.TypeInt, Required: true, - ForceNew: true, // TODO Can this be optional (resize)? }, // TODO: @@ -334,6 +334,51 @@ func resourceVSphereVirtualDiskRead(d *schema.ResourceData, meta interface{}) er return nil } +func resourceVSphereVirtualDiskUpdate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[INFO] Updating Virtual Disk") + client := meta.(*Client).vimClient + + oldSize, newSize := d.GetChange("size") + if newSize.(int) < oldSize.(int) { + return fmt.Errorf("shrinking a virtual disk is not supported") + } + + vDisk := virtualDisk{ + size: d.Get("size").(int), + } + + if v, ok := d.GetOk("vmdk_path"); ok { + vDisk.vmdkPath = v.(string) + } + + if v, ok := d.GetOk("datastore"); ok { + vDisk.datastore = v.(string) + } + + if v, ok := d.GetOk("datacenter"); ok { + vDisk.datacenter = v.(string) + } + + finder := find.NewFinder(client.Client, true) + + dc, err := getDatacenter(client, d.Get("datacenter").(string)) + if err != nil { + return fmt.Errorf("error finding Datacenter: %s: %s", vDisk.datacenter, err) + } + finder = finder.SetDatacenter(dc) + + ds, err := getDatastore(finder, vDisk.datastore) + if err != nil { + return fmt.Errorf("error finding Datastore: %s: %s", vDisk.datastore, err) + } + + if err := extendHardDisk(client, vDisk.size, ds.Path(vDisk.vmdkPath), vDisk.datacenter); err != nil { + return err + } + + return resourceVSphereVirtualDiskRead(d, meta) +} + func resourceVSphereVirtualDiskDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*Client).vimClient @@ -425,6 +470,29 @@ func createHardDisk(client *govmomi.Client, size int, diskPath string, diskType return nil } +func extendHardDisk(client *govmomi.Client, capacity int, diskPath string, dc string) error { + virtualDiskManager := object.NewVirtualDiskManager(client.Client) + datacenter, err := getDatacenter(client, dc) + if err != nil { + return err + } + + capacityKb := int64(1024 * 1024 * capacity) + task, err := virtualDiskManager.ExtendVirtualDisk(context.TODO(), diskPath, datacenter, capacityKb, nil) + if err != nil { + return err + } + + _, err = task.WaitForResultEx(context.TODO(), nil) + if err != nil { + log.Printf("[INFO] Failed to extend disk: %v", err) + return err + } + log.Printf("[INFO] Extended disk.") + + return nil +} + // Searches for the presence of a directory path. func searchForDirectory(client *govmomi.Client, datacenter string, datastore string, directoryPath string) error { log.Printf("[DEBUG] Searching for Directory") diff --git a/vsphere/resource_vsphere_virtual_disk_test.go b/vsphere/resource_vsphere_virtual_disk_test.go index 94a632c2e..ccdcabead 100644 --- a/vsphere/resource_vsphere_virtual_disk_test.go +++ b/vsphere/resource_vsphere_virtual_disk_test.go @@ -32,7 +32,7 @@ func TestAccResourceVSphereVirtualDisk_basic(t *testing.T) { CheckDestroy: testAccVSphereVirtualDiskExists("vsphere_virtual_disk.foo", false), Steps: []resource.TestStep{ { - Config: testacccheckvspherevirtuadiskconfigBasic(rString), + Config: testacccheckvspherevirtualdiskconfigBasic(rString), Check: resource.ComposeTestCheckFunc( testAccVSphereVirtualDiskExists("vsphere_virtual_disk.foo", true), ), @@ -41,6 +41,36 @@ func TestAccResourceVSphereVirtualDisk_basic(t *testing.T) { }) } +func TestAccResourceVSphereVirtualDisk_extend(t *testing.T) { + rString := acctest.RandString(5) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + RunSweepers() + testAccPreCheck(t) + testAccResourceVSphereVirtualDiskPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccVSphereVirtualDiskExists("vsphere_virtual_disk.foo", false), + Steps: []resource.TestStep{ + { + Config: testacccheckvspherevirtualdiskconfigBasic(rString), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "vsphere_virtual_disk.foo", "size", "1"), + ), + }, + { + Config: testacccheckvspherevirtualdiskconfigExtended(rString), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "vsphere_virtual_disk.foo", "size", "2"), + ), + }, + }, + }) +} + func TestAccResourceVSphereVirtualDisk_multi(t *testing.T) { rString := acctest.RandString(5) @@ -177,7 +207,7 @@ func testAccCheckVSphereVirtualDiskIsFileNotFoundError(err error) bool { return false } -func testacccheckvspherevirtuadiskconfigBasic(rName string) string { +func testacccheckvspherevirtualdiskconfigBasic(rName string) string { return fmt.Sprintf(` %s @@ -199,6 +229,28 @@ resource "vsphere_virtual_disk" "foo" { ) } +func testacccheckvspherevirtualdiskconfigExtended(rName string) string { + return fmt.Sprintf(` +%s + +variable "rstring" { + default = "%s" +} + +resource "vsphere_virtual_disk" "foo" { + size = 2 + vmdk_path = "tfTestDisk-${var.rstring}.vmdk" + adapter_type = "lsiLogic" + type = "thin" + datacenter = "${data.vsphere_datacenter.rootdc1.name}" + datastore = vsphere_nas_datastore.ds1.name +} +`, + testhelper.CombineConfigs(testhelper.ConfigDataRootDC1(), testhelper.ConfigDataRootHost1(), testhelper.ConfigDataRootHost2(), testhelper.ConfigResDS1()), + rName, + ) +} + func testacccheckvspherevirtuadiskconfigMulti(rName string) string { return fmt.Sprintf(` %s diff --git a/website/docs/r/virtual_disk.html.markdown b/website/docs/r/virtual_disk.html.markdown index 99c7f91b6..4f6006059 100644 --- a/website/docs/r/virtual_disk.html.markdown +++ b/website/docs/r/virtual_disk.html.markdown @@ -42,16 +42,18 @@ resource "vsphere_virtual_disk" "virtual_disk" { The following arguments are supported: -~> **NOTE:** All fields in the `vsphere_virtual_disk` resource are currently +~> **NOTE:** Some fields in the `vsphere_virtual_disk` resource are currently immutable and force a new resource if changed. * `vmdk_path` - (Required) The path, including filename, of the virtual disk to be created. This needs to end in `.vmdk`. * `datastore` - (Required) The name of the datastore in which to create the disk. -* `size` - (Required) Size of the disk (in GB). +* `size` - (Required) Size of the disk (in GB). Decreasing the size of a disk is not possible. +If a disk of a smaller size is required then the original has to be destroyed along with its data and a new one has to be +created. * `datacenter` - (Optional) The name of the datacenter in which to create the - disk. Can be omitted when when ESXi or if there is only one datacenter in + disk. Can be omitted when ESXi or if there is only one datacenter in your infrastructure. * `type` - (Optional) The type of disk to create. Can be one of `eagerZeroedThick`, `lazy`, or `thin`. Default: `eagerZeroedThick`. For