Elevated support for puppet-masterless provisioner

This should fix #5478.
This commit is contained in:
Matt Dainty 2018-12-07 11:08:11 +00:00
parent 11be4ffc4b
commit a42f8fac4d
1 changed files with 52 additions and 4 deletions

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"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/provisioner" "github.com/hashicorp/packer/provisioner"
@ -65,6 +66,12 @@ type Config struct {
// The directory from which the command will be executed. // The directory from which the command will be executed.
// Packer requires the directory to exist when running puppet. // Packer requires the directory to exist when running puppet.
WorkingDir string `mapstructure:"working_directory"` WorkingDir string `mapstructure:"working_directory"`
// Instructs the communicator to run the remote script as a Windows
// scheduled task, effectively elevating the remote user by impersonating
// a logged-in user
ElevatedUser string `mapstructure:"elevated_user"`
ElevatedPassword string `mapstructure:"elevated_password"`
} }
type guestOSTypeConfig struct { type guestOSTypeConfig struct {
@ -117,6 +124,7 @@ var guestOSTypeConfigs = map[string]guestOSTypeConfig{
type Provisioner struct { type Provisioner struct {
config Config config Config
communicator packer.Communicator
guestOSTypeConfig guestOSTypeConfig guestOSTypeConfig guestOSTypeConfig
guestCommands *provisioner.GuestCommands guestCommands *provisioner.GuestCommands
} }
@ -135,7 +143,17 @@ type ExecuteTemplate struct {
WorkingDir string WorkingDir string
} }
type EnvVarsTemplate struct {
WinRMPassword string
}
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
// it
p.config.ctx.Data = &EnvVarsTemplate{
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,
@ -240,6 +258,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) 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 Puppet...") ui.Say("Provisioning with Puppet...")
p.communicator = comm
ui.Message("Creating Puppet staging directory...") ui.Message("Creating Puppet staging directory...")
if err := p.createDir(ui, comm, p.config.StagingDir); err != nil { if err := p.createDir(ui, comm, p.config.StagingDir); err != nil {
return fmt.Errorf("Error creating staging directory: %s", err) return fmt.Errorf("Error creating staging directory: %s", err)
@ -316,6 +335,13 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
return err return err
} }
if p.config.ElevatedUser != "" {
command, err = provisioner.GenerateElevatedRunner(command, p)
if err != nil {
return err
}
}
cmd := &packer.RemoteCmd{ cmd := &packer.RemoteCmd{
Command: command, Command: command,
} }
@ -432,10 +458,7 @@ func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir stri
} }
func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error { func (p *Provisioner) removeDir(ui packer.Ui, comm packer.Communicator, dir string) error {
cmd := &packer.RemoteCmd{ cmd := &packer.RemoteCmd{Command: p.guestCommands.RemoveDir(dir)}
Command: fmt.Sprintf("rm -fr '%s'", dir),
}
if err := cmd.StartWithUi(comm, ui); err != nil { if err := cmd.StartWithUi(comm, ui); err != nil {
return err return err
} }
@ -460,3 +483,28 @@ func (p *Provisioner) uploadDirectory(ui packer.Ui, comm packer.Communicator, ds
return comm.UploadDir(dst, src, nil) return comm.UploadDir(dst, src, nil)
} }
func getWinRMPassword(buildName string) string {
winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName)
packer.LogSecretFilter.Set(winRMPass)
return winRMPass
}
func (p *Provisioner) Communicator() packer.Communicator {
return p.communicator
}
func (p *Provisioner) ElevatedUser() string {
return p.config.ElevatedUser
}
func (p *Provisioner) ElevatedPassword() string {
// Replace ElevatedPassword for winrm users who used this feature
p.config.ctx.Data = &EnvVarsTemplate{
WinRMPassword: getWinRMPassword(p.config.PackerBuildName),
}
elevatedPassword, _ := interpolate.Render(p.config.ElevatedPassword, &p.config.ctx)
return elevatedPassword
}