diff --git a/provisioner/chef-solo/provisioner.go b/provisioner/chef-solo/provisioner.go index 3ee0e74c7..686dc250e 100644 --- a/provisioner/chef-solo/provisioner.go +++ b/provisioner/chef-solo/provisioner.go @@ -7,12 +7,15 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" "io/ioutil" "os" "path/filepath" "strings" + + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type Config struct { @@ -34,7 +37,7 @@ type Config struct { SkipInstall bool `mapstructure:"skip_install"` StagingDir string `mapstructure:"staging_directory"` - tpl *packer.ConfigTemplate + ctx interpolate.Context } type Provisioner struct { @@ -69,16 +72,18 @@ type InstallChefTemplate struct { } func (p *Provisioner) Prepare(raws ...interface{}) error { - md, err := common.DecodeConfig(&p.config, raws...) - if err != nil { - return err - } - - p.config.tpl, err = packer.NewConfigTemplate() + err := config.Decode(&p.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{ + "execute_command", + "install_command", + }, + }, + }, raws...) if err != nil { return err } - p.config.tpl.UserVars = p.config.PackerUserVars if p.config.ExecuteCommand == "" { p.config.ExecuteCommand = "{{if .Sudo}}sudo {{end}}chef-solo --no-color -c {{.ConfigPath}} -j {{.JsonPath}}" @@ -96,57 +101,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.StagingDir = "/tmp/packer-chef-solo" } - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - - templates := map[string]*string{ - "config_template": &p.config.ConfigTemplate, - "data_bags_path": &p.config.DataBagsPath, - "encrypted_data_bag_secret": &p.config.EncryptedDataBagSecretPath, - "roles_path": &p.config.RolesPath, - "staging_dir": &p.config.StagingDir, - "environments_path": &p.config.EnvironmentsPath, - "chef_environment": &p.config.ChefEnvironment, - } - - for n, ptr := range templates { - var err error - *ptr, err = p.config.tpl.Process(*ptr, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - - sliceTemplates := map[string][]string{ - "cookbook_paths": p.config.CookbookPaths, - "remote_cookbook_paths": p.config.RemoteCookbookPaths, - "run_list": p.config.RunList, - } - - for n, slice := range sliceTemplates { - for i, elem := range slice { - var err error - slice[i], err = p.config.tpl.Process(elem, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err)) - } - } - } - - validates := map[string]*string{ - "execute_command": &p.config.ExecuteCommand, - "install_command": &p.config.InstallCommand, - } - - for n, ptr := range validates { - if err := p.config.tpl.Validate(*ptr); err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error parsing %s: %s", n, err)) - } - } - + var errs *packer.MultiError if p.config.ConfigTemplate != "" { fi, err := os.Stat(p.config.ConfigTemplate) if err != nil { @@ -362,7 +317,7 @@ func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, local tpl = string(tplBytes) } - configString, err := p.config.tpl.Process(tpl, &ConfigTemplate{ + p.config.ctx.Data = &ConfigTemplate{ CookbookPaths: strings.Join(cookbook_paths, ","), RolesPath: rolesPath, DataBagsPath: dataBagsPath, @@ -373,7 +328,8 @@ func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, local HasEncryptedDataBagSecretPath: encryptedDataBagSecretPath != "", HasEnvironmentsPath: environmentsPath != "", ChefEnvironment: chefEnvironment, - }) + } + configString, err := interpolate.Render(tpl, &p.config.ctx) if err != nil { return "", err } @@ -433,11 +389,12 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri } func (p *Provisioner) executeChef(ui packer.Ui, comm packer.Communicator, config string, json string) error { - command, err := p.config.tpl.Process(p.config.ExecuteCommand, &ExecuteTemplate{ + p.config.ctx.Data = &ExecuteTemplate{ ConfigPath: config, JsonPath: json, Sudo: !p.config.PreventSudo, - }) + } + command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) if err != nil { return err } @@ -462,9 +419,10 @@ func (p *Provisioner) executeChef(ui packer.Ui, comm packer.Communicator, config func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error { ui.Message("Installing Chef...") - command, err := p.config.tpl.Process(p.config.InstallCommand, &InstallChefTemplate{ + p.config.ctx.Data = &InstallChefTemplate{ Sudo: !p.config.PreventSudo, - }) + } + command, err := interpolate.Render(p.config.InstallCommand, &p.config.ctx) if err != nil { return err } @@ -533,24 +491,25 @@ func (p *Provisioner) processJsonUserVars() (map[string]interface{}, error) { // Copy the user variables so that we can restore them later, and // make sure we make the quotes JSON-friendly in the user variables. originalUserVars := make(map[string]string) - for k, v := range p.config.tpl.UserVars { + for k, v := range p.config.ctx.UserVariables { originalUserVars[k] = v } // Make sure we reset them no matter what defer func() { - p.config.tpl.UserVars = originalUserVars + p.config.ctx.UserVariables = originalUserVars }() // Make the current user variables JSON string safe. - for k, v := range p.config.tpl.UserVars { + for k, v := range p.config.ctx.UserVariables { v = strings.Replace(v, `\`, `\\`, -1) v = strings.Replace(v, `"`, `\"`, -1) - p.config.tpl.UserVars[k] = v + p.config.ctx.UserVariables[k] = v } // Process the bytes with the template processor - jsonBytesProcessed, err := p.config.tpl.Process(string(jsonBytes), nil) + p.config.ctx.Data = nil + jsonBytesProcessed, err := interpolate.Render(string(jsonBytes), &p.config.ctx) if err != nil { return nil, err } diff --git a/provisioner/file/provisioner.go b/provisioner/file/provisioner.go index 1cb69acd4..ce359a407 100644 --- a/provisioner/file/provisioner.go +++ b/provisioner/file/provisioner.go @@ -3,12 +3,15 @@ package file import ( "errors" "fmt" + "os" + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" "github.com/mitchellh/packer/packer" - "os" + "github.com/mitchellh/packer/template/interpolate" ) -type config struct { +type Config struct { common.PackerConfig `mapstructure:",squash"` // The local path of the file to upload. @@ -17,42 +20,25 @@ type config struct { // The remote path where the local file will be uploaded to. Destination string - tpl *packer.ConfigTemplate + ctx interpolate.Context } type Provisioner struct { - config config + config Config } func (p *Provisioner) Prepare(raws ...interface{}) error { - md, err := common.DecodeConfig(&p.config, raws...) - if err != nil { - return err - } - - p.config.tpl, err = packer.NewConfigTemplate() + err := config.Decode(&p.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{}, + }, + }, raws...) if err != nil { return err } - p.config.tpl.UserVars = p.config.PackerUserVars - - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - - templates := map[string]*string{ - "source": &p.config.Source, - "destination": &p.config.Destination, - } - - for n, ptr := range templates { - var err error - *ptr, err = p.config.tpl.Process(*ptr, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } + var errs *packer.MultiError if _, err := os.Stat(p.config.Source); err != nil { errs = packer.MultiErrorAppend(errs, fmt.Errorf("Bad source '%s': %s", p.config.Source, err)) diff --git a/provisioner/puppet-masterless/provisioner.go b/provisioner/puppet-masterless/provisioner.go index efb5e53e2..eb364da58 100644 --- a/provisioner/puppet-masterless/provisioner.go +++ b/provisioner/puppet-masterless/provisioner.go @@ -5,16 +5,19 @@ package puppetmasterless import ( "fmt" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" "os" "path/filepath" "strings" + + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type Config struct { common.PackerConfig `mapstructure:",squash"` - tpl *packer.ConfigTemplate + ctx interpolate.Context // The command used to execute Puppet. ExecuteCommand string `mapstructure:"execute_command"` @@ -57,20 +60,18 @@ type ExecuteTemplate struct { } func (p *Provisioner) Prepare(raws ...interface{}) error { - md, err := common.DecodeConfig(&p.config, raws...) + err := config.Decode(&p.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{ + "execute_command", + }, + }, + }, raws...) if err != nil { return err } - p.config.tpl, err = packer.NewConfigTemplate() - if err != nil { - return err - } - p.config.tpl.UserVars = p.config.PackerUserVars - - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - // Set some defaults if p.config.ExecuteCommand == "" { p.config.ExecuteCommand = "{{.FacterVars}} {{if .Sudo}} sudo -E {{end}}" + @@ -85,71 +86,8 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.StagingDir = "/tmp/packer-puppet-masterless" } - // Templates - templates := map[string]*string{ - "hiera_config_path": &p.config.HieraConfigPath, - "manifest_file": &p.config.ManifestFile, - "manifest_dir": &p.config.ManifestDir, - "staging_dir": &p.config.StagingDir, - } - - for n, ptr := range templates { - var err error - *ptr, err = p.config.tpl.Process(*ptr, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - - sliceTemplates := map[string][]string{ - "module_paths": p.config.ModulePaths, - } - - for n, slice := range sliceTemplates { - for i, elem := range slice { - var err error - slice[i], err = p.config.tpl.Process(elem, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err)) - } - } - } - - validates := map[string]*string{ - "execute_command": &p.config.ExecuteCommand, - } - - for n, ptr := range validates { - if err := p.config.tpl.Validate(*ptr); err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error parsing %s: %s", n, err)) - } - } - - newFacts := make(map[string]string) - for k, v := range p.config.Facter { - k, err := p.config.tpl.Process(k, nil) - if err != nil { - errs = packer.MultiErrorAppend(errs, - fmt.Errorf("Error processing facter key %s: %s", k, err)) - continue - } - - v, err := p.config.tpl.Process(v, nil) - if err != nil { - errs = packer.MultiErrorAppend(errs, - fmt.Errorf("Error processing facter value '%s': %s", v, err)) - continue - } - - newFacts[k] = v - } - - p.config.Facter = newFacts - // Validation + var errs *packer.MultiError if p.config.HieraConfigPath != "" { info, err := os.Stat(p.config.HieraConfigPath) if err != nil { @@ -255,14 +193,15 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { } // Execute Puppet - command, err := p.config.tpl.Process(p.config.ExecuteCommand, &ExecuteTemplate{ + p.config.ctx.Data = &ExecuteTemplate{ FacterVars: strings.Join(facterVars, " "), HieraConfigPath: remoteHieraConfigPath, ManifestDir: remoteManifestDir, ManifestFile: remoteManifestFile, ModulePath: strings.Join(modulePaths, ":"), Sudo: !p.config.PreventSudo, - }) + } + command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) if err != nil { return err } diff --git a/provisioner/puppet-server/provisioner.go b/provisioner/puppet-server/provisioner.go index de21e0105..1188f8978 100644 --- a/provisioner/puppet-server/provisioner.go +++ b/provisioner/puppet-server/provisioner.go @@ -4,15 +4,18 @@ package puppetserver import ( "fmt" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" "os" "strings" + + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type Config struct { common.PackerConfig `mapstructure:",squash"` - tpl *packer.ConfigTemplate + ctx interpolate.Context // Additional facts to set when executing Puppet Facter map[string]string @@ -55,62 +58,21 @@ type ExecuteTemplate struct { } func (p *Provisioner) Prepare(raws ...interface{}) error { - md, err := common.DecodeConfig(&p.config, raws...) - if err != nil { - return err - } - - p.config.tpl, err = packer.NewConfigTemplate() + err := config.Decode(&p.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{}, + }, + }, raws...) if err != nil { return err } - p.config.tpl.UserVars = p.config.PackerUserVars - - // Accumulate any errors - errs := common.CheckUnusedConfig(md) if p.config.StagingDir == "" { p.config.StagingDir = "/tmp/packer-puppet-server" } - // Templates - templates := map[string]*string{ - "client_cert_dir": &p.config.ClientCertPath, - "client_private_key_dir": &p.config.ClientPrivateKeyPath, - "puppet_server": &p.config.PuppetServer, - "puppet_node": &p.config.PuppetNode, - "options": &p.config.Options, - } - - for n, ptr := range templates { - var err error - *ptr, err = p.config.tpl.Process(*ptr, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - - newFacts := make(map[string]string) - for k, v := range p.config.Facter { - k, err := p.config.tpl.Process(k, nil) - if err != nil { - errs = packer.MultiErrorAppend(errs, - fmt.Errorf("Error processing facter key %s: %s", k, err)) - continue - } - - v, err := p.config.tpl.Process(v, nil) - if err != nil { - errs = packer.MultiErrorAppend(errs, - fmt.Errorf("Error processing facter value '%s': %s", v, err)) - continue - } - - newFacts[k] = v - } - p.config.Facter = newFacts - + var errs *packer.MultiError if p.config.ClientCertPath != "" { info, err := os.Stat(p.config.ClientCertPath) if err != nil { @@ -178,7 +140,7 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { } // Execute Puppet - command, err := p.config.tpl.Process(p.commandTemplate(), &ExecuteTemplate{ + p.config.ctx.Data = &ExecuteTemplate{ FacterVars: strings.Join(facterVars, " "), ClientCertPath: remoteClientCertPath, ClientPrivateKeyPath: remoteClientPrivateKeyPath, @@ -186,7 +148,8 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { PuppetServer: p.config.PuppetServer, Options: p.config.Options, Sudo: !p.config.PreventSudo, - }) + } + command, err := interpolate.Render(p.commandTemplate(), &p.config.ctx) if err != nil { return err } diff --git a/provisioner/salt-masterless/provisioner.go b/provisioner/salt-masterless/provisioner.go index 1e2877fe3..9c9ef8b4c 100644 --- a/provisioner/salt-masterless/provisioner.go +++ b/provisioner/salt-masterless/provisioner.go @@ -5,10 +5,13 @@ package saltmasterless import ( "errors" "fmt" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" "os" "path/filepath" + + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) const DefaultTempConfigDir = "/tmp/salt" @@ -32,7 +35,7 @@ type Config struct { // Where files will be copied before moving to the /srv/salt directory TempConfigDir string `mapstructure:"temp_config_dir"` - tpl *packer.ConfigTemplate + ctx interpolate.Context } type Provisioner struct { @@ -40,40 +43,21 @@ type Provisioner struct { } func (p *Provisioner) Prepare(raws ...interface{}) error { - md, err := common.DecodeConfig(&p.config, raws...) - if err != nil { - return err - } - - p.config.tpl, err = packer.NewConfigTemplate() + err := config.Decode(&p.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{}, + }, + }, raws...) if err != nil { return err } - p.config.tpl.UserVars = p.config.PackerUserVars if p.config.TempConfigDir == "" { p.config.TempConfigDir = DefaultTempConfigDir } - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - - templates := map[string]*string{ - "bootstrap_args": &p.config.BootstrapArgs, - "minion_config": &p.config.MinionConfig, - "local_state_tree": &p.config.LocalStateTree, - "local_pillar_roots": &p.config.LocalPillarRoots, - "temp_config_dir": &p.config.TempConfigDir, - } - - for n, ptr := range templates { - var err error - *ptr, err = p.config.tpl.Process(*ptr, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } + var errs *packer.MultiError // require a salt state tree if p.config.LocalStateTree == "" { diff --git a/provisioner/shell/provisioner.go b/provisioner/shell/provisioner.go index ec22acf63..48904710d 100644 --- a/provisioner/shell/provisioner.go +++ b/provisioner/shell/provisioner.go @@ -6,19 +6,22 @@ import ( "bufio" "errors" "fmt" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" "io" "io/ioutil" "log" "os" "strings" "time" + + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) const DefaultRemotePath = "/tmp/script.sh" -type config struct { +type Config struct { common.PackerConfig `mapstructure:",squash"` // If true, the script contains binary and line endings will not be @@ -57,11 +60,11 @@ type config struct { RawStartRetryTimeout string `mapstructure:"start_retry_timeout"` startRetryTimeout time.Duration - tpl *packer.ConfigTemplate + ctx interpolate.Context } type Provisioner struct { - config config + config Config } type ExecuteCommandTemplate struct { @@ -70,20 +73,18 @@ type ExecuteCommandTemplate struct { } func (p *Provisioner) Prepare(raws ...interface{}) error { - md, err := common.DecodeConfig(&p.config, raws...) + err := config.Decode(&p.config, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{ + "execute_command", + }, + }, + }, raws...) if err != nil { return err } - p.config.tpl, err = packer.NewConfigTemplate() - if err != nil { - return err - } - p.config.tpl.UserVars = p.config.PackerUserVars - - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - if p.config.ExecuteCommand == "" { p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}" } @@ -112,6 +113,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.Vars = make([]string, 0) } + var errs *packer.MultiError if p.config.Script != "" && len(p.config.Scripts) > 0 { errs = packer.MultiErrorAppend(errs, errors.New("Only one of script or scripts can be specified.")) @@ -121,39 +123,6 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.Scripts = []string{p.config.Script} } - templates := map[string]*string{ - "inline_shebang": &p.config.InlineShebang, - "script": &p.config.Script, - "start_retry_timeout": &p.config.RawStartRetryTimeout, - "remote_path": &p.config.RemotePath, - } - - for n, ptr := range templates { - var err error - *ptr, err = p.config.tpl.Process(*ptr, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s: %s", n, err)) - } - } - - sliceTemplates := map[string][]string{ - "inline": p.config.Inline, - "scripts": p.config.Scripts, - "environment_vars": p.config.Vars, - } - - for n, slice := range sliceTemplates { - for i, elem := range slice { - var err error - slice[i], err = p.config.tpl.Process(elem, nil) - if err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err)) - } - } - } - if len(p.config.Scripts) == 0 && p.config.Inline == nil { errs = packer.MultiErrorAppend(errs, errors.New("Either a script file or inline script must be specified.")) @@ -248,10 +217,11 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { flattendVars := strings.Join(envVars, " ") // Compile the command - command, err := p.config.tpl.Process(p.config.ExecuteCommand, &ExecuteCommandTemplate{ + p.config.ctx.Data = &ExecuteCommandTemplate{ Vars: flattendVars, Path: p.config.RemotePath, - }) + } + command, err := interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) if err != nil { return fmt.Errorf("Error processing command: %s", err) }