diff --git a/builder/vmware/common/driver_config.go b/builder/vmware/common/driver_config.go index c28e30de0..ecd42b0f5 100644 --- a/builder/vmware/common/driver_config.go +++ b/builder/vmware/common/driver_config.go @@ -1,17 +1,16 @@ package common import ( - "fmt" "os" - "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type DriverConfig struct { FusionAppPath string `mapstructure:"fusion_app_path"` } -func (c *DriverConfig) Prepare(t *packer.ConfigTemplate) []error { +func (c *DriverConfig) Prepare(ctx *interpolate.Context) []error { if c.FusionAppPath == "" { c.FusionAppPath = os.Getenv("FUSION_APP_PATH") } @@ -19,18 +18,5 @@ func (c *DriverConfig) Prepare(t *packer.ConfigTemplate) []error { c.FusionAppPath = "/Applications/VMware Fusion.app" } - templates := map[string]*string{ - "fusion_app_path": &c.FusionAppPath, - } - - 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)) - } - } - - return errs + return nil } diff --git a/builder/vmware/common/output_config.go b/builder/vmware/common/output_config.go index 19be1ba00..f3427183c 100644 --- a/builder/vmware/common/output_config.go +++ b/builder/vmware/common/output_config.go @@ -2,33 +2,22 @@ package common import ( "fmt" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" "os" + + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/template/interpolate" ) type OutputConfig struct { OutputDir string `mapstructure:"output_directory"` } -func (c *OutputConfig) Prepare(t *packer.ConfigTemplate, pc *common.PackerConfig) []error { +func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { if c.OutputDir == "" { c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName) } - templates := map[string]*string{ - "output_directory": &c.OutputDir, - } - - errs := make([]error, 0) - for n, ptr := range templates { - var err error - *ptr, err = t.Process(*ptr, nil) - if err != nil { - errs = append(errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - + var errs []error if !pc.PackerForce { if _, err := os.Stat(c.OutputDir); err == nil { errs = append(errs, fmt.Errorf( diff --git a/builder/vmware/common/run_config.go b/builder/vmware/common/run_config.go index aef49683b..2f99984b1 100644 --- a/builder/vmware/common/run_config.go +++ b/builder/vmware/common/run_config.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type RunConfig struct { @@ -22,7 +22,7 @@ type RunConfig struct { BootWait time.Duration `` } -func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error { +func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { if c.RawBootWait == "" { c.RawBootWait = "10s" } @@ -43,20 +43,8 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error { c.VNCPortMax = 6000 } - templates := map[string]*string{ - "boot_wait": &c.RawBootWait, - "http_directory": &c.HTTPDir, - } - + var errs []error 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 c.RawBootWait != "" { c.BootWait, err = time.ParseDuration(c.RawBootWait) if err != nil { diff --git a/builder/vmware/common/shutdown_config.go b/builder/vmware/common/shutdown_config.go index 05e5fdfeb..83d2224c3 100644 --- a/builder/vmware/common/shutdown_config.go +++ b/builder/vmware/common/shutdown_config.go @@ -2,8 +2,9 @@ package common import ( "fmt" - "github.com/mitchellh/packer/packer" "time" + + "github.com/mitchellh/packer/template/interpolate" ) type ShutdownConfig struct { @@ -13,25 +14,12 @@ type ShutdownConfig struct { ShutdownTimeout time.Duration `` } -func (c *ShutdownConfig) Prepare(t *packer.ConfigTemplate) []error { +func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error { if c.RawShutdownTimeout == "" { c.RawShutdownTimeout = "5m" } - templates := map[string]*string{ - "shutdown_command": &c.ShutdownCommand, - "shutdown_timeout": &c.RawShutdownTimeout, - } - - errs := make([]error, 0) - for n, ptr := range templates { - var err error - *ptr, err = t.Process(*ptr, nil) - if err != nil { - errs = append(errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - + var errs []error var err error c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout) if err != nil { diff --git a/builder/vmware/common/ssh_config.go b/builder/vmware/common/ssh_config.go index 75d0a4b75..1bd481d92 100644 --- a/builder/vmware/common/ssh_config.go +++ b/builder/vmware/common/ssh_config.go @@ -8,7 +8,7 @@ import ( "time" commonssh "github.com/mitchellh/packer/common/ssh" - "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type SSHConfig struct { @@ -23,7 +23,7 @@ type SSHConfig struct { SSHWaitTimeout time.Duration } -func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error { +func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error { if c.SSHPort == 0 { c.SSHPort = 22 } @@ -32,23 +32,7 @@ func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error { c.RawSSHWaitTimeout = "20m" } - templates := map[string]*string{ - "ssh_host": &c.SSHHost, - "ssh_key_path": &c.SSHKeyPath, - "ssh_password": &c.SSHPassword, - "ssh_username": &c.SSHUser, - "ssh_wait_timeout": &c.RawSSHWaitTimeout, - } - - errs := make([]error, 0) - for n, ptr := range templates { - var err error - *ptr, err = t.Process(*ptr, nil) - if err != nil { - errs = append(errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - + var errs []error if c.SSHKeyPath != "" { if _, err := os.Stat(c.SSHKeyPath); err != nil { errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) diff --git a/builder/vmware/common/step_type_boot_command.go b/builder/vmware/common/step_type_boot_command.go index 82e8b3e17..397b515c5 100644 --- a/builder/vmware/common/step_type_boot_command.go +++ b/builder/vmware/common/step_type_boot_command.go @@ -13,6 +13,7 @@ import ( "github.com/mitchellh/go-vnc" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) const KeyLeftShift uint32 = 0xFFE1 @@ -35,7 +36,7 @@ type bootCommandTemplateData struct { type StepTypeBootCommand struct { BootCommand []string VMName string - Tpl *packer.ConfigTemplate + Ctx interpolate.Context } func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { @@ -87,7 +88,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction log.Printf("Host IP for the VMware machine: %s", hostIp) - tplData := &bootCommandTemplateData{ + s.Ctx.Data = &bootCommandTemplateData{ hostIp, httpPort, s.VMName, @@ -95,7 +96,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction ui.Say("Typing the boot command over VNC...") for _, command := range s.BootCommand { - command, err := s.Tpl.Process(command, tplData) + command, err := interpolate.Render(command, &s.Ctx) if err != nil { err := fmt.Errorf("Error preparing boot command: %s", err) state.Put("error", err) diff --git a/builder/vmware/common/step_upload_tools.go b/builder/vmware/common/step_upload_tools.go index 03387a13f..aa7dd08e7 100644 --- a/builder/vmware/common/step_upload_tools.go +++ b/builder/vmware/common/step_upload_tools.go @@ -2,9 +2,11 @@ package common import ( "fmt" + "os" + "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" - "os" + "github.com/mitchellh/packer/template/interpolate" ) type toolsUploadPathTemplate struct { @@ -15,7 +17,7 @@ type StepUploadTools struct { RemoteType string ToolsUploadFlavor string ToolsUploadPath string - Tpl *packer.ConfigTemplate + Ctx interpolate.Context } func (c *StepUploadTools) Run(state multistep.StateBag) multistep.StepAction { @@ -44,10 +46,10 @@ func (c *StepUploadTools) Run(state multistep.StateBag) multistep.StepAction { } defer f.Close() - tplData := &toolsUploadPathTemplate{ + c.Ctx.Data = &toolsUploadPathTemplate{ Flavor: c.ToolsUploadFlavor, } - c.ToolsUploadPath, err = c.Tpl.Process(c.ToolsUploadPath, tplData) + c.ToolsUploadPath, err = interpolate.Render(c.ToolsUploadPath, &c.Ctx) if err != nil { err := fmt.Errorf("Error preparing upload path: %s", err) state.Put("error", err) diff --git a/builder/vmware/common/tools_config.go b/builder/vmware/common/tools_config.go index c50c22e6b..923e531bf 100644 --- a/builder/vmware/common/tools_config.go +++ b/builder/vmware/common/tools_config.go @@ -1,10 +1,7 @@ package common import ( - "fmt" - "text/template" - - "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type ToolsConfig struct { @@ -12,27 +9,10 @@ type ToolsConfig struct { ToolsUploadPath string `mapstructure:"tools_upload_path"` } -func (c *ToolsConfig) Prepare(t *packer.ConfigTemplate) []error { +func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []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 + return nil } diff --git a/builder/vmware/common/vmx_config.go b/builder/vmware/common/vmx_config.go index 98bf70a31..aac16d1e0 100644 --- a/builder/vmware/common/vmx_config.go +++ b/builder/vmware/common/vmx_config.go @@ -1,9 +1,7 @@ package common import ( - "fmt" - - "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type VMXConfig struct { @@ -11,49 +9,6 @@ type VMXConfig struct { VMXDataPost map[string]string `mapstructure:"vmx_data_post"` } -func (c *VMXConfig) Prepare(t *packer.ConfigTemplate) []error { - errs := make([]error, 0) - newVMXData := make(map[string]string) - for k, v := range c.VMXData { - var err error - k, err = t.Process(k, nil) - if err != nil { - errs = append(errs, - fmt.Errorf("Error processing vmx_data key %s: %s", k, err)) - continue - } - - v, err = t.Process(v, nil) - if err != nil { - errs = append(errs, - fmt.Errorf("Error processing vmx_data value '%s': %s", v, err)) - continue - } - - newVMXData[k] = v - } - c.VMXData = newVMXData - - newVMXDataPost := make(map[string]string) - for k, v := range c.VMXDataPost { - var err error - k, err = t.Process(k, nil) - if err != nil { - errs = append(errs, - fmt.Errorf("Error processing vmx_post_data key %s: %s", k, err)) - continue - } - - v, err = t.Process(v, nil) - if err != nil { - errs = append(errs, - fmt.Errorf("Error processing vmx_post_data value '%s': %s", v, err)) - continue - } - - newVMXDataPost[k] = v - } - c.VMXDataPost = newVMXDataPost - - return errs +func (c *VMXConfig) Prepare(ctx *interpolate.Context) []error { + return nil } diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index 674b308c9..c63bfdc8b 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -3,26 +3,29 @@ package iso import ( "errors" "fmt" - "github.com/mitchellh/multistep" - vmwcommon "github.com/mitchellh/packer/builder/vmware/common" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" "io/ioutil" "log" "math/rand" "os" "strings" "time" + + "github.com/mitchellh/multistep" + vmwcommon "github.com/mitchellh/packer/builder/vmware/common" + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) const BuilderIdESX = "mitchellh.vmware-esx" type Builder struct { - config config + config Config runner multistep.Runner } -type config struct { +type Config struct { common.PackerConfig `mapstructure:",squash"` vmwcommon.DriverConfig `mapstructure:",squash"` vmwcommon.OutputConfig `mapstructure:",squash"` @@ -57,31 +60,33 @@ type config struct { RawSingleISOUrl string `mapstructure:"iso_url"` - tpl *packer.ConfigTemplate + ctx interpolate.Context } func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { - md, err := common.DecodeConfig(&b.config, raws...) - if err != nil { - return nil, err - } - - b.config.tpl, err = packer.NewConfigTemplate() + err := config.Decode(&b.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{ + "boot_command", + "tools_upload_path", + }, + }, + }, raws...) if err != nil { return nil, err } - b.config.tpl.UserVars = b.config.PackerUserVars - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - errs = packer.MultiErrorAppend(errs, b.config.DriverConfig.Prepare(b.config.tpl)...) + // Accumulate any errors and warnings + var errs *packer.MultiError + errs = packer.MultiErrorAppend(errs, b.config.DriverConfig.Prepare(&b.config.ctx)...) errs = packer.MultiErrorAppend(errs, - b.config.OutputConfig.Prepare(b.config.tpl, &b.config.PackerConfig)...) - 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)...) + b.config.OutputConfig.Prepare(&b.config.ctx, &b.config.PackerConfig)...) + errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) + errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...) + errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...) + errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(&b.config.ctx)...) + errs = packer.MultiErrorAppend(errs, b.config.VMXConfig.Prepare(&b.config.ctx)...) warnings := make([]string, 0) if b.config.DiskName == "" { @@ -137,59 +142,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.RemotePort = 22 } - // Errors - templates := map[string]*string{ - "disk_name": &b.config.DiskName, - "guest_os_type": &b.config.GuestOSType, - "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_cache_datastore": &b.config.RemoteCacheDatastore, - "remote_cache_directory": &b.config.RemoteCacheDirectory, - "remote_user": &b.config.RemoteUser, - "remote_password": &b.config.RemotePassword, - } - - for n, ptr := range templates { - var err error - *ptr, err = b.config.tpl.Process(*ptr, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - - for i, url := range b.config.ISOUrls { - var err error - b.config.ISOUrls[i], err = b.config.tpl.Process(url, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing iso_urls[%d]: %s", i, err)) - } - } - - for i, command := range b.config.BootCommand { - if err := b.config.tpl.Validate(command); err != nil { - errs = packer.MultiErrorAppend(errs, - fmt.Errorf("Error processing boot_command[%d]: %s", i, err)) - } - } - - for i, file := range b.config.FloppyFiles { - var err error - b.config.FloppyFiles[i], err = b.config.tpl.Process(file, nil) - if err != nil { - errs = packer.MultiErrorAppend(errs, - fmt.Errorf("Error processing floppy_files[%d]: %s", - i, err)) - } - } - if b.config.ISOChecksumType == "" { errs = packer.MultiErrorAppend( errs, errors.New("The iso_checksum_type must be specified.")) @@ -343,7 +295,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &vmwcommon.StepTypeBootCommand{ BootCommand: b.config.BootCommand, VMName: b.config.VMName, - Tpl: b.config.tpl, + Ctx: b.config.ctx, }, &common.StepConnectSSH{ SSHAddress: driver.SSHAddress, @@ -355,7 +307,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe RemoteType: b.config.RemoteType, ToolsUploadFlavor: b.config.ToolsUploadFlavor, ToolsUploadPath: b.config.ToolsUploadPath, - Tpl: b.config.tpl, + Ctx: b.config.ctx, }, &common.StepProvision{}, &vmwcommon.StepShutdown{ @@ -369,7 +321,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &vmwcommon.StepCleanVMX{}, &StepUploadVMX{ - RemoteType: b.config.RemoteType, + RemoteType: b.config.RemoteType, }, &vmwcommon.StepCompactDisk{ Skip: b.config.SkipCompaction, @@ -440,5 +392,5 @@ func (b *Builder) validateVMXTemplatePath() error { return err } - return b.config.tpl.Validate(string(data)) + return interpolate.Validate(string(data), &b.config.ctx) } diff --git a/builder/vmware/iso/driver.go b/builder/vmware/iso/driver.go index e98019a7e..2c6c7465d 100644 --- a/builder/vmware/iso/driver.go +++ b/builder/vmware/iso/driver.go @@ -8,7 +8,7 @@ import ( // NewDriver returns a new driver implementation for this operating // system, or an error if the driver couldn't be initialized. -func NewDriver(config *config) (vmwcommon.Driver, error) { +func NewDriver(config *Config) (vmwcommon.Driver, error) { drivers := []vmwcommon.Driver{} if config.RemoteType == "" { diff --git a/builder/vmware/iso/driver_esx5.go b/builder/vmware/iso/driver_esx5.go index 1f9bd7a78..d81149511 100644 --- a/builder/vmware/iso/driver_esx5.go +++ b/builder/vmware/iso/driver_esx5.go @@ -3,13 +3,9 @@ package iso import ( "bufio" "bytes" - gossh "code.google.com/p/go.crypto/ssh" "encoding/csv" "errors" "fmt" - "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/communicator/ssh" - "github.com/mitchellh/packer/packer" "io" "log" "net" @@ -17,6 +13,11 @@ import ( "path/filepath" "strings" "time" + + gossh "code.google.com/p/go.crypto/ssh" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/communicator/ssh" + "github.com/mitchellh/packer/packer" ) // ESX5 driver talks to an ESXi5 hypervisor remotely over SSH to build @@ -218,7 +219,7 @@ func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint, error) { } func (d *ESX5Driver) SSHAddress(state multistep.StateBag) (string, error) { - config := state.Get("config").(*config) + config := state.Get("config").(*Config) if address, ok := state.GetOk("vm_address"); ok { return address.(string), nil diff --git a/builder/vmware/iso/step_create_disk.go b/builder/vmware/iso/step_create_disk.go index cade63f75..b357cad01 100644 --- a/builder/vmware/iso/step_create_disk.go +++ b/builder/vmware/iso/step_create_disk.go @@ -20,7 +20,7 @@ import ( type stepCreateDisk struct{} func (stepCreateDisk) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(*config) + config := state.Get("config").(*Config) driver := state.Get("driver").(vmwcommon.Driver) ui := state.Get("ui").(packer.Ui) diff --git a/builder/vmware/iso/step_create_vmx.go b/builder/vmware/iso/step_create_vmx.go index e490e639b..5a1a829b5 100644 --- a/builder/vmware/iso/step_create_vmx.go +++ b/builder/vmware/iso/step_create_vmx.go @@ -2,12 +2,14 @@ package iso import ( "fmt" - "github.com/mitchellh/multistep" - vmwcommon "github.com/mitchellh/packer/builder/vmware/common" - "github.com/mitchellh/packer/packer" "io/ioutil" "os" "path/filepath" + + "github.com/mitchellh/multistep" + vmwcommon "github.com/mitchellh/packer/builder/vmware/common" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type vmxTemplateData struct { @@ -32,13 +34,14 @@ type stepCreateVMX struct { } func (s *stepCreateVMX) Run(state multistep.StateBag) multistep.StepAction { - config := state.Get("config").(*config) + config := state.Get("config").(*Config) isoPath := state.Get("iso_path").(string) ui := state.Get("ui").(packer.Ui) ui.Say("Building and writing VMX file") - tplData := &vmxTemplateData{ + ctx := config.ctx + ctx.Data = &vmxTemplateData{ Name: config.VMName, GuestOS: config.GuestOSType, DiskName: config.DiskName, @@ -68,7 +71,7 @@ func (s *stepCreateVMX) Run(state multistep.StateBag) multistep.StepAction { vmxTemplate = string(rawBytes) } - vmxContents, err := config.tpl.Process(vmxTemplate, tplData) + vmxContents, err := interpolate.Render(vmxTemplate, &ctx) if err != nil { err := fmt.Errorf("Error procesing VMX template: %s", err) state.Put("error", err) diff --git a/builder/vmware/iso/step_remote_upload.go b/builder/vmware/iso/step_remote_upload.go index 927c16c2a..1fc66a541 100644 --- a/builder/vmware/iso/step_remote_upload.go +++ b/builder/vmware/iso/step_remote_upload.go @@ -29,7 +29,7 @@ func (s *stepRemoteUpload) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } - config := state.Get("config").(*config) + config := state.Get("config").(*Config) checksum := config.ISOChecksum checksumType := config.ISOChecksumType diff --git a/template/interpolate/i.go b/template/interpolate/i.go index fa3a31395..c0cd13f85 100644 --- a/template/interpolate/i.go +++ b/template/interpolate/i.go @@ -27,6 +27,11 @@ func Render(v string, ctx *Context) (string, error) { return (&I{Value: v}).Render(ctx) } +// Validate is shorthand for constructing an I and calling Validate. +func Validate(v string, ctx *Context) error { + return (&I{Value: v}).Validate(ctx) +} + // I stands for "interpolation" and is the main interpolation struct // in order to render values. type I struct { @@ -52,6 +57,12 @@ func (i *I) Render(ctx *Context) (string, error) { return result.String(), nil } +// Validate validates that the template is syntactically valid. +func (i *I) Validate(ctx *Context) error { + _, err := i.template(ctx) + return err +} + func (i *I) template(ctx *Context) (*template.Template, error) { return template.New("root").Funcs(Funcs(ctx)).Parse(i.Value) } diff --git a/template/interpolate/render.go b/template/interpolate/render.go index a4c33222d..2120c171f 100644 --- a/template/interpolate/render.go +++ b/template/interpolate/render.go @@ -34,6 +34,11 @@ func RenderMap(v interface{}, ctx *Context, f *RenderFilter) (map[string]interfa // Now go through each value and render it for k, raw := range m { + // Always validate every field + if err := ValidateInterface(raw, ctx); err != nil { + return nil, fmt.Errorf("invalid '%s': %s", k, err) + } + if !f.include(k) { continue } @@ -70,6 +75,24 @@ func RenderInterface(v interface{}, ctx *Context) (interface{}, error) { return v, nil } +// ValidateInterface renders any value and returns the resulting value. +func ValidateInterface(v interface{}, ctx *Context) error { + f := func(v string) (string, error) { + return v, Validate(v, ctx) + } + + walker := &renderWalker{ + F: f, + Replace: false, + } + err := reflectwalk.Walk(v, walker) + if err != nil { + return err + } + + return nil +} + // Include checks whether a key should be included. func (f *RenderFilter) include(k string) bool { if f == nil {