mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-20 11:48:24 -06:00
For both the file and virtual_disk resource, Stat is used during read, but if Stat returns an error, read() will return that error. In doing so, if a resource is deleted manually, the TF user would then not be able to destroy the resource because the read would block the Delete() call. With this patch, read() will only return an error if that error is NOT a DatastoreNoSuchFileError.
265 lines
6.2 KiB
Go
265 lines
6.2 KiB
Go
package vsphere
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
"github.com/vmware/govmomi"
|
|
"github.com/vmware/govmomi/find"
|
|
"github.com/vmware/govmomi/object"
|
|
"github.com/vmware/govmomi/vim25/types"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
type virtualDisk struct {
|
|
size int
|
|
vmdkPath string
|
|
initType string
|
|
adapterType string
|
|
datacenter string
|
|
datastore string
|
|
}
|
|
|
|
// Define VirtualDisk args
|
|
func resourceVSphereVirtualDisk() *schema.Resource {
|
|
return &schema.Resource{
|
|
Create: resourceVSphereVirtualDiskCreate,
|
|
Read: resourceVSphereVirtualDiskRead,
|
|
Delete: resourceVSphereVirtualDiskDelete,
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
// Size in GB
|
|
"size": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Required: true,
|
|
ForceNew: true, //TODO Can this be optional (resize)?
|
|
},
|
|
|
|
"vmdk_path": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true, //TODO Can this be optional (move)?
|
|
},
|
|
|
|
"type": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Default: "eagerZeroedThick",
|
|
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
|
|
value := v.(string)
|
|
if value != "thin" && value != "eagerZeroedThick" {
|
|
errors = append(errors, fmt.Errorf(
|
|
"only 'thin' and 'eagerZeroedThick' are supported values for 'type'"))
|
|
}
|
|
return
|
|
},
|
|
},
|
|
|
|
"adapter_type": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Default: "ide",
|
|
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
|
|
value := v.(string)
|
|
if value != "ide" && value != "busLogic" && value != "lsiLogic" {
|
|
errors = append(errors, fmt.Errorf(
|
|
"only 'ide', 'busLogic', and 'lsiLogic' are supported values for 'adapter_type'"))
|
|
}
|
|
return
|
|
},
|
|
},
|
|
|
|
"datacenter": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"datastore": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func resourceVSphereVirtualDiskCreate(d *schema.ResourceData, meta interface{}) error {
|
|
log.Printf("[INFO] Creating Virtual Disk")
|
|
client := meta.(*govmomi.Client)
|
|
|
|
vDisk := virtualDisk{
|
|
size: d.Get("size").(int),
|
|
}
|
|
|
|
if v, ok := d.GetOk("vmdk_path"); ok {
|
|
vDisk.vmdkPath = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("type"); ok {
|
|
vDisk.initType = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("adapter_type"); ok {
|
|
vDisk.adapterType = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("datacenter"); ok {
|
|
vDisk.datacenter = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("datastore"); ok {
|
|
vDisk.datastore = v.(string)
|
|
}
|
|
|
|
diskPath := fmt.Sprintf("[%v] %v", vDisk.datastore, vDisk.vmdkPath)
|
|
|
|
err := createHardDisk(client, vDisk.size, diskPath, vDisk.initType, vDisk.adapterType, vDisk.datacenter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
d.SetId(diskPath)
|
|
log.Printf("[DEBUG] Virtual Disk id: %v", diskPath)
|
|
|
|
return resourceVSphereVirtualDiskRead(d, meta)
|
|
}
|
|
|
|
func resourceVSphereVirtualDiskRead(d *schema.ResourceData, meta interface{}) error {
|
|
log.Printf("[DEBUG] Reading virtual disk.")
|
|
client := meta.(*govmomi.Client)
|
|
|
|
vDisk := virtualDisk{
|
|
size: d.Get("size").(int),
|
|
}
|
|
|
|
if v, ok := d.GetOk("vmdk_path"); ok {
|
|
vDisk.vmdkPath = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("type"); ok {
|
|
vDisk.initType = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("adapter_type"); ok {
|
|
vDisk.adapterType = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("datacenter"); ok {
|
|
vDisk.datacenter = v.(string)
|
|
}
|
|
|
|
if v, ok := d.GetOk("datastore"); ok {
|
|
vDisk.datastore = v.(string)
|
|
}
|
|
|
|
dc, err := getDatacenter(client, d.Get("datacenter").(string))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
finder := find.NewFinder(client.Client, true)
|
|
finder = finder.SetDatacenter(dc)
|
|
|
|
ds, err := finder.Datastore(context.TODO(), d.Get("datastore").(string))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fileInfo, err := ds.Stat(context.TODO(), vDisk.vmdkPath)
|
|
if err != nil {
|
|
log.Printf("[DEBUG] resourceVSphereVirtualDiskRead - stat failed on: %v", vDisk.vmdkPath)
|
|
d.SetId("")
|
|
|
|
_, ok := err.(object.DatastoreNoSuchFileError)
|
|
if !ok {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
fileInfo = fileInfo.GetFileInfo()
|
|
log.Printf("[DEBUG] resourceVSphereVirtualDiskRead - fileinfo: %#v", fileInfo)
|
|
size := fileInfo.(*types.FileInfo).FileSize / 1024 / 1024 / 1024
|
|
|
|
d.SetId(vDisk.vmdkPath)
|
|
|
|
d.Set("size", size)
|
|
d.Set("vmdk_path", vDisk.vmdkPath)
|
|
d.Set("datacenter", d.Get("datacenter"))
|
|
d.Set("datastore", d.Get("datastore"))
|
|
// Todo collect and write type info
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func resourceVSphereVirtualDiskDelete(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*govmomi.Client)
|
|
|
|
vDisk := virtualDisk{}
|
|
|
|
if v, ok := d.GetOk("vmdk_path"); ok {
|
|
vDisk.vmdkPath = v.(string)
|
|
}
|
|
if v, ok := d.GetOk("datastore"); ok {
|
|
vDisk.datastore = v.(string)
|
|
}
|
|
|
|
dc, err := getDatacenter(client, d.Get("datacenter").(string))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
diskPath := fmt.Sprintf("[%v] %v", vDisk.datastore, vDisk.vmdkPath)
|
|
|
|
virtualDiskManager := object.NewVirtualDiskManager(client.Client)
|
|
|
|
task, err := virtualDiskManager.DeleteVirtualDisk(context.TODO(), diskPath, dc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = task.WaitForResult(context.TODO(), nil)
|
|
if err != nil {
|
|
log.Printf("[INFO] Failed to delete disk: %v", err)
|
|
return err
|
|
}
|
|
|
|
log.Printf("[INFO] Deleted disk: %v", diskPath)
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
|
|
// createHardDisk creates a new Hard Disk.
|
|
func createHardDisk(client *govmomi.Client, size int, diskPath string, diskType string, adapterType string, dc string) error {
|
|
virtualDiskManager := object.NewVirtualDiskManager(client.Client)
|
|
spec := &types.FileBackedVirtualDiskSpec{
|
|
VirtualDiskSpec: types.VirtualDiskSpec{
|
|
AdapterType: adapterType,
|
|
DiskType: diskType,
|
|
},
|
|
CapacityKb: int64(1024 * 1024 * size),
|
|
}
|
|
datacenter, err := getDatacenter(client, dc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("[DEBUG] Disk spec: %v", spec)
|
|
|
|
task, err := virtualDiskManager.CreateVirtualDisk(context.TODO(), diskPath, datacenter, spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = task.WaitForResult(context.TODO(), nil)
|
|
if err != nil {
|
|
log.Printf("[INFO] Failed to create disk: %v", err)
|
|
return err
|
|
}
|
|
log.Printf("[INFO] Created disk.")
|
|
|
|
return nil
|
|
}
|