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)
|
||||
}
|
||||
|
||||
if vm.template != "" {
|
||||
err := vm.deployVirtualMachine(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := vm.createVirtualMachine(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := vm.setupVirtualMachine(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(vm.Path())
|
||||
|
@ -1157,8 +1150,7 @@ func createCdroms(vm *object.VirtualMachine, cdroms []cdrom) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// createVirtualMachine creates a new VirtualMachine.
|
||||
func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
||||
func (vm *virtualMachine) setupVirtualMachine(c *govmomi.Client) error {
|
||||
dc, err := getDatacenter(c, vm.datacenter)
|
||||
|
||||
if err != nil {
|
||||
|
@ -1167,6 +1159,21 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
|||
finder := find.NewFinder(c.Client, true)
|
||||
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
|
||||
if vm.resourcePool == "" {
|
||||
if vm.cluster == "" {
|
||||
|
@ -1192,8 +1199,8 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
|||
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)
|
||||
|
@ -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
|
||||
configSpec := types.VirtualMachineConfigSpec{
|
||||
GuestId: "otherLinux64Guest",
|
||||
Name: vm.name,
|
||||
NumCPUs: vm.vcpu,
|
||||
NumCoresPerSocket: 1,
|
||||
|
@ -1229,7 +1224,9 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
|||
MemoryAllocation: &types.ResourceAllocationInfo{
|
||||
Reservation: vm.memoryAllocation.reservation,
|
||||
},
|
||||
DeviceChange: networkDevices,
|
||||
}
|
||||
if vm.template == "" {
|
||||
configSpec.GuestId = "otherLinux64Guest"
|
||||
}
|
||||
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
|
||||
|
||||
|
@ -1270,7 +1267,14 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
|||
sp := object.StoragePod{
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1283,353 +1287,139 @@ func (vm *virtualMachine) createVirtualMachine(c *govmomi.Client) error {
|
|||
|
||||
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
|
||||
networkDevices := []types.BaseVirtualDeviceConfigSpec{}
|
||||
networkConfigs := []types.CustomizationAdapterMapping{}
|
||||
for _, network := range vm.networkInterfaces {
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
networkDevices = append(networkDevices, nd)
|
||||
|
||||
var ipSetting types.CustomizationIPSettings
|
||||
if network.ipv4Address == "" {
|
||||
ipSetting.Ip = &types.CustomizationDhcpIpGenerator{}
|
||||
} else {
|
||||
if network.ipv4PrefixLength == 0 {
|
||||
return fmt.Errorf("Error: ipv4_prefix_length argument is empty.")
|
||||
if vm.template != "" {
|
||||
var ipSetting types.CustomizationIPSettings
|
||||
if network.ipv4Address == "" {
|
||||
ipSetting.Ip = &types.CustomizationDhcpIpGenerator{}
|
||||
} else {
|
||||
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{}
|
||||
if network.ipv6Address == "" {
|
||||
ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{
|
||||
&types.CustomizationDhcpIpV6Generator{},
|
||||
}
|
||||
} else {
|
||||
log.Printf("[DEBUG] ipv6 gateway: %v\n", network.ipv6Gateway)
|
||||
log.Printf("[DEBUG] ipv6 address: %v\n", network.ipv6Address)
|
||||
log.Printf("[DEBUG] ipv6 prefix length: %v\n", network.ipv6PrefixLength)
|
||||
ipv6Spec := &types.CustomizationIPSettingsIpV6AddressSpec{}
|
||||
if network.ipv6Address == "" {
|
||||
ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{
|
||||
&types.CustomizationDhcpIpV6Generator{},
|
||||
}
|
||||
} else {
|
||||
log.Printf("[DEBUG] ipv6 gateway: %v\n", network.ipv6Gateway)
|
||||
log.Printf("[DEBUG] ipv6 address: %v\n", network.ipv6Address)
|
||||
log.Printf("[DEBUG] ipv6 prefix length: %v\n", network.ipv6PrefixLength)
|
||||
|
||||
ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{
|
||||
&types.CustomizationFixedIpV6{
|
||||
IpAddress: network.ipv6Address,
|
||||
SubnetMask: int32(network.ipv6PrefixLength),
|
||||
},
|
||||
ipv6Spec.Ip = []types.BaseCustomizationIpV6Generator{
|
||||
&types.CustomizationFixedIpV6{
|
||||
IpAddress: network.ipv6Address,
|
||||
SubnetMask: int32(network.ipv6PrefixLength),
|
||||
},
|
||||
}
|
||||
ipv6Spec.Gateway = []string{network.ipv6Gateway}
|
||||
}
|
||||
ipv6Spec.Gateway = []string{network.ipv6Gateway}
|
||||
}
|
||||
ipSetting.IpV6Spec = ipv6Spec
|
||||
ipSetting.IpV6Spec = ipv6Spec
|
||||
|
||||
// network config
|
||||
config := types.CustomizationAdapterMapping{
|
||||
Adapter: ipSetting,
|
||||
// network config
|
||||
config := types.CustomizationAdapterMapping{
|
||||
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
|
||||
configSpec := types.VirtualMachineConfigSpec{
|
||||
NumCPUs: vm.vcpu,
|
||||
NumCoresPerSocket: 1,
|
||||
MemoryMB: vm.memoryMb,
|
||||
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)
|
||||
var task *object.Task
|
||||
if vm.template == "" {
|
||||
var mds mo.Datastore
|
||||
if err = datastore.Properties(context.TODO(), datastore.Reference(), []string{"name"}, &mds); err != nil {
|
||||
return err
|
||||
}
|
||||
configSpec.ExtraConfig = ov
|
||||
log.Printf("[DEBUG] virtual machine Extra Config spec: %v", configSpec.ExtraConfig)
|
||||
}
|
||||
|
||||
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)
|
||||
log.Printf("[DEBUG] datastore: %#v", mds.Name)
|
||||
scsi, err := object.SCSIControllerTypes().CreateSCSIController("scsi")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error converting TimeZone: %s", err)
|
||||
log.Printf("[ERROR] %s", err)
|
||||
}
|
||||
|
||||
guiUnattended := types.CustomizationGuiUnattended{
|
||||
AutoLogon: false,
|
||||
AutoLogonCount: 1,
|
||||
TimeZone: int32(timeZone),
|
||||
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)
|
||||
}
|
||||
|
||||
customIdentification := types.CustomizationIdentification{}
|
||||
|
||||
userData := types.CustomizationUserData{
|
||||
ComputerName: &types.CustomizationFixedName{
|
||||
Name: strings.Split(vm.name, ".")[0],
|
||||
},
|
||||
ProductId: vm.windowsOptionalConfig.productKey,
|
||||
FullName: "terraform",
|
||||
OrgName: "terraform",
|
||||
err = task.Wait(context.TODO())
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] %s", err)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// make vm clone spec
|
||||
cloneSpec := types.VirtualMachineCloneSpec{
|
||||
Location: relocateSpec,
|
||||
Template: false,
|
||||
Config: &configSpec,
|
||||
PowerOn: false,
|
||||
}
|
||||
if vm.linkedClone {
|
||||
relocateSpec, err := buildVMRelocateSpec(resourcePool, datastore, template, vm.linkedClone, vm.hardDisks[0].initType)
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
log.Printf("[DEBUG] relocate spec: %v", relocateSpec)
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
log.Printf("[ERROR] %s", err)
|
||||
}
|
||||
|
||||
newVM, err := finder.VirtualMachine(context.TODO(), vm.Path())
|
||||
|
@ -1667,9 +1457,92 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
|
|||
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")
|
||||
} 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")
|
||||
taskb, err := newVM.Customize(context.TODO(), customSpec)
|
||||
if err != nil {
|
||||
|
@ -1682,16 +1555,8 @@ func (vm *virtualMachine) deployVirtualMachine(c *govmomi.Client) error {
|
|||
log.Printf("[DEBUG] VM customization finished")
|
||||
}
|
||||
|
||||
for i := 1; i < len(vm.hardDisks); 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.bootableVmdk || vm.template != "" {
|
||||
newVM.PowerOn(context.TODO())
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] virtual machine config spec: %v", configSpec)
|
||||
|
||||
newVM.PowerOn(context.TODO())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue