Merge pull request #8319 from hashicorp/f-shell-provisioner-env-var-format
provisioners/shell: Add support for the `env_var_format` parameter
This commit is contained in:
commit
fdd12c4e9f
|
@ -39,4 +39,8 @@ type Provisioner struct {
|
|||
// An array of environment variables that will be injected before
|
||||
// your command(s) are executed.
|
||||
Vars []string `mapstructure:"environment_vars"`
|
||||
|
||||
// This is used in the template generation to format environment variables
|
||||
// inside the `ExecuteCommand` template.
|
||||
EnvVarFormat string `mapstructure:"env_var_format"`
|
||||
}
|
||||
|
|
|
@ -55,10 +55,6 @@ type Config struct {
|
|||
// can be set high to allow for reboots.
|
||||
StartRetryTimeout time.Duration `mapstructure:"start_retry_timeout"`
|
||||
|
||||
// This is used in the template generation to format environment variables
|
||||
// inside the `ExecuteCommand` template.
|
||||
EnvVarFormat string
|
||||
|
||||
// This is used in the template generation to format environment variables
|
||||
// inside the `ElevatedExecuteCommand` template.
|
||||
ElevatedEnvVarFormat string `mapstructure:"elevated_env_var_format"`
|
||||
|
|
|
@ -24,10 +24,10 @@ type FlatConfig struct {
|
|||
Scripts []string `cty:"scripts"`
|
||||
ValidExitCodes []int `mapstructure:"valid_exit_codes" cty:"valid_exit_codes"`
|
||||
Vars []string `mapstructure:"environment_vars" cty:"environment_vars"`
|
||||
EnvVarFormat *string `mapstructure:"env_var_format" cty:"env_var_format"`
|
||||
RemoteEnvVarPath *string `mapstructure:"remote_env_var_path" cty:"remote_env_var_path"`
|
||||
ElevatedExecuteCommand *string `mapstructure:"elevated_execute_command" cty:"elevated_execute_command"`
|
||||
StartRetryTimeout *string `mapstructure:"start_retry_timeout" cty:"start_retry_timeout"`
|
||||
EnvVarFormat *string `cty:"env_var_format"`
|
||||
ElevatedEnvVarFormat *string `mapstructure:"elevated_env_var_format" cty:"elevated_env_var_format"`
|
||||
ElevatedUser *string `mapstructure:"elevated_user" cty:"elevated_user"`
|
||||
ElevatedPassword *string `mapstructure:"elevated_password" cty:"elevated_password"`
|
||||
|
@ -58,10 +58,10 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"scripts": &hcldec.AttrSpec{Name: "scripts", Type: cty.List(cty.String), Required: false},
|
||||
"valid_exit_codes": &hcldec.AttrSpec{Name: "valid_exit_codes", Type: cty.List(cty.Number), Required: false},
|
||||
"environment_vars": &hcldec.AttrSpec{Name: "environment_vars", Type: cty.List(cty.String), Required: false},
|
||||
"env_var_format": &hcldec.AttrSpec{Name: "env_var_format", Type: cty.String, Required: false},
|
||||
"remote_env_var_path": &hcldec.AttrSpec{Name: "remote_env_var_path", Type: cty.String, Required: false},
|
||||
"elevated_execute_command": &hcldec.AttrSpec{Name: "elevated_execute_command", Type: cty.String, Required: false},
|
||||
"start_retry_timeout": &hcldec.AttrSpec{Name: "start_retry_timeout", Type: cty.String, Required: false},
|
||||
"env_var_format": &hcldec.AttrSpec{Name: "env_var_format", Type: cty.String, Required: false},
|
||||
"elevated_env_var_format": &hcldec.AttrSpec{Name: "elevated_env_var_format", Type: cty.String, Required: false},
|
||||
"elevated_user": &hcldec.AttrSpec{Name: "elevated_user", Type: cty.String, Required: false},
|
||||
"elevated_password": &hcldec.AttrSpec{Name: "elevated_password", Type: cty.String, Required: false},
|
||||
|
|
|
@ -57,9 +57,10 @@ type Config struct {
|
|||
|
||||
ExpectDisconnect bool `mapstructure:"expect_disconnect"`
|
||||
|
||||
ctx interpolate.Context
|
||||
// name of the tmp environment variable file, if UseEnvVarFile is true
|
||||
envVarFile string
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
type Provisioner struct {
|
||||
|
@ -82,10 +83,19 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
|||
},
|
||||
},
|
||||
}, raws...)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.config.EnvVarFormat == "" {
|
||||
p.config.EnvVarFormat = "%s='%s' "
|
||||
|
||||
if p.config.UseEnvVarFile == true {
|
||||
p.config.EnvVarFormat = "export %s='%s'\n"
|
||||
}
|
||||
}
|
||||
|
||||
if p.config.ExecuteCommand == "" {
|
||||
p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}"
|
||||
if p.config.UseEnvVarFile == true {
|
||||
|
@ -430,21 +440,22 @@ func (p *Provisioner) escapeEnvVars() ([]string, map[string]string) {
|
|||
func (p *Provisioner) createEnvVarFileContent() string {
|
||||
keys, envVars := p.escapeEnvVars()
|
||||
|
||||
flattened := ""
|
||||
// Re-assemble vars surrounding value with single quotes and flatten
|
||||
var flattened string
|
||||
for _, key := range keys {
|
||||
flattened += fmt.Sprintf("export %s='%s'\n", key, envVars[key])
|
||||
flattened += fmt.Sprintf(p.config.EnvVarFormat, key, envVars[key])
|
||||
}
|
||||
|
||||
return flattened
|
||||
}
|
||||
|
||||
func (p *Provisioner) createFlattenedEnvVars() (flattened string) {
|
||||
func (p *Provisioner) createFlattenedEnvVars() string {
|
||||
keys, envVars := p.escapeEnvVars()
|
||||
|
||||
// Re-assemble vars surrounding value with single quotes and flatten
|
||||
// Re-assemble vars into specified format and flatten
|
||||
var flattened string
|
||||
for _, key := range keys {
|
||||
flattened += fmt.Sprintf("%s='%s' ", key, envVars[key])
|
||||
flattened += fmt.Sprintf(p.config.EnvVarFormat, key, envVars[key])
|
||||
}
|
||||
return
|
||||
|
||||
return flattened
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ type FlatConfig struct {
|
|||
Scripts []string `cty:"scripts"`
|
||||
ValidExitCodes []int `mapstructure:"valid_exit_codes" cty:"valid_exit_codes"`
|
||||
Vars []string `mapstructure:"environment_vars" cty:"environment_vars"`
|
||||
EnvVarFormat *string `mapstructure:"env_var_format" cty:"env_var_format"`
|
||||
InlineShebang *string `mapstructure:"inline_shebang" cty:"inline_shebang"`
|
||||
PauseAfter *string `mapstructure:"pause_after" cty:"pause_after"`
|
||||
UseEnvVarFile *bool `mapstructure:"use_env_var_file" cty:"use_env_var_file"`
|
||||
|
@ -58,6 +59,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"scripts": &hcldec.AttrSpec{Name: "scripts", Type: cty.List(cty.String), Required: false},
|
||||
"valid_exit_codes": &hcldec.AttrSpec{Name: "valid_exit_codes", Type: cty.List(cty.Number), Required: false},
|
||||
"environment_vars": &hcldec.AttrSpec{Name: "environment_vars", Type: cty.List(cty.String), Required: false},
|
||||
"env_var_format": &hcldec.AttrSpec{Name: "env_var_format", Type: cty.String, Required: false},
|
||||
"inline_shebang": &hcldec.AttrSpec{Name: "inline_shebang", Type: cty.String, Required: false},
|
||||
"pause_after": &hcldec.AttrSpec{Name: "pause_after", Type: cty.String, Required: false},
|
||||
"use_env_var_file": &hcldec.AttrSpec{Name: "use_env_var_file", Type: cty.Bool, Required: false},
|
||||
|
|
|
@ -286,6 +286,45 @@ func TestProvisioner_createFlattenedEnvVars(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProvisioner_createFlattenedEnvVars_withEnvVarFormat(t *testing.T) {
|
||||
var flattenedEnvVars string
|
||||
config := testConfig()
|
||||
|
||||
userEnvVarTests := [][]string{
|
||||
{}, // No user env var
|
||||
{"FOO=bar"}, // Single user env var
|
||||
{"FOO=bar's"}, // User env var with single quote in value
|
||||
{"FOO=bar", "BAZ=qux"}, // Multiple user env vars
|
||||
{"FOO=bar=baz"}, // User env var with value containing equals
|
||||
{"FOO==bar"}, // User env var with value starting with equals
|
||||
}
|
||||
expected := []string{
|
||||
`PACKER_BUILDER_TYPE=iso PACKER_BUILD_NAME=vmware `,
|
||||
`FOO=bar PACKER_BUILDER_TYPE=iso PACKER_BUILD_NAME=vmware `,
|
||||
`FOO=bar'"'"'s PACKER_BUILDER_TYPE=iso PACKER_BUILD_NAME=vmware `,
|
||||
`BAZ=qux FOO=bar PACKER_BUILDER_TYPE=iso PACKER_BUILD_NAME=vmware `,
|
||||
`FOO=bar=baz PACKER_BUILDER_TYPE=iso PACKER_BUILD_NAME=vmware `,
|
||||
`FOO==bar PACKER_BUILDER_TYPE=iso PACKER_BUILD_NAME=vmware `,
|
||||
}
|
||||
|
||||
p := new(Provisioner)
|
||||
|
||||
p.config.EnvVarFormat = "%s=%s "
|
||||
p.Prepare(config)
|
||||
|
||||
// Defaults provided by Packer
|
||||
p.config.PackerBuildName = "vmware"
|
||||
p.config.PackerBuilderType = "iso"
|
||||
|
||||
for i, expectedValue := range expected {
|
||||
p.config.Vars = userEnvVarTests[i]
|
||||
flattenedEnvVars = p.createFlattenedEnvVars()
|
||||
if flattenedEnvVars != expectedValue {
|
||||
t.Fatalf("expected flattened env vars to be: %s, got %s.", expectedValue, flattenedEnvVars)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisioner_createEnvVarFileContent(t *testing.T) {
|
||||
var flattenedEnvVars string
|
||||
config := testConfig()
|
||||
|
@ -326,6 +365,7 @@ export PACKER_BUILD_NAME='vmware'
|
|||
}
|
||||
|
||||
p := new(Provisioner)
|
||||
p.config.UseEnvVarFile = true
|
||||
p.Prepare(config)
|
||||
|
||||
// Defaults provided by Packer
|
||||
|
@ -341,6 +381,55 @@ export PACKER_BUILD_NAME='vmware'
|
|||
}
|
||||
}
|
||||
|
||||
func TestProvisioner_createEnvVarFileContent_withEnvVarFormat(t *testing.T) {
|
||||
var flattenedEnvVars string
|
||||
config := testConfig()
|
||||
|
||||
userEnvVarTests := [][]string{
|
||||
{}, // No user env var
|
||||
{"FOO=bar", "BAZ=qux"}, // Multiple user env vars
|
||||
{"FOO=bar=baz"}, // User env var with value containing equals
|
||||
{"FOO==bar"}, // User env var with value starting with equals
|
||||
}
|
||||
expected := []string{
|
||||
`PACKER_BUILDER_TYPE=iso
|
||||
PACKER_BUILD_NAME=vmware
|
||||
`,
|
||||
`BAZ=qux
|
||||
FOO=bar
|
||||
PACKER_BUILDER_TYPE=iso
|
||||
PACKER_BUILD_NAME=vmware
|
||||
`,
|
||||
`FOO=bar=baz
|
||||
PACKER_BUILDER_TYPE=iso
|
||||
PACKER_BUILD_NAME=vmware
|
||||
`,
|
||||
`FOO==bar
|
||||
PACKER_BUILDER_TYPE=iso
|
||||
PACKER_BUILD_NAME=vmware
|
||||
`,
|
||||
}
|
||||
|
||||
p := new(Provisioner)
|
||||
|
||||
p.config.UseEnvVarFile = true
|
||||
//User provided env_var_format without export prefix
|
||||
p.config.EnvVarFormat = "%s=%s\n"
|
||||
p.Prepare(config)
|
||||
|
||||
// Defaults provided by Packer
|
||||
p.config.PackerBuildName = "vmware"
|
||||
p.config.PackerBuilderType = "iso"
|
||||
|
||||
for i, expectedValue := range expected {
|
||||
p.config.Vars = userEnvVarTests[i]
|
||||
flattenedEnvVars = p.createEnvVarFileContent()
|
||||
if flattenedEnvVars != expectedValue {
|
||||
t.Fatalf("expected flattened env vars to be: %q, got %q.", expectedValue, flattenedEnvVars)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisioner_RemoteFolderSetSuccessfully(t *testing.T) {
|
||||
config := testConfig()
|
||||
|
||||
|
|
|
@ -37,10 +37,6 @@ type Config struct {
|
|||
// This can be set high to allow for reboots.
|
||||
StartRetryTimeout time.Duration `mapstructure:"start_retry_timeout"`
|
||||
|
||||
// This is used in the template generation to format environment variables
|
||||
// inside the `ExecuteCommand` template.
|
||||
EnvVarFormat string `mapstructure:"env_var_format"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ type FlatConfig struct {
|
|||
Scripts []string `cty:"scripts"`
|
||||
ValidExitCodes []int `mapstructure:"valid_exit_codes" cty:"valid_exit_codes"`
|
||||
Vars []string `mapstructure:"environment_vars" cty:"environment_vars"`
|
||||
StartRetryTimeout *string `mapstructure:"start_retry_timeout" cty:"start_retry_timeout"`
|
||||
EnvVarFormat *string `mapstructure:"env_var_format" cty:"env_var_format"`
|
||||
StartRetryTimeout *string `mapstructure:"start_retry_timeout" cty:"start_retry_timeout"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatConfig.
|
||||
|
@ -52,8 +52,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"scripts": &hcldec.AttrSpec{Name: "scripts", Type: cty.List(cty.String), Required: false},
|
||||
"valid_exit_codes": &hcldec.AttrSpec{Name: "valid_exit_codes", Type: cty.List(cty.Number), Required: false},
|
||||
"environment_vars": &hcldec.AttrSpec{Name: "environment_vars", Type: cty.List(cty.String), Required: false},
|
||||
"start_retry_timeout": &hcldec.AttrSpec{Name: "start_retry_timeout", Type: cty.String, Required: false},
|
||||
"env_var_format": &hcldec.AttrSpec{Name: "env_var_format", Type: cty.String, Required: false},
|
||||
"start_retry_timeout": &hcldec.AttrSpec{Name: "start_retry_timeout", Type: cty.String, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -40,6 +40,11 @@ The example below is fully functional.
|
|||
Packer injects some environmental variables by default into the
|
||||
environment, as well, which are covered in the section below.
|
||||
|
||||
- `env_var_format` (string) - When we parse the environment\_vars that you
|
||||
provide, this gives us a string template to use in order to make sure that
|
||||
we are setting the environment vars correctly. By default it is `"%s='%s' "`.
|
||||
When used in conjunction with `use_env_var_file` the default is `"export %s='%s'\n"`
|
||||
|
||||
- `use_env_var_file` (boolean) - If true, Packer will write your environment
|
||||
variables to a tempfile and source them from that file, rather than
|
||||
declaring them inline in our execute\_command. The default
|
||||
|
|
Loading…
Reference in New Issue