diff --git a/provisioner/ansible-local/provisioner.go b/provisioner/ansible-local/provisioner.go index 3ab37c086..1d18ffc49 100644 --- a/provisioner/ansible-local/provisioner.go +++ b/provisioner/ansible-local/provisioner.go @@ -8,14 +8,16 @@ import ( "strings" "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) const DefaultStagingDir = "/tmp/packer-provisioner-ansible-local" type Config struct { common.PackerConfig `mapstructure:",squash"` - tpl *packer.ConfigTemplate + ctx interpolate.Context // The command to run ansible Command string @@ -54,21 +56,16 @@ type Provisioner 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{}, + }, + }, 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) - // Defaults if p.config.Command == "" { p.config.Command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 ansible-playbook" @@ -78,44 +75,8 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.StagingDir = DefaultStagingDir } - // Templates - templates := map[string]*string{ - "command": &p.config.Command, - "group_vars": &p.config.GroupVars, - "host_vars": &p.config.HostVars, - "playbook_file": &p.config.PlaybookFile, - "playbook_dir": &p.config.PlaybookDir, - "staging_dir": &p.config.StagingDir, - "inventory_file": &p.config.InventoryFile, - } - - 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{ - "extra_arguments": p.config.ExtraArguments, - "playbook_paths": p.config.PlaybookPaths, - "role_paths": p.config.RolePaths, - } - - 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)) - } - } - } - // Validation + var errs *packer.MultiError err = validateFileConfig(p.config.PlaybookFile, "playbook_file", true) if err != nil { errs = packer.MultiErrorAppend(errs, err) diff --git a/provisioner/chef-client/provisioner.go b/provisioner/chef-client/provisioner.go index b3d91b3e4..ea41e954c 100644 --- a/provisioner/chef-client/provisioner.go +++ b/provisioner/chef-client/provisioner.go @@ -15,7 +15,9 @@ import ( "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common/uuid" + "github.com/mitchellh/packer/helper/config" "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" ) type Config struct { @@ -38,7 +40,7 @@ type Config struct { ValidationKeyPath string `mapstructure:"validation_key_path"` ValidationClientName string `mapstructure:"validation_client_name"` - tpl *packer.ConfigTemplate + ctx interpolate.Context } type Provisioner struct { @@ -65,42 +67,19 @@ type InstallChefTemplate 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", + "install_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) - - templates := map[string]*string{ - "chef_environment": &p.config.ChefEnvironment, - "ssl_verify_mode": &p.config.SslVerifyMode, - "config_template": &p.config.ConfigTemplate, - "node_name": &p.config.NodeName, - "staging_dir": &p.config.StagingDir, - "chef_server_url": &p.config.ServerUrl, - "execute_command": &p.config.ExecuteCommand, - "install_command": &p.config.InstallCommand, - "validation_key_path": &p.config.ValidationKeyPath, - "validation_client_name": &p.config.ValidationClientName, - } - - 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)) - } - } - if p.config.ExecuteCommand == "" { p.config.ExecuteCommand = "{{if .Sudo}}sudo {{end}}chef-client " + "--no-color -c {{.ConfigPath}} -j {{.JsonPath}}" @@ -120,33 +99,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.StagingDir = "/tmp/packer-chef-client" } - sliceTemplates := map[string][]string{ - "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 { @@ -291,14 +244,16 @@ func (p *Provisioner) createConfig(ui packer.Ui, comm packer.Communicator, nodeN tpl = string(tplBytes) } - configString, err := p.config.tpl.Process(tpl, &ConfigTemplate{ + ctx := p.config.ctx + ctx.Data = &ConfigTemplate{ NodeName: nodeName, ServerUrl: serverUrl, ValidationKeyPath: remoteKeyPath, ValidationClientName: validationClientName, ChefEnvironment: chefEnvironment, SslVerifyMode: sslVerifyMode, - }) + } + configString, err := interpolate.Render(tpl, &ctx) if err != nil { return "", err } @@ -415,11 +370,12 @@ func (p *Provisioner) removeDir(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 } @@ -444,9 +400,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 } @@ -532,24 +489,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 }