Changes requested applied

This commit is contained in:
bugbuilder 2017-07-18 23:10:05 -04:00
parent 2ddc07d3b9
commit fa10616f57
8 changed files with 73 additions and 101 deletions

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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) {}

View File

@ -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) {}

View File

@ -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) {}

View File

@ -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) {}

View File

@ -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) {}

View File

@ -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.