Updated mark as template to be able to use --force
This commit is contained in:
parent
5e1d241db4
commit
81272d1427
|
@ -97,11 +97,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
|||
break
|
||||
}
|
||||
}
|
||||
// In some occasions when the VM is mark as template it loses its configuration if it's done immediately
|
||||
// after the ESXi creates it. If vSphere is given a few seconds this behavior doesn't reappear.
|
||||
// In some occasions the VM state is powered on and if we immediately try to mark as template
|
||||
// (after the ESXi creates it) it will fail. If vSphere is given a few seconds this behavior doesn't reappear.
|
||||
ui.Message("Waiting 10s for VMWare vSphere to start")
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
c, err := govmomi.NewClient(context.Background(), p.url, p.config.Insecure)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Error connecting to vSphere: %s", err)
|
||||
|
@ -120,14 +119,10 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
|||
&stepCreateFolder{
|
||||
Folder: p.config.Folder,
|
||||
},
|
||||
&stepFetchVm{
|
||||
&stepMarkAsTemplate{
|
||||
VMName: p.config.VMName,
|
||||
Source: source,
|
||||
},
|
||||
&stepMarkAsTemplate{},
|
||||
&stepMoveTemplate{
|
||||
Folder: p.config.Folder,
|
||||
},
|
||||
}
|
||||
|
||||
runner := &multistep.BasicRunner{Steps: steps}
|
||||
|
|
|
@ -18,17 +18,17 @@ func (s *stepChooseDatacenter) Run(state multistep.StateBag) multistep.StepActio
|
|||
cli := state.Get("client").(*govmomi.Client)
|
||||
finder := find.NewFinder(cli.Client, false)
|
||||
|
||||
ui.Message("Choosing datacenter...")
|
||||
|
||||
dc, err := finder.DatacenterOrDefault(context.Background(), s.Datacenter)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
finder.SetDatacenter(dc)
|
||||
state.Put("dcPath", dc.InventoryPath)
|
||||
state.Put("finder", finder)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ func (s *stepCreateFolder) Run(state multistep.StateBag) multistep.StepAction {
|
|||
cli := state.Get("client").(*govmomi.Client)
|
||||
dcPath := state.Get("dcPath").(string)
|
||||
|
||||
if s.Folder != "" {
|
||||
ui.Say("Creating or checking destination folders...")
|
||||
ui.Message("Creating or checking destination folders...")
|
||||
|
||||
base := path.Join(dcPath, "vm")
|
||||
fullPath := path.Join(base, s.Folder)
|
||||
|
@ -41,6 +40,7 @@ func (s *stepCreateFolder) Run(state multistep.StateBag) multistep.StepAction {
|
|||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if ref == nil {
|
||||
dir, folder := path.Split(fullPath)
|
||||
fullPath = path.Clean(dir)
|
||||
|
@ -58,17 +58,28 @@ func (s *stepCreateFolder) Run(state multistep.StateBag) multistep.StepAction {
|
|||
}
|
||||
}
|
||||
|
||||
root := ref.(*object.Folder)
|
||||
if root, ok := ref.(*object.Folder); ok {
|
||||
for i := len(folders) - 1; i >= 0; i-- {
|
||||
ui.Message(fmt.Sprintf("Creating folder: %v", folders[i]))
|
||||
|
||||
root, err = root.CreateFolder(context.Background(), folders[i])
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
fullPath = path.Join(fullPath, folders[i])
|
||||
}
|
||||
root.SetInventoryPath(fullPath)
|
||||
state.Put("folder", root)
|
||||
} else {
|
||||
err = fmt.Errorf("folder not found: '%v'", ref)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
package vsphere_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/vmware/govmomi/find"
|
||||
)
|
||||
|
||||
type stepFetchVm struct {
|
||||
VMName string
|
||||
Source string
|
||||
}
|
||||
|
||||
func (s *stepFetchVm) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
finder := state.Get("finder").(*find.Finder)
|
||||
|
||||
ui.Say("Fetching VM...")
|
||||
|
||||
if err := avoidOrphaned(finder, s.VMName); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
path := strings.Split(s.Source, "/vmfs/volumes/")[1]
|
||||
i := strings.Index(path, "/")
|
||||
storage := path[:i]
|
||||
vmx := path[i:]
|
||||
|
||||
ds, err := finder.DatastoreOrDefault(context.Background(), storage)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
folder, err := finder.DefaultFolder(context.Background())
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
pool, err := finder.DefaultResourcePool(context.Background())
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
task, err := folder.RegisterVM(context.Background(), ds.Path(vmx), s.VMName, false, pool, nil)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if err = task.Wait(context.Background()); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
vm, err := finder.VirtualMachine(context.Background(), s.VMName)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
state.Put("vm", vm)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
// When ESXi remove the VM, vSphere keep the VM as orphaned
|
||||
func avoidOrphaned(f *find.Finder, vm_name string) error {
|
||||
vm, err := f.VirtualMachine(context.Background(), vm_name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return vm.Unregister(context.Background())
|
||||
}
|
||||
|
||||
func (s *stepFetchVm) Cleanup(multistep.StateBag) {}
|
|
@ -2,26 +2,117 @@ package vsphere_template
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/object"
|
||||
)
|
||||
|
||||
type stepMarkAsTemplate struct{}
|
||||
type stepMarkAsTemplate struct {
|
||||
VMName string
|
||||
Source string
|
||||
}
|
||||
|
||||
func (s *stepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
cli := state.Get("client").(*govmomi.Client)
|
||||
folder := state.Get("folder").(*object.Folder)
|
||||
dcPath := state.Get("dcPath").(string)
|
||||
|
||||
ui.Say("Marking as a template...")
|
||||
ui.Message("Marking as a template...")
|
||||
|
||||
if err := vm.MarkAsTemplate(context.Background()); err != nil {
|
||||
vm, err := findRuntimeVM(cli, dcPath, s.VMName)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
host, err := vm.HostSystem(context.Background())
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if err := vm.Unregister(context.Background()); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
source := strings.Split(s.Source, "/vmfs/volumes/")[1]
|
||||
i := strings.Index(source, "/")
|
||||
|
||||
path := (&object.DatastorePath{
|
||||
Datastore: source[:i],
|
||||
Path: source[i:],
|
||||
}).String()
|
||||
|
||||
if err := unregisterPreviousVM(cli, folder, s.VMName); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
task, err := folder.RegisterVM(context.Background(), path, s.VMName, true, nil, host)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if err = task.Wait(context.Background()); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
// We will use the virtual machine created by vmware-iso builder
|
||||
func findRuntimeVM(cli *govmomi.Client, dcPath, name string) (*object.VirtualMachine, error) {
|
||||
si := object.NewSearchIndex(cli.Client)
|
||||
fullPath := path.Join(dcPath, "vm", "Discovered virtual machine", name)
|
||||
|
||||
ref, err := si.FindByInventoryPath(context.Background(), fullPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ref == nil {
|
||||
return nil, fmt.Errorf("VM at path %s not found", fullPath)
|
||||
}
|
||||
|
||||
return ref.(*object.VirtualMachine), nil
|
||||
}
|
||||
|
||||
// If in the target folder a virtual machine or template already exists
|
||||
// it will be removed to maintain consistency
|
||||
func unregisterPreviousVM(cli *govmomi.Client, folder *object.Folder, name string) error {
|
||||
si := object.NewSearchIndex(cli.Client)
|
||||
fullPath := path.Join(folder.InventoryPath, name)
|
||||
|
||||
ref, err := si.FindByInventoryPath(context.Background(), fullPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ref != nil {
|
||||
if vm, ok := ref.(*object.VirtualMachine); ok {
|
||||
return vm.Unregister(context.Background())
|
||||
} else {
|
||||
return fmt.Errorf("an object name '%v' already exists", name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stepMarkAsTemplate) Cleanup(multistep.StateBag) {}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
package vsphere_template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type stepMoveTemplate struct {
|
||||
Folder string
|
||||
}
|
||||
|
||||
func (s *stepMoveTemplate) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
finder := state.Get("finder").(*find.Finder)
|
||||
dcPath := state.Get("dcPath").(string)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
|
||||
if s.Folder != "" {
|
||||
ui.Say("Moving template...")
|
||||
|
||||
folder, err := finder.Folder(context.Background(), path.Join(dcPath, "vm", s.Folder))
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
task, err := folder.MoveInto(context.Background(), []types.ManagedObjectReference{vm.Reference()})
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
if err = task.Wait(context.Background()); err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepMoveTemplate) Cleanup(multistep.StateBag) {}
|
Loading…
Reference in New Issue