From 644ac5b367b10d0dd1b82dd84bd3176a804ed739 Mon Sep 17 00:00:00 2001 From: bugbuilder Date: Wed, 20 Sep 2017 22:50:37 -0300 Subject: [PATCH] enable vsphere-template to work with local builders --- .../vsphere-template/post-processor.go | 17 ++++++--- .../vsphere-template/step_mark_as_template.go | 34 ++++++++++++++--- post-processor/vsphere/artifact.go | 38 +++++++++++++++++++ post-processor/vsphere/post-processor.go | 9 ++++- 4 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 post-processor/vsphere/artifact.go diff --git a/post-processor/vsphere-template/post-processor.go b/post-processor/vsphere-template/post-processor.go index 86c9f54b4..e68e2d21c 100644 --- a/post-processor/vsphere-template/post-processor.go +++ b/post-processor/vsphere-template/post-processor.go @@ -7,16 +7,19 @@ import ( "strings" "time" + "github.com/hashicorp/packer/builder/vmware/iso" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/post-processor/vsphere" "github.com/hashicorp/packer/template/interpolate" "github.com/mitchellh/multistep" "github.com/vmware/govmomi" ) var builtins = map[string]string{ - "mitchellh.vmware-esx": "vmware", + vsphere.BuilderId: "vmware", + iso.BuilderIdESX: "vmware", } type Config struct { @@ -90,11 +93,16 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac source := "" for _, path := range artifact.Files() { - if strings.HasSuffix(path, ".vmx") { + if strings.HasSuffix(path, ".vmx") || strings.HasSuffix(path, ".ovf") || strings.HasSuffix(path, ".ova") { source = path break } } + + if source == "" { + return nil, false, fmt.Errorf("VMX, OVF or OVA file not found") + } + // 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") @@ -117,10 +125,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac &stepCreateFolder{ Folder: p.config.Folder, }, - &stepMarkAsTemplate{ - VMName: artifact.Id(), - Source: source, - }, + NewStepMarkAsTemplate(artifact.Id(), source), } runner := common.NewRunnerWithPauseFn(steps, p.config.PackerConfig, ui, state) runner.Run(state) diff --git a/post-processor/vsphere-template/step_mark_as_template.go b/post-processor/vsphere-template/step_mark_as_template.go index 0e5465054..dda3984a6 100644 --- a/post-processor/vsphere-template/step_mark_as_template.go +++ b/post-processor/vsphere-template/step_mark_as_template.go @@ -13,8 +13,30 @@ import ( ) type stepMarkAsTemplate struct { - VMName string - Source string + VMName string + Source string + RemoteFolder string +} + +func NewStepMarkAsTemplate(vmname, source string) *stepMarkAsTemplate { + remoteFolder := "Discovered virtual machine" + + if strings.Contains(vmname, "::") { + local := strings.Split(vmname, "::") + + datastore := local[0] + remoteFolder = local[1] + vmname = local[2] + + source = path.Join("/vmfs/volumes/", datastore, vmname, path.Base(source)) + + } + + return &stepMarkAsTemplate{ + VMName: vmname, + Source: source, + RemoteFolder: remoteFolder, + } } func (s *stepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction { @@ -25,7 +47,7 @@ func (s *stepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction ui.Message("Marking as a template...") - vm, err := findRuntimeVM(cli, dcPath, s.VMName) + vm, err := findRuntimeVM(cli, dcPath, s.VMName, s.RemoteFolder) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -75,10 +97,10 @@ func (s *stepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction 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) { +// We will use the virtual machine created/uploaded by vmware builder (remote or local) +func findRuntimeVM(cli *govmomi.Client, dcPath, name, remoteFolder string) (*object.VirtualMachine, error) { si := object.NewSearchIndex(cli.Client) - fullPath := path.Join(dcPath, "vm", "Discovered virtual machine", name) + fullPath := path.Join(dcPath, "vm", remoteFolder, name) ref, err := si.FindByInventoryPath(context.Background(), fullPath) if err != nil { diff --git a/post-processor/vsphere/artifact.go b/post-processor/vsphere/artifact.go new file mode 100644 index 000000000..d8ef75491 --- /dev/null +++ b/post-processor/vsphere/artifact.go @@ -0,0 +1,38 @@ +package vsphere + +import ( + "fmt" +) + +const BuilderId = "packer.post-processor.vsphere" + +type Artifact struct { + files []string + datastore string + vmfolder string + vmname string +} + +func (*Artifact) BuilderId() string { + return BuilderId +} + +func (a *Artifact) Files() []string { + return a.files +} + +func (a *Artifact) Id() string { + return fmt.Sprintf("%s::%s::%s", a.datastore, a.vmfolder, a.vmname) +} + +func (a *Artifact) String() string { + return fmt.Sprintf("VM: %s Folder: %s Datastore: %s", a.vmname, a.vmfolder, a.datastore) +} + +func (*Artifact) State(name string) interface{} { + return nil +} + +func (a *Artifact) Destroy() error { + return nil +} diff --git a/post-processor/vsphere/post-processor.go b/post-processor/vsphere/post-processor.go index e97147334..ead3b50fd 100644 --- a/post-processor/vsphere/post-processor.go +++ b/post-processor/vsphere/post-processor.go @@ -142,7 +142,14 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac return nil, false, fmt.Errorf("Failed: %s\n", err) } - return artifact, false, nil + artifact = &Artifact{ + datastore: p.config.Datastore, + files: artifact.Files(), + vmfolder: p.config.VMFolder, + vmname: p.config.VMName, + } + + return artifact, true, nil } func (p *PostProcessor) BuildArgs(source, ovftool_uri string) ([]string, error) {