Merge pull request #6579 from hashicorp/reinterpolate_winrm_step

use statebag instead of SetSharedState for winRM password
This commit is contained in:
Megan Marsh 2018-08-24 14:02:13 -07:00 committed by GitHub
commit d356817890
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 128 additions and 67 deletions

View File

@ -12,7 +12,6 @@ import (
"time" "time"
"github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
@ -95,15 +94,13 @@ WaitLoop:
"Password (since debug is enabled): %s", s.Comm.WinRMPassword)) "Password (since debug is enabled): %s", s.Comm.WinRMPassword))
} }
// store so that we can access this later during provisioning // store so that we can access this later during provisioning
state.Put("winrm_password", s.Comm.WinRMPassword)
commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword, s.BuildName)
packer.LogSecretFilter.Set(s.Comm.WinRMPassword) packer.LogSecretFilter.Set(s.Comm.WinRMPassword)
return multistep.ActionContinue return multistep.ActionContinue
} }
func (s *StepGetPassword) Cleanup(multistep.StateBag) { func (s *StepGetPassword) Cleanup(multistep.StateBag) {
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
} }
func (s *StepGetPassword) waitForPassword(state multistep.StateBag, cancel <-chan struct{}) (string, error) { func (s *StepGetPassword) waitForPassword(state multistep.StateBag, cancel <-chan struct{}) (string, error) {

View File

@ -22,7 +22,6 @@ import (
"github.com/hashicorp/packer/builder/azure/common/constants" "github.com/hashicorp/packer/builder/azure/common/constants"
"github.com/hashicorp/packer/builder/azure/pkcs12" "github.com/hashicorp/packer/builder/azure/pkcs12"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
@ -361,10 +360,7 @@ func setRuntimeValues(c *Config) {
var tempName = NewTempName() var tempName = NewTempName()
c.tmpAdminPassword = tempName.AdminPassword c.tmpAdminPassword = tempName.AdminPassword
// store so that we can access this later during provisioning
commonhelper.SetSharedState("winrm_password", c.tmpAdminPassword, c.PackerConfig.PackerBuildName)
packer.LogSecretFilter.Set(c.tmpAdminPassword) packer.LogSecretFilter.Set(c.tmpAdminPassword)
c.tmpCertificatePassword = tempName.CertificatePassword c.tmpCertificatePassword = tempName.CertificatePassword
if c.TempComputeName == "" { if c.TempComputeName == "" {
c.tmpComputeName = tempName.ComputeName c.tmpComputeName = tempName.ComputeName

View File

@ -3,7 +3,6 @@ package arm
import ( import (
"context" "context"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
) )
@ -15,11 +14,10 @@ type StepSaveWinRMPassword struct {
func (s *StepSaveWinRMPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepSaveWinRMPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
// store so that we can access this later during provisioning // store so that we can access this later during provisioning
commonhelper.SetSharedState("winrm_password", s.Password, s.BuildName) state.Put("winrm_password", s.Password)
packer.LogSecretFilter.Set(s.Password) packer.LogSecretFilter.Set(s.Password)
return multistep.ActionContinue return multistep.ActionContinue
} }
func (s *StepSaveWinRMPassword) Cleanup(multistep.StateBag) { func (s *StepSaveWinRMPassword) Cleanup(multistep.StateBag) {
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
} }

View File

@ -13,7 +13,6 @@ import (
"os" "os"
"time" "time"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
) )
@ -114,7 +113,6 @@ func (s *StepCreateWindowsPassword) Run(_ context.Context, state multistep.State
} }
state.Put("winrm_password", data.password) state.Put("winrm_password", data.password)
commonhelper.SetSharedState("winrm_password", data.password, c.PackerConfig.PackerBuildName)
packer.LogSecretFilter.Set(data.password) packer.LogSecretFilter.Set(data.password)
return multistep.ActionContinue return multistep.ActionContinue

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"log" "log"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
@ -52,8 +51,9 @@ func (s *stepGetDefaultCredentials) Run(ctx context.Context, state multistep.Sta
} }
// store so that we can access this later during provisioning // store so that we can access this later during provisioning
commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword, s.BuildName) state.Put("winrm_password", s.Comm.WinRMPassword)
packer.LogSecretFilter.Set(s.Comm.WinRMPassword) packer.LogSecretFilter.Set(s.Comm.WinRMPassword)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -53,6 +53,9 @@ type Config struct {
UseLinuxPathing bool `mapstructure:"use_linux_pathing"` UseLinuxPathing bool `mapstructure:"use_linux_pathing"`
Ctx interpolate.Context Ctx interpolate.Context
// internal use only; for the provisioner.
WinRMPassword string
} }
func Decode(config *Config, raws ...interface{}) error { func Decode(config *Config, raws ...interface{}) error {

View File

@ -10,7 +10,6 @@ import (
"strings" "strings"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
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"
) )
@ -70,6 +69,7 @@ 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}
packer.LogSecretFilter.Set(config.WinRMPassword)
log.Printf("[INFO] (shell-local): starting local command: %s", flattenedCmd) log.Printf("[INFO] (shell-local): starting local command: %s", flattenedCmd)
if err := cmd.StartWithUi(comm, ui); err != nil { if err := cmd.StartWithUi(comm, ui); err != nil {
return false, fmt.Errorf( return false, fmt.Errorf(
@ -105,7 +105,7 @@ func createInlineScriptFile(config *Config) (string, error) {
// generate context so you can interpolate the command // generate context so you can interpolate the command
config.Ctx.Data = &EnvVarsTemplate{ config.Ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(config.PackerBuildName), WinRMPassword: config.WinRMPassword,
} }
for _, command := range config.Inline { for _, command := range config.Inline {
@ -139,7 +139,7 @@ func createInterpolatedCommands(config *Config, script string, flattenedEnvVars
Vars: flattenedEnvVars, Vars: flattenedEnvVars,
Script: script, Script: script,
Command: script, Command: script,
WinRMPassword: getWinRMPassword(config.PackerBuildName), WinRMPassword: config.WinRMPassword,
} }
interpolatedCmds := make([]string, len(config.ExecuteCommand)) interpolatedCmds := make([]string, len(config.ExecuteCommand))
@ -169,7 +169,7 @@ func createFlattenedEnvVars(config *Config) (string, error) {
// interpolate environment variables // interpolate environment variables
config.Ctx.Data = &EnvVarsTemplate{ config.Ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(config.PackerBuildName), WinRMPassword: config.WinRMPassword,
} }
// Split vars into key/value components // Split vars into key/value components
for _, envVar := range config.Vars { for _, envVar := range config.Vars {
@ -196,9 +196,3 @@ func createFlattenedEnvVars(config *Config) (string, error) {
} }
return flattened, nil return flattened, nil
} }
func getWinRMPassword(buildName string) string {
winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName)
packer.LogSecretFilter.Set(winRMPass)
return winRMPass
}

View File

@ -22,6 +22,10 @@ type StepProvision struct {
Comm packer.Communicator Comm packer.Communicator
} }
type ProvisionHookData struct {
WinRMPassword string
}
func (s *StepProvision) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepProvision) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
comm := s.Comm comm := s.Comm
if comm == nil { if comm == nil {
@ -33,12 +37,21 @@ func (s *StepProvision) Run(_ context.Context, state multistep.StateBag) multist
hook := state.Get("hook").(packer.Hook) hook := state.Get("hook").(packer.Hook)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
// Save data we need to give to provisioners
WinRMPassword, ok := state.GetOk("winrm_password")
if !ok {
WinRMPassword = ""
} else {
WinRMPassword = WinRMPassword.(string)
}
phd := ProvisionHookData{WinRMPassword.(string)}
// Run the provisioner in a goroutine so we can continually check // Run the provisioner in a goroutine so we can continually check
// for cancellations... // for cancellations...
log.Println("Running the provision hook") log.Println("Running the provision hook")
errCh := make(chan error, 1) errCh := make(chan error, 1)
go func() { go func() {
errCh <- hook.Run(packer.HookProvision, ui, comm, nil) errCh <- hook.Run(packer.HookProvision, ui, comm, phd)
}() }()
for { for {

View File

@ -44,6 +44,10 @@ type ProvisionHook struct {
runningProvisioner Provisioner runningProvisioner Provisioner
} }
type ProvisionHookData struct {
WinRMPassword string
}
// Runs the provisioners in order. // Runs the provisioners in order.
func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interface{}) error { func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
// Shortcut // Shortcut
@ -71,8 +75,15 @@ func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interfac
h.lock.Unlock() h.lock.Unlock()
ts := CheckpointReporter.AddSpan(p.TypeName, "provisioner", p.Config) ts := CheckpointReporter.AddSpan(p.TypeName, "provisioner", p.Config)
// re-run prepare with builder-generated config variables (e.g. WinRMPassword)
// Hack Alert. #SorryNotSorry.
err := p.Provisioner.Prepare(data)
if err != nil {
log.Printf("Error performing secondary Prepare: %s", err)
}
err := p.Provisioner.Provision(ui, comm) // Finally, provision.
err = p.Provisioner.Provision(ui, comm)
ts.End(err) ts.End(err)
if err != nil { if err != nil {

View File

@ -14,8 +14,10 @@ type MockProvisioner struct {
} }
func (t *MockProvisioner) Prepare(configs ...interface{}) error { func (t *MockProvisioner) Prepare(configs ...interface{}) error {
if !t.PrepCalled {
t.PrepCalled = true t.PrepCalled = true
t.PrepConfigs = configs t.PrepConfigs = configs
}
return nil return nil
} }

View File

@ -26,7 +26,6 @@ import (
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
@ -58,6 +57,8 @@ type Config struct {
UseSFTP bool `mapstructure:"use_sftp"` UseSFTP bool `mapstructure:"use_sftp"`
InventoryDirectory string `mapstructure:"inventory_directory"` InventoryDirectory string `mapstructure:"inventory_directory"`
InventoryFile string `mapstructure:"inventory_file"` InventoryFile string `mapstructure:"inventory_file"`
// for internal use only; unsettable by user.
winrmpassword string
} }
type Provisioner struct { type Provisioner struct {
@ -73,14 +74,35 @@ type PassthroughTemplate struct {
} }
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
// This is a bit of a hack. For provisioners that need access to
// auto-generated WinRMPasswords, the mechanism of keeping provisioner data
// and build data totally segregated breaks down. We get around this by
// having the builder stash the WinRMPassword in the state bag, then
// grabbing it out of the statebag inside of StepProvision. Then, when
// the time comes to provision for real, we run the prepare step one more
// time, now with WinRMPassword defined in the raws, and can store the
// password on the provisioner config without overwriting the rest of the
// work we've already done in the first prepare run.
if len(raws) == 1 {
for k, v := range raws[0].(map[interface{}]interface{}) {
if k.(string) == "WinRMPassword" {
p.config.winrmpassword = v.(string)
// Even if WinRMPassword is not gonna be used, we've stored the
// key and pointed it to an empty string. That means we'll
// always reach this on our second-run of Prepare()
return nil
}
}
}
p.done = make(chan struct{}) p.done = make(chan struct{})
// Create passthrough for winrm password so we can fill it in once we know // don't interpolate winrmpassword yet; if we've made it to this line, then
// it // we have not obtained the winrm password yet.
p.config.ctx.Data = &PassthroughTemplate{ p.config.ctx.Data = &PassthroughTemplate{
WinRMPassword: `{{.WinRMPassword}}`, WinRMPassword: `{{.WinRMPassword}}`,
} }
err := config.Decode(&p.config, &config.DecodeOpts{ err := config.Decode(&p.config, &config.DecodeOpts{
Interpolate: true, Interpolate: true,
InterpolateContext: &p.config.ctx, InterpolateContext: &p.config.ctx,
@ -200,8 +222,9 @@ func (p *Provisioner) getVersion() error {
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
ui.Say("Provisioning with Ansible...") ui.Say("Provisioning with Ansible...")
// Interpolate env vars to check for .WinRMPassword // Interpolate env vars to check for .WinRMPassword
packer.LogSecretFilter.Set(p.config.winrmpassword)
p.config.ctx.Data = &PassthroughTemplate{ p.config.ctx.Data = &PassthroughTemplate{
WinRMPassword: getWinRMPassword(p.config.PackerBuildName), WinRMPassword: p.config.winrmpassword,
} }
for i, envVar := range p.config.AnsibleEnvVars { for i, envVar := range p.config.AnsibleEnvVars {
envVar, err := interpolate.Render(envVar, &p.config.ctx) envVar, err := interpolate.Render(envVar, &p.config.ctx)
@ -420,12 +443,7 @@ func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator, pri
// remove winrm password from command, if it's been added // remove winrm password from command, if it's been added
flattenedCmd := strings.Join(cmd.Args, " ") flattenedCmd := strings.Join(cmd.Args, " ")
sanitized := flattenedCmd ui.Say(fmt.Sprintf("Executing Ansible: %s", flattenedCmd))
if len(getWinRMPassword(p.config.PackerBuildName)) > 0 {
sanitized = strings.Replace(sanitized,
getWinRMPassword(p.config.PackerBuildName), "*****", -1)
}
ui.Say(fmt.Sprintf("Executing Ansible: %s", sanitized))
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return err return err
@ -553,12 +571,6 @@ func newSigner(privKeyFile string) (*signer, error) {
return signer, nil return signer, nil
} }
func getWinRMPassword(buildName string) string {
winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName)
packer.LogSecretFilter.Set(winRMPass)
return winRMPass
}
// Ui provides concurrency-safe access to packer.Ui. // Ui provides concurrency-safe access to packer.Ui.
type Ui struct { type Ui struct {
sem chan int sem chan int

View File

@ -16,8 +16,8 @@ import (
// Be sure to remove the Ansible stub file in each test with: // Be sure to remove the Ansible stub file in each test with:
// defer os.Remove(config["command"].(string)) // defer os.Remove(config["command"].(string))
func testConfig(t *testing.T) map[string]interface{} { func testConfig(t *testing.T) map[interface{}]interface{} {
m := make(map[string]interface{}) m := make((map[interface{}]interface{}))
wd, err := os.Getwd() wd, err := os.Getwd()
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)

View File

@ -17,7 +17,6 @@ import (
"github.com/hashicorp/packer/common" "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/common/uuid"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
@ -98,6 +97,9 @@ type Config struct {
// Changes will not be effective until the system is rebooted." // Changes will not be effective until the system is rebooted."
ValidExitCodes []int `mapstructure:"valid_exit_codes"` ValidExitCodes []int `mapstructure:"valid_exit_codes"`
// internal variable, to be written to at provisioner run time.
winrmpassword string
ctx interpolate.Context ctx interpolate.Context
} }
@ -117,8 +119,28 @@ type EnvVarsTemplate struct {
} }
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
// Create passthrough for winrm password so we can fill it in once we know // This is a bit of a hack. For provisioners that need access to
// it // auto-generated WinRMPasswords, the mechanism of keeping provisioner data
// and build data totally segregated breaks down. We get around this by
// having the builder stash the WinRMPassword in the state bag, then
// grabbing it out of the statebag inside of StepProvision. Then, when
// the time comes to provision for real, we run the prepare step one more
// time, now with WinRMPassword defined in the raws, and can store the
// password on the provisioner config without overwriting the rest of the
// work we've already done in the first prepare run.
if len(raws) == 1 {
for k, v := range raws[0].(map[interface{}]interface{}) {
if k.(string) == "WinRMPassword" {
p.config.winrmpassword = v.(string)
// Even if WinRMPassword is not gonna be used, we've stored the
// key and pointed it to an empty string. That means we'll
// always reach this on our second-run of Prepare()
return nil
}
}
}
// Only get here if it's the first time the Provisioner's Prepare is run
p.config.ctx.Data = &EnvVarsTemplate{ p.config.ctx.Data = &EnvVarsTemplate{
WinRMPassword: `{{.WinRMPassword}}`, WinRMPassword: `{{.WinRMPassword}}`,
} }
@ -135,7 +157,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}, raws...) }, raws...)
if err != nil { if err != nil {
return err return fmt.Errorf("Error decoding powershell provisioner template: %s", err)
} }
if p.config.EnvVarFormat == "" { if p.config.EnvVarFormat == "" {
@ -261,7 +283,7 @@ func extractScript(p *Provisioner) (string, error) {
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
ui.Say(fmt.Sprintf("Provisioning with Powershell...")) ui.Say(fmt.Sprintf("Provisioning with Powershell..."))
p.communicator = comm p.communicator = comm
packer.LogSecretFilter.Set(p.config.winrmpassword)
scripts := make([]string, len(p.config.Scripts)) scripts := make([]string, len(p.config.Scripts))
copy(scripts, p.config.Scripts) copy(scripts, p.config.Scripts)
@ -392,7 +414,7 @@ func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string) {
// interpolate environment variables // interpolate environment variables
p.config.ctx.Data = &EnvVarsTemplate{ p.config.ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(p.config.PackerBuildName), WinRMPassword: p.config.winrmpassword,
} }
// Split vars into key/value components // Split vars into key/value components
for _, envVar := range p.config.Vars { for _, envVar := range p.config.Vars {
@ -467,7 +489,7 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
p.config.ctx.Data = &ExecuteCommandTemplate{ p.config.ctx.Data = &ExecuteCommandTemplate{
Path: p.config.RemotePath, Path: p.config.RemotePath,
Vars: p.config.RemoteEnvVarPath, Vars: p.config.RemoteEnvVarPath,
WinRMPassword: getWinRMPassword(p.config.PackerBuildName), WinRMPassword: p.config.winrmpassword,
} }
command, err = interpolate.Render(p.config.ExecuteCommand, &p.config.ctx) command, err = interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
@ -479,12 +501,6 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
return command, nil return command, nil
} }
func getWinRMPassword(buildName string) string {
winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName)
packer.LogSecretFilter.Set(winRMPass)
return winRMPass
}
func (p *Provisioner) createCommandTextPrivileged() (command string, err error) { func (p *Provisioner) createCommandTextPrivileged() (command string, err error) {
// Prepare everything needed to enable the required env vars within the // Prepare everything needed to enable the required env vars within the
// remote environment // remote environment
@ -496,7 +512,7 @@ func (p *Provisioner) createCommandTextPrivileged() (command string, err error)
p.config.ctx.Data = &ExecuteCommandTemplate{ p.config.ctx.Data = &ExecuteCommandTemplate{
Path: p.config.RemotePath, Path: p.config.RemotePath,
Vars: p.config.RemoteEnvVarPath, Vars: p.config.RemoteEnvVarPath,
WinRMPassword: getWinRMPassword(p.config.PackerBuildName), WinRMPassword: p.config.winrmpassword,
} }
command, err = interpolate.Render(p.config.ElevatedExecuteCommand, &p.config.ctx) command, err = interpolate.Render(p.config.ElevatedExecuteCommand, &p.config.ctx)
if err != nil { if err != nil {
@ -555,7 +571,7 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin
} }
// Replace ElevatedPassword for winrm users who used this feature // Replace ElevatedPassword for winrm users who used this feature
p.config.ctx.Data = &EnvVarsTemplate{ p.config.ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(p.config.PackerBuildName), WinRMPassword: p.config.winrmpassword,
} }
p.config.ElevatedPassword, _ = interpolate.Render(p.config.ElevatedPassword, &p.config.ctx) p.config.ElevatedPassword, _ = interpolate.Render(p.config.ElevatedPassword, &p.config.ctx)

View File

@ -14,8 +14,8 @@ import (
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
) )
func testConfig() map[string]interface{} { func testConfig() map[interface{}]interface{} {
return map[string]interface{}{ return map[interface{}]interface{}{
"inline": []interface{}{"foo", "bar"}, "inline": []interface{}{"foo", "bar"},
} }
} }

View File

@ -10,6 +10,27 @@ type Provisioner struct {
} }
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
// This is a bit of a hack. For provisioners that need access to
// auto-generated WinRMPasswords, the mechanism of keeping provisioner data
// and build data totally segregated breaks down. We get around this by
// having the builder stash the WinRMPassword in the state bag, then
// grabbing it out of the statebag inside of StepProvision. Then, when
// the time comes to provision for real, we run the prepare step one more
// time, now with WinRMPassword defined in the raws, and can store the
// password on the provisioner config without overwriting the rest of the
// work we've already done in the first prepare run.
if len(raws) == 1 {
for k, v := range raws[0].(map[interface{}]interface{}) {
if k.(string) == "WinRMPassword" {
p.config.WinRMPassword = v.(string)
// Even if WinRMPassword is not gonna be used, we've stored the
// key and pointed it to an empty string. That means we'll
// always reach this on our second-run of Prepare()
return nil
}
}
}
err := sl.Decode(&p.config, raws...) err := sl.Decode(&p.config, raws...)
if err != nil { if err != nil {
return err return err

View File

@ -48,8 +48,8 @@ func TestConfigPrepare(t *testing.T) {
} }
} }
func testConfig(t *testing.T) map[string]interface{} { func testConfig(t *testing.T) map[interface{}]interface{} {
return map[string]interface{}{ return map[interface{}]interface{}{
"command": "echo foo", "command": "echo foo",
} }
} }