Add driver mocks and write tests to steps Remote Upload and Create VM (#9833)

This commit is contained in:
Sylvia Moss 2020-08-31 10:34:41 +02:00 committed by GitHub
parent cf622346ab
commit 942bfbf221
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 959 additions and 144 deletions

View File

@ -139,7 +139,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
}
artifact := &common.Artifact{
Name: b.config.VMName,
VM: state.Get("vm").(*driver.VirtualMachine),
VM: state.Get("vm").(*driver.VirtualMachineDriver),
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
}
if b.config.Export != nil {

View File

@ -67,7 +67,7 @@ type StepCloneVM struct {
func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
d := state.Get("driver").(*driver.Driver)
d := state.Get("driver").(*driver.VCenterDriver)
vmPath := path.Join(s.Location.Folder, s.Location.VMName)
err := d.PreCleanVM(ui, vmPath, s.Force)
@ -128,7 +128,7 @@ func (s *StepCloneVM) Cleanup(state multistep.StateBag) {
if st == nil {
return
}
vm := st.(*driver.VirtualMachine)
vm := st.(*driver.VirtualMachineDriver)
ui.Say("Destroying VM...")

View File

@ -123,7 +123,7 @@ func (c *CustomizeConfig) Prepare() []error {
}
func (s *StepCustomize) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
ui := state.Get("ui").(packer.Ui)
identity, err := s.identitySettings()

View File

@ -11,7 +11,7 @@ const BuilderId = "jetbrains.vsphere"
type Artifact struct {
Outconfig *OutputConfig
Name string
VM *driver.VirtualMachine
VM *driver.VirtualMachineDriver
// StateData should store data such as GeneratedData
// to be shared with post-processors

View File

@ -43,7 +43,7 @@ type StepBootCommand struct {
func (s *StepBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
debug := state.Get("debug").(bool)
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if s.Config.BootCommand == nil {
return multistep.ActionContinue

View File

@ -33,7 +33,7 @@ type StepConfigParams struct {
func (s *StepConfigParams) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
configParams := make(map[string]string)
if s.Config.ConfigParams != nil {

View File

@ -154,7 +154,7 @@ func (s *StepExport) Cleanup(multistep.StateBag) {
func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
ui.Message("Starting export...")
lease, err := vm.Export()

View File

@ -65,7 +65,7 @@ type StepConfigureHardware struct {
func (s *StepConfigureHardware) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if *s.Config != (HardwareConfig{}) {
ui.Say("Customizing hardware...")

View File

@ -118,7 +118,7 @@ type StepImportToContentLibrary struct {
func (s *StepImportToContentLibrary) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
var err error
if s.ContentLibConfig.Ovf {
@ -142,7 +142,7 @@ func (s *StepImportToContentLibrary) Run(_ context.Context, state multistep.Stat
return multistep.ActionContinue
}
func (s *StepImportToContentLibrary) importOvfTemplate(vm *driver.VirtualMachine) error {
func (s *StepImportToContentLibrary) importOvfTemplate(vm *driver.VirtualMachineDriver) error {
ovf := vcenter.OVF{
Spec: vcenter.CreateSpec{
Name: s.ContentLibConfig.Name,
@ -154,7 +154,7 @@ func (s *StepImportToContentLibrary) importOvfTemplate(vm *driver.VirtualMachine
return vm.ImportOvfToContentLibrary(ovf)
}
func (s *StepImportToContentLibrary) importVmTemplate(vm *driver.VirtualMachine) error {
func (s *StepImportToContentLibrary) importVmTemplate(vm *driver.VirtualMachineDriver) error {
template := vcenter.Template{
Name: s.ContentLibConfig.Name,
Description: s.ContentLibConfig.Description,

View File

@ -24,7 +24,7 @@ type StepRun struct {
func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if s.Config.BootOrder != "" {
ui.Say("Set boot order...")
@ -55,7 +55,7 @@ func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.Ste
func (s *StepRun) Cleanup(state multistep.StateBag) {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if s.Config.BootOrder == "" && s.SetOrder {
ui.Say("Clear boot order...")

View File

@ -48,7 +48,7 @@ type StepShutdown struct {
func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
comm := state.Get("communicator").(packer.Communicator)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if off, _ := vm.IsPoweredOff(); off {
// Probably power off initiated by last provisioner, though disable_shutdown is not set

View File

@ -14,7 +14,7 @@ type StepCreateSnapshot struct {
func (s *StepCreateSnapshot) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if s.CreateSnapshot {
ui.Say("Creating snapshot...")

View File

@ -81,7 +81,7 @@ func (s *StepSshKeyPair) Run(ctx context.Context, state multistep.StateBag) mult
s.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine
s.Comm.SSHClearAuthorizedKeys = true
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
err = vm.AddPublicKeys(ctx, string(s.Comm.SSHPublicKey))
if err != nil {
state.Put("error", fmt.Errorf("error saving temporary keypair in the vm: %s", err))

View File

@ -14,7 +14,7 @@ type StepConvertToTemplate struct {
func (s *StepConvertToTemplate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if s.ConvertToTemplate {
ui.Say("Convert VM into template...")

View File

@ -75,7 +75,7 @@ func (c *WaitIpConfig) GetIPNet() *net.IPNet {
func (s *StepWaitForIp) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
var ip string
var err error
@ -128,7 +128,7 @@ func (s *StepWaitForIp) Run(ctx context.Context, state multistep.StateBag) multi
}
}
func doGetIp(vm *driver.VirtualMachine, ctx context.Context, c *WaitIpConfig) (string, error) {
func doGetIp(vm *driver.VirtualMachineDriver, ctx context.Context, c *WaitIpConfig) (string, error) {
var prevIp = ""
var stopTime time.Time
var interval time.Duration

View File

@ -34,7 +34,7 @@ func RenderConfig(config map[string]interface{}) string {
return string(j)
}
func TestConn(t *testing.T) *driver.Driver {
func TestConn(t *testing.T) driver.Driver {
username := os.Getenv("VSPHERE_USERNAME")
if username == "" {
username = "root"
@ -56,7 +56,7 @@ func TestConn(t *testing.T) *driver.Driver {
return d
}
func GetVM(t *testing.T, d *driver.Driver, artifacts []packer.Artifact) *driver.VirtualMachine {
func GetVM(t *testing.T, d driver.Driver, artifacts []packer.Artifact) driver.VirtualMachine {
artifactRaw := artifacts[0]
artifact, _ := artifactRaw.(*common.Artifact)

View File

@ -3,11 +3,11 @@ package driver
import "github.com/vmware/govmomi/object"
type Cluster struct {
driver *Driver
driver *VCenterDriver
cluster *object.ClusterComputeResource
}
func (d *Driver) FindCluster(name string) (*Cluster, error) {
func (d *VCenterDriver) FindCluster(name string) (*Cluster, error) {
c, err := d.finder.ClusterComputeResource(d.ctx, name)
if err != nil {
return nil, err

View File

@ -13,20 +13,31 @@ import (
"github.com/vmware/govmomi/vim25/types"
)
type Datastore struct {
ds *object.Datastore
driver *Driver
type Datastore interface {
Info(params ...string) (*mo.Datastore, error)
FileExists(path string) bool
Name() string
ResolvePath(path string) string
UploadFile(src, dst, host string, setHost bool) error
Delete(path string) error
MakeDirectory(path string) error
Reference() types.ManagedObjectReference
}
func (d *Driver) NewDatastore(ref *types.ManagedObjectReference) *Datastore {
return &Datastore{
type DatastoreDriver struct {
ds *object.Datastore
driver *VCenterDriver
}
func (d *VCenterDriver) NewDatastore(ref *types.ManagedObjectReference) Datastore {
return &DatastoreDriver{
ds: object.NewDatastore(d.client.Client, *ref),
driver: d,
}
}
// If name is an empty string, then resolve host's one
func (d *Driver) FindDatastore(name string, host string) (*Datastore, error) {
func (d *VCenterDriver) FindDatastore(name string, host string) (Datastore, error) {
if name == "" {
h, err := d.FindHost(host)
if err != nil {
@ -55,13 +66,13 @@ func (d *Driver) FindDatastore(name string, host string) (*Datastore, error) {
return nil, err
}
return &Datastore{
return &DatastoreDriver{
ds: ds,
driver: d,
}, nil
}
func (d *Driver) GetDatastoreName(id string) (string, error) {
func (d *VCenterDriver) GetDatastoreName(id string) (string, error) {
obj := types.ManagedObjectReference{
Type: "Datastore",
Value: id,
@ -76,7 +87,7 @@ func (d *Driver) GetDatastoreName(id string) (string, error) {
return me.Name, nil
}
func (ds *Datastore) Info(params ...string) (*mo.Datastore, error) {
func (ds *DatastoreDriver) Info(params ...string) (*mo.Datastore, error) {
var p []string
if len(params) == 0 {
p = []string{"*"}
@ -91,21 +102,25 @@ func (ds *Datastore) Info(params ...string) (*mo.Datastore, error) {
return &info, nil
}
func (ds *Datastore) FileExists(path string) bool {
func (ds *DatastoreDriver) FileExists(path string) bool {
_, err := ds.ds.Stat(ds.driver.ctx, path)
return err == nil
}
func (ds *Datastore) Name() string {
func (ds *DatastoreDriver) Name() string {
return ds.ds.Name()
}
func (ds *Datastore) ResolvePath(path string) string {
func (ds *DatastoreDriver) Reference() types.ManagedObjectReference {
return ds.ds.Reference()
}
func (ds *DatastoreDriver) ResolvePath(path string) string {
return ds.ds.Path(path)
}
// The file ID isn't available via the API, so we use DatastoreBrowser to search
func (d *Driver) GetDatastoreFilePath(datastoreID, dir, filename string) (string, error) {
func (d *VCenterDriver) GetDatastoreFilePath(datastoreID, dir, filename string) (string, error) {
ref := types.ManagedObjectReference{Type: "Datastore", Value: datastoreID}
ds := object.NewDatastore(d.vimClient, ref)
@ -140,11 +155,11 @@ func (d *Driver) GetDatastoreFilePath(datastoreID, dir, filename string) (string
return res.File[0].GetFileInfo().Path, nil
}
func (ds *Datastore) UploadFile(src, dst, host string, set_host_for_datastore_uploads bool) error {
func (ds *DatastoreDriver) UploadFile(src, dst, host string, setHost bool) error {
p := soap.DefaultUpload
ctx := ds.driver.ctx
if set_host_for_datastore_uploads && host != "" {
if setHost && host != "" {
h, err := ds.driver.FindHost(host)
if err != nil {
return err
@ -155,7 +170,7 @@ func (ds *Datastore) UploadFile(src, dst, host string, set_host_for_datastore_up
return ds.ds.UploadFile(ctx, src, dst, &p)
}
func (ds *Datastore) Delete(path string) error {
func (ds *DatastoreDriver) Delete(path string) error {
dc, err := ds.driver.finder.Datacenter(ds.driver.ctx, ds.ds.DatacenterPath)
if err != nil {
return err
@ -164,7 +179,7 @@ func (ds *Datastore) Delete(path string) error {
return fm.Delete(ds.driver.ctx, path)
}
func (ds *Datastore) MakeDirectory(path string) error {
func (ds *DatastoreDriver) MakeDirectory(path string) error {
dc, err := ds.driver.finder.Datacenter(ds.driver.ctx, ds.ds.DatacenterPath)
if err != nil {
return err

View File

@ -0,0 +1,47 @@
package driver
import (
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type DatastoreMock struct {
FileExistsCalled bool
MakeDirectoryCalled bool
UploadFileCalled bool
}
func (ds *DatastoreMock) Info(params ...string) (*mo.Datastore, error) {
return nil, nil
}
func (ds *DatastoreMock) FileExists(path string) bool {
ds.FileExistsCalled = true
return false
}
func (ds *DatastoreMock) Name() string {
return "datastore-mock"
}
func (ds *DatastoreMock) Reference() types.ManagedObjectReference {
return types.ManagedObjectReference{}
}
func (ds *DatastoreMock) ResolvePath(path string) string {
return ""
}
func (ds *DatastoreMock) UploadFile(src, dst, host string, setHost bool) error {
ds.UploadFileCalled = true
return nil
}
func (ds *DatastoreMock) Delete(path string) error {
return nil
}
func (ds *DatastoreMock) MakeDirectory(path string) error {
ds.MakeDirectoryCalled = true
return nil
}

View File

@ -6,16 +6,46 @@ import (
"net/url"
"time"
"github.com/hashicorp/packer/packer"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/vapi/library"
"github.com/vmware/govmomi/vapi/rest"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
)
type Driver struct {
type Driver interface {
NewVM(ref *types.ManagedObjectReference) VirtualMachine
FindVM(name string) (VirtualMachine, error)
FindCluster(name string) (*Cluster, error)
PreCleanVM(ui packer.Ui, vmPath string, force bool) error
CreateVM(config *CreateConfig) (VirtualMachine, error)
NewDatastore(ref *types.ManagedObjectReference) Datastore
FindDatastore(name string, host string) (Datastore, error)
GetDatastoreName(id string) (string, error)
GetDatastoreFilePath(datastoreID, dir, filename string) (string, error)
NewFolder(ref *types.ManagedObjectReference) *Folder
FindFolder(name string) (*Folder, error)
NewHost(ref *types.ManagedObjectReference) *Host
FindHost(name string) (*Host, error)
NewNetwork(ref *types.ManagedObjectReference) *Network
FindNetwork(name string) (*Network, error)
FindNetworks(name string) ([]*Network, error)
NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool
FindResourcePool(cluster string, host string, name string) (*ResourcePool, error)
FindContentLibraryByName(name string) (*Library, error)
FindContentLibraryItem(libraryId string, name string) (*library.Item, error)
FindContentLibraryFileDatastorePath(isoPath string) (string, error)
}
type VCenterDriver struct {
// context that controls the authenticated sessions used to run the VM commands
ctx context.Context
client *govmomi.Client
@ -33,7 +63,7 @@ type ConnectConfig struct {
Datacenter string
}
func NewDriver(config *ConnectConfig) (*Driver, error) {
func NewDriver(config *ConnectConfig) (Driver, error) {
ctx := context.TODO()
vcenterUrl, err := url.Parse(fmt.Sprintf("https://%v/sdk", config.VCenterServer))
@ -67,7 +97,8 @@ func NewDriver(config *ConnectConfig) (*Driver, error) {
}
finder.SetDatacenter(datacenter)
d := Driver{
var d Driver
d = &VCenterDriver{
ctx: ctx,
client: client,
vimClient: vimClient,
@ -78,7 +109,7 @@ func NewDriver(config *ConnectConfig) (*Driver, error) {
datacenter: datacenter,
finder: finder,
}
return &d, nil
return d, nil
}
// The rest.Client requires vCenter.

View File

@ -0,0 +1,106 @@
package driver
import (
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/vmware/govmomi/vapi/library"
"github.com/vmware/govmomi/vim25/types"
)
type DriverMock struct {
FindDatastoreCalled bool
DatastoreMock *DatastoreMock
PreCleanShouldFail bool
PreCleanVMCalled bool
PreCleanForce bool
PreCleanVMPath string
CreateVMShouldFail bool
CreateVMCalled bool
CreateConfig *CreateConfig
VM VirtualMachine
}
func NewDriverMock() *DriverMock {
return new(DriverMock)
}
func (d *DriverMock) FindDatastore(name string, host string) (Datastore, error) {
d.FindDatastoreCalled = true
if d.DatastoreMock == nil {
d.DatastoreMock = new(DatastoreMock)
}
return d.DatastoreMock, nil
}
func (d *DriverMock) NewVM(ref *types.ManagedObjectReference) VirtualMachine {
return nil
}
func (d *DriverMock) FindVM(name string) (VirtualMachine, error) {
return nil, nil
}
func (d *DriverMock) FindCluster(name string) (*Cluster, error) {
return nil, nil
}
func (d *DriverMock) PreCleanVM(ui packer.Ui, vmPath string, force bool) error {
d.PreCleanVMCalled = true
if d.PreCleanShouldFail {
return fmt.Errorf("pre clean failed")
}
d.PreCleanForce = true
d.PreCleanVMPath = vmPath
return nil
}
func (d *DriverMock) CreateVM(config *CreateConfig) (VirtualMachine, error) {
d.CreateVMCalled = true
if d.CreateVMShouldFail {
return nil, fmt.Errorf("create vm failed")
}
d.CreateConfig = config
d.VM = new(VirtualMachineDriver)
return d.VM, nil
}
func (d *DriverMock) NewDatastore(ref *types.ManagedObjectReference) Datastore { return nil }
func (d *DriverMock) GetDatastoreName(id string) (string, error) { return "", nil }
func (d *DriverMock) GetDatastoreFilePath(datastoreID, dir, filename string) (string, error) {
return "", nil
}
func (d *DriverMock) NewFolder(ref *types.ManagedObjectReference) *Folder { return nil }
func (d *DriverMock) FindFolder(name string) (*Folder, error) { return nil, nil }
func (d *DriverMock) NewHost(ref *types.ManagedObjectReference) *Host { return nil }
func (d *DriverMock) FindHost(name string) (*Host, error) { return nil, nil }
func (d *DriverMock) NewNetwork(ref *types.ManagedObjectReference) *Network { return nil }
func (d *DriverMock) FindNetwork(name string) (*Network, error) { return nil, nil }
func (d *DriverMock) FindNetworks(name string) ([]*Network, error) { return nil, nil }
func (d *DriverMock) NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool { return nil }
func (d *DriverMock) FindResourcePool(cluster string, host string, name string) (*ResourcePool, error) {
return nil, nil
}
func (d *DriverMock) FindContentLibraryByName(name string) (*Library, error) { return nil, nil }
func (d *DriverMock) FindContentLibraryItem(libraryId string, name string) (*library.Item, error) {
return nil, nil
}
func (d *DriverMock) FindContentLibraryFileDatastorePath(isoPath string) (string, error) {
return "", nil
}

View File

@ -11,7 +11,7 @@ import (
// Defines whether acceptance tests should be run
const TestHostName = "esxi-1.vsphere65.test"
func newTestDriver(t *testing.T) *Driver {
func newTestDriver(t *testing.T) Driver {
username := os.Getenv("VSPHERE_USERNAME")
if username == "" {
username = "root"

View File

@ -12,18 +12,18 @@ import (
)
type Folder struct {
driver *Driver
driver *VCenterDriver
folder *object.Folder
}
func (d *Driver) NewFolder(ref *types.ManagedObjectReference) *Folder {
func (d *VCenterDriver) NewFolder(ref *types.ManagedObjectReference) *Folder {
return &Folder{
folder: object.NewFolder(d.client.Client, *ref),
driver: d,
}
}
func (d *Driver) FindFolder(name string) (*Folder, error) {
func (d *VCenterDriver) FindFolder(name string) (*Folder, error) {
if name != "" {
// create folders if they don't exist
parent := ""

View File

@ -7,18 +7,18 @@ import (
)
type Host struct {
driver *Driver
driver *VCenterDriver
host *object.HostSystem
}
func (d *Driver) NewHost(ref *types.ManagedObjectReference) *Host {
func (d *VCenterDriver) NewHost(ref *types.ManagedObjectReference) *Host {
return &Host{
host: object.NewHostSystem(d.client.Client, *ref),
driver: d,
}
}
func (d *Driver) FindHost(name string) (*Host, error) {
func (d *VCenterDriver) FindHost(name string) (*Host, error) {
h, err := d.finder.HostSystem(d.ctx, name)
if err != nil {
return nil, err

View File

@ -10,11 +10,11 @@ import (
)
type Library struct {
driver *Driver
driver *VCenterDriver
library *library.Library
}
func (d *Driver) FindContentLibraryByName(name string) (*Library, error) {
func (d *VCenterDriver) FindContentLibraryByName(name string) (*Library, error) {
lm := library.NewManager(d.restClient.client)
l, err := lm.GetLibraryByName(d.ctx, name)
if err != nil {
@ -26,7 +26,7 @@ func (d *Driver) FindContentLibraryByName(name string) (*Library, error) {
}, nil
}
func (d *Driver) FindContentLibraryItem(libraryId string, name string) (*library.Item, error) {
func (d *VCenterDriver) FindContentLibraryItem(libraryId string, name string) (*library.Item, error) {
lm := library.NewManager(d.restClient.client)
items, err := lm.GetLibraryItems(d.ctx, libraryId)
if err != nil {
@ -40,7 +40,7 @@ func (d *Driver) FindContentLibraryItem(libraryId string, name string) (*library
return nil, fmt.Errorf("Item %s not found", name)
}
func (d *Driver) FindContentLibraryFileDatastorePath(isoPath string) (string, error) {
func (d *VCenterDriver) FindContentLibraryFileDatastorePath(isoPath string) (string, error) {
log.Printf("Check if ISO path is a Content Library path")
err := d.restClient.Login(d.ctx)
if err != nil {

View File

@ -9,18 +9,18 @@ import (
)
type Network struct {
driver *Driver
driver *VCenterDriver
network object.NetworkReference
}
func (d *Driver) NewNetwork(ref *types.ManagedObjectReference) *Network {
func (d *VCenterDriver) NewNetwork(ref *types.ManagedObjectReference) *Network {
return &Network{
network: object.NewNetwork(d.client.Client, *ref),
driver: d,
}
}
func (d *Driver) FindNetwork(name string) (*Network, error) {
func (d *VCenterDriver) FindNetwork(name string) (*Network, error) {
n, err := d.finder.Network(d.ctx, name)
if err != nil {
return nil, err
@ -31,7 +31,7 @@ func (d *Driver) FindNetwork(name string) (*Network, error) {
}, nil
}
func (d *Driver) FindNetworks(name string) ([]*Network, error) {
func (d *VCenterDriver) FindNetworks(name string) ([]*Network, error) {
ns, err := d.finder.NetworkList(d.ctx, name)
if err != nil {
return nil, err

View File

@ -10,17 +10,17 @@ import (
type ResourcePool struct {
pool *object.ResourcePool
driver *Driver
driver *VCenterDriver
}
func (d *Driver) NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool {
func (d *VCenterDriver) NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool {
return &ResourcePool{
pool: object.NewResourcePool(d.client.Client, *ref),
driver: d,
}
}
func (d *Driver) FindResourcePool(cluster string, host string, name string) (*ResourcePool, error) {
func (d *VCenterDriver) FindResourcePool(cluster string, host string, name string) (*ResourcePool, error) {
var res string
if cluster != "" {
res = cluster

View File

@ -21,9 +21,43 @@ import (
"github.com/vmware/govmomi/vim25/types"
)
type VirtualMachine struct {
type VirtualMachine interface {
Info(params ...string) (*mo.VirtualMachine, error)
Devices() (object.VirtualDeviceList, error)
Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error)
updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error)
AddPublicKeys(ctx context.Context, publicKeys string) error
Properties(ctx context.Context) (*mo.VirtualMachine, error)
Destroy() error
Configure(config *HardwareConfig) error
Customize(spec types.CustomizationSpec) error
ResizeDisk(diskSize int64) error
PowerOn() error
WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error)
PowerOff() error
IsPoweredOff() (bool, error)
StartShutdown() error
WaitForShutdown(ctx context.Context, timeout time.Duration) error
CreateSnapshot(name string) error
ConvertToTemplate() error
ImportOvfToContentLibrary(ovf vcenter.OVF) error
ImportToContentLibrary(template vcenter.Template) error
GetDir() (string, error)
AddCdrom(controllerType string, datastoreIsoPath string) error
AddFloppy(imgPath string) error
SetBootOrder(order []string) error
RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error
addDevice(device types.BaseVirtualDevice) error
AddConfigParams(params map[string]string, info *types.ToolsConfigInfo) error
Export() (*nfc.Lease, error)
CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error)
NewOvfManager() *ovf.Manager
GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error)
}
type VirtualMachineDriver struct {
vm *object.VirtualMachine
driver *Driver
driver *VCenterDriver
}
type CloneConfig struct {
@ -87,25 +121,25 @@ type Disk struct {
ControllerIndex int
}
func (d *Driver) NewVM(ref *types.ManagedObjectReference) *VirtualMachine {
return &VirtualMachine{
func (d *VCenterDriver) NewVM(ref *types.ManagedObjectReference) VirtualMachine {
return &VirtualMachineDriver{
vm: object.NewVirtualMachine(d.client.Client, *ref),
driver: d,
}
}
func (d *Driver) FindVM(name string) (*VirtualMachine, error) {
func (d *VCenterDriver) FindVM(name string) (VirtualMachine, error) {
vm, err := d.finder.VirtualMachine(d.ctx, name)
if err != nil {
return nil, err
}
return &VirtualMachine{
return &VirtualMachineDriver{
vm: vm,
driver: d,
}, nil
}
func (d *Driver) PreCleanVM(ui packer.Ui, vmPath string, force bool) error {
func (d *VCenterDriver) PreCleanVM(ui packer.Ui, vmPath string, force bool) error {
vm, err := d.FindVM(vmPath)
if err != nil {
if _, ok := err.(*find.NotFoundError); !ok {
@ -130,7 +164,7 @@ func (d *Driver) PreCleanVM(ui packer.Ui, vmPath string, force bool) error {
return nil
}
func (d *Driver) CreateVM(config *CreateConfig) (*VirtualMachine, error) {
func (d *VCenterDriver) CreateVM(config *CreateConfig) (VirtualMachine, error) {
createSpec := types.VirtualMachineConfigSpec{
Name: config.Name,
Annotation: config.Annotation,
@ -219,7 +253,7 @@ func (d *Driver) CreateVM(config *CreateConfig) (*VirtualMachine, error) {
return d.NewVM(&vmRef), nil
}
func (vm *VirtualMachine) Info(params ...string) (*mo.VirtualMachine, error) {
func (vm *VirtualMachineDriver) Info(params ...string) (*mo.VirtualMachine, error) {
var p []string
if len(params) == 0 {
p = []string{"*"}
@ -234,7 +268,7 @@ func (vm *VirtualMachine) Info(params ...string) (*mo.VirtualMachine, error) {
return &info, nil
}
func (vm *VirtualMachine) Devices() (object.VirtualDeviceList, error) {
func (vm *VirtualMachineDriver) Devices() (object.VirtualDeviceList, error) {
vmInfo, err := vm.Info("config.hardware.device")
if err != nil {
return nil, err
@ -243,7 +277,7 @@ func (vm *VirtualMachine) Devices() (object.VirtualDeviceList, error) {
return vmInfo.Config.Hardware.Device, nil
}
func (vm *VirtualMachine) Clone(ctx context.Context, config *CloneConfig) (*VirtualMachine, error) {
func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) {
folder, err := vm.driver.FindFolder(config.Folder)
if err != nil {
return nil, err
@ -262,7 +296,7 @@ func (vm *VirtualMachine) Clone(ctx context.Context, config *CloneConfig) (*Virt
if err != nil {
return nil, err
}
datastoreRef := datastore.ds.Reference()
datastoreRef := datastore.Reference()
relocateSpec.Datastore = &datastoreRef
var cloneSpec types.VirtualMachineCloneSpec
@ -350,7 +384,7 @@ func (vm *VirtualMachine) Clone(ctx context.Context, config *CloneConfig) (*Virt
return created, nil
}
func (vm *VirtualMachine) updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error) {
func (vm *VirtualMachineDriver) updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error) {
if len(newProps) == 0 {
return nil, nil
}
@ -398,7 +432,7 @@ func (vm *VirtualMachine) updateVAppConfig(ctx context.Context, newProps map[str
}, nil
}
func (vm *VirtualMachine) AddPublicKeys(ctx context.Context, publicKeys string) error {
func (vm *VirtualMachineDriver) AddPublicKeys(ctx context.Context, publicKeys string) error {
newProps := map[string]string{"public-keys": publicKeys}
config, err := vm.updateVAppConfig(ctx, newProps)
if err != nil {
@ -415,7 +449,7 @@ func (vm *VirtualMachine) AddPublicKeys(ctx context.Context, publicKeys string)
return err
}
func (vm *VirtualMachine) Properties(ctx context.Context) (*mo.VirtualMachine, error) {
func (vm *VirtualMachineDriver) Properties(ctx context.Context) (*mo.VirtualMachine, error) {
log.Printf("fetching properties for VM %q", vm.vm.InventoryPath)
var props mo.VirtualMachine
if err := vm.vm.Properties(ctx, vm.vm.Reference(), nil, &props); err != nil {
@ -424,7 +458,7 @@ func (vm *VirtualMachine) Properties(ctx context.Context) (*mo.VirtualMachine, e
return &props, nil
}
func (vm *VirtualMachine) Destroy() error {
func (vm *VirtualMachineDriver) Destroy() error {
task, err := vm.vm.Destroy(vm.driver.ctx)
if err != nil {
return err
@ -433,7 +467,7 @@ func (vm *VirtualMachine) Destroy() error {
return err
}
func (vm *VirtualMachine) Configure(config *HardwareConfig) error {
func (vm *VirtualMachineDriver) Configure(config *HardwareConfig) error {
var confSpec types.VirtualMachineConfigSpec
confSpec.NumCPUs = config.CPUs
confSpec.NumCoresPerSocket = config.CpuCores
@ -524,7 +558,7 @@ func (vm *VirtualMachine) Configure(config *HardwareConfig) error {
return err
}
func (vm *VirtualMachine) Customize(spec types.CustomizationSpec) error {
func (vm *VirtualMachineDriver) Customize(spec types.CustomizationSpec) error {
task, err := vm.vm.Customize(vm.driver.ctx, spec)
if err != nil {
return err
@ -532,7 +566,7 @@ func (vm *VirtualMachine) Customize(spec types.CustomizationSpec) error {
return task.Wait(vm.driver.ctx)
}
func (vm *VirtualMachine) ResizeDisk(diskSize int64) error {
func (vm *VirtualMachineDriver) ResizeDisk(diskSize int64) error {
var confSpec types.VirtualMachineConfigSpec
devices, err := vm.vm.Device(vm.driver.ctx)
@ -581,7 +615,7 @@ func findDisk(devices object.VirtualDeviceList) (*types.VirtualDisk, error) {
return nil, errors.New("VM has multiple disks")
}
func (vm *VirtualMachine) PowerOn() error {
func (vm *VirtualMachineDriver) PowerOn() error {
task, err := vm.vm.PowerOn(vm.driver.ctx)
if err != nil {
return err
@ -590,7 +624,7 @@ func (vm *VirtualMachine) PowerOn() error {
return err
}
func (vm *VirtualMachine) WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error) {
func (vm *VirtualMachineDriver) WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error) {
netIP, err := vm.vm.WaitForNetIP(ctx, false)
if err != nil {
return "", err
@ -614,7 +648,7 @@ func (vm *VirtualMachine) WaitForIP(ctx context.Context, ipNet *net.IPNet) (stri
return "", fmt.Errorf("unable to find an IP")
}
func (vm *VirtualMachine) PowerOff() error {
func (vm *VirtualMachineDriver) PowerOff() error {
state, err := vm.vm.PowerState(vm.driver.ctx)
if err != nil {
return err
@ -632,7 +666,7 @@ func (vm *VirtualMachine) PowerOff() error {
return err
}
func (vm *VirtualMachine) IsPoweredOff() (bool, error) {
func (vm *VirtualMachineDriver) IsPoweredOff() (bool, error) {
state, err := vm.vm.PowerState(vm.driver.ctx)
if err != nil {
return false, err
@ -641,12 +675,12 @@ func (vm *VirtualMachine) IsPoweredOff() (bool, error) {
return state == types.VirtualMachinePowerStatePoweredOff, nil
}
func (vm *VirtualMachine) StartShutdown() error {
func (vm *VirtualMachineDriver) StartShutdown() error {
err := vm.vm.ShutdownGuest(vm.driver.ctx)
return err
}
func (vm *VirtualMachine) WaitForShutdown(ctx context.Context, timeout time.Duration) error {
func (vm *VirtualMachineDriver) WaitForShutdown(ctx context.Context, timeout time.Duration) error {
shutdownTimer := time.After(timeout)
for {
off, err := vm.IsPoweredOff()
@ -670,7 +704,7 @@ func (vm *VirtualMachine) WaitForShutdown(ctx context.Context, timeout time.Dura
return nil
}
func (vm *VirtualMachine) CreateSnapshot(name string) error {
func (vm *VirtualMachineDriver) CreateSnapshot(name string) error {
task, err := vm.vm.CreateSnapshot(vm.driver.ctx, name, "", false, false)
if err != nil {
return err
@ -679,11 +713,11 @@ func (vm *VirtualMachine) CreateSnapshot(name string) error {
return err
}
func (vm *VirtualMachine) ConvertToTemplate() error {
func (vm *VirtualMachineDriver) ConvertToTemplate() error {
return vm.vm.MarkAsTemplate(vm.driver.ctx)
}
func (vm *VirtualMachine) ImportOvfToContentLibrary(ovf vcenter.OVF) error {
func (vm *VirtualMachineDriver) ImportOvfToContentLibrary(ovf vcenter.OVF) error {
err := vm.driver.restClient.Login(vm.driver.ctx)
if err != nil {
return err
@ -717,7 +751,7 @@ func (vm *VirtualMachine) ImportOvfToContentLibrary(ovf vcenter.OVF) error {
return vm.driver.restClient.Logout(vm.driver.ctx)
}
func (vm *VirtualMachine) ImportToContentLibrary(template vcenter.Template) error {
func (vm *VirtualMachineDriver) ImportToContentLibrary(template vcenter.Template) error {
err := vm.driver.restClient.Login(vm.driver.ctx)
if err != nil {
return err
@ -769,7 +803,7 @@ func (vm *VirtualMachine) ImportToContentLibrary(template vcenter.Template) erro
if err != nil {
return err
}
template.VMHomeStorage.Datastore = d.ds.Reference().Value
template.VMHomeStorage.Datastore = d.Reference().Value
}
vcm := vcenter.NewManager(vm.driver.restClient.client)
@ -781,7 +815,7 @@ func (vm *VirtualMachine) ImportToContentLibrary(template vcenter.Template) erro
return vm.driver.restClient.Logout(vm.driver.ctx)
}
func (vm *VirtualMachine) GetDir() (string, error) {
func (vm *VirtualMachineDriver) GetDir() (string, error) {
vmInfo, err := vm.Info("name", "layoutEx.file")
if err != nil {
return "", err
@ -789,14 +823,14 @@ func (vm *VirtualMachine) GetDir() (string, error) {
vmxName := fmt.Sprintf("/%s.vmx", vmInfo.Name)
for _, file := range vmInfo.LayoutEx.File {
if strings.HasSuffix(file.Name, vmxName) {
if strings.Contains(file.Name, vmInfo.Name) {
return RemoveDatastorePrefix(file.Name[:len(file.Name)-len(vmxName)]), nil
}
}
return "", fmt.Errorf("cannot find '%s'", vmxName)
}
func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
func addDisk(_ *VCenterDriver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
if len(config.Storage) == 0 {
return nil, errors.New("no storage devices have been defined")
}
@ -839,7 +873,7 @@ func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig)
return devices, nil
}
func addNetwork(d *Driver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
func addNetwork(d *VCenterDriver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
if len(config.NICs) == 0 {
return nil, errors.New("no network adapters have been defined")
}
@ -872,7 +906,7 @@ func addNetwork(d *Driver, devices object.VirtualDeviceList, config *CreateConfi
return devices, nil
}
func findNetwork(network string, host string, d *Driver) (object.NetworkReference, error) {
func findNetwork(network string, host string, d *VCenterDriver) (object.NetworkReference, error) {
if network != "" {
var err error
networks, err := d.FindNetworks(network)
@ -941,7 +975,7 @@ func newVGPUProfile(vGPUProfile string) types.VirtualPCIPassthrough {
}
}
func (vm *VirtualMachine) AddCdrom(controllerType string, datastoreIsoPath string) error {
func (vm *VirtualMachineDriver) AddCdrom(controllerType string, datastoreIsoPath string) error {
devices, err := vm.vm.Device(vm.driver.ctx)
if err != nil {
return err
@ -985,7 +1019,7 @@ func (vm *VirtualMachine) AddCdrom(controllerType string, datastoreIsoPath strin
return vm.addDevice(cdrom)
}
func (vm *VirtualMachine) AddFloppy(imgPath string) error {
func (vm *VirtualMachineDriver) AddFloppy(imgPath string) error {
devices, err := vm.vm.Device(vm.driver.ctx)
if err != nil {
return err
@ -1003,7 +1037,7 @@ func (vm *VirtualMachine) AddFloppy(imgPath string) error {
return vm.addDevice(floppy)
}
func (vm *VirtualMachine) SetBootOrder(order []string) error {
func (vm *VirtualMachineDriver) SetBootOrder(order []string) error {
devices, err := vm.vm.Device(vm.driver.ctx)
if err != nil {
return err
@ -1016,11 +1050,11 @@ func (vm *VirtualMachine) SetBootOrder(order []string) error {
return vm.vm.SetBootOptions(vm.driver.ctx, &bootOptions)
}
func (vm *VirtualMachine) RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error {
func (vm *VirtualMachineDriver) RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error {
return vm.vm.RemoveDevice(vm.driver.ctx, keepFiles, device...)
}
func (vm *VirtualMachine) addDevice(device types.BaseVirtualDevice) error {
func (vm *VirtualMachineDriver) addDevice(device types.BaseVirtualDevice) error {
newDevices := object.VirtualDeviceList{device}
confSpec := types.VirtualMachineConfigSpec{}
var err error
@ -1038,7 +1072,7 @@ func (vm *VirtualMachine) addDevice(device types.BaseVirtualDevice) error {
return err
}
func (vm *VirtualMachine) AddConfigParams(params map[string]string, info *types.ToolsConfigInfo) error {
func (vm *VirtualMachineDriver) AddConfigParams(params map[string]string, info *types.ToolsConfigInfo) error {
var confSpec types.VirtualMachineConfigSpec
var ov []types.BaseOptionValue
@ -1066,19 +1100,19 @@ func (vm *VirtualMachine) AddConfigParams(params map[string]string, info *types.
return nil
}
func (vm *VirtualMachine) Export() (*nfc.Lease, error) {
func (vm *VirtualMachineDriver) Export() (*nfc.Lease, error) {
return vm.vm.Export(vm.driver.ctx)
}
func (vm *VirtualMachine) CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) {
func (vm *VirtualMachineDriver) CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) {
return m.CreateDescriptor(vm.driver.ctx, vm.vm, cdp)
}
func (vm *VirtualMachine) NewOvfManager() *ovf.Manager {
func (vm *VirtualMachineDriver) NewOvfManager() *ovf.Manager {
return ovf.NewManager(vm.vm.Client())
}
func (vm *VirtualMachine) GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error) {
func (vm *VirtualMachineDriver) GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error) {
var mgr mo.OvfManager
err := property.DefaultCollector(vm.vm.Client()).RetrieveOne(vm.driver.ctx, m.Reference(), nil, &mgr)
if err != nil {

View File

@ -10,12 +10,12 @@ var (
ErrNoSataController = errors.New("no available SATA controller")
)
func (vm *VirtualMachine) AddSATAController() error {
func (vm *VirtualMachineDriver) AddSATAController() error {
sata := &types.VirtualAHCIController{}
return vm.addDevice(sata)
}
func (vm *VirtualMachine) FindSATAController() (*types.VirtualAHCIController, error) {
func (vm *VirtualMachineDriver) FindSATAController() (*types.VirtualAHCIController, error) {
l, err := vm.Devices()
if err != nil {
return nil, err
@ -29,7 +29,7 @@ func (vm *VirtualMachine) FindSATAController() (*types.VirtualAHCIController, er
return c.(*types.VirtualAHCIController), nil
}
func (vm *VirtualMachine) CreateCdrom(c *types.VirtualController) (*types.VirtualCdrom, error) {
func (vm *VirtualMachineDriver) CreateCdrom(c *types.VirtualController) (*types.VirtualCdrom, error) {
l, err := vm.Devices()
if err != nil {
return nil, err
@ -52,7 +52,7 @@ func (vm *VirtualMachine) CreateCdrom(c *types.VirtualController) (*types.Virtua
return device, nil
}
func (vm *VirtualMachine) RemoveCdroms() error {
func (vm *VirtualMachineDriver) RemoveCdroms() error {
devices, err := vm.Devices()
if err != nil {
return err
@ -69,7 +69,7 @@ func (vm *VirtualMachine) RemoveCdroms() error {
return nil
}
func (vm *VirtualMachine) EjectCdroms() error {
func (vm *VirtualMachineDriver) EjectCdroms() error {
devices, err := vm.Devices()
if err != nil {
return err

View File

@ -13,7 +13,7 @@ func TestVMAcc_clone(t *testing.T) {
testCases := []struct {
name string
config *CloneConfig
checkFunction func(*testing.T, *VirtualMachine, *CloneConfig)
checkFunction func(*testing.T, VirtualMachine, *CloneConfig)
}{
{"Default", &CloneConfig{}, cloneDefaultCheck},
{"LinkedClone", &CloneConfig{LinkedClone: true}, cloneLinkedCloneCheck},
@ -53,8 +53,8 @@ func TestVMAcc_clone(t *testing.T) {
}
}
func cloneDefaultCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
d := vm.driver
func cloneDefaultCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
d := vm.(*VirtualMachineDriver).driver
// Check that the clone can be found by its name
if _, err := d.FindVM(config.Name); err != nil {
@ -112,7 +112,7 @@ func cloneDefaultCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
}
}
func configureCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfig) {
func configureCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
log.Printf("[DEBUG] Configuring the vm")
hwConfig := &HardwareConfig{
CPUs: 2,
@ -170,7 +170,7 @@ func configureCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfig) {
}
}
func configureRAMReserveAllCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfig) {
func configureRAMReserveAllCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
log.Printf("[DEBUG] Configuring the vm")
err := vm.Configure(&HardwareConfig{RAMReserveAll: true})
if err != nil {
@ -188,7 +188,7 @@ func configureRAMReserveAllCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfi
}
}
func cloneLinkedCloneCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfig) {
func cloneLinkedCloneCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
vmInfo, err := vm.Info("layoutEx.disk")
if err != nil {
t.Fatalf("Cannot read VM properties: %v", err)
@ -199,13 +199,13 @@ func cloneLinkedCloneCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfig) {
}
}
func cloneFolderCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
func cloneFolderCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
vmInfo, err := vm.Info("parent")
if err != nil {
t.Fatalf("Cannot read VM properties: %v", err)
}
f := vm.driver.NewFolder(vmInfo.Parent)
f := vm.(*VirtualMachineDriver).driver.NewFolder(vmInfo.Parent)
path, err := f.Path()
if err != nil {
t.Fatalf("Cannot read folder name: %v", err)
@ -215,13 +215,13 @@ func cloneFolderCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
}
}
func cloneResourcePoolCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
func cloneResourcePoolCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
vmInfo, err := vm.Info("resourcePool")
if err != nil {
t.Fatalf("Cannot read VM properties: %v", err)
}
p := vm.driver.NewResourcePool(vmInfo.ResourcePool)
p := vm.(*VirtualMachineDriver).driver.NewResourcePool(vmInfo.ResourcePool)
path, err := p.Path()
if err != nil {
t.Fatalf("Cannot read resource pool name: %v", err)
@ -231,7 +231,7 @@ func cloneResourcePoolCheck(t *testing.T, vm *VirtualMachine, config *CloneConfi
}
}
func startAndStopCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
func startAndStopCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
stopper := startVM(t, vm, config.Name)
defer stopper()
@ -253,7 +253,7 @@ func startAndStopCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
}
}
func snapshotCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
func snapshotCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
stopper := startVM(t, vm, config.Name)
defer stopper()
@ -273,7 +273,7 @@ func snapshotCheck(t *testing.T, vm *VirtualMachine, config *CloneConfig) {
}
}
func templateCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfig) {
func templateCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
err := vm.ConvertToTemplate()
if err != nil {
t.Fatalf("Failed to convert to template: %v", err)
@ -286,7 +286,7 @@ func templateCheck(t *testing.T, vm *VirtualMachine, _ *CloneConfig) {
}
}
func startVM(t *testing.T, vm *VirtualMachine, vmName string) (stopper func()) {
func startVM(t *testing.T, vm VirtualMachine, vmName string) (stopper func()) {
log.Printf("[DEBUG] Starting the vm")
if err := vm.PowerOn(); err != nil {
t.Fatalf("Cannot start vm '%v': %v", vmName, err)
@ -299,14 +299,14 @@ func startVM(t *testing.T, vm *VirtualMachine, vmName string) (stopper func()) {
}
}
func destroyVM(t *testing.T, vm *VirtualMachine, vmName string) {
func destroyVM(t *testing.T, vm VirtualMachine, vmName string) {
log.Printf("[DEBUG] Deleting the VM")
if err := vm.Destroy(); err != nil {
t.Errorf("!!! ERROR DELETING VM '%v': %v!!!", vmName, err)
}
// Check that the clone is no longer exists
if _, err := vm.driver.FindVM(vmName); err == nil {
if _, err := vm.(*VirtualMachineDriver).driver.FindVM(vmName); err == nil {
t.Errorf("!!! STILL CAN FIND VM '%v'. IT MIGHT NOT HAVE BEEN DELETED !!!", vmName)
}
}

View File

@ -10,7 +10,7 @@ func TestVMAcc_create(t *testing.T) {
testCases := []struct {
name string
config *CreateConfig
checkFunction func(*testing.T, *VirtualMachine, *CreateConfig)
checkFunction func(*testing.T, VirtualMachine, *CreateConfig)
}{
{"MinimalConfiguration", &CreateConfig{}, createDefaultCheck},
}
@ -36,8 +36,8 @@ func TestVMAcc_create(t *testing.T) {
}
}
func createDefaultCheck(t *testing.T, vm *VirtualMachine, config *CreateConfig) {
d := vm.driver
func createDefaultCheck(t *testing.T, vm VirtualMachine, config *CreateConfig) {
d := vm.(*VirtualMachineDriver).driver
// Check that the clone can be found by its name
if _, err := d.FindVM(config.Name); err != nil {

View File

@ -13,7 +13,7 @@ type KeyInput struct {
Shift bool
}
func (vm *VirtualMachine) TypeOnKeyboard(input KeyInput) (int32, error) {
func (vm *VirtualMachineDriver) TypeOnKeyboard(input KeyInput) (int32, error) {
var spec types.UsbScanCodeSpec
spec.KeyEvents = append(spec.KeyEvents, types.UsbScanCodeSpecKeyEvent{

View File

@ -0,0 +1,147 @@
package driver
import (
"context"
"net"
"time"
"github.com/vmware/govmomi/nfc"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/ovf"
"github.com/vmware/govmomi/vapi/vcenter"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
type VirtualMachineMock struct {
DestroyError error
DestroyCalled bool
}
func (vm *VirtualMachineMock) Info(params ...string) (*mo.VirtualMachine, error) {
return nil, nil
}
func (vm *VirtualMachineMock) Devices() (object.VirtualDeviceList, error) {
return object.VirtualDeviceList{}, nil
}
func (vm *VirtualMachineMock) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) {
return nil, nil
}
func (vm *VirtualMachineMock) updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error) {
return nil, nil
}
func (vm *VirtualMachineMock) AddPublicKeys(ctx context.Context, publicKeys string) error {
return nil
}
func (vm *VirtualMachineMock) Properties(ctx context.Context) (*mo.VirtualMachine, error) {
return nil, nil
}
func (vm *VirtualMachineMock) Destroy() error {
vm.DestroyCalled = true
if vm.DestroyError != nil {
return vm.DestroyError
}
return nil
}
func (vm *VirtualMachineMock) Configure(config *HardwareConfig) error {
return nil
}
func (vm *VirtualMachineMock) Customize(spec types.CustomizationSpec) error {
return nil
}
func (vm *VirtualMachineMock) ResizeDisk(diskSize int64) error {
return nil
}
func (vm *VirtualMachineMock) PowerOn() error {
return nil
}
func (vm *VirtualMachineMock) WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error) {
return "", nil
}
func (vm *VirtualMachineMock) PowerOff() error {
return nil
}
func (vm *VirtualMachineMock) IsPoweredOff() (bool, error) {
return false, nil
}
func (vm *VirtualMachineMock) StartShutdown() error {
return nil
}
func (vm *VirtualMachineMock) WaitForShutdown(ctx context.Context, timeout time.Duration) error {
return nil
}
func (vm *VirtualMachineMock) CreateSnapshot(name string) error {
return nil
}
func (vm *VirtualMachineMock) ConvertToTemplate() error {
return nil
}
func (vm *VirtualMachineMock) ImportOvfToContentLibrary(ovf vcenter.OVF) error {
return nil
}
func (vm *VirtualMachineMock) ImportToContentLibrary(template vcenter.Template) error {
return nil
}
func (vm *VirtualMachineMock) GetDir() (string, error) {
return "", nil
}
func (vm *VirtualMachineMock) AddCdrom(controllerType string, datastoreIsoPath string) error {
return nil
}
func (vm *VirtualMachineMock) AddFloppy(imgPath string) error {
return nil
}
func (vm *VirtualMachineMock) SetBootOrder(order []string) error {
return nil
}
func (vm *VirtualMachineMock) RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error {
return nil
}
func (vm *VirtualMachineMock) addDevice(device types.BaseVirtualDevice) error {
return nil
}
func (vm *VirtualMachineMock) AddConfigParams(params map[string]string, info *types.ToolsConfigInfo) error {
return nil
}
func (vm *VirtualMachineMock) Export() (*nfc.Lease, error) {
return nil, nil
}
func (vm *VirtualMachineMock) CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) {
return nil, nil
}
func (vm *VirtualMachineMock) NewOvfManager() *ovf.Manager {
return nil
}
func (vm *VirtualMachineMock) GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error) {
return nil, nil
}

View File

@ -170,7 +170,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
artifact := &common.Artifact{
Name: b.config.VMName,
VM: state.Get("vm").(*driver.VirtualMachine),
VM: state.Get("vm").(*driver.VirtualMachineDriver),
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
}

View File

@ -0,0 +1,17 @@
package iso
import (
"bytes"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
func basicStateBag() *multistep.BasicStateBag {
state := new(multistep.BasicStateBag)
state.Put("ui", &packer.BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
})
return state
}

View File

@ -42,7 +42,7 @@ func (c *CDRomConfig) Prepare() []error {
func (s *StepAddCDRom) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
if s.Config.CdromType == "sata" {
if _, err := vm.FindSATAController(); err == driver.ErrNoSataController {

View File

@ -37,8 +37,8 @@ type StepAddFloppy struct {
func (s *StepAddFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
d := state.Get("driver").(*driver.Driver)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
d := state.Get("driver").(*driver.VCenterDriver)
if floppyPath, ok := state.GetOk("floppy_path"); ok {
ui.Say("Uploading created floppy image")
@ -90,7 +90,7 @@ func (s *StepAddFloppy) Cleanup(state multistep.StateBag) {
}
ui := state.Get("ui").(packer.Ui)
d := state.Get("driver").(*driver.Driver)
d := state.Get("driver").(*driver.VCenterDriver)
if UploadedFloppyPath, ok := state.GetOk("uploaded_floppy_path"); ok {
ui.Say("Deleting Floppy image ...")

View File

@ -216,7 +216,7 @@ type StepCreateVM struct {
func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
d := state.Get("driver").(*driver.Driver)
d := state.Get("driver").(driver.Driver)
vmPath := path.Join(s.Location.Folder, s.Location.VMName)
err := d.PreCleanVM(ui, vmPath, s.Force)
@ -287,7 +287,7 @@ func (s *StepCreateVM) Cleanup(state multistep.StateBag) {
if st == nil {
return
}
vm := st.(*driver.VirtualMachine)
vm := st.(driver.VirtualMachine)
ui.Say("Destroying VM...")
err := vm.Destroy()

View File

@ -0,0 +1,351 @@
package iso
import (
"context"
"errors"
"io/ioutil"
"path"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/packer/builder/vsphere/common"
"github.com/hashicorp/packer/builder/vsphere/driver"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
func TestCreateConfig_Prepare(t *testing.T) {
// Empty config - check defaults
config := &CreateConfig{}
if errs := config.Prepare(); len(errs) != 0 {
t.Fatalf("Config preprare should not fail")
}
if config.GuestOSType != "otherGuest" {
t.Fatalf("GuestOSType should default to 'otherGuest'")
}
if len(config.DiskControllerType) != 1 {
t.Fatalf("DiskControllerType should have at least one element as default")
}
// Data validation
tc := []struct {
name string
config *CreateConfig
fail bool
expectedErrMsg string
}{
{
name: "Storage validate disk_size",
config: &CreateConfig{
Storage: []DiskConfig{
{
DiskSize: 0,
DiskThinProvisioned: true,
},
},
},
fail: true,
expectedErrMsg: "storage[0].'disk_size' is required",
},
{
name: "Storage validate disk_controller_index",
config: &CreateConfig{
Storage: []DiskConfig{
{
DiskSize: 32768,
DiskControllerIndex: 3,
},
},
},
fail: true,
expectedErrMsg: "storage[0].'disk_controller_index' references an unknown disk controller",
},
{
name: "USBController validate 'usb' and 'xhci' can be set together",
config: &CreateConfig{
USBController: []string{"usb", "xhci"},
},
fail: false,
},
{
name: "USBController validate '1' and '0' can be set together",
config: &CreateConfig{
USBController: []string{"1", "0"},
},
fail: false,
},
{
name: "USBController validate 'true' and 'false' can be set together",
config: &CreateConfig{
USBController: []string{"true", "false"},
},
fail: false,
},
{
name: "USBController validate 'true' and 'usb' cannot be set together",
config: &CreateConfig{
USBController: []string{"true", "usb"},
},
fail: true,
expectedErrMsg: "there can only be one usb controller and one xhci controller",
},
{
name: "USBController validate '1' and 'usb' cannot be set together",
config: &CreateConfig{
USBController: []string{"1", "usb"},
},
fail: true,
expectedErrMsg: "there can only be one usb controller and one xhci controller",
},
{
name: "USBController validate 'xhci' cannot be set more that once",
config: &CreateConfig{
USBController: []string{"xhci", "xhci"},
},
fail: true,
expectedErrMsg: "there can only be one usb controller and one xhci controller",
},
{
name: "USBController validate unknown value cannot be set",
config: &CreateConfig{
USBController: []string{"unknown"},
},
fail: true,
expectedErrMsg: "usb_controller[0] references an unknown usb controller",
},
}
for _, c := range tc {
errs := c.config.Prepare()
if c.fail {
if len(errs) == 0 {
t.Fatalf("Config preprare should fail")
}
if errs[0].Error() != c.expectedErrMsg {
t.Fatalf("Expected error message: %s but was '%s'", c.expectedErrMsg, errs[0].Error())
}
} else {
if len(errs) != 0 {
t.Fatalf("Config preprare should not fail")
}
}
}
}
func TestStepCreateVM_Run(t *testing.T) {
state := basicStateBag()
driverMock := driver.NewDriverMock()
state.Put("driver", driverMock)
step := basicStepCreateVM()
step.Force = true
vmPath := path.Join(step.Location.Folder, step.Location.VMName)
if action := step.Run(context.TODO(), state); action == multistep.ActionHalt {
t.Fatalf("Should not halt.")
}
// Pre clean VM
if !driverMock.PreCleanVMCalled {
t.Fatalf("driver.PreCleanVM should be called.")
}
if driverMock.PreCleanForce != step.Force {
t.Fatalf("Force PreCleanVM should be %t but was %t.", step.Force, driverMock.PreCleanForce)
}
if driverMock.PreCleanVMPath != vmPath {
t.Fatalf("VM path expected to be %s but was %s", vmPath, driverMock.PreCleanVMPath)
}
if !driverMock.CreateVMCalled {
t.Fatalf("driver.CreateVM should be called.")
}
if diff := cmp.Diff(driverMock.CreateConfig, driverCreateConfig(step.Config, step.Location)); diff != "" {
t.Fatalf("wrog driver.CreateConfig: %s", diff)
}
vm, ok := state.GetOk("vm")
if !ok {
t.Fatal("state must contain the VM")
}
if vm != driverMock.VM {
t.Fatalf("state doesn't contain the created VM.")
}
}
func TestStepCreateVM_RunHalt(t *testing.T) {
state := basicStateBag()
step := basicStepCreateVM()
// PreCleanVM fails
driverMock := driver.NewDriverMock()
driverMock.PreCleanShouldFail = true
state.Put("driver", driverMock)
if action := step.Run(context.TODO(), state); action != multistep.ActionHalt {
t.Fatalf("Step should halt.")
}
if !driverMock.PreCleanVMCalled {
t.Fatalf("driver.PreCleanVM should be called")
}
// CreateVM fails
driverMock = driver.NewDriverMock()
driverMock.CreateVMShouldFail = true
state.Put("driver", driverMock)
if action := step.Run(context.TODO(), state); action != multistep.ActionHalt {
t.Fatalf("Step should halt.")
}
if !driverMock.PreCleanVMCalled {
t.Fatalf("driver.PreCleanVM should be called")
}
if !driverMock.CreateVMCalled {
t.Fatalf("driver.PreCleanVM should be called")
}
if _, ok := state.GetOk("vm"); ok {
t.Fatal("state should not contain a VM")
}
}
func TestStepCreateVM_Cleanup(t *testing.T) {
state := basicStateBag()
step := basicStepCreateVM()
vm := new(driver.VirtualMachineMock)
state.Put("vm", vm)
// Clean up when state is cancelled
state.Put(multistep.StateCancelled, true)
step.Cleanup(state)
if !vm.DestroyCalled {
t.Fatalf("vm.Destroy should be called")
}
vm.DestroyCalled = false
state.Remove(multistep.StateCancelled)
// Clean up when state is halted
state.Put(multistep.StateHalted, true)
step.Cleanup(state)
if !vm.DestroyCalled {
t.Fatalf("vm.Destroy should be called")
}
vm.DestroyCalled = false
state.Remove(multistep.StateHalted)
// Clean up when state is destroy_vm is set
state.Put("destroy_vm", true)
step.Cleanup(state)
if !vm.DestroyCalled {
t.Fatalf("vm.Destroy should be called")
}
vm.DestroyCalled = false
state.Remove("destroy_vm")
// Don't clean up if state is not set with previous values
step.Cleanup(state)
if vm.DestroyCalled {
t.Fatalf("vm.Destroy should not be called")
}
// Destroy fail
errorBuffer := &strings.Builder{}
ui := &packer.BasicUi{
Reader: strings.NewReader(""),
Writer: ioutil.Discard,
ErrorWriter: errorBuffer,
}
state.Put("ui", ui)
state.Put(multistep.StateCancelled, true)
vm.DestroyError = errors.New("destroy failed")
step.Cleanup(state)
if !vm.DestroyCalled {
t.Fatalf("vm.Destroy should be called")
}
if !strings.Contains(errorBuffer.String(), vm.DestroyError.Error()) {
t.Fatalf("Destroy should fail with error message '%s' but failed with '%s'", vm.DestroyError.Error(), errorBuffer.String())
}
vm.DestroyCalled = false
state.Remove(multistep.StateCancelled)
// Should not destroy if VM is not set
state.Remove("vm")
state.Put(multistep.StateCancelled, true)
step.Cleanup(state)
if vm.DestroyCalled {
t.Fatalf("vm.Destroy should not be called")
}
}
func basicStepCreateVM() *StepCreateVM {
step := &StepCreateVM{
Config: createConfig(),
Location: basicLocationConfig(),
}
return step
}
func basicLocationConfig() *common.LocationConfig {
return &common.LocationConfig{
VMName: "test-vm",
Folder: "test-folder",
Cluster: "test-cluster",
Host: "test-host",
ResourcePool: "test-resource-pool",
Datastore: "test-datastore",
}
}
func createConfig() *CreateConfig {
return &CreateConfig{
Version: 1,
GuestOSType: "ubuntu64Guest",
DiskControllerType: []string{"pvscsi"},
Storage: []DiskConfig{
{
DiskSize: 32768,
DiskThinProvisioned: true,
},
},
NICs: []NIC{
{
Network: "VM Network",
NetworkCard: "vmxnet3",
},
},
}
}
func driverCreateConfig(config *CreateConfig, location *common.LocationConfig) *driver.CreateConfig {
var networkCards []driver.NIC
for _, nic := range config.NICs {
networkCards = append(networkCards, driver.NIC{
Network: nic.Network,
NetworkCard: nic.NetworkCard,
MacAddress: nic.MacAddress,
Passthrough: nic.Passthrough,
})
}
var disks []driver.Disk
for _, disk := range config.Storage {
disks = append(disks, driver.Disk{
DiskSize: disk.DiskSize,
DiskEagerlyScrub: disk.DiskEagerlyScrub,
DiskThinProvisioned: disk.DiskThinProvisioned,
ControllerIndex: disk.DiskControllerIndex,
})
}
return &driver.CreateConfig{
DiskControllerType: config.DiskControllerType,
Storage: disks,
Annotation: config.Notes,
Name: location.VMName,
Folder: location.Folder,
Cluster: location.Cluster,
Host: location.Host,
ResourcePool: location.ResourcePool,
Datastore: location.Datastore,
GuestOS: config.GuestOSType,
NICs: networkCards,
USBController: config.USBController,
Version: config.Version,
}
}

View File

@ -18,7 +18,7 @@ type StepRemoteUpload struct {
func (s *StepRemoteUpload) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
d := state.Get("driver").(*driver.Driver)
d := state.Get("driver").(driver.Driver)
if path, ok := state.GetOk("iso_path"); ok {
filename := filepath.Base(path.(string))

View File

@ -0,0 +1,67 @@
package iso
import (
"context"
"fmt"
"testing"
"github.com/hashicorp/packer/builder/vsphere/driver"
"github.com/hashicorp/packer/helper/multistep"
)
func TestStepRemoteUpload_Run(t *testing.T) {
state := basicStateBag()
driverMock := driver.NewDriverMock()
state.Put("driver", driverMock)
state.Put("iso_path", "[datastore] iso/path")
step := &StepRemoteUpload{
Datastore: "datastore",
Host: "host",
SetHostForDatastoreUploads: false,
}
if action := step.Run(context.TODO(), state); action == multistep.ActionHalt {
t.Fatalf("Should not halt.")
}
if !driverMock.FindDatastoreCalled {
t.Fatalf("driver.FindDatastore should be called.")
}
if !driverMock.DatastoreMock.FileExistsCalled {
t.Fatalf("datastore.FindDatastore should be called.")
}
if !driverMock.DatastoreMock.MakeDirectoryCalled {
t.Fatalf("datastore.MakeDirectory should be called.")
}
if !driverMock.DatastoreMock.UploadFileCalled {
t.Fatalf("datastore.UploadFile should be called.")
}
remotePath, ok := state.GetOk("iso_remote_path")
if !ok {
t.Fatalf("state should contain iso_remote_path")
}
expectedRemovePath := fmt.Sprintf("[%s] packer_cache//path", driverMock.DatastoreMock.Name())
if remotePath != expectedRemovePath {
t.Fatalf("iso_remote_path expected to be %s but was %s", expectedRemovePath, remotePath)
}
}
func TestStepRemoteUpload_SkipRun(t *testing.T) {
state := basicStateBag()
driverMock := driver.NewDriverMock()
state.Put("driver", driverMock)
step := &StepRemoteUpload{}
if action := step.Run(context.TODO(), state); action == multistep.ActionHalt {
t.Fatalf("Should not halt.")
}
if driverMock.FindDatastoreCalled {
t.Fatalf("driver.FindDatastore should not be called.")
}
if _, ok := state.GetOk("iso_remote_path"); ok {
t.Fatalf("state should not contain iso_remote_path")
}
}

View File

@ -22,7 +22,7 @@ type StepRemoveCDRom struct {
func (s *StepRemoveCDRom) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
ui.Say("Eject CD-ROM drives...")
err := vm.EjectCdroms()

View File

@ -16,8 +16,8 @@ type StepRemoveFloppy struct {
func (s *StepRemoveFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
vm := state.Get("vm").(*driver.VirtualMachine)
d := state.Get("driver").(*driver.Driver)
vm := state.Get("vm").(*driver.VirtualMachineDriver)
d := state.Get("driver").(*driver.VCenterDriver)
ui.Say("Deleting Floppy drives...")
devices, err := vm.Devices()