merged createVirtualMachine and deployVirtualMachine to setupVirtualMachine (#6659)
This commit is contained in:
parent
40db82f25e
commit
62639620e1
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue