-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding volume resource creation to vSphere provider
Allows the user to create a vmdk in vSphere to the given path. In the future this could support updates for rename and move.
- Loading branch information
Showing
5 changed files
with
430 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
259 changes: 259 additions & 0 deletions
259
builtin/providers/vsphere/resource_vsphere_virtual_disk.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
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("") | ||
return err | ||
} | ||
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 | ||
} |
129 changes: 129 additions & 0 deletions
129
builtin/providers/vsphere/resource_vsphere_virtual_disk_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package vsphere | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
"github.com/vmware/govmomi" | ||
"github.com/vmware/govmomi/find" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
func TestAccVSphereVirtualDisk_basic(t *testing.T) { | ||
var datacenterOpt string | ||
var datastoreOpt string | ||
var initTypeOpt string | ||
var adapterTypeOpt string | ||
|
||
if v := os.Getenv("VSPHERE_DATACENTER"); v != "" { | ||
datacenterOpt = v | ||
} | ||
if v := os.Getenv("VSPHERE_DATASTORE"); v != "" { | ||
datastoreOpt = v | ||
} | ||
if v := os.Getenv("VSPHERE_INIT_TYPE"); v != "" { | ||
initTypeOpt += fmt.Sprintf(" type = \"%s\"\n", v) | ||
} | ||
if v := os.Getenv("VSPHERE_ADAPTER_TYPE"); v != "" { | ||
adapterTypeOpt += fmt.Sprintf(" adapter_type = \"%s\"\n", v) | ||
} | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckVSphereVirtualDiskDestroy, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ | ||
Config: fmt.Sprintf( | ||
testAccCheckVSphereVirtuaDiskConfig_basic, | ||
initTypeOpt, | ||
adapterTypeOpt, | ||
datacenterOpt, | ||
datastoreOpt, | ||
), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccVSphereVirtualDiskExists("vsphere_virtual_disk.foo"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccVSphereVirtualDiskExists(name string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[name] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", name) | ||
} | ||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("No ID is set") | ||
} | ||
|
||
client := testAccProvider.Meta().(*govmomi.Client) | ||
finder := find.NewFinder(client.Client, true) | ||
|
||
dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"]) | ||
if err != nil { | ||
return fmt.Errorf("error %s", err) | ||
} | ||
finder = finder.SetDatacenter(dc) | ||
|
||
ds, err := finder.Datastore(context.TODO(), rs.Primary.Attributes["datastore"]) | ||
if err != nil { | ||
return fmt.Errorf("error %s", err) | ||
} | ||
|
||
_, err = ds.Stat(context.TODO(), rs.Primary.Attributes["vmdk_path"]) | ||
if err != nil { | ||
return fmt.Errorf("error %s", err) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccCheckVSphereVirtualDiskDestroy(s *terraform.State) error { | ||
log.Printf("[FINDME] test Destroy") | ||
client := testAccProvider.Meta().(*govmomi.Client) | ||
finder := find.NewFinder(client.Client, true) | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "vsphere_virtual_disk" { | ||
continue | ||
} | ||
|
||
dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"]) | ||
if err != nil { | ||
return fmt.Errorf("error %s", err) | ||
} | ||
|
||
finder = finder.SetDatacenter(dc) | ||
|
||
ds, err := finder.Datastore(context.TODO(), rs.Primary.Attributes["datastore"]) | ||
if err != nil { | ||
return fmt.Errorf("error %s", err) | ||
} | ||
|
||
_, err = ds.Stat(context.TODO(), rs.Primary.Attributes["vmdk_path"]) | ||
if err == nil { | ||
return fmt.Errorf("error %s", err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
const testAccCheckVSphereVirtuaDiskConfig_basic = ` | ||
resource "vsphere_virtual_disk" "foo" { | ||
size = 1 | ||
vmdk_path = "tfTestDisk.vmdk" | ||
%s | ||
%s | ||
datacenter = "%s" | ||
datastore = "%s" | ||
} | ||
` |
Oops, something went wrong.