builder/vmware-vmx: Added tools_upload_flavor support

This commit is contained in:
Ross Smith II 2014-05-09 17:24:19 -07:00
parent c1cfd1da46
commit ba13239672
7 changed files with 124 additions and 66 deletions

View File

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

View File

@ -1,9 +1,8 @@
package iso package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
vmwcommon "github.com/mitchellh/packer/builder/vmware/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"os" "os"
) )
@ -12,20 +11,24 @@ type toolsUploadPathTemplate struct {
Flavor string 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 { func (c *StepUploadTools) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*config) driver := state.Get("driver").(Driver)
driver := state.Get("driver").(vmwcommon.Driver)
if config.RemoteType == "esx5" { if c.RemoteType == "esx5" {
if err := driver.ToolsInstall(); err != nil { if err := driver.ToolsInstall(); err != nil {
state.Put("error", fmt.Errorf("Couldn't mount VMware tools ISO.")) state.Put("error", fmt.Errorf("Couldn't mount VMware tools ISO."))
} }
return multistep.ActionContinue return multistep.ActionContinue
} }
if config.ToolsUploadFlavor == "" { if c.ToolsUploadFlavor == "" {
return multistep.ActionContinue return multistep.ActionContinue
} }
@ -33,7 +36,7 @@ func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction {
tools_source := state.Get("tools_upload_source").(string) tools_source := state.Get("tools_upload_source").(string)
ui := state.Get("ui").(packer.Ui) 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) f, err := os.Open(tools_source)
if err != nil { if err != nil {
state.Put("error", fmt.Errorf("Error opening VMware Tools ISO: %s", err)) 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() defer f.Close()
tplData := &toolsUploadPathTemplate{Flavor: config.ToolsUploadFlavor} tplData := &toolsUploadPathTemplate{
config.ToolsUploadPath, err = config.tpl.Process(config.ToolsUploadPath, tplData) Flavor: c.ToolsUploadFlavor,
}
c.ToolsUploadPath, err = c.Tpl.Process(c.ToolsUploadPath, tplData)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing upload path: %s", err) err := fmt.Errorf("Error preparing upload path: %s", err)
state.Put("error", err) state.Put("error", err)
@ -50,7 +55,7 @@ func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt 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) err := fmt.Errorf("Error uploading VMware Tools: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
@ -60,4 +65,4 @@ func (*stepUploadTools) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
func (*stepUploadTools) Cleanup(multistep.StateBag) {} func (c *StepUploadTools) Cleanup(multistep.StateBag) {}

View File

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

View File

@ -12,7 +12,6 @@ import (
"math/rand" "math/rand"
"os" "os"
"strings" "strings"
"text/template"
"time" "time"
) )
@ -30,6 +29,7 @@ type config struct {
vmwcommon.RunConfig `mapstructure:",squash"` vmwcommon.RunConfig `mapstructure:",squash"`
vmwcommon.ShutdownConfig `mapstructure:",squash"` vmwcommon.ShutdownConfig `mapstructure:",squash"`
vmwcommon.SSHConfig `mapstructure:",squash"` vmwcommon.SSHConfig `mapstructure:",squash"`
vmwcommon.ToolsConfig `mapstructure:",squash"`
vmwcommon.VMXConfig `mapstructure:",squash"` vmwcommon.VMXConfig `mapstructure:",squash"`
DiskName string `mapstructure:"vmdk_name"` DiskName string `mapstructure:"vmdk_name"`
@ -46,8 +46,6 @@ type config struct {
HTTPPortMax uint `mapstructure:"http_port_max"` HTTPPortMax uint `mapstructure:"http_port_max"`
BootCommand []string `mapstructure:"boot_command"` BootCommand []string `mapstructure:"boot_command"`
SkipCompaction bool `mapstructure:"skip_compaction"` SkipCompaction bool `mapstructure:"skip_compaction"`
ToolsUploadFlavor string `mapstructure:"tools_upload_flavor"`
ToolsUploadPath string `mapstructure:"tools_upload_path"`
VMXTemplatePath string `mapstructure:"vmx_template_path"` VMXTemplatePath string `mapstructure:"vmx_template_path"`
VNCPortMin uint `mapstructure:"vnc_port_min"` VNCPortMin uint `mapstructure:"vnc_port_min"`
VNCPortMax uint `mapstructure:"vnc_port_max"` VNCPortMax uint `mapstructure:"vnc_port_max"`
@ -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.RunConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.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.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)...) errs = packer.MultiErrorAppend(errs, b.config.VMXConfig.Prepare(b.config.tpl)...)
warnings := make([]string, 0) warnings := make([]string, 0)
@ -144,10 +143,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.RemotePort = 22 b.config.RemotePort = 22
} }
if b.config.ToolsUploadPath == "" {
b.config.ToolsUploadPath = "{{ .Flavor }}.iso"
}
// Errors // Errors
templates := map[string]*string{ templates := map[string]*string{
"disk_name": &b.config.DiskName, "disk_name": &b.config.DiskName,
@ -156,7 +151,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
"iso_checksum": &b.config.ISOChecksum, "iso_checksum": &b.config.ISOChecksum,
"iso_checksum_type": &b.config.ISOChecksumType, "iso_checksum_type": &b.config.ISOChecksumType,
"iso_url": &b.config.RawSingleISOUrl, "iso_url": &b.config.RawSingleISOUrl,
"tools_upload_flavor": &b.config.ToolsUploadFlavor,
"vm_name": &b.config.VMName, "vm_name": &b.config.VMName,
"vmx_template_path": &b.config.VMXTemplatePath, "vmx_template_path": &b.config.VMXTemplatePath,
"remote_type": &b.config.RemoteType, "remote_type": &b.config.RemoteType,
@ -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 b.config.VMXTemplatePath != "" {
if err := b.validateVMXTemplatePath(); err != nil { if err := b.validateVMXTemplatePath(); err != nil {
errs = packer.MultiErrorAppend( 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()) rand.Seed(time.Now().UTC().UnixNano())
steps := []multistep.Step{ steps := []multistep.Step{
&stepPrepareTools{}, &vmwcommon.StepPrepareTools{
RemoteType: b.config.RemoteType,
ToolsUploadFlavor: b.config.ToolsUploadFlavor,
ToolsUploadPath: b.config.ToolsUploadPath,
},
&common.StepDownload{ &common.StepDownload{
Checksum: b.config.ISOChecksum, Checksum: b.config.ISOChecksum,
ChecksumType: b.config.ISOChecksumType, 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, SSHWaitTimeout: b.config.SSHWaitTimeout,
NoPty: b.config.SSHSkipRequestPty, 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{}, &common.StepProvision{},
&vmwcommon.StepShutdown{ &vmwcommon.StepShutdown{
Command: b.config.ShutdownCommand, Command: b.config.ShutdownCommand,

View File

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

View File

@ -52,6 +52,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
// Build the steps. // Build the steps.
steps := []multistep.Step{ steps := []multistep.Step{
&vmwcommon.StepPrepareTools{
RemoteType: b.config.RemoteType,
ToolsUploadFlavor: b.config.ToolsUploadFlavor,
ToolsUploadPath: b.config.ToolsUploadPath,
},
&vmwcommon.StepOutputDir{ &vmwcommon.StepOutputDir{
Force: b.config.PackerForce, 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, SSHWaitTimeout: b.config.SSHWaitTimeout,
NoPty: b.config.SSHSkipRequestPty, NoPty: b.config.SSHSkipRequestPty,
}, },
&vmwcommon.StepUploadTools{
RemoteType: b.config.RemoteType,
ToolsUploadFlavor: b.config.ToolsUploadFlavor,
ToolsUploadPath: b.config.ToolsUploadPath,
Tpl: b.config.tpl,
},
&common.StepProvision{}, &common.StepProvision{},
&vmwcommon.StepShutdown{ &vmwcommon.StepShutdown{
Command: b.config.ShutdownCommand, Command: b.config.ShutdownCommand,

View File

@ -17,9 +17,11 @@ type Config struct {
vmwcommon.RunConfig `mapstructure:",squash"` vmwcommon.RunConfig `mapstructure:",squash"`
vmwcommon.ShutdownConfig `mapstructure:",squash"` vmwcommon.ShutdownConfig `mapstructure:",squash"`
vmwcommon.SSHConfig `mapstructure:",squash"` vmwcommon.SSHConfig `mapstructure:",squash"`
vmwcommon.ToolsConfig `mapstructure:",squash"`
vmwcommon.VMXConfig `mapstructure:",squash"` vmwcommon.VMXConfig `mapstructure:",squash"`
FloppyFiles []string `mapstructure:"floppy_files"` FloppyFiles []string `mapstructure:"floppy_files"`
RemoteType string `mapstructure:"remote_type"`
SkipCompaction bool `mapstructure:"skip_compaction"` SkipCompaction bool `mapstructure:"skip_compaction"`
SourcePath string `mapstructure:"source_path"` SourcePath string `mapstructure:"source_path"`
VMName string `mapstructure:"vm_name"` 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.RunConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.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.SSHConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.ToolsConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.VMXConfig.Prepare(c.tpl)...) errs = packer.MultiErrorAppend(errs, c.VMXConfig.Prepare(c.tpl)...)
templates := map[string]*string{ templates := map[string]*string{
"remote_type": &c.RemoteType,
"source_path": &c.SourcePath, "source_path": &c.SourcePath,
"vm_name": &c.VMName, "vm_name": &c.VMName,
} }