packer-cn/driver/vm.go

288 lines
6.2 KiB
Go
Raw Normal View History

package driver
import (
"errors"
"fmt"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
2017-08-23 20:06:50 -04:00
"github.com/vmware/govmomi/vim25/types"
"time"
)
2017-08-23 20:06:50 -04:00
type VirtualMachine struct {
vm *object.VirtualMachine
driver *Driver
}
2017-08-23 20:06:50 -04:00
type CloneConfig struct {
Name string
Folder string
Host string
ResourcePool string
Datastore string
LinkedClone bool
}
type HardwareConfig struct {
CPUs int32
CPUReservation int64
CPULimit int64
RAM int64
RAMReservation int64
RAMReserveAll bool
2017-12-01 06:09:47 -05:00
DiskSize int64
NestedHV bool
2017-08-23 20:06:50 -04:00
}
func (d *Driver) NewVM(ref *types.ManagedObjectReference) *VirtualMachine {
return &VirtualMachine{
vm: object.NewVirtualMachine(d.client.Client, *ref),
driver: d,
}
}
func (d *Driver) FindVM(name string) (*VirtualMachine, error) {
vm, err := d.finder.VirtualMachine(d.ctx, name)
if err != nil {
return nil, err
}
return &VirtualMachine{
vm: vm,
2017-08-23 20:06:50 -04:00
driver: d,
}, nil
}
func (vm *VirtualMachine) Info(params ...string) (*mo.VirtualMachine, error) {
var p []string
if len(params) == 0 {
p = []string{"*"}
} else {
p = params
}
2017-08-23 20:06:50 -04:00
var info mo.VirtualMachine
err := vm.vm.Properties(vm.driver.ctx, vm.vm.Reference(), p, &info)
if err != nil {
return nil, err
}
return &info, nil
}
func (template *VirtualMachine) Clone(config *CloneConfig) (*VirtualMachine, error) {
folder, err := template.driver.FindFolder(config.Folder)
if err != nil {
return nil, err
}
2017-08-23 20:06:50 -04:00
var relocateSpec types.VirtualMachineRelocateSpec
pool, err := template.driver.FindResourcePool(config.Host, config.ResourcePool)
if err != nil {
return nil, err
}
poolRef := pool.pool.Reference()
relocateSpec.Pool = &poolRef
if config.Datastore == "" {
host, err := template.driver.FindHost(config.Host)
2017-08-23 20:06:50 -04:00
if err != nil {
return nil, err
}
info, err := host.Info("datastore")
if err != nil {
return nil, err
}
if len(info.Datastore) > 1 {
return nil, fmt.Errorf("Target host has several datastores. Specify 'datastore' parameter explicitly")
}
ref := info.Datastore[0].Reference()
relocateSpec.Datastore = &ref
} else {
ds, err := template.driver.FindDatastore(config.Datastore)
if err != nil {
return nil, err
}
ref := ds.ds.Reference()
relocateSpec.Datastore = &ref
2017-08-23 20:06:50 -04:00
}
var cloneSpec types.VirtualMachineCloneSpec
cloneSpec.Location = relocateSpec
cloneSpec.PowerOn = false
if config.LinkedClone == true {
cloneSpec.Location.DiskMoveType = "createNewChildDiskBacking"
tpl, err := template.Info("snapshot")
if err != nil {
return nil, err
}
if tpl.Snapshot == nil {
err = errors.New("`linked_clone=true`, but template has no snapshots")
return nil, err
}
cloneSpec.Snapshot = tpl.Snapshot.CurrentSnapshot
}
task, err := template.vm.Clone(template.driver.ctx, folder.folder, config.Name, cloneSpec)
if err != nil {
return nil, err
}
info, err := task.WaitForResult(template.driver.ctx, nil)
if err != nil {
return nil, err
}
ref := info.Result.(types.ManagedObjectReference)
vm := template.driver.NewVM(&ref)
return vm, nil
}
func (vm *VirtualMachine) Destroy() error {
task, err := vm.vm.Destroy(vm.driver.ctx)
if err != nil {
return err
}
_, err = task.WaitForResult(vm.driver.ctx, nil)
return err
}
func (vm *VirtualMachine) Configure(config *HardwareConfig) error {
var confSpec types.VirtualMachineConfigSpec
confSpec.NumCPUs = config.CPUs
confSpec.MemoryMB = config.RAM
var cpuSpec types.ResourceAllocationInfo
cpuSpec.Reservation = config.CPUReservation
cpuSpec.Limit = config.CPULimit
confSpec.CpuAllocation = &cpuSpec
var ramSpec types.ResourceAllocationInfo
ramSpec.Reservation = config.RAMReservation
confSpec.MemoryAllocation = &ramSpec
confSpec.MemoryReservationLockedToMax = &config.RAMReserveAll
confSpec.NestedHVEnabled = &config.NestedHV
2017-08-23 20:06:50 -04:00
2017-12-01 06:09:47 -05:00
if config.DiskSize > 0 {
devices, err := vm.vm.Device(vm.driver.ctx)
if err != nil {
return err
}
disk, err := findDisk(devices)
if err != nil {
return err
}
disk.CapacityInKB = config.DiskSize * 1024 * 1024 // Gb
confSpec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{
&types.VirtualDeviceConfigSpec{
Device: disk,
Operation: types.VirtualDeviceConfigSpecOperationEdit,
},
}
}
2017-08-23 20:06:50 -04:00
task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec)
if err != nil {
return err
}
_, err = task.WaitForResult(vm.driver.ctx, nil)
return err
}
2017-12-01 06:09:47 -05:00
func findDisk(devices object.VirtualDeviceList) (*types.VirtualDisk, error) {
var disks []*types.VirtualDisk
for _, device := range devices {
switch d := device.(type) {
case *types.VirtualDisk:
disks = append(disks, d)
}
}
switch len(disks) {
case 0:
return nil, errors.New("VM has no disks")
case 1:
return disks[0], nil
}
return nil, errors.New("VM has multiple disks")
}
2017-08-23 20:06:50 -04:00
func (vm *VirtualMachine) PowerOn() error {
task, err := vm.vm.PowerOn(vm.driver.ctx)
if err != nil {
return err
}
_, err = task.WaitForResult(vm.driver.ctx, nil)
return err
}
func (vm *VirtualMachine) WaitForIP() (string, error) {
return vm.vm.WaitForIP(vm.driver.ctx)
2017-08-23 20:06:50 -04:00
}
func (vm *VirtualMachine) PowerOff() error {
state, err := vm.vm.PowerState(vm.driver.ctx)
if err != nil {
return err
}
if state == types.VirtualMachinePowerStatePoweredOff {
return nil
}
task, err := vm.vm.PowerOff(vm.driver.ctx)
if err != nil {
return err
}
_, err = task.WaitForResult(vm.driver.ctx, nil)
return err
}
func (vm *VirtualMachine) StartShutdown() error {
err := vm.vm.ShutdownGuest(vm.driver.ctx)
return err
}
func (vm *VirtualMachine) WaitForShutdown(timeout time.Duration) error {
shutdownTimer := time.After(timeout)
for {
powerState, err := vm.vm.PowerState(vm.driver.ctx)
if err != nil {
return err
}
if powerState == "poweredOff" {
break
}
select {
case <-shutdownTimer:
err := errors.New("Timeout while waiting for machine to shut down.")
return err
default:
time.Sleep(1 * time.Second)
}
}
return nil
}
func (vm *VirtualMachine) CreateSnapshot(name string) error {
task, err := vm.vm.CreateSnapshot(vm.driver.ctx, name, "", false, false)
if err != nil {
return err
}
_, err = task.WaitForResult(vm.driver.ctx, nil)
return err
}
func (vm *VirtualMachine) ConvertToTemplate() error {
return vm.vm.MarkAsTemplate(vm.driver.ctx)
}