Merge pull request #6251 from hashicorp/do_winrm_shell_local

access automatically generated winrm password from shell-local
This commit is contained in:
M. Marsh 2018-05-29 12:09:40 -07:00 committed by GitHub
commit a012f70e71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 17 deletions

View File

@ -56,6 +56,11 @@ type Config struct {
} }
func Decode(config *Config, raws ...interface{}) error { func Decode(config *Config, raws ...interface{}) error {
//Create passthrough for winrm password so we can fill it in once we know it
config.Ctx.Data = &EnvVarsTemplate{
WinRMPassword: `{{.WinRMPassword}}`,
}
err := configHelper.Decode(&config, &configHelper.DecodeOpts{ err := configHelper.Decode(&config, &configHelper.DecodeOpts{
Interpolate: true, Interpolate: true,
InterpolateContext: &config.Ctx, InterpolateContext: &config.Ctx,

View File

@ -0,0 +1,16 @@
package shell_local
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestConvertToLinuxPath(t *testing.T) {
winPath := "C:/path/to/your/file"
winBashPath := "/mnt/c/path/to/your/file"
converted, _ := ConvertToLinuxPath(winPath)
assert.Equal(t, winBashPath, converted,
"Should have converted %s to %s -- not %s", winPath, winBashPath, converted)
}

View File

@ -9,6 +9,7 @@ import (
"sort" "sort"
"strings" "strings"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
) )
@ -17,6 +18,11 @@ type ExecuteCommandTemplate struct {
Vars string Vars string
Script string Script string
Command string Command string
WinRMPassword string
}
type EnvVarsTemplate struct {
WinRMPassword string
} }
func Run(ui packer.Ui, config *Config) (bool, error) { func Run(ui packer.Ui, config *Config) (bool, error) {
@ -63,8 +69,12 @@ func Run(ui packer.Ui, config *Config) (bool, error) {
// buffers and for reading the final exit status. // buffers and for reading the final exit status.
flattenedCmd := strings.Join(interpolatedCmds, " ") flattenedCmd := strings.Join(interpolatedCmds, " ")
cmd := &packer.RemoteCmd{Command: flattenedCmd} cmd := &packer.RemoteCmd{Command: flattenedCmd}
log.Printf("[INFO] (shell-local): starting local command: %s", flattenedCmd) sanitized := flattenedCmd
if len(getWinRMPassword(config.PackerBuildName)) > 0 {
sanitized = strings.Replace(flattenedCmd,
getWinRMPassword(config.PackerBuildName), "*****", -1)
}
log.Printf("[INFO] (shell-local): starting local command: %s", sanitized)
if err := cmd.StartWithUi(comm, ui); err != nil { if err := cmd.StartWithUi(comm, ui); err != nil {
return false, fmt.Errorf( return false, fmt.Errorf(
"Error executing script: %s\n\n"+ "Error executing script: %s\n\n"+
@ -96,7 +106,19 @@ func createInlineScriptFile(config *Config) (string, error) {
log.Printf("[INFO] (shell-local): Prepending inline script with %s", shebang) log.Printf("[INFO] (shell-local): Prepending inline script with %s", shebang)
writer.WriteString(shebang) writer.WriteString(shebang)
} }
// generate context so you can interpolate the command
config.Ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(config.PackerBuildName),
}
for _, command := range config.Inline { for _, command := range config.Inline {
// interpolate command to check for template variables.
command, err := interpolate.Render(command, &config.Ctx)
if err != nil {
return "", err
}
if _, err := writer.WriteString(command + "\n"); err != nil { if _, err := writer.WriteString(command + "\n"); err != nil {
return "", fmt.Errorf("Error preparing shell script: %s", err) return "", fmt.Errorf("Error preparing shell script: %s", err)
} }
@ -121,6 +143,7 @@ func createInterpolatedCommands(config *Config, script string, flattenedEnvVars
Vars: flattenedEnvVars, Vars: flattenedEnvVars,
Script: script, Script: script,
Command: script, Command: script,
WinRMPassword: getWinRMPassword(config.PackerBuildName),
} }
interpolatedCmds := make([]string, len(config.ExecuteCommand)) interpolatedCmds := make([]string, len(config.ExecuteCommand))
@ -142,8 +165,17 @@ func createFlattenedEnvVars(config *Config) (string, error) {
envVars["PACKER_BUILD_NAME"] = fmt.Sprintf("%s", config.PackerBuildName) envVars["PACKER_BUILD_NAME"] = fmt.Sprintf("%s", config.PackerBuildName)
envVars["PACKER_BUILDER_TYPE"] = fmt.Sprintf("%s", config.PackerBuilderType) envVars["PACKER_BUILDER_TYPE"] = fmt.Sprintf("%s", config.PackerBuilderType)
// interpolate environment variables
config.Ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(config.PackerBuildName),
}
// Split vars into key/value components // Split vars into key/value components
for _, envVar := range config.Vars { for _, envVar := range config.Vars {
envVar, err := interpolate.Render(envVar, &config.Ctx)
if err != nil {
return "", err
}
// Split vars into key/value components
keyValue := strings.SplitN(envVar, "=", 2) keyValue := strings.SplitN(envVar, "=", 2)
// Store pair, replacing any single quotes in value so they parse // Store pair, replacing any single quotes in value so they parse
// correctly with required environment variable format // correctly with required environment variable format
@ -162,3 +194,8 @@ func createFlattenedEnvVars(config *Config) (string, error) {
} }
return flattened, nil return flattened, nil
} }
func getWinRMPassword(buildName string) string {
winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName)
return winRMPass
}

View File

@ -41,6 +41,10 @@ Exactly *one* of the following is required:
- `command` (string) - This is a single command to execute. It will be written - `command` (string) - This is a single command to execute. It will be written
to a temporary file and run using the `execute_command` call below. to a temporary file and run using the `execute_command` call below.
If you are building a windows vm on AWS, Azure or Google Compute and would
like to access the generated password that Packer uses to connect to the
instance via WinRM, you can use the template variable `{{.WinRMPassword}}`
to set this as an environment variable.
- `inline` (array of strings) - This is an array of commands to execute. The - `inline` (array of strings) - This is an array of commands to execute. The
commands are concatenated by newlines and turned into a single file, so they commands are concatenated by newlines and turned into a single file, so they
@ -60,24 +64,22 @@ Exactly *one* of the following is required:
Optional parameters: Optional parameters:
- `execute_command` (array of strings) - The command to use to execute
the script. By default this is `["/bin/sh", "-c", "{{.Command}}"]`. The value
is an array of arguments executed directly by the OS. The value of this is
treated as [configuration
template](/docs/templates/engine.html). The only available
variable is `Command` which is the command to execute.
- `environment_vars` (array of strings) - An array of key/value pairs to - `environment_vars` (array of strings) - An array of key/value pairs to
inject prior to the `execute_command`. The format should be `key=value`. inject prior to the `execute_command`. The format should be `key=value`.
Packer injects some environmental variables by default into the environment, Packer injects some environmental variables by default into the environment,
as well, which are covered in the section below. as well, which are covered in the section below. If you are building a
windows vm on AWS, Azure or Google Compute and would like to access the
generated password that Packer uses to connect to the instance via WinRM,
you can use the template variable `{{.WinRMPassword}}` to set this as an
environment variable. For example:
`"environment_vars": "WINRMPASS={{.WinRMPassword}}"`
- `execute_command` (array of strings) - The command used to execute the script. - `execute_command` (array of strings) - The command used to execute the script.
By default this is `["/bin/sh", "-c", "{{.Vars}}, "{{.Script}}"]` By default this is `["/bin/sh", "-c", "{{.Vars}}, "{{.Script}}"]`
on unix and `["cmd", "/c", "{{.Vars}}", "{{.Script}}"]` on windows. on unix and `["cmd", "/c", "{{.Vars}}", "{{.Script}}"]` on windows.
This is treated as a [template engine](/docs/templates/engine.html). This is treated as a [template engine](/docs/templates/engine.html).
There are two available variables: `Script`, which is the path to the script There are two available variables: `Script`, which is the path to the script
to run, and `Vars`, which is the list of `environment_vars`, if configured to run, and `Vars`, which is the list of `environment_vars`, if configured.
If you choose to set this option, make sure that the first element in the If you choose to set this option, make sure that the first element in the
array is the shell program you want to use (for example, "sh"), and a later array is the shell program you want to use (for example, "sh"), and a later
@ -94,6 +96,11 @@ Optional parameters:
sake of clarity, as even when you set only a single `command` to run, sake of clarity, as even when you set only a single `command` to run,
Packer writes it to a temporary file and then runs it as a script. Packer writes it to a temporary file and then runs it as a script.
If you are building a windows vm on AWS, Azure or Google Compute and would
like to access the generated password that Packer uses to connect to the
instance via WinRM, you can use the template variable `{{.WinRMPassword}}`
to set this as an environment variable.
- `inline_shebang` (string) - The - `inline_shebang` (string) - The
[shebang](http://en.wikipedia.org/wiki/Shebang_%28Unix%29) value to use when [shebang](http://en.wikipedia.org/wiki/Shebang_%28Unix%29) value to use when
running commands specified by `inline`. By default, this is `/bin/sh -e`. If running commands specified by `inline`. By default, this is `/bin/sh -e`. If