Merge pull request #6579 from hashicorp/reinterpolate_winrm_step
use statebag instead of SetSharedState for winRM password
This commit is contained in:
commit
d356817890
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -14,8 +14,10 @@ type MockProvisioner struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MockProvisioner) Prepare(configs ...interface{}) error {
|
func (t *MockProvisioner) Prepare(configs ...interface{}) error {
|
||||||
t.PrepCalled = true
|
if !t.PrepCalled {
|
||||||
t.PrepConfigs = configs
|
t.PrepCalled = true
|
||||||
|
t.PrepConfigs = configs
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue