implement template variable for accessing WinRM password in either environemnt variables or directly in execute_command or inline commands.

This commit is contained in:
Megan Marsh 2018-05-08 10:35:09 -07:00
parent 62e1323577
commit 846f94c964
4 changed files with 85 additions and 17 deletions

View File

@ -56,6 +56,11 @@ type Config struct {
}
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{
Interpolate: true,
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,14 +9,20 @@ import (
"sort"
"strings"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
)
type ExecuteCommandTemplate struct {
Vars string
Script string
Command string
Vars string
Script string
Command string
WinRMPassword string
}
type EnvVarsTemplate struct {
WinRMPassword string
}
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.
flattenedCmd := strings.Join(interpolatedCmds, " ")
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 {
return false, fmt.Errorf(
"Error executing script: %s\n\n"+
@ -96,7 +106,22 @@ func createInlineScriptFile(config *Config) (string, error) {
log.Printf("[INFO] (shell-local): Prepending inline script with %s", shebang)
writer.WriteString(shebang)
}
config.Ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(config.PackerBuildName),
}
// generate context so you can interpolate the command
config.Ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(config.PackerBuildName),
}
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 {
return "", fmt.Errorf("Error preparing shell script: %s", err)
}
@ -118,9 +143,10 @@ func createInlineScriptFile(config *Config) (string, error) {
// the host OS
func createInterpolatedCommands(config *Config, script string, flattenedEnvVars string) ([]string, error) {
config.Ctx.Data = &ExecuteCommandTemplate{
Vars: flattenedEnvVars,
Script: script,
Command: script,
Vars: flattenedEnvVars,
Script: script,
Command: script,
WinRMPassword: getWinRMPassword(config.PackerBuildName),
}
interpolatedCmds := make([]string, len(config.ExecuteCommand))
@ -142,8 +168,17 @@ func createFlattenedEnvVars(config *Config) (string, error) {
envVars["PACKER_BUILD_NAME"] = fmt.Sprintf("%s", config.PackerBuildName)
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
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)
// Store pair, replacing any single quotes in value so they parse
// correctly with required environment variable format
@ -162,3 +197,8 @@ func createFlattenedEnvVars(config *Config) (string, error) {
}
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
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
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:
- `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
inject prior to the `execute_command`. The format should be `key=value`.
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.
By default this is `["/bin/sh", "-c", "{{.Vars}}, "{{.Script}}"]`
on unix and `["cmd", "/c", "{{.Vars}}", "{{.Script}}"]` on windows.
This is treated as a [template engine](/docs/templates/engine.html).
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
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,
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
[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