merged createVirtualMachine and deployVirtualMachine to setupVirtualMachine (#6659)

This commit is contained in:
thetuxkeeper 2016-05-17 23:18:35 +02:00 committed by Paul Stack
parent 40db82f25e
commit 62639620e1
1 changed files with 216 additions and 351 deletions

View File

@ -691,16 +691,9 @@ func resourceVSphereVirtualMachineCreate(d *schema.ResourceData, meta interface{
log.Printf("[DEBUG] cdrom init: %v", cdroms) log.Printf("[DEBUG] cdrom init: %v", cdroms)
} }
if vm.template != "" { err := vm.setupVirtualMachine(client)
err := vm.deployVirtualMachine(client) if err != nil {
if err != nil { return err
return err
}
} else {
err := vm.createVirtualMachine(client)
if err != nil {
return err
}
} }
d.SetId(vm.Path()) d.SetId(vm.Path())
@ -1157,8 +1150,7 @@ func createCdroms(vm *object.VirtualMachine, cdroms []cdrom) error {
return nil return nil
} }
// createVirtualMachine creates a new VirtualMachine. func (vm *virtualMachine) setupVirtualMachine(c *govmomi.Client) error {
func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
dc, err := getDatacenter(c, vm.datacenter) dc, err := getDatacenter(c, vm.datacenter)
if err != nil { if err != nil {
@ -1167,6 +1159,21 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
finder := find.NewFinder(c.Client, true) finder := find.NewFinder(c.Client, true)
finder = finder.SetDatacenter(dc) finder = finder.SetDatacenter(dc)
var template *object.VirtualMachine
var template_mo mo.VirtualMachine
if vm.template != "" {
template, err = finder.VirtualMachine(context.TODO(), vm.template)
if err != nil {
return err
}
log.Printf("[DEBUG] template: %#v", template)
err = template.Properties(context.TODO(), template.Reference(), []string{"parent", "config.template", "config.guestId", "resourcePool", "snapshot", "guest.toolsVersionStatus2", "config.guestFullName"}, &template_mo)
if err != nil {
return err
}
}
var resourcePool *object.ResourcePool var resourcePool *object.ResourcePool
if vm.resourcePool == "" { if vm.resourcePool == "" {
if vm.cluster == "" { if vm.cluster == "" {
@ -1192,8 +1199,8 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
if err != nil { if err != nil {
return err return err
} }
log.Printf("[DEBUG] folder: %#v", vm.folder) log.Printf("[DEBUG] folder: %#v", vm.folder)
folder := dcFolders.VmFolder folder := dcFolders.VmFolder
if len(vm.folder) > 0 { if len(vm.folder) > 0 {
si := object.NewSearchIndex(c.Client) si := object.NewSearchIndex(c.Client)
@ -1208,20 +1215,8 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
} }
} }
// network
networkDevices := []types.BaseVirtualDeviceConfigSpec{}
for _, network := range vm.networkInterfaces {
// network device
nd, err := buildNetworkDevice(finder, network.label, "e1000")
if err != nil {
return err
}
networkDevices = append(networkDevices, nd)
}
// make config spec // make config spec
configSpec := types.VirtualMachineConfigSpec{ configSpec := types.VirtualMachineConfigSpec{
GuestId: "otherLinux64Guest",
Name: vm.name, Name: vm.name,
NumCPUs: vm.vcpu, NumCPUs: vm.vcpu,
NumCoresPerSocket: 1, NumCoresPerSocket: 1,
@ -1229,7 +1224,9 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
MemoryAllocation: &types.ResourceAllocationInfo{ MemoryAllocation: &types.ResourceAllocationInfo{
Reservation: vm.memoryAllocation.reservation, Reservation: vm.memoryAllocation.reservation,
}, },
DeviceChange: networkDevices, }
if vm.template == "" {
configSpec.GuestId = "otherLinux64Guest"
} }
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec) log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
@ -1270,7 +1267,14 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
sp := object.StoragePod{ sp := object.StoragePod{
Folder: object.NewFolder(c.Client, d), Folder: object.NewFolder(c.Client, d),
} }
sps := buildStoragePlacementSpecCreate(dcFolders, resourcePool, sp, configSpec)
var sps types.StoragePlacementSpec
if vm.template != "" {
sps = buildStoragePlacementSpecClone(c, dcFolders, template, resourcePool, sp)
} else {
sps = buildStoragePlacementSpecCreate(dcFolders, resourcePool, sp, configSpec)
}
datastore, err = findDatastore(c, sps) datastore, err = findDatastore(c, sps)
if err != nil { if err != nil {
return err return err
@ -1283,353 +1287,139 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
log.Printf("[DEBUG] datastore: %#v", datastore) log.Printf("[DEBUG] datastore: %#v", datastore)
var mds mo.Datastore
if err = datastore.Properties(context.TODO(), datastore.Reference(), []string{"name"}, &mds); err != nil {
return err
}
log.Printf("[DEBUG] datastore: %#v", mds.Name)
scsi, err := object.SCSIControllerTypes().CreateSCSIController("scsi")
if err != nil {
log.Printf("[ERROR] %s", err)
}
configSpec.DeviceChange = append(configSpec.DeviceChange, &types.VirtualDeviceConfigSpec{
Operation: types.VirtualDeviceConfigSpecOperationAdd,
Device: scsi,
})
configSpec.Files = &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", mds.Name)}
task, err := folder.CreateVM(context.TODO(), configSpec, resourcePool, nil)
if err != nil {
log.Printf("[ERROR] %s", err)
}
err = task.Wait(context.TODO())
if err != nil {
log.Printf("[ERROR] %s", err)
}
newVM, err := finder.VirtualMachine(context.TODO(), vm.Path())
if err != nil {
return err
}
log.Printf("[DEBUG] new vm: %v", newVM)
log.Printf("[DEBUG] add hard disk: %v", vm.hardDisks)
for _, hd := range vm.hardDisks {
log.Printf("[DEBUG] add hard disk: %v", hd.size)
log.Printf("[DEBUG] add hard disk: %v", hd.iops)
err = addHardDisk(newVM, hd.size, hd.iops, "thin", datastore, hd.vmdkPath)
if err != nil {
return err
}
}
// Create the cdroms if needed.
if err := createCdroms(newVM, vm.cdroms); err != nil {
return err
}
if vm.bootableVmdk {
newVM.PowerOn(context.TODO())
ip, err := newVM.WaitForIP(context.TODO())
if err != nil {
return err
}
log.Printf("[DEBUG] ip address: %v", ip)
}
return nil
}
// deployVirtualMachine deploys a new VirtualMachine.
func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
dc, err := getDatacenter(c, vm.datacenter)
if err != nil {
return err
}
finder := find.NewFinder(c.Client, true)
finder = finder.SetDatacenter(dc)
template, err := finder.VirtualMachine(context.TODO(), vm.template)
if err != nil {
return err
}
log.Printf("[DEBUG] template: %#v", template)
var resourcePool *object.ResourcePool
if vm.resourcePool == "" {
if vm.cluster == "" {
resourcePool, err = finder.DefaultResourcePool(context.TODO())
if err != nil {
return err
}
} else {
resourcePool, err = finder.ResourcePool(context.TODO(), "*"+vm.cluster+"/Resources")
if err != nil {
return err
}
}
} else {
resourcePool, err = finder.ResourcePool(context.TODO(), vm.resourcePool)
if err != nil {
return err
}
}
log.Printf("[DEBUG] resource pool: %#v", resourcePool)
dcFolders, err := dc.Folders(context.TODO())
if err != nil {
return err
}
log.Printf("[DEBUG] folder: %#v", vm.folder)
folder := dcFolders.VmFolder
if len(vm.folder) > 0 {
si := object.NewSearchIndex(c.Client)
folderRef, err := si.FindByInventoryPath(
context.TODO(), fmt.Sprintf("%v/vm/%v", vm.datacenter, vm.folder))
if err != nil {
return fmt.Errorf("Error reading folder %s: %s", vm.folder, err)
} else if folderRef == nil {
return fmt.Errorf("Cannot find folder %s", vm.folder)
} else {
folder = folderRef.(*object.Folder)
}
}
var datastore *object.Datastore
if vm.datastore == "" {
datastore, err = finder.DefaultDatastore(context.TODO())
if err != nil {
return err
}
} else {
datastore, err = finder.Datastore(context.TODO(), vm.datastore)
if err != nil {
// TODO: datastore cluster support in govmomi finder function
d, err := getDatastoreObject(c, dcFolders, vm.datastore)
if err != nil {
return err
}
if d.Type == "StoragePod" {
sp := object.StoragePod{
Folder: object.NewFolder(c.Client, d),
}
sps := buildStoragePlacementSpecClone(c, dcFolders, template, resourcePool, sp)
datastore, err = findDatastore(c, sps)
if err != nil {
return err
}
} else {
datastore = object.NewDatastore(c.Client, d)
}
}
}
log.Printf("[DEBUG] datastore: %#v", datastore)
relocateSpec, err := buildVMRelocateSpec(resourcePool, datastore, template, vm.linkedClone, vm.hardDisks[0].initType)
if err != nil {
return err
}
log.Printf("[DEBUG] relocate spec: %v", relocateSpec)
// network // network
networkDevices := []types.BaseVirtualDeviceConfigSpec{} networkDevices := []types.BaseVirtualDeviceConfigSpec{}
networkConfigs := []types.CustomizationAdapterMapping{} networkConfigs := []types.CustomizationAdapterMapping{}
for _, network := range vm.networkInterfaces { for _, network := range vm.networkInterfaces {
// network device // network device
nd, err := buildNetworkDevice(finder, network.label, "vmxnet3") var networkDeviceType string
if vm.template == "" {
networkDeviceType = "e1000"
} else {
networkDeviceType = "vmxnet3"
}
nd, err := buildNetworkDevice(finder, network.label, networkDeviceType)
if err != nil { if err != nil {
return err return err
} }
networkDevices = append(networkDevices, nd) networkDevices = append(networkDevices, nd)
var ipSetting types.CustomizationIPSettings if vm.template != "" {
if network.ipv4Address == "" { var ipSetting types.CustomizationIPSettings
ipSetting.Ip = &types.CustomizationDhcpIpGenerator{} if network.ipv4Address == "" {
} else { ipSetting.Ip = &types.CustomizationDhcpIpGenerator{}
if network.ipv4PrefixLength == 0 { } else {
return fmt.Errorf("Error: ipv4_prefix_length argument is empty.") if network.ipv4PrefixLength == 0 {
return fmt.Errorf("Error: ipv4_prefix_length argument is empty.")
}
m := net.CIDRMask(network.ipv4PrefixLength, 32)
sm := net.IPv4(m[0], m[1], m[2], m[3])
subnetMask := sm.String()
log.Printf("[DEBUG] ipv4 gateway: %v\n", network.ipv4Gateway)
log.Printf("[DEBUG] ipv4 address: %v\n", network.ipv4Address)
log.Printf("[DEBUG] ipv4 prefix length: %v\n", network.ipv4PrefixLength)
log.Printf("[DEBUG] ipv4 subnet mask: %v\n", subnetMask)
ipSetting.Gateway = []string{
network.ipv4Gateway,
}
ipSetting.Ip = &types.CustomizationFixedIp{
IpAddress: network.ipv4Address,
}
ipSetting.SubnetMask = subnetMask
} }
m := net.CIDRMask(network.ipv4PrefixLength, 32)
sm := net.IPv4(m[0], m[1], m[2], m[3])
subnetMask := sm.String()
log.Printf("[DEBUG] ipv4 gateway: %v\n", network.ipv4Gateway)
log.Printf("[DEBUG] ipv4 address: %v\n", network.ipv4Address)
log.Printf("[DEBUG] ipv4 prefix length: %v\n", network.ipv4PrefixLength)
log.Printf("[DEBUG] ipv4 subnet mask: %v\n", subnetMask)
ipSetting.Gateway = []string{
network.ipv4Gateway,
}
ipSetting.Ip = &types.CustomizationFixedIp{
IpAddress: network.ipv4Address,
}
ipSetting.SubnetMask = subnetMask
}
ipv6Spec := &types.CustomizationIPSettingsIpV6AddressSpec{} ipv6Spec := &types.CustomizationIPSettingsIpV6AddressSpec{}
if network.ipv6Address == "" { if network.ipv6Address == "" {
ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{ ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{
&types.CustomizationDhcpIpV6Generator{}, &types.CustomizationDhcpIpV6Generator{},
} }
} else { } else {
log.Printf("[DEBUG] ipv6 gateway: %v\n", network.ipv6Gateway) log.Printf("[DEBUG] ipv6 gateway: %v\n", network.ipv6Gateway)
log.Printf("[DEBUG] ipv6 address: %v\n", network.ipv6Address) log.Printf("[DEBUG] ipv6 address: %v\n", network.ipv6Address)
log.Printf("[DEBUG] ipv6 prefix length: %v\n", network.ipv6PrefixLength) log.Printf("[DEBUG] ipv6 prefix length: %v\n", network.ipv6PrefixLength)
ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{ ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{
&types.CustomizationFixedIpV6{ &types.CustomizationFixedIpV6{
IpAddress: network.ipv6Address, IpAddress: network.ipv6Address,
SubnetMask: int32(network.ipv6PrefixLength), SubnetMask: int32(network.ipv6PrefixLength),
}, },
}
ipv6Spec.Gateway = []string{network.ipv6Gateway}
} }
ipv6Spec.Gateway = []string{network.ipv6Gateway} ipSetting.IpV6Spec = ipv6Spec
}
ipSetting.IpV6Spec = ipv6Spec
// network config // network config
config := types.CustomizationAdapterMapping{ config := types.CustomizationAdapterMapping{
Adapter: ipSetting, Adapter: ipSetting,
}
networkConfigs = append(networkConfigs, config)
} }
networkConfigs = append(networkConfigs, config)
} }
log.Printf("[DEBUG] network configs: %v", networkConfigs[0].Adapter) log.Printf("[DEBUG] network devices: %v", networkDevices)
log.Printf("[DEBUG] network configs: %v", networkConfigs)
// make config spec var task *object.Task
configSpec := types.VirtualMachineConfigSpec{ if vm.template == "" {
NumCPUs: vm.vcpu, var mds mo.Datastore
NumCoresPerSocket: 1, if err = datastore.Properties(context.TODO(), datastore.Reference(), []string{"name"}, &mds); err != nil {
MemoryMB: vm.memoryMb, return err
MemoryAllocation: &types.ResourceAllocationInfo{
Reservation: vm.memoryAllocation.reservation,
},
}
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
log.Printf("[DEBUG] starting extra custom config spec: %v", vm.customConfigurations)
// make ExtraConfig
if len(vm.customConfigurations) > 0 {
var ov []types.BaseOptionValue
for k, v := range vm.customConfigurations {
key := k
value := v
o := types.OptionValue{
Key: key,
Value: &value,
}
ov = append(ov, &o)
} }
configSpec.ExtraConfig = ov log.Printf("[DEBUG] datastore: %#v", mds.Name)
log.Printf("[DEBUG] virtual machine Extra Config spec: %v", configSpec.ExtraConfig) scsi, err := object.SCSIControllerTypes().CreateSCSIController("scsi")
}
var template_mo mo.VirtualMachine
err = template.Properties(context.TODO(), template.Reference(), []string{"parent", "config.template", "config.guestId", "resourcePool", "snapshot", "guest.toolsVersionStatus2", "config.guestFullName"}, &template_mo)
var identity_options types.BaseCustomizationIdentitySettings
if strings.HasPrefix(template_mo.Config.GuestId, "win") {
var timeZone int
if vm.timeZone == "Etc/UTC" {
vm.timeZone = "085"
}
timeZone, err := strconv.Atoi(vm.timeZone)
if err != nil { if err != nil {
return fmt.Errorf("Error converting TimeZone: %s", err) log.Printf("[ERROR] %s", err)
} }
guiUnattended := types.CustomizationGuiUnattended{ configSpec.DeviceChange = append(configSpec.DeviceChange, &types.VirtualDeviceConfigSpec{
AutoLogon: false, Operation: types.VirtualDeviceConfigSpecOperationAdd,
AutoLogonCount: 1, Device: scsi,
TimeZone: int32(timeZone), })
configSpec.Files = &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", mds.Name)}
task, err = folder.CreateVM(context.TODO(), configSpec, resourcePool, nil)
if err != nil {
log.Printf("[ERROR] %s", err)
} }
customIdentification := types.CustomizationIdentification{} err = task.Wait(context.TODO())
if err != nil {
userData := types.CustomizationUserData{ log.Printf("[ERROR] %s", err)
ComputerName: &types.CustomizationFixedName{
Name: strings.Split(vm.name, ".")[0],
},
ProductId: vm.windowsOptionalConfig.productKey,
FullName: "terraform",
OrgName: "terraform",
} }
if vm.windowsOptionalConfig.domainUserPassword != "" && vm.windowsOptionalConfig.domainUser != "" && vm.windowsOptionalConfig.domain != "" {
customIdentification.DomainAdminPassword = &types.CustomizationPassword{
PlainText: true,
Value: vm.windowsOptionalConfig.domainUserPassword,
}
customIdentification.DomainAdmin = vm.windowsOptionalConfig.domainUser
customIdentification.JoinDomain = vm.windowsOptionalConfig.domain
}
if vm.windowsOptionalConfig.adminPassword != "" {
guiUnattended.Password = &types.CustomizationPassword{
PlainText: true,
Value: vm.windowsOptionalConfig.adminPassword,
}
}
identity_options = &types.CustomizationSysprep{
GuiUnattended: guiUnattended,
Identification: customIdentification,
UserData: userData,
}
} else { } else {
identity_options = &types.CustomizationLinuxPrep{
HostName: &types.CustomizationFixedName{
Name: strings.Split(vm.name, ".")[0],
},
Domain: vm.domain,
TimeZone: vm.timeZone,
HwClockUTC: types.NewBool(true),
}
}
// create CustomizationSpec relocateSpec, err := buildVMRelocateSpec(resourcePool, datastore, template, vm.linkedClone, vm.hardDisks[0].initType)
customSpec := types.CustomizationSpec{
Identity: identity_options,
GlobalIPSettings: types.CustomizationGlobalIPSettings{
DnsSuffixList: vm.dnsSuffixes,
DnsServerList: vm.dnsServers,
},
NicSettingMap: networkConfigs,
}
log.Printf("[DEBUG] custom spec: %v", customSpec)
// make vm clone spec
cloneSpec := types.VirtualMachineCloneSpec{
Location: relocateSpec,
Template: false,
Config: &configSpec,
PowerOn: false,
}
if vm.linkedClone {
if err != nil { if err != nil {
return fmt.Errorf("Error reading base VM properties: %s", err) return err
} }
if template_mo.Snapshot == nil {
return fmt.Errorf("`linkedClone=true`, but image VM has no snapshots")
}
cloneSpec.Snapshot = template_mo.Snapshot.CurrentSnapshot
}
log.Printf("[DEBUG] clone spec: %v", cloneSpec)
task, err := template.Clone(context.TODO(), folder, vm.name, cloneSpec) log.Printf("[DEBUG] relocate spec: %v", relocateSpec)
if err != nil {
return err // make vm clone spec
cloneSpec := types.VirtualMachineCloneSpec{
Location: relocateSpec,
Template: false,
Config: &configSpec,
PowerOn: false,
}
if vm.linkedClone {
if template_mo.Snapshot == nil {
return fmt.Errorf("`linkedClone=true`, but image VM has no snapshots")
}
cloneSpec.Snapshot = template_mo.Snapshot.CurrentSnapshot
}
log.Printf("[DEBUG] clone spec: %v", cloneSpec)
task, err = template.Clone(context.TODO(), folder, vm.name, cloneSpec)
if err != nil {
return err
}
} }
_, err = task.WaitForResult(context.TODO(), nil) err = task.Wait(context.TODO())
if err != nil { if err != nil {
return err log.Printf("[ERROR] %s", err)
} }
newVM, err := finder.VirtualMachine(context.TODO(), vm.Path()) newVM, err := finder.VirtualMachine(context.TODO(), vm.Path())
@ -1667,9 +1457,92 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
return err return err
} }
if vm.skipCustomization { firstDisk := 0
if vm.template != "" {
firstDisk++
}
for i := firstDisk; i < len(vm.hardDisks); i++ {
log.Printf("[DEBUG] disk index: %v", i)
err = addHardDisk(newVM, vm.hardDisks[i].size, vm.hardDisks[i].iops, vm.hardDisks[i].initType, datastore, vm.hardDisks[i].vmdkPath)
if err != nil {
return err
}
}
if vm.skipCustomization || vm.template == "" {
log.Printf("[DEBUG] VM customization skipped") log.Printf("[DEBUG] VM customization skipped")
} else { } else {
var identity_options types.BaseCustomizationIdentitySettings
if strings.HasPrefix(template_mo.Config.GuestId, "win") {
var timeZone int
if vm.timeZone == "Etc/UTC" {
vm.timeZone = "085"
}
timeZone, err := strconv.Atoi(vm.timeZone)
if err != nil {
return fmt.Errorf("Error converting TimeZone: %s", err)
}
guiUnattended := types.CustomizationGuiUnattended{
AutoLogon: false,
AutoLogonCount: 1,
TimeZone: int32(timeZone),
}
customIdentification := types.CustomizationIdentification{}
userData := types.CustomizationUserData{
ComputerName: &types.CustomizationFixedName{
Name: strings.Split(vm.name, ".")[0],
},
ProductId: vm.windowsOptionalConfig.productKey,
FullName: "terraform",
OrgName: "terraform",
}
if vm.windowsOptionalConfig.domainUserPassword != "" && vm.windowsOptionalConfig.domainUser != "" && vm.windowsOptionalConfig.domain != "" {
customIdentification.DomainAdminPassword = &types.CustomizationPassword{
PlainText: true,
Value: vm.windowsOptionalConfig.domainUserPassword,
}
customIdentification.DomainAdmin = vm.windowsOptionalConfig.domainUser
customIdentification.JoinDomain = vm.windowsOptionalConfig.domain
}
if vm.windowsOptionalConfig.adminPassword != "" {
guiUnattended.Password = &types.CustomizationPassword{
PlainText: true,
Value: vm.windowsOptionalConfig.adminPassword,
}
}
identity_options = &types.CustomizationSysprep{
GuiUnattended: guiUnattended,
Identification: customIdentification,
UserData: userData,
}
} else {
identity_options = &types.CustomizationLinuxPrep{
HostName: &types.CustomizationFixedName{
Name: strings.Split(vm.name, ".")[0],
},
Domain: vm.domain,
TimeZone: vm.timeZone,
HwClockUTC: types.NewBool(true),
}
}
// create CustomizationSpec
customSpec := types.CustomizationSpec{
Identity: identity_options,
GlobalIPSettings: types.CustomizationGlobalIPSettings{
DnsSuffixList: vm.dnsSuffixes,
DnsServerList: vm.dnsServers,
},
NicSettingMap: networkConfigs,
}
log.Printf("[DEBUG] custom spec: %v", customSpec)
log.Printf("[DEBUG] VM customization starting") log.Printf("[DEBUG] VM customization starting")
taskb, err := newVM.Customize(context.TODO(), customSpec) taskb, err := newVM.Customize(context.TODO(), customSpec)
if err != nil { if err != nil {
@ -1682,16 +1555,8 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
log.Printf("[DEBUG] VM customization finished") log.Printf("[DEBUG] VM customization finished")
} }
for i := 1; i < len(vm.hardDisks); i++ { if vm.bootableVmdk || vm.template != "" {
err = addHardDisk(newVM, vm.hardDisks[i].size, vm.hardDisks[i].iops, vm.hardDisks[i].initType, datastore, vm.hardDisks[i].vmdkPath) newVM.PowerOn(context.TODO())
if err != nil {
return err
}
} }
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
newVM.PowerOn(context.TODO())
return nil return nil
} }