From fa10616f57f1801713a70793cb2596967b6bbb32 Mon Sep 17 00:00:00 2001 From: bugbuilder Date: Tue, 18 Jul 2017 23:10:05 -0400 Subject: [PATCH] Changes requested applied --- .../vsphere-template/post-processor.go | 49 +++++++++---------- .../vsphere-template/post_processor_test.go | 19 ------- .../step_choose_datacenter.go | 11 ++--- .../vsphere-template/step_create_folder.go | 27 +++++----- .../vsphere-template/step_fetch_vm.go | 29 ++++++----- .../vsphere-template/step_mark_as_template.go | 9 ++-- .../vsphere-template/step_move_template.go | 15 +++--- .../post-processors/vsphere-template.html.md | 15 +++--- 8 files changed, 73 insertions(+), 101 deletions(-) delete mode 100644 post-processor/vsphere-template/post_processor_test.go diff --git a/post-processor/vsphere-template/post-processor.go b/post-processor/vsphere-template/post-processor.go index 52cdff1bd..7f1ccd190 100644 --- a/post-processor/vsphere-template/post-processor.go +++ b/post-processor/vsphere-template/post-processor.go @@ -25,7 +25,7 @@ type Config struct { Insecure bool `mapstructure:"insecure"` Username string `mapstructure:"username"` Password string `mapstructure:"password"` - Datacenter string `mapstructure:"datacenter"` + Datacenter string `mapstructure:"Datacenter"` VMName string `mapstructure:"vm_name"` Folder string `mapstructure:"folder"` @@ -64,11 +64,20 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } } - if err := p.configureURL(); err != nil { + if p.config.Folder != "" && !strings.HasPrefix(p.config.Folder, "/") { errs = packer.MultiErrorAppend( - errs, err) + errs, fmt.Errorf("Folder must be bound to the root")) } + sdk, err := url.Parse(fmt.Sprintf("https://%v/sdk", p.config.Host)) + if err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("Error invalid vSphere sdk endpoint: %s", err)) + } + + sdk.User = url.UserPassword(p.config.Username, p.config.Password) + p.url = sdk + if len(errs.Errors) > 0 { return errs } @@ -77,7 +86,7 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { if _, ok := builtins[artifact.BuilderId()]; !ok { - return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId()) + return nil, false, fmt.Errorf("Unknown artifact type, can't build template: %s", artifact.BuilderId()) } source := "" @@ -87,34 +96,33 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac break } } - //We give a vSphere-ESXI 10s to sync + // 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. 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) + c, err := govmomi.NewClient(context.Background(), p.url, p.config.Insecure) if err != nil { - return artifact, true, fmt.Errorf("Error trying to connect: %s", err) + return nil, true, fmt.Errorf("Error connecting to vSphere: %s", err) } state := new(multistep.BasicStateBag) state.Put("ui", ui) - state.Put("context", ctx) state.Put("client", c) steps := []multistep.Step{ - &StepChooseDatacenter{ + &stepChooseDatacenter{ Datacenter: p.config.Datacenter, }, - &StepFetchVm{ + &stepFetchVm{ VMName: p.config.VMName, Source: source, }, - &StepCreateFolder{ + &stepCreateFolder{ Folder: p.config.Folder, }, - &StepMarkAsTemplate{}, - &StepMoveTemplate{ + &stepMarkAsTemplate{}, + &stepMoveTemplate{ Folder: p.config.Folder, }, } @@ -123,18 +131,7 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac runner.Run(state) if rawErr, ok := state.GetOk("error"); ok { - return artifact, true, rawErr.(error) + return nil, true, rawErr.(error) } return artifact, true, nil } - -func (p *PostProcessor) configureURL() error { - sdk, err := url.Parse(fmt.Sprintf("https://%v/sdk", p.config.Host)) - if err != nil { - return nil - } - - sdk.User = url.UserPassword(p.config.Username, p.config.Password) - p.url = sdk - return nil -} diff --git a/post-processor/vsphere-template/post_processor_test.go b/post-processor/vsphere-template/post_processor_test.go deleted file mode 100644 index 75b00ec38..000000000 --- a/post-processor/vsphere-template/post_processor_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package vsphere_template - -import ( - "testing" -) - -func TestConfigureURL(t *testing.T) { - var p PostProcessor - p.config.Username = "me" - p.config.Password = "notpassword" - p.config.Host = "myhost" - p.config.Datacenter = "mydc" - p.config.VMName = "my vm" - p.config.Insecure = true - - if err := p.configureURL(); err != nil { - t.Errorf("Error: %s", err) - } -} diff --git a/post-processor/vsphere-template/step_choose_datacenter.go b/post-processor/vsphere-template/step_choose_datacenter.go index 05f366195..71eef585e 100644 --- a/post-processor/vsphere-template/step_choose_datacenter.go +++ b/post-processor/vsphere-template/step_choose_datacenter.go @@ -9,17 +9,16 @@ import ( "github.com/vmware/govmomi/find" ) -type StepChooseDatacenter struct { +type stepChooseDatacenter struct { Datacenter string } -func (s *StepChooseDatacenter) 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) finder := find.NewFinder(cli.Client, false) - datacenter, err := finder.DatacenterOrDefault(ctx, s.Datacenter) + datacenter, err := finder.DatacenterOrDefault(context.Background(), s.Datacenter) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -28,9 +27,9 @@ func (s *StepChooseDatacenter) Run(state multistep.StateBag) multistep.StepActio } finder.SetDatacenter(datacenter) - state.Put("datacenter", datacenter.Name()) + state.Put("Datacenter", datacenter.Name()) state.Put("finder", finder) return multistep.ActionContinue } -func (s *StepChooseDatacenter) Cleanup(multistep.StateBag) {} +func (s *stepChooseDatacenter) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/step_create_folder.go b/post-processor/vsphere-template/step_create_folder.go index 48ade578e..a0bcb14fd 100644 --- a/post-processor/vsphere-template/step_create_folder.go +++ b/post-processor/vsphere-template/step_create_folder.go @@ -12,36 +12,33 @@ import ( "github.com/vmware/govmomi/object" ) -type StepCreateFolder struct { +type stepCreateFolder struct { Folder string } -func (s *StepCreateFolder) Run(state multistep.StateBag) multistep.StepAction { +func (s *stepCreateFolder) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) - ctx := state.Get("context").(context.Context) - f := state.Get("finder").(*find.Finder) - d := state.Get("datacenter").(string) + finder := state.Get("finder").(*find.Finder) + dc := state.Get("Datacenter").(string) if s.Folder != "" { ui.Say("Creating or checking destination folders...") - if !strings.HasPrefix(s.Folder, "/") { - s.Folder = filepath.Join("/", s.Folder) - } - path := s.Folder - base := filepath.Join("/", d, "vm") + base := filepath.Join("/", dc, "vm") var folders []string var root *object.Folder var err error - + // We iterate over the path starting with full path + // If we don't find it, we save the folder name and continue with the previous path + // The iteration ends when we find an existing path for { - root, err = f.Folder(ctx, filepath.ToSlash(filepath.Join(base, path))) + root, err = finder.Folder(context.Background(), filepath.ToSlash(filepath.Join(base, path))) if err != nil { _, folder := filepath.Split(path) folders = append(folders, folder) if i := strings.LastIndex(path, "/"); i == 0 { - root, err = f.Folder(ctx, filepath.ToSlash(base)) + root, err = finder.Folder(context.Background(), filepath.ToSlash(base)) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -58,7 +55,7 @@ func (s *StepCreateFolder) Run(state multistep.StateBag) multistep.StepAction { for i := len(folders) - 1; i >= 0; i-- { ui.Message(fmt.Sprintf("Creating folder: %v", folders[i])) - root, err = root.CreateFolder(ctx, folders[i]) + root, err = root.CreateFolder(context.Background(), folders[i]) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -69,4 +66,4 @@ func (s *StepCreateFolder) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } -func (s *StepCreateFolder) Cleanup(multistep.StateBag) {} +func (s *stepCreateFolder) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/step_fetch_vm.go b/post-processor/vsphere-template/step_fetch_vm.go index 5f1d2eaae..84d6b8bac 100644 --- a/post-processor/vsphere-template/step_fetch_vm.go +++ b/post-processor/vsphere-template/step_fetch_vm.go @@ -9,19 +9,18 @@ import ( "github.com/vmware/govmomi/find" ) -type StepFetchVm struct { +type stepFetchVm struct { VMName string Source string } -func (s *StepFetchVm) Run(state multistep.StateBag) multistep.StepAction { +func (s *stepFetchVm) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) - ctx := state.Get("context").(context.Context) f := state.Get("finder").(*find.Finder) ui.Say("Fetching VM...") - if err := avoidOrphaned(ctx, f, s.VMName); err != nil { + if err := avoidOrphaned(f, s.VMName); err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -32,41 +31,41 @@ func (s *StepFetchVm) Run(state multistep.StateBag) multistep.StepAction { storage := path[:i] vmx := path[i:] - ds, err := f.DatastoreOrDefault(ctx, storage) + ds, err := f.DatastoreOrDefault(context.Background(), storage) if err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - folder, err := f.DefaultFolder(ctx) + folder, err := f.DefaultFolder(context.Background()) if err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - pool, err := f.DefaultResourcePool(ctx) + pool, err := f.DefaultResourcePool(context.Background()) 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) + 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(ctx); err != nil { + if err = task.Wait(context.Background()); err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - vm, err := f.VirtualMachine(ctx, s.VMName) + vm, err := f.VirtualMachine(context.Background(), s.VMName) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -77,13 +76,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) +// 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(ctx) + return vm.Unregister(context.Background()) } -func (s *StepFetchVm) Cleanup(multistep.StateBag) {} +func (s *stepFetchVm) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/step_mark_as_template.go b/post-processor/vsphere-template/step_mark_as_template.go index 2f8834d2f..8948764a0 100644 --- a/post-processor/vsphere-template/step_mark_as_template.go +++ b/post-processor/vsphere-template/step_mark_as_template.go @@ -8,16 +8,15 @@ import ( "github.com/vmware/govmomi/object" ) -type StepMarkAsTemplate struct{} +type stepMarkAsTemplate struct{} -func (s *StepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction { +func (s *stepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) - ctx := state.Get("context").(context.Context) vm := state.Get("vm").(*object.VirtualMachine) ui.Say("Marking as a template...") - if err := vm.MarkAsTemplate(ctx); err != nil { + if err := vm.MarkAsTemplate(context.Background()); err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -25,4 +24,4 @@ func (s *StepMarkAsTemplate) Run(state multistep.StateBag) multistep.StepAction return multistep.ActionContinue } -func (s *StepMarkAsTemplate) Cleanup(multistep.StateBag) {} +func (s *stepMarkAsTemplate) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/step_move_template.go b/post-processor/vsphere-template/step_move_template.go index 00f6ba711..8b288fefc 100644 --- a/post-processor/vsphere-template/step_move_template.go +++ b/post-processor/vsphere-template/step_move_template.go @@ -11,21 +11,20 @@ import ( "github.com/vmware/govmomi/vim25/types" ) -type StepMoveTemplate struct { +type stepMoveTemplate struct { Folder string } -func (s *StepMoveTemplate) Run(state multistep.StateBag) multistep.StepAction { +func (s *stepMoveTemplate) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) - ctx := state.Get("context").(context.Context) finder := state.Get("finder").(*find.Finder) - d := state.Get("datacenter").(string) + dc := state.Get("Datacenter").(string) vm := state.Get("vm").(*object.VirtualMachine) if s.Folder != "" { ui.Say("Moving template...") - folder, err := finder.Folder(ctx, filepath.ToSlash(filepath.Join("/", d, "vm", s.Folder))) + folder, err := finder.Folder(context.Background(), filepath.ToSlash(filepath.Join("/", dc, "vm", s.Folder))) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -33,13 +32,13 @@ func (s *StepMoveTemplate) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } - task, err := folder.MoveInto(ctx, []types.ManagedObjectReference{vm.Reference()}) + 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(ctx); err != nil { + if err = task.Wait(context.Background()); err != nil { state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -48,4 +47,4 @@ func (s *StepMoveTemplate) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } -func (s *StepMoveTemplate) Cleanup(multistep.StateBag) {} +func (s *stepMoveTemplate) Cleanup(multistep.StateBag) {} diff --git a/website/source/docs/post-processors/vsphere-template.html.md b/website/source/docs/post-processors/vsphere-template.html.md index fb78857f5..e97a32ff4 100644 --- a/website/source/docs/post-processors/vsphere-template.html.md +++ b/website/source/docs/post-processors/vsphere-template.html.md @@ -1,6 +1,6 @@ --- description: | - The Packer vSphere Template post-processor takes an artifact from the VMware-iso builder -**only if remote ESXI was chosen**- + The Packer vSphere Template post-processor takes an artifact from the VMware-iso builder built on ESXi (i.e. remote) and allows to mark a VM as a template and leaving it in a path of choice. layout: docs page_title: 'vSphere Template - Post-Processors' @@ -11,7 +11,7 @@ sidebar_current: 'docs-post-processors-vSphere-template' Type: `vsphere-template` -The Packer vSphere template post-processor takes an artifact from the VMware-iso builder -**only if remote ESXI was chosen**- +The Packer vSphere template post-processor takes an artifact from the VMware-iso builder built on ESXi (i.e. remote) allows to mark a VM as a template and leaving it in a path of choice. ## Example @@ -22,11 +22,12 @@ An example is shown below, showing only the post-processor configuration: { "type": "vsphere-template", "host": "vcenter.local", + "insecure": true, "username": "root", - "password": "secret", - "datacenter": "murlock", + "password": "secret", "vm_name": "distro-7.3", - "folder": "/packer-templates/os/distro-7" + "datacenter": "mydatacenter", + "folder": "/packer-templates/os/distro-7" } ``` @@ -53,6 +54,6 @@ Required: Optional: +- `datacenter` (string) - If you have more than one, you will need to specify which one the ESXi used. + - `folder` (string) - Target path where the template will be created. - -- `datacenter` (string) - If you have more than one, you will need to specify which one the ESXI used.