Going to revert this change for now, becuase of potential issues that arise from calling Prepare() twice

Revert "use statebag instead of SetSharedState for winRM password"

This reverts commit b35acbd879.
This commit is contained in:
Megan Marsh 2018-09-10 16:48:42 -07:00
parent 351cdc8508
commit a0edaf6c46
16 changed files with 67 additions and 128 deletions

View File

@ -12,6 +12,7 @@ import (
"time"
"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/multistep"
"github.com/hashicorp/packer/packer"
@ -94,13 +95,15 @@ WaitLoop:
"Password (since debug is enabled): %s", s.Comm.WinRMPassword))
}
// 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)
return multistep.ActionContinue
}
func (s *StepGetPassword) Cleanup(multistep.StateBag) {
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
}
func (s *StepGetPassword) waitForPassword(state multistep.StateBag, cancel <-chan struct{}) (string, error) {

View File

@ -22,6 +22,7 @@ import (
"github.com/hashicorp/packer/builder/azure/common/constants"
"github.com/hashicorp/packer/builder/azure/pkcs12"
"github.com/hashicorp/packer/common"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
@ -359,7 +360,10 @@ func setRuntimeValues(c *Config) {
var tempName = NewTempName()
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)
c.tmpCertificatePassword = tempName.CertificatePassword
if c.TempComputeName == "" {
c.tmpComputeName = tempName.ComputeName

View File

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

View File

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

View File

@ -5,6 +5,7 @@ import (
"fmt"
"log"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
@ -51,9 +52,8 @@ func (s *stepGetDefaultCredentials) Run(ctx context.Context, state multistep.Sta
}
// 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)
return multistep.ActionContinue
}

View File

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

View File

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

View File

@ -22,10 +22,6 @@ type StepProvision struct {
Comm packer.Communicator
}
type ProvisionHookData struct {
WinRMPassword string
}
func (s *StepProvision) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
comm := s.Comm
if comm == nil {
@ -37,21 +33,12 @@ func (s *StepProvision) Run(_ context.Context, state multistep.StateBag) multist
hook := state.Get("hook").(packer.Hook)
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
// for cancellations...
log.Println("Running the provision hook")
errCh := make(chan error, 1)
go func() {
errCh <- hook.Run(packer.HookProvision, ui, comm, phd)
errCh <- hook.Run(packer.HookProvision, ui, comm, nil)
}()
for {

View File

@ -44,10 +44,6 @@ type ProvisionHook struct {
runningProvisioner Provisioner
}
type ProvisionHookData struct {
WinRMPassword string
}
// Runs the provisioners in order.
func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
// Shortcut
@ -75,15 +71,8 @@ func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interfac
h.lock.Unlock()
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)
}
// Finally, provision.
err = p.Provisioner.Provision(ui, comm)
err := p.Provisioner.Provision(ui, comm)
ts.End(err)
if err != nil {

View File

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

View File

@ -26,6 +26,7 @@ import (
"golang.org/x/crypto/ssh"
"github.com/hashicorp/packer/common"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
@ -57,8 +58,6 @@ type Config struct {
UseSFTP bool `mapstructure:"use_sftp"`
InventoryDirectory string `mapstructure:"inventory_directory"`
InventoryFile string `mapstructure:"inventory_file"`
// for internal use only; unsettable by user.
winrmpassword string
}
type Provisioner struct {
@ -74,35 +73,14 @@ type PassthroughTemplate struct {
}
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{})
// don't interpolate winrmpassword yet; if we've made it to this line, then
// we have not obtained the winrm password yet.
// Create passthrough for winrm password so we can fill it in once we know
// it
p.config.ctx.Data = &PassthroughTemplate{
WinRMPassword: `{{.WinRMPassword}}`,
}
err := config.Decode(&p.config, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: &p.config.ctx,
@ -222,9 +200,8 @@ func (p *Provisioner) getVersion() error {
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
ui.Say("Provisioning with Ansible...")
// Interpolate env vars to check for .WinRMPassword
packer.LogSecretFilter.Set(p.config.winrmpassword)
p.config.ctx.Data = &PassthroughTemplate{
WinRMPassword: p.config.winrmpassword,
WinRMPassword: getWinRMPassword(p.config.PackerBuildName),
}
for i, envVar := range p.config.AnsibleEnvVars {
envVar, err := interpolate.Render(envVar, &p.config.ctx)
@ -443,7 +420,12 @@ func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator, pri
// remove winrm password from command, if it's been added
flattenedCmd := strings.Join(cmd.Args, " ")
ui.Say(fmt.Sprintf("Executing Ansible: %s", flattenedCmd))
sanitized := 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 {
return err
@ -571,6 +553,12 @@ func newSigner(privKeyFile string) (*signer, error) {
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.
type Ui struct {
sem chan int

View File

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

View File

@ -17,6 +17,7 @@ import (
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/uuid"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
@ -97,9 +98,6 @@ type Config struct {
// Changes will not be effective until the system is rebooted."
ValidExitCodes []int `mapstructure:"valid_exit_codes"`
// internal variable, to be written to at provisioner run time.
winrmpassword string
ctx interpolate.Context
}
@ -119,28 +117,8 @@ type EnvVarsTemplate struct {
}
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
}
}
}
// Only get here if it's the first time the Provisioner's Prepare is run
// Create passthrough for winrm password so we can fill it in once we know
// it
p.config.ctx.Data = &EnvVarsTemplate{
WinRMPassword: `{{.WinRMPassword}}`,
}
@ -157,7 +135,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}, raws...)
if err != nil {
return fmt.Errorf("Error decoding powershell provisioner template: %s", err)
return err
}
if p.config.EnvVarFormat == "" {
@ -283,7 +261,7 @@ func extractScript(p *Provisioner) (string, error) {
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
ui.Say(fmt.Sprintf("Provisioning with Powershell..."))
p.communicator = comm
packer.LogSecretFilter.Set(p.config.winrmpassword)
scripts := make([]string, len(p.config.Scripts))
copy(scripts, p.config.Scripts)
@ -414,7 +392,7 @@ func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string) {
// interpolate environment variables
p.config.ctx.Data = &EnvVarsTemplate{
WinRMPassword: p.config.winrmpassword,
WinRMPassword: getWinRMPassword(p.config.PackerBuildName),
}
// Split vars into key/value components
for _, envVar := range p.config.Vars {
@ -489,7 +467,7 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
p.config.ctx.Data = &ExecuteCommandTemplate{
Path: p.config.RemotePath,
Vars: p.config.RemoteEnvVarPath,
WinRMPassword: p.config.winrmpassword,
WinRMPassword: getWinRMPassword(p.config.PackerBuildName),
}
command, err = interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
@ -501,6 +479,12 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
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) {
// Prepare everything needed to enable the required env vars within the
// remote environment
@ -512,7 +496,7 @@ func (p *Provisioner) createCommandTextPrivileged() (command string, err error)
p.config.ctx.Data = &ExecuteCommandTemplate{
Path: p.config.RemotePath,
Vars: p.config.RemoteEnvVarPath,
WinRMPassword: p.config.winrmpassword,
WinRMPassword: getWinRMPassword(p.config.PackerBuildName),
}
command, err = interpolate.Render(p.config.ElevatedExecuteCommand, &p.config.ctx)
if err != nil {
@ -571,7 +555,7 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin
}
// Replace ElevatedPassword for winrm users who used this feature
p.config.ctx.Data = &EnvVarsTemplate{
WinRMPassword: p.config.winrmpassword,
WinRMPassword: getWinRMPassword(p.config.PackerBuildName),
}
p.config.ElevatedPassword, _ = interpolate.Render(p.config.ElevatedPassword, &p.config.ctx)

View File

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

View File

@ -10,27 +10,6 @@ type Provisioner struct {
}
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...)
if err != nil {
return err

View File

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