cloning step uses vSphere driver

This commit is contained in:
Michael Kuzmin 2017-07-02 07:37:44 +03:00
parent 1e747c8c93
commit b7d58590a7
2 changed files with 87 additions and 108 deletions

View File

@ -7,6 +7,9 @@ import (
"net/url"
"fmt"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/govmomi/vim25/mo"
"errors"
)
type Driver struct {
@ -44,3 +47,85 @@ func NewDriverVSphere(config *ConnectConfig) (Driver, error) {
}
return d, nil
}
func (d *Driver) cloneVM(config *CloneConfig) (*object.VirtualMachine, error) {
vmSrc, err := d.finder.VirtualMachine(d.ctx, config.Template)
if err != nil {
return nil, err
}
folder, err := d.finder.FolderOrDefault(d.ctx, fmt.Sprintf("/%v/vm/%v", d.datacenter.Name(), config.FolderName))
if err != nil {
return nil, err
}
pool, err := d.finder.ResourcePoolOrDefault(d.ctx, fmt.Sprintf("/%v/host/%v/Resources/%v", d.datacenter.Name(), config.Host, config.ResourcePool))
if err != nil {
return nil, err
}
poolRef := pool.Reference()
var datastore *object.Datastore
if config.Datastore != "" {
datastore, err = d.finder.Datastore(d.ctx, config.Datastore)
if err != nil {
return nil, err
}
}
// Creating specs for cloning
relocateSpec := types.VirtualMachineRelocateSpec{
Pool: &(poolRef),
}
if datastore != nil {
datastoreRef := datastore.Reference()
relocateSpec.Datastore = &datastoreRef
}
if config.LinkedClone == true {
relocateSpec.DiskMoveType = "createNewChildDiskBacking"
}
cloneSpec := types.VirtualMachineCloneSpec{
Location: relocateSpec,
PowerOn: false,
}
if config.LinkedClone == true {
var vmImage mo.VirtualMachine
err = vmSrc.Properties(d.ctx, vmSrc.Reference(), []string{"snapshot"}, &vmImage)
if err != nil {
err = fmt.Errorf("Error reading base VM properties: %s", err)
return nil, err
}
if vmImage.Snapshot == nil {
err = errors.New("`linked_clone=true`, but image VM has no snapshots")
return nil, err
}
cloneSpec.Snapshot = vmImage.Snapshot.CurrentSnapshot
}
// Cloning itself
task, err := vmSrc.Clone(d.ctx, folder, config.VMName, cloneSpec)
if err != nil {
return nil, err
}
info, err := task.WaitForResult(d.ctx, nil)
if err != nil {
return nil, err
}
vm := object.NewVirtualMachine(vmSrc.Client(), info.Result.(types.ManagedObjectReference))
return vm, nil
}
func (d *Driver) destroyVM(vm *object.VirtualMachine) error {
task, err := vm.Destroy(d.ctx)
if err != nil {
return err
}
_, err = task.WaitForResult(d.ctx, nil)
if err != nil {
return err
}
return nil
}

View File

@ -1,14 +1,10 @@
package main
import (
"context"
"github.com/mitchellh/multistep"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/govmomi/object"
"github.com/hashicorp/packer/packer"
"fmt"
"github.com/vmware/govmomi/vim25/mo"
"errors"
)
type CloneConfig struct {
@ -37,16 +33,6 @@ func (c *CloneConfig) Prepare() []error {
return errs
}
type CloneParameters struct {
ctx context.Context
vmSrc *object.VirtualMachine
vmName string
folder *object.Folder
resourcePool *object.ResourcePool
datastore *object.Datastore
linkedClone bool
}
type StepCloneVM struct {
config *CloneConfig
}
@ -55,45 +41,9 @@ func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction {
d := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
vmSrc, err := d.finder.VirtualMachine(d.ctx, s.config.Template)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
state.Put("vmSrc", vmSrc)
ui.Say("Cloning VM...")
folder, err := d.finder.FolderOrDefault(d.ctx, fmt.Sprintf("/%v/vm/%v", d.datacenter.Name(), s.config.FolderName))
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
pool, err := d.finder.ResourcePoolOrDefault(d.ctx, fmt.Sprintf("/%v/host/%v/Resources/%v", d.datacenter.Name(), s.config.Host, s.config.ResourcePool))
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
var datastore *object.Datastore
if s.config.Datastore != "" {
datastore, err = d.finder.Datastore(d.ctx, s.config.Datastore)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
}
vm, err := cloneVM(&CloneParameters{
ctx: d.ctx,
vmSrc: vmSrc,
vmName: s.config.VMName,
folder: folder,
resourcePool: pool,
datastore: datastore,
linkedClone: s.config.LinkedClone,
})
vm, err := d.cloneVM(s.config)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
@ -116,65 +66,9 @@ func (s *StepCloneVM) Cleanup(state multistep.StateBag) {
ui.Say("Destroying VM...")
task, err := vm.(*object.VirtualMachine).Destroy(d.ctx)
err := d.destroyVM(vm.(*object.VirtualMachine))
if err != nil {
ui.Error(err.Error())
return
}
_, err = task.WaitForResult(d.ctx, nil)
if err != nil {
ui.Error(err.Error())
return
}
}
}
func cloneVM(params *CloneParameters) (vm *object.VirtualMachine, err error) {
vm = nil
err = nil
poolRef := params.resourcePool.Reference()
// Creating specs for cloning
relocateSpec := types.VirtualMachineRelocateSpec{
Pool: &(poolRef),
}
if params.datastore != nil {
datastoreRef := params.datastore.Reference()
relocateSpec.Datastore = &datastoreRef
}
if params.linkedClone == true {
relocateSpec.DiskMoveType = "createNewChildDiskBacking"
}
cloneSpec := types.VirtualMachineCloneSpec{
Location: relocateSpec,
PowerOn: false,
}
if params.linkedClone == true {
var vmImage mo.VirtualMachine
err = params.vmSrc.Properties(params.ctx, params.vmSrc.Reference(), []string{"snapshot"}, &vmImage)
if err != nil {
err = fmt.Errorf("Error reading base VM properties: %s", err)
return
}
if vmImage.Snapshot == nil {
err = errors.New("`linked_clone=true`, but image VM has no snapshots")
return
}
cloneSpec.Snapshot = vmImage.Snapshot.CurrentSnapshot
}
// Cloning itself
task, err := params.vmSrc.Clone(params.ctx, params.folder, params.vmName, cloneSpec)
if err != nil {
return
}
info, err := task.WaitForResult(params.ctx, nil)
if err != nil {
return
}
vm = object.NewVirtualMachine(params.vmSrc.Client(), info.Result.(types.ManagedObjectReference))
return vm, nil
}