From 4e7feea184fc3b157b9b59fc534fc4db47387d39 Mon Sep 17 00:00:00 2001 From: DanHam Date: Fri, 23 Mar 2018 11:46:55 +0000 Subject: [PATCH] Allow users to specify the location that the env vars file is uploaded to Previously the location the file was uploaded to was set internally and used ${env:SYSTEMROOT}/Temp as the destination folder. By default, in order to inject the required environment variables, the file is 'dot sourced' by the 'execute_command' using the {{ .Vars }} variable. Unfortunately the inclusion of the dollar in the path caused issues for users connecting over ssh as the (typically bash) shell running the execute command would try and interpret the dollar sign. The change allows users to specify the location the file is uploaded to, thereby allowing the user to specify a custom 'execute_command' that escapes any dollar signs that could be present in the path. If not set the upload path now defaults to using C:/Windows/Temp as the upload folder. --- provisioner/powershell/provisioner.go | 34 +++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index c5a4845f7..8bcdaded4 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -57,6 +57,11 @@ type Config struct { // This should be set to a writable file that is in a pre-existing directory. RemotePath string `mapstructure:"remote_path"` + // The remote path where the file containing the environment variables + // will be uploaded to. This should be set to a writable file that is + // in a pre-existing directory. + RemoteEnvVarPath string `mapstructure:"remote_env_var_path"` + // The command used to execute the script. The '{{ .Path }}' variable // should be used to specify where the script goes, {{ .Vars }} // can be used to inject the environment_vars into the environment. @@ -159,6 +164,11 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.RemotePath = fmt.Sprintf(`c:/Windows/Temp/script-%s.ps1`, uuid) } + if p.config.RemoteEnvVarPath == "" { + uuid := uuid.TimeOrderedUUID() + p.config.RemoteEnvVarPath = fmt.Sprintf(`c:/Windows/Temp/packer-ps-env-vars-%s.ps1`, uuid) + } + if p.config.Scripts == nil { p.config.Scripts = make([]string, 0) } @@ -351,13 +361,13 @@ func (p *Provisioner) retryable(f func() error) error { // Environment variables required within the remote environment are uploaded within a PS script and // then enabled by 'dot sourcing' the script immediately prior to execution of the main command -func (p *Provisioner) prepareEnvVars(elevated bool) (envVarPath string, err error) { +func (p *Provisioner) prepareEnvVars(elevated bool) (err error) { // Collate all required env vars into a plain string with required formatting applied flattenedEnvVars := p.createFlattenedEnvVars(elevated) // Create a powershell script on the target build fs containing the flattened env vars - envVarPath, err = p.uploadEnvVars(flattenedEnvVars) + err = p.uploadEnvVars(flattenedEnvVars) if err != nil { - return "", err + return err } return } @@ -413,15 +423,13 @@ func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string) { return } -func (p *Provisioner) uploadEnvVars(flattenedEnvVars string) (envVarPath string, err error) { +func (p *Provisioner) uploadEnvVars(flattenedEnvVars string) (err error) { // Upload all env vars to a powershell script on the target build file system envVarReader := strings.NewReader(flattenedEnvVars) - uuid := uuid.TimeOrderedUUID() - envVarPath = fmt.Sprintf(`${env:SYSTEMROOT}/Temp/packer-env-vars-%s.ps1`, uuid) - log.Printf("Uploading env vars to %s", envVarPath) - err = p.communicator.Upload(envVarPath, envVarReader, nil) + log.Printf("Uploading env vars to %s", p.config.RemoteEnvVarPath) + err = p.communicator.Upload(p.config.RemoteEnvVarPath, envVarReader, nil) if err != nil { - return "", fmt.Errorf("Error uploading ps script containing env vars: %s", err) + return fmt.Errorf("Error uploading ps script containing env vars: %s", err) } return } @@ -437,14 +445,14 @@ func (p *Provisioner) createCommandText() (command string, err error) { func (p *Provisioner) createCommandTextNonPrivileged() (command string, err error) { // Prepare everything needed to enable the required env vars within the remote environment - envVarPath, err := p.prepareEnvVars(false) + err = p.prepareEnvVars(false) if err != nil { return "", err } p.config.ctx.Data = &ExecuteCommandTemplate{ Path: p.config.RemotePath, - Vars: envVarPath, + Vars: p.config.RemoteEnvVarPath, WinRMPassword: getWinRMPassword(p.config.PackerBuildName), } command, err = interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) @@ -464,14 +472,14 @@ func getWinRMPassword(buildName string) string { func (p *Provisioner) createCommandTextPrivileged() (command string, err error) { // Prepare everything needed to enable the required env vars within the remote environment - envVarPath, err := p.prepareEnvVars(true) + err = p.prepareEnvVars(true) if err != nil { return "", err } p.config.ctx.Data = &ExecuteCommandTemplate{ Path: p.config.RemotePath, - Vars: envVarPath, + Vars: p.config.RemoteEnvVarPath, WinRMPassword: getWinRMPassword(p.config.PackerBuildName), } command, err = interpolate.Render(p.config.ElevatedExecuteCommand, &p.config.ctx)