Merge branch 'shell-env-vars'
Conflicts: website/source/docs/provisioners/shell.html.markdown
This commit is contained in:
commit
919c3935e1
|
@ -31,12 +31,17 @@ type config struct {
|
||||||
// An array of multiple scripts to run.
|
// An array of multiple scripts to run.
|
||||||
Scripts []string
|
Scripts []string
|
||||||
|
|
||||||
|
// An array of environment variables that will be injected before
|
||||||
|
// your command(s) are executed.
|
||||||
|
Vars []string `mapstructure:"environment_vars"`
|
||||||
|
|
||||||
// The remote path where the local shell script will be uploaded to.
|
// The remote path where the local shell script will be uploaded to.
|
||||||
// This should be set to a writable file that is in a pre-existing directory.
|
// This should be set to a writable file that is in a pre-existing directory.
|
||||||
RemotePath string `mapstructure:"remote_path"`
|
RemotePath string `mapstructure:"remote_path"`
|
||||||
|
|
||||||
// The command used to execute the script. The '{{ .Path }}' variable
|
// The command used to execute the script. The '{{ .Path }}' variable
|
||||||
// should be used to specify where the script goes.
|
// should be used to specify where the script goes, {{ .Vars }}
|
||||||
|
// can be used to inject the environment_vars into the environment.
|
||||||
ExecuteCommand string `mapstructure:"execute_command"`
|
ExecuteCommand string `mapstructure:"execute_command"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +50,7 @@ type Provisioner struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExecuteCommandTemplate struct {
|
type ExecuteCommandTemplate struct {
|
||||||
|
Vars string
|
||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +62,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.ExecuteCommand == "" {
|
if p.config.ExecuteCommand == "" {
|
||||||
p.config.ExecuteCommand = "sh {{.Path}}"
|
p.config.ExecuteCommand = "{{.Vars}} sh {{.Path}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.Inline != nil && len(p.config.Inline) == 0 {
|
if p.config.Inline != nil && len(p.config.Inline) == 0 {
|
||||||
|
@ -71,6 +77,10 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
p.config.Scripts = make([]string, 0)
|
p.config.Scripts = make([]string, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.config.Vars == nil {
|
||||||
|
p.config.Vars = make([]string, 0)
|
||||||
|
}
|
||||||
|
|
||||||
errs := make([]error, 0)
|
errs := make([]error, 0)
|
||||||
|
|
||||||
if p.config.Script != "" && len(p.config.Scripts) > 0 {
|
if p.config.Script != "" && len(p.config.Scripts) > 0 {
|
||||||
|
@ -93,6 +103,14 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do a check for bad environment variables, such as '=foo', 'foobar'
|
||||||
|
for _, kv := range p.config.Vars {
|
||||||
|
vs := strings.Split(kv, "=")
|
||||||
|
if len(vs) != 2 || vs[0] == "" {
|
||||||
|
errs = append(errs, fmt.Errorf("Environment variable not in format 'key=value': %s", kv))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return &packer.MultiError{errs}
|
return &packer.MultiError{errs}
|
||||||
}
|
}
|
||||||
|
@ -146,10 +164,13 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||||
return fmt.Errorf("Error uploading shell script: %s", err)
|
return fmt.Errorf("Error uploading shell script: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flatten the environment variables
|
||||||
|
flattendVars := strings.Join(p.config.Vars, " ")
|
||||||
|
|
||||||
// Compile the command
|
// Compile the command
|
||||||
var command bytes.Buffer
|
var command bytes.Buffer
|
||||||
t := template.Must(template.New("command").Parse(p.config.ExecuteCommand))
|
t := template.Must(template.New("command").Parse(p.config.ExecuteCommand))
|
||||||
t.Execute(&command, &ExecuteCommandTemplate{p.config.RemotePath})
|
t.Execute(&command, &ExecuteCommandTemplate{flattendVars, p.config.RemotePath})
|
||||||
|
|
||||||
// Setup the remote command
|
// Setup the remote command
|
||||||
stdout_r, stdout_w := io.Pipe()
|
stdout_r, stdout_w := io.Pipe()
|
||||||
|
|
|
@ -131,3 +131,32 @@ func TestProvisionerPrepare_Scripts(t *testing.T) {
|
||||||
t.Fatalf("should not have error: %s", err)
|
t.Fatalf("should not have error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProvisionerPrepare_EnvironmentVars(t *testing.T) {
|
||||||
|
config := testConfig()
|
||||||
|
|
||||||
|
// Test with a bad case
|
||||||
|
config["environment_vars"] = []string{"badvar", "good=var"}
|
||||||
|
p := new(Provisioner)
|
||||||
|
err := p.Prepare(config)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("should have error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with a trickier case
|
||||||
|
config["environment_vars"] = []string{"=bad"}
|
||||||
|
p = new(Provisioner)
|
||||||
|
err = p.Prepare(config)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("should have error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with a good case
|
||||||
|
// Note: baz= is a real env variable, just empty
|
||||||
|
config["environment_vars"] = []string{"FOO=bar", "baz="}
|
||||||
|
p = new(Provisioner)
|
||||||
|
err = p.Prepare(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not have error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -46,11 +46,16 @@ Exactly _one_ of the following is required:
|
||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
|
|
||||||
|
* `environment_vars` (array of strings) - An array of key/value pairs
|
||||||
|
to inject prior to the execute_command. The format should be
|
||||||
|
`key=value`.
|
||||||
|
|
||||||
* `execute_command` (string) - The command to use to execute the script.
|
* `execute_command` (string) - The command to use to execute the script.
|
||||||
By default this is `sh {{ .Path }}`. The value of this is treated as a
|
By default this is `{{ .Vars }} sh {{ .Path }}`. The value of this is
|
||||||
[configuration template](/docs/templates/configuration-templates.html).
|
treated as [configuration template](/docs/templates/configuration-
|
||||||
The only available variable in it is `Path` which is the path to the
|
templates.html). There are two available variables: `Path`, which is
|
||||||
script to run.
|
the path to the script to run, and `Vars`, which is the list of
|
||||||
|
`environment_vars`, if configured.
|
||||||
|
|
||||||
* `remote_path` (string) - The path where the script will be uploaded to
|
* `remote_path` (string) - The path where the script will be uploaded to
|
||||||
in the machine. This defaults to "/tmp/script.sh". This value must be
|
in the machine. This defaults to "/tmp/script.sh". This value must be
|
||||||
|
|
Loading…
Reference in New Issue