From 2da36b737474ebaf6d6b13412775beb4d128a85a Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 22 May 2019 16:43:29 +0200 Subject: [PATCH 1/6] builder/docker: default container dir to "c:/packer-files" on windows --- builder/docker/config.go | 7 ++++++- website/source/docs/builders/docker.html.md | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/builder/docker/config.go b/builder/docker/config.go index 8b41589e0..6f2dba809 100644 --- a/builder/docker/config.go +++ b/builder/docker/config.go @@ -3,6 +3,7 @@ package docker import ( "fmt" "os" + "runtime" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" @@ -124,7 +125,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { } if c.ContainerDir == "" { - c.ContainerDir = "/packer-files" + if runtime.GOOS == "windows" { + c.ContainerDir = "c:/packer-files" + } else { + c.ContainerDir = "/packer-files" + } } if c.EcrLogin && c.LoginServer == "" { diff --git a/website/source/docs/builders/docker.html.md b/website/source/docs/builders/docker.html.md index 6e70ef6de..e59e6f2c1 100644 --- a/website/source/docs/builders/docker.html.md +++ b/website/source/docs/builders/docker.html.md @@ -232,8 +232,8 @@ You must specify (only) one of `commit`, `discard`, or `export_path`. - `container_dir` (string) - The directory inside container to mount temp directory from host server for work [file - provisioner](/docs/provisioners/file.html). By default this is set to - `/packer-files`. + provisioner](/docs/provisioners/file.html). This defaults to + `c:/packer-files` on windows and `/packer-files` on other systems. - `fix_upload_owner` (boolean) - If true, files uploaded to the container will be owned by the user the container is running as. If false, the owner From e96409954aefb69f267cca744a74b2d4d5be3057 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 23 May 2019 14:10:41 +0200 Subject: [PATCH 2/6] add execution policy type and use it to default the powershell cmd --- helper/config/decode.go | 19 +++++-- provisioner/powershell/execution_policy.go | 38 +++++++++++++ .../powershell/execution_policy_test.go | 21 +++++++ .../powershell/executionpolicy_enumer.go | 55 +++++++++++++++++++ provisioner/powershell/provisioner.go | 16 +++++- 5 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 provisioner/powershell/execution_policy.go create mode 100644 provisioner/powershell/execution_policy_test.go create mode 100644 provisioner/powershell/executionpolicy_enumer.go diff --git a/helper/config/decode.go b/helper/config/decode.go index 27c1bf0b7..efb17cb00 100644 --- a/helper/config/decode.go +++ b/helper/config/decode.go @@ -23,6 +23,14 @@ type DecodeOpts struct { Interpolate bool InterpolateContext *interpolate.Context InterpolateFilter *interpolate.RenderFilter + + DecodeHooks []mapstructure.DecodeHookFunc +} + +var DefaultDecodeHookFuncs = []mapstructure.DecodeHookFunc{ + uint8ToStringHook, + mapstructure.StringToSliceHookFunc(","), + mapstructure.StringToTimeDurationHookFunc(), } // Decode decodes the configuration into the target and optionally @@ -60,17 +68,18 @@ func Decode(target interface{}, config *DecodeOpts, raws ...interface{}) error { } } + decodeHookFuncs := DefaultDecodeHookFuncs + if len(config.DecodeHooks) != 0 { + decodeHookFuncs = config.DecodeHooks + } + // Build our decoder var md mapstructure.Metadata decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ Result: target, Metadata: &md, WeaklyTypedInput: true, - DecodeHook: mapstructure.ComposeDecodeHookFunc( - uint8ToStringHook, - mapstructure.StringToSliceHookFunc(","), - mapstructure.StringToTimeDurationHookFunc(), - ), + DecodeHook: mapstructure.ComposeDecodeHookFunc(decodeHookFuncs...), }) if err != nil { return err diff --git a/provisioner/powershell/execution_policy.go b/provisioner/powershell/execution_policy.go new file mode 100644 index 000000000..e39be2d31 --- /dev/null +++ b/provisioner/powershell/execution_policy.go @@ -0,0 +1,38 @@ +package powershell + +import ( + "fmt" + "reflect" +) + +// ExecutionPolicy setting to run the command(s). +// For the powershell provider the default has historically been to bypass. +type ExecutionPolicy int + +const ( + Bypass ExecutionPolicy = 0 + AllSigned ExecutionPolicy = 1 + Default ExecutionPolicy = 2 + RemoteSigned ExecutionPolicy = 3 + Restricted ExecutionPolicy = 4 + Undefined ExecutionPolicy = 5 + Unrestricted ExecutionPolicy = 6 +) + +func (ep *ExecutionPolicy) Decode(v interface{}) (err error) { + str, ok := v.(string) + if !ok { + return fmt.Errorf("%#v is not a string", v) + } + *ep, err = ExecutionPolicyString(str) + return err +} + +func StringToExecutionPolicyHook(f reflect.Kind, t reflect.Kind, data interface{}) (interface{}, error) { + if f != reflect.String || t != reflect.Int { + return data, nil + } + + raw := data.(string) + return ExecutionPolicyString(raw) +} diff --git a/provisioner/powershell/execution_policy_test.go b/provisioner/powershell/execution_policy_test.go new file mode 100644 index 000000000..d7ffacf32 --- /dev/null +++ b/provisioner/powershell/execution_policy_test.go @@ -0,0 +1,21 @@ +package powershell + +import ( + "testing" +) + +func TestExecutionPolicy_Decode(t *testing.T) { + config := map[string]interface{}{ + "inline": []interface{}{"foo", "bar"}, + "execution_policy": "AllSigned", + } + p := new(Provisioner) + err := p.Prepare(config) + if err != nil { + t.Fatal(err) + } + + if p.config.ExecutionPolicy != AllSigned { + t.Fatalf("Expected AllSigned execution policy; got: %s", p.config.ExecutionPolicy) + } +} diff --git a/provisioner/powershell/executionpolicy_enumer.go b/provisioner/powershell/executionpolicy_enumer.go new file mode 100644 index 000000000..18f31b9c7 --- /dev/null +++ b/provisioner/powershell/executionpolicy_enumer.go @@ -0,0 +1,55 @@ +// Code generated by "enumer -type ExecutionPolicy provisioner/powershell/execution_policy.go"; DO NOT EDIT. + +// +package powershell + +import ( + "fmt" +) + +const _ExecutionPolicyName = "BypassAllSignedDefaultRemoteSignedRestrictedUndefinedUnrestricted" + +var _ExecutionPolicyIndex = [...]uint8{0, 6, 15, 22, 34, 44, 53, 65} + +func (i ExecutionPolicy) String() string { + if i < 0 || i >= ExecutionPolicy(len(_ExecutionPolicyIndex)-1) { + return fmt.Sprintf("ExecutionPolicy(%d)", i) + } + return _ExecutionPolicyName[_ExecutionPolicyIndex[i]:_ExecutionPolicyIndex[i+1]] +} + +var _ExecutionPolicyValues = []ExecutionPolicy{0, 1, 2, 3, 4, 5, 6} + +var _ExecutionPolicyNameToValueMap = map[string]ExecutionPolicy{ + _ExecutionPolicyName[0:6]: 0, + _ExecutionPolicyName[6:15]: 1, + _ExecutionPolicyName[15:22]: 2, + _ExecutionPolicyName[22:34]: 3, + _ExecutionPolicyName[34:44]: 4, + _ExecutionPolicyName[44:53]: 5, + _ExecutionPolicyName[53:65]: 6, +} + +// ExecutionPolicyString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func ExecutionPolicyString(s string) (ExecutionPolicy, error) { + if val, ok := _ExecutionPolicyNameToValueMap[s]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to ExecutionPolicy values", s) +} + +// ExecutionPolicyValues returns all values of the enum +func ExecutionPolicyValues() []ExecutionPolicy { + return _ExecutionPolicyValues +} + +// IsAExecutionPolicy returns "true" if the value is listed in the enum definition. "false" otherwise +func (i ExecutionPolicy) IsAExecutionPolicy() bool { + for _, v := range _ExecutionPolicyValues { + if i == v { + return true + } + } + return false +} diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index eac61b9c9..070c31ed3 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -66,6 +66,8 @@ type Config struct { ElevatedUser string `mapstructure:"elevated_user"` ElevatedPassword string `mapstructure:"elevated_password"` + ExecutionPolicy ExecutionPolicy `mapstructure:"execution_policy"` + ctx interpolate.Context } @@ -84,6 +86,13 @@ type EnvVarsTemplate struct { WinRMPassword string } +func (p *Provisioner) defaultExecuteCommand() string { + return `powershell -executionpolicy ` + p.config.ExecutionPolicy.String() + + ` "& { if (Test-Path variable:global:ProgressPreference)` + + `{set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};` + + `. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` +} + func (p *Provisioner) Prepare(raws ...interface{}) error { // Create passthrough for winrm password so we can fill it in once we know // it @@ -100,6 +109,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { "elevated_execute_command", }, }, + DecodeHooks: append(config.DefaultDecodeHookFuncs, StringToExecutionPolicyHook), }, raws...) if err != nil { @@ -115,11 +125,11 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } if p.config.ExecuteCommand == "" { - p.config.ExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` + p.config.ExecuteCommand = p.defaultExecuteCommand() } if p.config.ElevatedExecuteCommand == "" { - p.config.ElevatedExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` + p.config.ElevatedExecuteCommand = p.defaultExecuteCommand() } if p.config.Inline != nil && len(p.config.Inline) == 0 { @@ -272,6 +282,8 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C // Close the original file since we copied it f.Close() + log.Printf("%s returned with exit code %d", p.config.RemotePath, cmd.ExitStatus()) + if err := p.config.ValidExitCode(cmd.ExitStatus()); err != nil { return err } From e62aba37888b6a7bf21883f88c1ed6c788a3effd Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 23 May 2019 16:42:44 +0200 Subject: [PATCH 3/6] allow to set ExecutionPolicy to none for powershell provisioner this has the effect to not wrap the command, which will allow to know the exit status of a command in docker --- provisioner/powershell/execution_policy.go | 15 ++++++++------- provisioner/powershell/executionpolicy_enumer.go | 7 ++++--- provisioner/powershell/provisioner.go | 10 +++++++--- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/provisioner/powershell/execution_policy.go b/provisioner/powershell/execution_policy.go index e39be2d31..2453957e5 100644 --- a/provisioner/powershell/execution_policy.go +++ b/provisioner/powershell/execution_policy.go @@ -10,13 +10,14 @@ import ( type ExecutionPolicy int const ( - Bypass ExecutionPolicy = 0 - AllSigned ExecutionPolicy = 1 - Default ExecutionPolicy = 2 - RemoteSigned ExecutionPolicy = 3 - Restricted ExecutionPolicy = 4 - Undefined ExecutionPolicy = 5 - Unrestricted ExecutionPolicy = 6 + Bypass ExecutionPolicy = iota + AllSigned + Default + RemoteSigned + Restricted + Undefined + Unrestricted + None // not set ) func (ep *ExecutionPolicy) Decode(v interface{}) (err error) { diff --git a/provisioner/powershell/executionpolicy_enumer.go b/provisioner/powershell/executionpolicy_enumer.go index 18f31b9c7..ed29b4678 100644 --- a/provisioner/powershell/executionpolicy_enumer.go +++ b/provisioner/powershell/executionpolicy_enumer.go @@ -7,9 +7,9 @@ import ( "fmt" ) -const _ExecutionPolicyName = "BypassAllSignedDefaultRemoteSignedRestrictedUndefinedUnrestricted" +const _ExecutionPolicyName = "BypassAllSignedDefaultRemoteSignedRestrictedUndefinedUnrestrictedNone" -var _ExecutionPolicyIndex = [...]uint8{0, 6, 15, 22, 34, 44, 53, 65} +var _ExecutionPolicyIndex = [...]uint8{0, 6, 15, 22, 34, 44, 53, 65, 69} func (i ExecutionPolicy) String() string { if i < 0 || i >= ExecutionPolicy(len(_ExecutionPolicyIndex)-1) { @@ -18,7 +18,7 @@ func (i ExecutionPolicy) String() string { return _ExecutionPolicyName[_ExecutionPolicyIndex[i]:_ExecutionPolicyIndex[i+1]] } -var _ExecutionPolicyValues = []ExecutionPolicy{0, 1, 2, 3, 4, 5, 6} +var _ExecutionPolicyValues = []ExecutionPolicy{0, 1, 2, 3, 4, 5, 6, 7} var _ExecutionPolicyNameToValueMap = map[string]ExecutionPolicy{ _ExecutionPolicyName[0:6]: 0, @@ -28,6 +28,7 @@ var _ExecutionPolicyNameToValueMap = map[string]ExecutionPolicy{ _ExecutionPolicyName[34:44]: 4, _ExecutionPolicyName[44:53]: 5, _ExecutionPolicyName[53:65]: 6, + _ExecutionPolicyName[65:69]: 7, } // ExecutionPolicyString retrieves an enum value from the enum constants string name. diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index 070c31ed3..3a0430d1e 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -87,10 +87,14 @@ type EnvVarsTemplate struct { } func (p *Provisioner) defaultExecuteCommand() string { - return `powershell -executionpolicy ` + p.config.ExecutionPolicy.String() + - ` "& { if (Test-Path variable:global:ProgressPreference)` + + baseCmd := `& { if (Test-Path variable:global:ProgressPreference)` + `{set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};` + - `. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` + `. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }` + if p.config.ExecutionPolicy == None { + return baseCmd + } else { + return fmt.Sprintf(`powershell -executionpolicy %s "%s"`, p.config.ExecutionPolicy, baseCmd) + } } func (p *Provisioner) Prepare(raws ...interface{}) error { From 70059581556756749db14327040199d94b718c8c Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 23 May 2019 17:05:37 +0200 Subject: [PATCH 4/6] execution policy: make everything more idiomatic * make possible execution policy values lowercase * prefix execution policies possibilities --- provisioner/powershell/execution_policy.go | 16 ++++++++-------- provisioner/powershell/execution_policy_test.go | 4 ++-- provisioner/powershell/executionpolicy_enumer.go | 4 ++-- provisioner/powershell/provisioner.go | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/provisioner/powershell/execution_policy.go b/provisioner/powershell/execution_policy.go index 2453957e5..e1c2d0d53 100644 --- a/provisioner/powershell/execution_policy.go +++ b/provisioner/powershell/execution_policy.go @@ -10,14 +10,14 @@ import ( type ExecutionPolicy int const ( - Bypass ExecutionPolicy = iota - AllSigned - Default - RemoteSigned - Restricted - Undefined - Unrestricted - None // not set + ExecutionPolicyBypass ExecutionPolicy = iota + ExecutionPolicyAllsigned + ExecutionPolicyDefault + ExecutionPolicyRemotesigned + ExecutionPolicyRestricted + ExecutionPolicyUndefined + ExecutionPolicyUnrestricted + ExecutionPolicyNone // not set ) func (ep *ExecutionPolicy) Decode(v interface{}) (err error) { diff --git a/provisioner/powershell/execution_policy_test.go b/provisioner/powershell/execution_policy_test.go index d7ffacf32..ae8680c67 100644 --- a/provisioner/powershell/execution_policy_test.go +++ b/provisioner/powershell/execution_policy_test.go @@ -7,7 +7,7 @@ import ( func TestExecutionPolicy_Decode(t *testing.T) { config := map[string]interface{}{ "inline": []interface{}{"foo", "bar"}, - "execution_policy": "AllSigned", + "execution_policy": "allsigned", } p := new(Provisioner) err := p.Prepare(config) @@ -15,7 +15,7 @@ func TestExecutionPolicy_Decode(t *testing.T) { t.Fatal(err) } - if p.config.ExecutionPolicy != AllSigned { + if p.config.ExecutionPolicy != ExecutionPolicyAllsigned { t.Fatalf("Expected AllSigned execution policy; got: %s", p.config.ExecutionPolicy) } } diff --git a/provisioner/powershell/executionpolicy_enumer.go b/provisioner/powershell/executionpolicy_enumer.go index ed29b4678..881a74b20 100644 --- a/provisioner/powershell/executionpolicy_enumer.go +++ b/provisioner/powershell/executionpolicy_enumer.go @@ -1,4 +1,4 @@ -// Code generated by "enumer -type ExecutionPolicy provisioner/powershell/execution_policy.go"; DO NOT EDIT. +// Code generated by "enumer -transform snake -trimprefix ExecutionPolicy -type ExecutionPolicy provisioner/powershell/execution_policy.go"; DO NOT EDIT. // package powershell @@ -7,7 +7,7 @@ import ( "fmt" ) -const _ExecutionPolicyName = "BypassAllSignedDefaultRemoteSignedRestrictedUndefinedUnrestrictedNone" +const _ExecutionPolicyName = "bypassallsigneddefaultremotesignedrestrictedundefinedunrestrictednone" var _ExecutionPolicyIndex = [...]uint8{0, 6, 15, 22, 34, 44, 53, 65, 69} diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index 3a0430d1e..b554ca6f2 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -90,7 +90,7 @@ func (p *Provisioner) defaultExecuteCommand() string { baseCmd := `& { if (Test-Path variable:global:ProgressPreference)` + `{set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};` + `. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }` - if p.config.ExecutionPolicy == None { + if p.config.ExecutionPolicy == ExecutionPolicyNone { return baseCmd } else { return fmt.Sprintf(`powershell -executionpolicy %s "%s"`, p.config.ExecutionPolicy, baseCmd) From 478f80af83fc780995d8e1cb161122dc0b2f23df Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 23 May 2019 17:33:46 +0200 Subject: [PATCH 5/6] remove unused func --- provisioner/powershell/execution_policy.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/provisioner/powershell/execution_policy.go b/provisioner/powershell/execution_policy.go index e1c2d0d53..5338282bc 100644 --- a/provisioner/powershell/execution_policy.go +++ b/provisioner/powershell/execution_policy.go @@ -1,7 +1,6 @@ package powershell import ( - "fmt" "reflect" ) @@ -20,15 +19,6 @@ const ( ExecutionPolicyNone // not set ) -func (ep *ExecutionPolicy) Decode(v interface{}) (err error) { - str, ok := v.(string) - if !ok { - return fmt.Errorf("%#v is not a string", v) - } - *ep, err = ExecutionPolicyString(str) - return err -} - func StringToExecutionPolicyHook(f reflect.Kind, t reflect.Kind, data interface{}) (interface{}, error) { if f != reflect.String || t != reflect.Int { return data, nil From 68a3be9f90e1b6085dd59dea28fde2b2c547c54e Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 23 May 2019 17:39:02 +0200 Subject: [PATCH 6/6] document execution_policy for powershell --- website/source/docs/provisioners/powershell.html.md.erb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/source/docs/provisioners/powershell.html.md.erb b/website/source/docs/provisioners/powershell.html.md.erb index 2dfcc90a6..074f4f8f3 100644 --- a/website/source/docs/provisioners/powershell.html.md.erb +++ b/website/source/docs/provisioners/powershell.html.md.erb @@ -102,6 +102,12 @@ The example below is fully functional. "elevated_password": "", ``` +- `execution_policy` - To run ps scripts on windows packer defaults this to + "bypass" and wraps the command to run. Setting this to "none" will prevent + wrapping, allowing to see exit codes on docker for windows. Possible values + are "bypass", "allsigned", "default", "remotesigned", "restricted", + "undefined", "unrestricted", "none". + - `remote_path` (string) - The path where the PowerShell script will be uploaded to within the target build machine. This defaults to `C:/Windows/Temp/script-UUID.ps1` where UUID is replaced with a dynamically