diff --git a/post-processor/vsphere-tpl/post-processor.go b/post-processor/vsphere-tpl/post-processor.go index 855142abc..07f749c3f 100644 --- a/post-processor/vsphere-tpl/post-processor.go +++ b/post-processor/vsphere-tpl/post-processor.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "time" + "strings" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/config" @@ -14,6 +15,10 @@ import ( "github.com/vmware/govmomi" ) +var builtins = map[string]string{ + "mitchellh.vmware-esx": "vmware", +} + type Config struct { common.PackerConfig `mapstructure:",squash"` Host string `mapstructure:"host"` @@ -71,12 +76,22 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { - ctx := context.Background() + if _, ok := builtins[artifact.BuilderId()]; !ok { + return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) + } - //FIXME I've trash environment, so I need to wait :( + source := "" + for _, path := range artifact.Files() { + if strings.HasSuffix(path, ".vmx") { + source = path + break + } + } + //We give a vSphere-ESXI 10s to sync ui.Message("Waiting 10s for VMWare vSphere to start") time.Sleep(10 * time.Second) + ctx := context.Background() c, err := govmomi.NewClient(ctx, p.url, p.config.Insecure) if err != nil { return artifact, true, fmt.Errorf("Error trying to connect: %s", err) @@ -88,18 +103,19 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac state.Put("client", c) steps := []multistep.Step{ - &StepPickDatacenter{ + &StepChooseDatacenter{ Datacenter: p.config.Datacenter, }, &StepFetchVm{ VMName: p.config.VMName, + Source: source, }, &StepCreateFolder{ - Folder: p.config.Folder, + Folder: p.config.Folder, }, &StepMarkAsTemplate{}, &StepMoveTemplate{ - Folder: p.config.Folder, + Folder: p.config.Folder, }, } diff --git a/post-processor/vsphere-tpl/step_pick_datacenter.go b/post-processor/vsphere-tpl/step_choose_datacenter.go similarity index 79% rename from post-processor/vsphere-tpl/step_pick_datacenter.go rename to post-processor/vsphere-tpl/step_choose_datacenter.go index c037fef96..a60c53ddc 100644 --- a/post-processor/vsphere-tpl/step_pick_datacenter.go +++ b/post-processor/vsphere-tpl/step_choose_datacenter.go @@ -9,11 +9,11 @@ import ( "github.com/vmware/govmomi/find" ) -type StepPickDatacenter struct { +type StepChooseDatacenter struct { Datacenter string } -func (s *StepPickDatacenter) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepChooseDatacenter) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) cli := state.Get("client").(*govmomi.Client) ctx := state.Get("context").(context.Context) @@ -33,4 +33,4 @@ func (s *StepPickDatacenter) Run(state multistep.StateBag) multistep.StepAction return multistep.ActionContinue } -func (s *StepPickDatacenter) Cleanup(multistep.StateBag) {} +func (s *StepChooseDatacenter) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-tpl/step_fetch_vm.go b/post-processor/vsphere-tpl/step_fetch_vm.go index 8f64d3ace..dbe05eeb0 100644 --- a/post-processor/vsphere-tpl/step_fetch_vm.go +++ b/post-processor/vsphere-tpl/step_fetch_vm.go @@ -2,6 +2,7 @@ package vsphere_tpl import ( "context" + "strings" "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" @@ -10,6 +11,7 @@ import ( type StepFetchVm struct { VMName string + Source string } func (s *StepFetchVm) Run(state multistep.StateBag) multistep.StepAction { @@ -19,8 +21,53 @@ func (s *StepFetchVm) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Fetching VM...") - vm, err := f.VirtualMachine(ctx, s.VMName) + if err := avoidOrphaned(ctx, f, 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 := f.DatastoreOrDefault(ctx, storage) + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + folder, err := f.DefaultFolder(ctx) + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + pool, err := f.DefaultResourcePool(ctx) + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + task, err := folder.RegisterVM(ctx, ds.Path(vmx), s.VMName, false, pool, nil) + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + err = task.Wait(ctx) + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + vm, err := f.VirtualMachine(ctx, s.VMName) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -31,4 +78,13 @@ func (s *StepFetchVm) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } +// When ESXI remove the VM, vSphere keep the VM as orphaned +func avoidOrphaned(ctx context.Context, f *find.Finder, vm_name string) error { + vm, err := f.VirtualMachine(ctx, vm_name) + if err != nil { + return err + } + return vm.Unregister(ctx) +} + func (s *StepFetchVm) Cleanup(multistep.StateBag) {}