Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow resizing of virtual disks #2244

Merged
merged 2 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion vsphere/resource_vsphere_virtual_disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func resourceVSphereVirtualDisk() *schema.Resource {
return &schema.Resource{
Create: resourceVSphereVirtualDiskCreate,
Read: resourceVSphereVirtualDiskRead,
Update: resourceVSphereVirtualDiskUpdate,
Delete: resourceVSphereVirtualDiskDelete,
Importer: &schema.ResourceImporter{
State: resourceVSphereVirtualDiskImport,
Expand All @@ -48,7 +49,6 @@ func resourceVSphereVirtualDisk() *schema.Resource {
"size": {
Type: schema.TypeInt,
Required: true,
ForceNew: true, // TODO Can this be optional (resize)?
},

// TODO:
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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")
Expand Down
56 changes: 54 additions & 2 deletions vsphere/resource_vsphere_virtual_disk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
),
Expand All @@ -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)

Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down
8 changes: 5 additions & 3 deletions website/docs/r/virtual_disk.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down