diff --git a/builder/vmware/common/step_prepare_tools.go b/builder/vmware/common/step_prepare_tools.go new file mode 100644 index 000000000..070220a5c --- /dev/null +++ b/builder/vmware/common/step_prepare_tools.go @@ -0,0 +1,40 @@ +package common + +import ( + "fmt" + "github.com/mitchellh/multistep" + "os" +) + +type StepPrepareTools struct { + RemoteType string `mapstructure:"remote_type"` + ToolsUploadFlavor string `mapstructure:"tools_upload_flavor"` + ToolsUploadPath string `mapstructure:"tools_upload_path"` +} + +func (c *StepPrepareTools) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) + + if c.RemoteType == "esx5" { + return multistep.ActionContinue + } + + if c.ToolsUploadFlavor == "" { + return multistep.ActionContinue + } + + path := driver.ToolsIsoPath(c.ToolsUploadFlavor) + if _, err := os.Stat(path); err != nil { + state.Put("error", fmt.Errorf( + "Couldn't find VMware tools for '%s'! VMware often downloads these\n"+ + "tools on-demand. However, to do this, you need to create a fake VM\n"+ + "of the proper type then click the 'install tools' option in the\n"+ + "VMware GUI.", c.ToolsUploadFlavor)) + return multistep.ActionHalt + } + + state.Put("tools_upload_source", path) + return multistep.ActionContinue +} + +func (c *StepPrepareTools) Cleanup(multistep.StateBag) {} diff --git a/builder/vmware/iso/step_upload_tools.go b/builder/vmware/common/step_upload_tools.go similarity index 56% rename from builder/vmware/iso/step_upload_tools.go rename to builder/vmware/common/step_upload_tools.go index 3fdf5db4d..6225ecf2b 100644 --- a/builder/vmware/iso/step_upload_tools.go +++ b/builder/vmware/common/step_upload_tools.go @@ -1,9 +1,8 @@ -package iso +package common import ( "fmt" "github.com/mitchellh/multistep" - vmwcommon "github.com/mitchellh/packer/builder/vmware/common" "github.com/mitchellh/packer/packer" "os" ) @@ -12,20 +11,24 @@ type toolsUploadPathTemplate struct { Flavor string } -type stepUploadTools struct{} +type StepUploadTools struct { + RemoteType string `mapstructure:"remote_type"` + ToolsUploadFlavor string `mapstructure:"tools_upload_flavor"` + ToolsUploadPath string `mapstructure:"tools_upload_path"` + Tpl *packer.ConfigTemplate +} -func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(*config) - driver := state.Get("driver").(vmwcommon.Driver) +func (c *StepUploadTools) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) - if config.RemoteType == "esx5" { + if c.RemoteType == "esx5" { if err := driver.ToolsInstall(); err != nil { state.Put("error", fmt.Errorf("Couldn't mount VMware tools ISO.")) } return multistep.ActionContinue } - if config.ToolsUploadFlavor == "" { + if c.ToolsUploadFlavor == "" { return multistep.ActionContinue } @@ -33,7 +36,7 @@ func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction { tools_source := state.Get("tools_upload_source").(string) ui := state.Get("ui").(packer.Ui) - ui.Say(fmt.Sprintf("Uploading the '%s' VMware Tools", config.ToolsUploadFlavor)) + ui.Say(fmt.Sprintf("Uploading the '%s' VMware Tools", c.ToolsUploadFlavor)) f, err := os.Open(tools_source) if err != nil { state.Put("error", fmt.Errorf("Error opening VMware Tools ISO: %s", err)) @@ -41,8 +44,10 @@ func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction { } defer f.Close() - tplData := &toolsUploadPathTemplate{Flavor: config.ToolsUploadFlavor} - config.ToolsUploadPath, err = config.tpl.Process(config.ToolsUploadPath, tplData) + tplData := &toolsUploadPathTemplate{ + Flavor: c.ToolsUploadFlavor, + } + c.ToolsUploadPath, err = c.Tpl.Process(c.ToolsUploadPath, tplData) if err != nil { err := fmt.Errorf("Error preparing upload path: %s", err) state.Put("error", err) @@ -50,7 +55,7 @@ func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } - if err := comm.Upload(config.ToolsUploadPath, f); err != nil { + if err := comm.Upload(c.ToolsUploadPath, f); err != nil { err := fmt.Errorf("Error uploading VMware Tools: %s", err) state.Put("error", err) ui.Error(err.Error()) @@ -60,4 +65,4 @@ func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } -func (*stepUploadTools) Cleanup(multistep.StateBag) {} +func (c *StepUploadTools) Cleanup(multistep.StateBag) {} diff --git a/builder/vmware/common/tools_config.go b/builder/vmware/common/tools_config.go new file mode 100644 index 000000000..c50c22e6b --- /dev/null +++ b/builder/vmware/common/tools_config.go @@ -0,0 +1,38 @@ +package common + +import ( + "fmt" + "text/template" + + "github.com/mitchellh/packer/packer" +) + +type ToolsConfig struct { + ToolsUploadFlavor string `mapstructure:"tools_upload_flavor"` + ToolsUploadPath string `mapstructure:"tools_upload_path"` +} + +func (c *ToolsConfig) Prepare(t *packer.ConfigTemplate) []error { + if c.ToolsUploadPath == "" { + c.ToolsUploadPath = "{{ .Flavor }}.iso" + } + + templates := map[string]*string{ + "tools_upload_flavor": &c.ToolsUploadFlavor, + } + + var err error + errs := make([]error, 0) + for n, ptr := range templates { + *ptr, err = t.Process(*ptr, nil) + if err != nil { + errs = append(errs, fmt.Errorf("Error processing %s: %s", n, err)) + } + } + + if _, err := template.New("path").Parse(c.ToolsUploadPath); err != nil { + errs = append(errs, fmt.Errorf("tools_upload_path invalid: %s", err)) + } + + return errs +} diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index c46a4a1b2..ae8a7dba3 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -12,7 +12,6 @@ import ( "math/rand" "os" "strings" - "text/template" "time" ) @@ -30,27 +29,26 @@ type config struct { vmwcommon.RunConfig `mapstructure:",squash"` vmwcommon.ShutdownConfig `mapstructure:",squash"` vmwcommon.SSHConfig `mapstructure:",squash"` + vmwcommon.ToolsConfig `mapstructure:",squash"` vmwcommon.VMXConfig `mapstructure:",squash"` - DiskName string `mapstructure:"vmdk_name"` - DiskSize uint `mapstructure:"disk_size"` - DiskTypeId string `mapstructure:"disk_type_id"` - FloppyFiles []string `mapstructure:"floppy_files"` - GuestOSType string `mapstructure:"guest_os_type"` - ISOChecksum string `mapstructure:"iso_checksum"` - ISOChecksumType string `mapstructure:"iso_checksum_type"` - ISOUrls []string `mapstructure:"iso_urls"` - VMName string `mapstructure:"vm_name"` - HTTPDir string `mapstructure:"http_directory"` - HTTPPortMin uint `mapstructure:"http_port_min"` - HTTPPortMax uint `mapstructure:"http_port_max"` - BootCommand []string `mapstructure:"boot_command"` - SkipCompaction bool `mapstructure:"skip_compaction"` - ToolsUploadFlavor string `mapstructure:"tools_upload_flavor"` - ToolsUploadPath string `mapstructure:"tools_upload_path"` - VMXTemplatePath string `mapstructure:"vmx_template_path"` - VNCPortMin uint `mapstructure:"vnc_port_min"` - VNCPortMax uint `mapstructure:"vnc_port_max"` + DiskName string `mapstructure:"vmdk_name"` + DiskSize uint `mapstructure:"disk_size"` + DiskTypeId string `mapstructure:"disk_type_id"` + FloppyFiles []string `mapstructure:"floppy_files"` + GuestOSType string `mapstructure:"guest_os_type"` + ISOChecksum string `mapstructure:"iso_checksum"` + ISOChecksumType string `mapstructure:"iso_checksum_type"` + ISOUrls []string `mapstructure:"iso_urls"` + VMName string `mapstructure:"vm_name"` + HTTPDir string `mapstructure:"http_directory"` + HTTPPortMin uint `mapstructure:"http_port_min"` + HTTPPortMax uint `mapstructure:"http_port_max"` + BootCommand []string `mapstructure:"boot_command"` + SkipCompaction bool `mapstructure:"skip_compaction"` + VMXTemplatePath string `mapstructure:"vmx_template_path"` + VNCPortMin uint `mapstructure:"vnc_port_min"` + VNCPortMax uint `mapstructure:"vnc_port_max"` RemoteType string `mapstructure:"remote_type"` RemoteDatastore string `mapstructure:"remote_datastore"` @@ -84,6 +82,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(b.config.tpl)...) + errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.VMXConfig.Prepare(b.config.tpl)...) warnings := make([]string, 0) @@ -144,26 +143,21 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.RemotePort = 22 } - if b.config.ToolsUploadPath == "" { - b.config.ToolsUploadPath = "{{ .Flavor }}.iso" - } - // Errors templates := map[string]*string{ - "disk_name": &b.config.DiskName, - "guest_os_type": &b.config.GuestOSType, - "http_directory": &b.config.HTTPDir, - "iso_checksum": &b.config.ISOChecksum, - "iso_checksum_type": &b.config.ISOChecksumType, - "iso_url": &b.config.RawSingleISOUrl, - "tools_upload_flavor": &b.config.ToolsUploadFlavor, - "vm_name": &b.config.VMName, - "vmx_template_path": &b.config.VMXTemplatePath, - "remote_type": &b.config.RemoteType, - "remote_host": &b.config.RemoteHost, - "remote_datastore": &b.config.RemoteDatastore, - "remote_user": &b.config.RemoteUser, - "remote_password": &b.config.RemotePassword, + "disk_name": &b.config.DiskName, + "guest_os_type": &b.config.GuestOSType, + "http_directory": &b.config.HTTPDir, + "iso_checksum": &b.config.ISOChecksum, + "iso_checksum_type": &b.config.ISOChecksumType, + "iso_url": &b.config.RawSingleISOUrl, + "vm_name": &b.config.VMName, + "vmx_template_path": &b.config.VMXTemplatePath, + "remote_type": &b.config.RemoteType, + "remote_host": &b.config.RemoteHost, + "remote_datastore": &b.config.RemoteDatastore, + "remote_user": &b.config.RemoteUser, + "remote_password": &b.config.RemotePassword, } for n, ptr := range templates { @@ -245,11 +239,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } } - if _, err := template.New("path").Parse(b.config.ToolsUploadPath); err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("tools_upload_path invalid: %s", err)) - } - if b.config.VMXTemplatePath != "" { if err := b.validateVMXTemplatePath(); err != nil { errs = packer.MultiErrorAppend( @@ -320,7 +309,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe rand.Seed(time.Now().UTC().UnixNano()) steps := []multistep.Step{ - &stepPrepareTools{}, + &vmwcommon.StepPrepareTools{ + RemoteType: b.config.RemoteType, + ToolsUploadFlavor: b.config.ToolsUploadFlavor, + ToolsUploadPath: b.config.ToolsUploadPath, + }, &common.StepDownload{ Checksum: b.config.ISOChecksum, ChecksumType: b.config.ISOChecksumType, @@ -363,7 +356,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe SSHWaitTimeout: b.config.SSHWaitTimeout, NoPty: b.config.SSHSkipRequestPty, }, - &stepUploadTools{}, + &vmwcommon.StepUploadTools{ + RemoteType: b.config.RemoteType, + ToolsUploadFlavor: b.config.ToolsUploadFlavor, + ToolsUploadPath: b.config.ToolsUploadPath, + Tpl: b.config.tpl, + }, &common.StepProvision{}, &vmwcommon.StepShutdown{ Command: b.config.ShutdownCommand, diff --git a/builder/vmware/iso/step_prepare_tools.go b/builder/vmware/iso/step_prepare_tools.go deleted file mode 100644 index d9ad4acce..000000000 --- a/builder/vmware/iso/step_prepare_tools.go +++ /dev/null @@ -1,38 +0,0 @@ -package iso - -import ( - "fmt" - "github.com/mitchellh/multistep" - vmwcommon "github.com/mitchellh/packer/builder/vmware/common" - "os" -) - -type stepPrepareTools struct{} - -func (*stepPrepareTools) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(*config) - driver := state.Get("driver").(vmwcommon.Driver) - - if config.RemoteType == "esx5" { - return multistep.ActionContinue - } - - if config.ToolsUploadFlavor == "" { - return multistep.ActionContinue - } - - path := driver.ToolsIsoPath(config.ToolsUploadFlavor) - if _, err := os.Stat(path); err != nil { - state.Put("error", fmt.Errorf( - "Couldn't find VMware tools for '%s'! VMware often downloads these\n"+ - "tools on-demand. However, to do this, you need to create a fake VM\n"+ - "of the proper type then click the 'install tools' option in the\n"+ - "VMware GUI.", config.ToolsUploadFlavor)) - return multistep.ActionHalt - } - - state.Put("tools_upload_source", path) - return multistep.ActionContinue -} - -func (*stepPrepareTools) Cleanup(multistep.StateBag) {} diff --git a/builder/vmware/vmx/builder.go b/builder/vmware/vmx/builder.go index 3c02b19cd..0497c215f 100644 --- a/builder/vmware/vmx/builder.go +++ b/builder/vmware/vmx/builder.go @@ -52,6 +52,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Build the steps. steps := []multistep.Step{ + &vmwcommon.StepPrepareTools{ + RemoteType: b.config.RemoteType, + ToolsUploadFlavor: b.config.ToolsUploadFlavor, + ToolsUploadPath: b.config.ToolsUploadPath, + }, &vmwcommon.StepOutputDir{ Force: b.config.PackerForce, }, @@ -78,6 +83,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe SSHWaitTimeout: b.config.SSHWaitTimeout, NoPty: b.config.SSHSkipRequestPty, }, + &vmwcommon.StepUploadTools{ + RemoteType: b.config.RemoteType, + ToolsUploadFlavor: b.config.ToolsUploadFlavor, + ToolsUploadPath: b.config.ToolsUploadPath, + Tpl: b.config.tpl, + }, &common.StepProvision{}, &vmwcommon.StepShutdown{ Command: b.config.ShutdownCommand, diff --git a/builder/vmware/vmx/config.go b/builder/vmware/vmx/config.go index 4756d6488..4aac4d970 100644 --- a/builder/vmware/vmx/config.go +++ b/builder/vmware/vmx/config.go @@ -17,9 +17,11 @@ type Config struct { vmwcommon.RunConfig `mapstructure:",squash"` vmwcommon.ShutdownConfig `mapstructure:",squash"` vmwcommon.SSHConfig `mapstructure:",squash"` + vmwcommon.ToolsConfig `mapstructure:",squash"` vmwcommon.VMXConfig `mapstructure:",squash"` FloppyFiles []string `mapstructure:"floppy_files"` + RemoteType string `mapstructure:"remote_type"` SkipCompaction bool `mapstructure:"skip_compaction"` SourcePath string `mapstructure:"source_path"` VMName string `mapstructure:"vm_name"` @@ -52,9 +54,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs = packer.MultiErrorAppend(errs, c.RunConfig.Prepare(c.tpl)...) errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare(c.tpl)...) errs = packer.MultiErrorAppend(errs, c.SSHConfig.Prepare(c.tpl)...) + errs = packer.MultiErrorAppend(errs, c.ToolsConfig.Prepare(c.tpl)...) errs = packer.MultiErrorAppend(errs, c.VMXConfig.Prepare(c.tpl)...) templates := map[string]*string{ + "remote_type": &c.RemoteType, "source_path": &c.SourcePath, "vm_name": &c.VMName, }