Commit f5945eeb authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

vmware/iso: new interpolation

parent 0dc42268
package common package common
import ( import (
"fmt"
"os" "os"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate"
) )
type DriverConfig struct { type DriverConfig struct {
FusionAppPath string `mapstructure:"fusion_app_path"` 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 == "" { if c.FusionAppPath == "" {
c.FusionAppPath = os.Getenv("FUSION_APP_PATH") c.FusionAppPath = os.Getenv("FUSION_APP_PATH")
} }
...@@ -19,18 +18,5 @@ func (c *DriverConfig) Prepare(t *packer.ConfigTemplate) []error { ...@@ -19,18 +18,5 @@ func (c *DriverConfig) Prepare(t *packer.ConfigTemplate) []error {
c.FusionAppPath = "/Applications/VMware Fusion.app" c.FusionAppPath = "/Applications/VMware Fusion.app"
} }
templates := map[string]*string{ return nil
"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
} }
...@@ -2,33 +2,22 @@ package common ...@@ -2,33 +2,22 @@ package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"os" "os"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/template/interpolate"
) )
type OutputConfig struct { type OutputConfig struct {
OutputDir string `mapstructure:"output_directory"` 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 == "" { if c.OutputDir == "" {
c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName) c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName)
} }
templates := map[string]*string{ var errs []error
"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))
}
}
if !pc.PackerForce { if !pc.PackerForce {
if _, err := os.Stat(c.OutputDir); err == nil { if _, err := os.Stat(c.OutputDir); err == nil {
errs = append(errs, fmt.Errorf( errs = append(errs, fmt.Errorf(
......
...@@ -5,7 +5,7 @@ import ( ...@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate"
) )
type RunConfig struct { type RunConfig struct {
...@@ -22,7 +22,7 @@ type RunConfig struct { ...@@ -22,7 +22,7 @@ type RunConfig struct {
BootWait time.Duration `` BootWait time.Duration ``
} }
func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error { func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
if c.RawBootWait == "" { if c.RawBootWait == "" {
c.RawBootWait = "10s" c.RawBootWait = "10s"
} }
...@@ -43,20 +43,8 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error { ...@@ -43,20 +43,8 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
c.VNCPortMax = 6000 c.VNCPortMax = 6000
} }
templates := map[string]*string{ var errs []error
"boot_wait": &c.RawBootWait,
"http_directory": &c.HTTPDir,
}
var err 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 != "" { if c.RawBootWait != "" {
c.BootWait, err = time.ParseDuration(c.RawBootWait) c.BootWait, err = time.ParseDuration(c.RawBootWait)
if err != nil { if err != nil {
......
...@@ -2,8 +2,9 @@ package common ...@@ -2,8 +2,9 @@ package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/packer/packer"
"time" "time"
"github.com/mitchellh/packer/template/interpolate"
) )
type ShutdownConfig struct { type ShutdownConfig struct {
...@@ -13,25 +14,12 @@ type ShutdownConfig struct { ...@@ -13,25 +14,12 @@ type ShutdownConfig struct {
ShutdownTimeout time.Duration `` ShutdownTimeout time.Duration ``
} }
func (c *ShutdownConfig) Prepare(t *packer.ConfigTemplate) []error { func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error {
if c.RawShutdownTimeout == "" { if c.RawShutdownTimeout == "" {
c.RawShutdownTimeout = "5m" c.RawShutdownTimeout = "5m"
} }
templates := map[string]*string{ var errs []error
"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 err error var err error
c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout) c.ShutdownTimeout, err = time.ParseDuration(c.RawShutdownTimeout)
if err != nil { if err != nil {
......
...@@ -8,7 +8,7 @@ import ( ...@@ -8,7 +8,7 @@ import (
"time" "time"
commonssh "github.com/mitchellh/packer/common/ssh" commonssh "github.com/mitchellh/packer/common/ssh"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate"
) )
type SSHConfig struct { type SSHConfig struct {
...@@ -23,7 +23,7 @@ type SSHConfig struct { ...@@ -23,7 +23,7 @@ type SSHConfig struct {
SSHWaitTimeout time.Duration SSHWaitTimeout time.Duration
} }
func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error { func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error {
if c.SSHPort == 0 { if c.SSHPort == 0 {
c.SSHPort = 22 c.SSHPort = 22
} }
...@@ -32,23 +32,7 @@ func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error { ...@@ -32,23 +32,7 @@ func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error {
c.RawSSHWaitTimeout = "20m" c.RawSSHWaitTimeout = "20m"
} }
templates := map[string]*string{ var errs []error
"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))
}
}
if c.SSHKeyPath != "" { if c.SSHKeyPath != "" {
if _, err := os.Stat(c.SSHKeyPath); err != nil { if _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/mitchellh/go-vnc" "github.com/mitchellh/go-vnc"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
) )
const KeyLeftShift uint32 = 0xFFE1 const KeyLeftShift uint32 = 0xFFE1
...@@ -35,7 +36,7 @@ type bootCommandTemplateData struct { ...@@ -35,7 +36,7 @@ type bootCommandTemplateData struct {
type StepTypeBootCommand struct { type StepTypeBootCommand struct {
BootCommand []string BootCommand []string
VMName string VMName string
Tpl *packer.ConfigTemplate Ctx interpolate.Context
} }
func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
...@@ -87,7 +88,7 @@ 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) log.Printf("Host IP for the VMware machine: %s", hostIp)
tplData := &bootCommandTemplateData{ s.Ctx.Data = &bootCommandTemplateData{
hostIp, hostIp,
httpPort, httpPort,
s.VMName, s.VMName,
...@@ -95,7 +96,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction ...@@ -95,7 +96,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
ui.Say("Typing the boot command over VNC...") ui.Say("Typing the boot command over VNC...")
for _, command := range s.BootCommand { for _, command := range s.BootCommand {
command, err := s.Tpl.Process(command, tplData) command, err := interpolate.Render(command, &s.Ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing boot command: %s", err) err := fmt.Errorf("Error preparing boot command: %s", err)
state.Put("error", err) state.Put("error", err)
......
...@@ -2,9 +2,11 @@ package common ...@@ -2,9 +2,11 @@ package common
import ( import (
"fmt" "fmt"
"os"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"os" "github.com/mitchellh/packer/template/interpolate"
) )
type toolsUploadPathTemplate struct { type toolsUploadPathTemplate struct {
...@@ -15,7 +17,7 @@ type StepUploadTools struct { ...@@ -15,7 +17,7 @@ type StepUploadTools struct {
RemoteType string RemoteType string
ToolsUploadFlavor string ToolsUploadFlavor string
ToolsUploadPath string ToolsUploadPath string
Tpl *packer.ConfigTemplate Ctx interpolate.Context
} }
func (c *StepUploadTools) Run(state multistep.StateBag) multistep.StepAction { func (c *StepUploadTools) Run(state multistep.StateBag) multistep.StepAction {
...@@ -44,10 +46,10 @@ 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() defer f.Close()
tplData := &toolsUploadPathTemplate{ c.Ctx.Data = &toolsUploadPathTemplate{
Flavor: c.ToolsUploadFlavor, Flavor: c.ToolsUploadFlavor,
} }
c.ToolsUploadPath, err = c.Tpl.Process(c.ToolsUploadPath, tplData) c.ToolsUploadPath, err = interpolate.Render(c.ToolsUploadPath, &c.Ctx)
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)
......
package common package common
import ( import (
"fmt" "github.com/mitchellh/packer/template/interpolate"
"text/template"
"github.com/mitchellh/packer/packer"
) )
type ToolsConfig struct { type ToolsConfig struct {
...@@ -12,27 +9,10 @@ type ToolsConfig struct { ...@@ -12,27 +9,10 @@ type ToolsConfig struct {
ToolsUploadPath string `mapstructure:"tools_upload_path"` 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 == "" { if c.ToolsUploadPath == "" {
c.ToolsUploadPath = "{{ .Flavor }}.iso" c.ToolsUploadPath = "{{ .Flavor }}.iso"
} }
templates := map[string]*string{ return nil
"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
} }
package common package common
import ( import (
"fmt" "github.com/mitchellh/packer/template/interpolate"
"github.com/mitchellh/packer/packer"
) )
type VMXConfig struct { type VMXConfig struct {
...@@ -11,49 +9,6 @@ type VMXConfig struct { ...@@ -11,49 +9,6 @@ type VMXConfig struct {
VMXDataPost map[string]string `mapstructure:"vmx_data_post"` VMXDataPost map[string]string `mapstructure:"vmx_data_post"`
} }
func (c *VMXConfig) Prepare(t *packer.ConfigTemplate) []error { func (c *VMXConfig) Prepare(ctx *interpolate.Context) []error {
errs := make([]error, 0) return nil
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
} }
...@@ -3,26 +3,29 @@ package iso ...@@ -3,26 +3,29 @@ package iso
import ( import (
"errors" "errors"
"fmt" "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" "io/ioutil"
"log" "log"
"math/rand" "math/rand"
"os" "os"
"strings" "strings"
"time" "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" const BuilderIdESX = "mitchellh.vmware-esx"
type Builder struct { type Builder struct {
config config config Config
runner multistep.Runner runner multistep.Runner
} }
type config struct { type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
vmwcommon.DriverConfig `mapstructure:",squash"` vmwcommon.DriverConfig `mapstructure:",squash"`
vmwcommon.OutputConfig `mapstructure:",squash"` vmwcommon.OutputConfig `mapstructure:",squash"`
...@@ -57,31 +60,33 @@ type config struct { ...@@ -57,31 +60,33 @@ type config struct {
RawSingleISOUrl string `mapstructure:"iso_url"` RawSingleISOUrl string `mapstructure:"iso_url"`
tpl *packer.ConfigTemplate ctx interpolate.Context
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
md, err := common.DecodeConfig(&b.config, raws...) err := config.Decode(&b.config, &config.DecodeOpts{
if err != nil { Interpolate: true,
return nil, err InterpolateFilter: &interpolate.RenderFilter{
} Exclude: []string{
"boot_command",
b.config.tpl, err = packer.NewConfigTemplate() "tools_upload_path",
},
},
}, raws...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
b.config.tpl.UserVars = b.config.PackerUserVars
// Accumulate any errors // Accumulate any errors and warnings
errs := common.CheckUnusedConfig(md) var errs *packer.MultiError
errs = packer.MultiErrorAppend(errs, b.config.DriverConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.DriverConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, errs = packer.MultiErrorAppend(errs,
b.config.OutputConfig.Prepare(b.config.tpl, &b.config.PackerConfig)...) b.config.OutputConfig.Prepare(&b.config.ctx, &b.config.PackerConfig)...)
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.VMXConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.VMXConfig.Prepare(&b.config.ctx)...)
warnings := make([]string, 0) warnings := make([]string, 0)
if b.config.DiskName == "" { if b.config.DiskName == "" {
...@@ -137,59 +142,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { ...@@ -137,59 +142,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.RemotePort = 22 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 == "" { if b.config.ISOChecksumType == "" {
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, errors.New("The iso_checksum_type must be specified.")) 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 ...@@ -343,7 +295,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
&vmwcommon.StepTypeBootCommand{ &vmwcommon.StepTypeBootCommand{
BootCommand: b.config.BootCommand, BootCommand: b.config.BootCommand,
VMName: b.config.VMName, VMName: b.config.VMName,
Tpl: b.config.tpl, Ctx: b.config.ctx,
}, },
&common.StepConnectSSH{ &common.StepConnectSSH{
SSHAddress: driver.SSHAddress, SSHAddress: driver.SSHAddress,
...@@ -355,7 +307,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -355,7 +307,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
RemoteType: b.config.RemoteType, RemoteType: b.config.RemoteType,
ToolsUploadFlavor: b.config.ToolsUploadFlavor, ToolsUploadFlavor: b.config.ToolsUploadFlavor,
ToolsUploadPath: b.config.ToolsUploadPath, ToolsUploadPath: b.config.ToolsUploadPath,
Tpl: b.config.tpl, Ctx: b.config.ctx,
}, },
&common.StepProvision{}, &common.StepProvision{},
&vmwcommon.StepShutdown{ &vmwcommon.StepShutdown{
...@@ -369,7 +321,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe ...@@ -369,7 +321,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
}, },
&vmwcommon.StepCleanVMX{}, &vmwcommon.StepCleanVMX{},
&StepUploadVMX{ &StepUploadVMX{
RemoteType: b.config.RemoteType, RemoteType: b.config.RemoteType,
}, },
&vmwcommon.StepCompactDisk{ &vmwcommon.StepCompactDisk{
Skip: b.config.SkipCompaction, Skip: b.config.SkipCompaction,
...@@ -440,5 +392,5 @@ func (b *Builder) validateVMXTemplatePath() error { ...@@ -440,5 +392,5 @@ func (b *Builder) validateVMXTemplatePath() error {
return err return err
} }
return b.config.tpl.Validate(string(data)) return interpolate.Validate(string(data), &b.config.ctx)
} }
...@@ -8,7 +8,7 @@ import ( ...@@ -8,7 +8,7 @@ import (
// NewDriver returns a new driver implementation for this operating // NewDriver returns a new driver implementation for this operating
// system, or an error if the driver couldn't be initialized. // 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{} drivers := []vmwcommon.Driver{}
if config.RemoteType == "" { if config.RemoteType == "" {
......
...@@ -3,13 +3,9 @@ package iso ...@@ -3,13 +3,9 @@ package iso
import ( import (
"bufio" "bufio"
"bytes" "bytes"
gossh "code.google.com/p/go.crypto/ssh"
"encoding/csv" "encoding/csv"
"errors" "errors"
"fmt" "fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
"github.com/mitchellh/packer/packer"
"io" "io"
"log" "log"
"net" "net"
...@@ -17,6 +13,11 @@ import ( ...@@ -17,6 +13,11 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"time" "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 // 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) { ...@@ -218,7 +219,7 @@ func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint, error) {
} }
func (d *ESX5Driver) SSHAddress(state multistep.StateBag) (string, 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 { if address, ok := state.GetOk("vm_address"); ok {
return address.(string), nil return address.(string), nil
......
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
type stepCreateDisk struct{} type stepCreateDisk struct{}
func (stepCreateDisk) Run(state multistep.StateBag) multistep.StepAction { func (stepCreateDisk) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*config) config := state.Get("config").(*Config)
driver := state.Get("driver").(vmwcommon.Driver) driver := state.Get("driver").(vmwcommon.Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
......
...@@ -2,12 +2,14 @@ package iso ...@@ -2,12 +2,14 @@ package iso
import ( import (
"fmt" "fmt"
"github.com/mitchellh/multistep"
vmwcommon "github.com/mitchellh/packer/builder/vmware/common"
"github.com/mitchellh/packer/packer"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "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 { type vmxTemplateData struct {
...@@ -32,13 +34,14 @@ type stepCreateVMX struct { ...@@ -32,13 +34,14 @@ type stepCreateVMX struct {
} }
func (s *stepCreateVMX) Run(state multistep.StateBag) multistep.StepAction { 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) isoPath := state.Get("iso_path").(string)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
ui.Say("Building and writing VMX file") ui.Say("Building and writing VMX file")
tplData := &vmxTemplateData{ ctx := config.ctx
ctx.Data = &vmxTemplateData{
Name: config.VMName, Name: config.VMName,
GuestOS: config.GuestOSType, GuestOS: config.GuestOSType,
DiskName: config.DiskName, DiskName: config.DiskName,
...@@ -68,7 +71,7 @@ func (s *stepCreateVMX) Run(state multistep.StateBag) multistep.StepAction { ...@@ -68,7 +71,7 @@ func (s *stepCreateVMX) Run(state multistep.StateBag) multistep.StepAction {
vmxTemplate = string(rawBytes) vmxTemplate = string(rawBytes)
} }
vmxContents, err := config.tpl.Process(vmxTemplate, tplData) vmxContents, err := interpolate.Render(vmxTemplate, &ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error procesing VMX template: %s", err) err := fmt.Errorf("Error procesing VMX template: %s", err)
state.Put("error", err) state.Put("error", err)
......
...@@ -29,7 +29,7 @@ func (s *stepRemoteUpload) Run(state multistep.StateBag) multistep.StepAction { ...@@ -29,7 +29,7 @@ func (s *stepRemoteUpload) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
config := state.Get("config").(*config) config := state.Get("config").(*Config)
checksum := config.ISOChecksum checksum := config.ISOChecksum
checksumType := config.ISOChecksumType checksumType := config.ISOChecksumType
......
...@@ -27,6 +27,11 @@ func Render(v string, ctx *Context) (string, error) { ...@@ -27,6 +27,11 @@ func Render(v string, ctx *Context) (string, error) {
return (&I{Value: v}).Render(ctx) 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 // I stands for "interpolation" and is the main interpolation struct
// in order to render values. // in order to render values.
type I struct { type I struct {
...@@ -52,6 +57,12 @@ func (i *I) Render(ctx *Context) (string, error) { ...@@ -52,6 +57,12 @@ func (i *I) Render(ctx *Context) (string, error) {
return result.String(), nil 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) { func (i *I) template(ctx *Context) (*template.Template, error) {
return template.New("root").Funcs(Funcs(ctx)).Parse(i.Value) return template.New("root").Funcs(Funcs(ctx)).Parse(i.Value)
} }
...@@ -34,6 +34,11 @@ func RenderMap(v interface{}, ctx *Context, f *RenderFilter) (map[string]interfa ...@@ -34,6 +34,11 @@ func RenderMap(v interface{}, ctx *Context, f *RenderFilter) (map[string]interfa
// Now go through each value and render it // Now go through each value and render it
for k, raw := range m { 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) { if !f.include(k) {
continue continue
} }
...@@ -70,6 +75,24 @@ func RenderInterface(v interface{}, ctx *Context) (interface{}, error) { ...@@ -70,6 +75,24 @@ func RenderInterface(v interface{}, ctx *Context) (interface{}, error) {
return v, nil 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. // Include checks whether a key should be included.
func (f *RenderFilter) include(k string) bool { func (f *RenderFilter) include(k string) bool {
if f == nil { if f == nil {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment