Merge pull request #5998 from hashicorp/do_5895
allow users of AWS to use the dynamically-generated admin password wh…
This commit is contained in:
commit
072cd6b745
|
@ -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"
|
||||
|
@ -92,11 +93,15 @@ WaitLoop:
|
|||
ui.Message(fmt.Sprintf(
|
||||
"Password (since debug is enabled): %s", s.Comm.WinRMPassword))
|
||||
}
|
||||
// store so that we can access this later during provisioning
|
||||
commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepGetPassword) Cleanup(multistep.StateBag) {}
|
||||
func (s *StepGetPassword) Cleanup(multistep.StateBag) {
|
||||
commonhelper.RemoveSharedStateFile("winrm_password")
|
||||
}
|
||||
|
||||
func (s *StepGetPassword) waitForPassword(state multistep.StateBag, cancel <-chan struct{}) (string, error) {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
|
|
|
@ -3,14 +3,12 @@ package common
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/packer/helper/common"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
@ -77,25 +75,21 @@ func (s *StepHTTPServer) Run(_ context.Context, state multistep.StateBag) multis
|
|||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func httpAddrFilename(suffix string) string {
|
||||
uuid := os.Getenv("PACKER_RUN_UUID")
|
||||
return filepath.Join(os.TempDir(), fmt.Sprintf("packer-%s-%s", uuid, suffix))
|
||||
}
|
||||
|
||||
func SetHTTPPort(port string) error {
|
||||
return ioutil.WriteFile(httpAddrFilename("port"), []byte(port), 0644)
|
||||
return common.SetSharedState("port", port)
|
||||
}
|
||||
|
||||
func SetHTTPIP(ip string) error {
|
||||
return ioutil.WriteFile(httpAddrFilename("ip"), []byte(ip), 0644)
|
||||
return common.SetSharedState("ip", ip)
|
||||
}
|
||||
|
||||
func GetHTTPAddr() string {
|
||||
ip, err := ioutil.ReadFile(httpAddrFilename("ip"))
|
||||
ip, err := common.RetrieveSharedState("ip")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
port, err := ioutil.ReadFile(httpAddrFilename("port"))
|
||||
|
||||
port, err := common.RetrieveSharedState("port")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
@ -107,6 +101,6 @@ func (s *StepHTTPServer) Cleanup(multistep.StateBag) {
|
|||
// Close the listener so that the HTTP server stops
|
||||
s.l.Close()
|
||||
}
|
||||
os.Remove(httpAddrFilename("port"))
|
||||
os.Remove(httpAddrFilename("ip"))
|
||||
common.RemoveSharedStateFile("port")
|
||||
common.RemoveSharedStateFile("ip")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Used to set variables which we need to access later in the build, where
|
||||
// state bag and config information won't work
|
||||
func sharedStateFilename(suffix string) string {
|
||||
uuid := os.Getenv("PACKER_RUN_UUID")
|
||||
return filepath.Join(os.TempDir(), fmt.Sprintf("packer-%s-%s", uuid, suffix))
|
||||
}
|
||||
|
||||
func SetSharedState(key string, value string) error {
|
||||
return ioutil.WriteFile(sharedStateFilename(key), []byte(value), 0600)
|
||||
}
|
||||
|
||||
func RetrieveSharedState(key string) (string, error) {
|
||||
value, err := ioutil.ReadFile(sharedStateFilename(key))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(value), nil
|
||||
}
|
||||
|
||||
func RemoveSharedStateFile(key string) {
|
||||
os.Remove(sharedStateFilename(key))
|
||||
}
|
|
@ -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"
|
||||
|
@ -99,11 +100,22 @@ type Provisioner struct {
|
|||
}
|
||||
|
||||
type ExecuteCommandTemplate struct {
|
||||
Vars string
|
||||
Path string
|
||||
Vars string
|
||||
Path string
|
||||
WinRMPassword string
|
||||
}
|
||||
|
||||
type EnvVarsTemplate struct {
|
||||
WinRMPassword string
|
||||
}
|
||||
|
||||
func (p *Provisioner) Prepare(raws ...interface{}) error {
|
||||
//Create passthrough for winrm password so we can fill it in once we know it
|
||||
log.Printf("MEGAN context is %#v", p.config.ctx)
|
||||
p.config.ctx.Data = &EnvVarsTemplate{
|
||||
WinRMPassword: `{{.WinRMPassword}}`,
|
||||
}
|
||||
|
||||
err := config.Decode(&p.config, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
InterpolateContext: &p.config.ctx,
|
||||
|
@ -236,6 +248,7 @@ func extractScript(p *Provisioner) (string, error) {
|
|||
}
|
||||
|
||||
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
|
||||
log.Printf("MEGAN context is %#v", p.config.ctx)
|
||||
ui.Say(fmt.Sprintf("Provisioning with Powershell..."))
|
||||
p.communicator = comm
|
||||
|
||||
|
@ -358,13 +371,22 @@ func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string) {
|
|||
// Always available Packer provided env vars
|
||||
envVars["PACKER_BUILD_NAME"] = p.config.PackerBuildName
|
||||
envVars["PACKER_BUILDER_TYPE"] = p.config.PackerBuilderType
|
||||
|
||||
httpAddr := common.GetHTTPAddr()
|
||||
if httpAddr != "" {
|
||||
envVars["PACKER_HTTP_ADDR"] = httpAddr
|
||||
}
|
||||
|
||||
// interpolate environment variables
|
||||
p.config.ctx.Data = &EnvVarsTemplate{
|
||||
WinRMPassword: getWinRMPassword(),
|
||||
}
|
||||
// Split vars into key/value components
|
||||
for _, envVar := range p.config.Vars {
|
||||
envVar, err := interpolate.Render(envVar, &p.config.ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
keyValue := strings.SplitN(envVar, "=", 2)
|
||||
// Escape chars special to PS in each env var value
|
||||
escapedEnvVarValue := psEscape.Replace(keyValue[1])
|
||||
|
@ -423,8 +445,9 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
|
|||
}
|
||||
|
||||
p.config.ctx.Data = &ExecuteCommandTemplate{
|
||||
Path: p.config.RemotePath,
|
||||
Vars: envVarPath,
|
||||
Path: p.config.RemotePath,
|
||||
Vars: envVarPath,
|
||||
WinRMPassword: getWinRMPassword(),
|
||||
}
|
||||
command, err = interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
|
||||
|
||||
|
@ -436,6 +459,11 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
|
|||
return command, nil
|
||||
}
|
||||
|
||||
func getWinRMPassword() string {
|
||||
winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password")
|
||||
return winRMPass
|
||||
|
||||
}
|
||||
func (p *Provisioner) createCommandTextPrivileged() (command string, err error) {
|
||||
// Prepare everything needed to enable the required env vars within the remote environment
|
||||
envVarPath, err := p.prepareEnvVars(true)
|
||||
|
@ -444,8 +472,9 @@ func (p *Provisioner) createCommandTextPrivileged() (command string, err error)
|
|||
}
|
||||
|
||||
p.config.ctx.Data = &ExecuteCommandTemplate{
|
||||
Path: p.config.RemotePath,
|
||||
Vars: envVarPath,
|
||||
Path: p.config.RemotePath,
|
||||
Vars: envVarPath,
|
||||
WinRMPassword: getWinRMPassword(),
|
||||
}
|
||||
command, err = interpolate.Render(p.config.ElevatedExecuteCommand, &p.config.ctx)
|
||||
if err != nil {
|
||||
|
@ -501,6 +530,12 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin
|
|||
log.Printf("Elevated user %s converted to %s after escaping chars special to PowerShell",
|
||||
p.config.ElevatedUser, escapedElevatedUser)
|
||||
}
|
||||
// Replace ElevatedPassword for winrm users who used this feature
|
||||
p.config.ctx.Data = &EnvVarsTemplate{
|
||||
WinRMPassword: getWinRMPassword(),
|
||||
}
|
||||
|
||||
p.config.ElevatedPassword, _ = interpolate.Render(p.config.ElevatedPassword, &p.config.ctx)
|
||||
|
||||
// Escape chars special to PowerShell in the ElevatedPassword string
|
||||
escapedElevatedPassword := psEscape.Replace(p.config.ElevatedPassword)
|
||||
|
|
|
@ -72,7 +72,20 @@ Optional parameters:
|
|||
- `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.
|
||||
environment, as well, which are covered in the section below. If you are
|
||||
using AWS and would like to use the randomly-generated unique
|
||||
If you are running on AWS and would like to access the AWS-generated
|
||||
Administrator 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "powershell",
|
||||
"environment_vars": "WINRMPASS={{.WinRMPassword}}",
|
||||
"inline": ["Write-Host \"Automatically generated aws password is: $Env:WINRMPASS\""]
|
||||
},
|
||||
```
|
||||
|
||||
- `execute_command` (string) - The command to use to execute the script. By
|
||||
default this is as follows:
|
||||
|
@ -89,7 +102,15 @@ Optional parameters:
|
|||
|
||||
- `elevated_user` and `elevated_password` (string) - If specified, the
|
||||
PowerShell script will be run with elevated privileges using the given
|
||||
Windows user.
|
||||
Windows user. If you are running a build on AWS and would like to run using
|
||||
the AWS-generated password that Packer uses to connect to the instance via,
|
||||
WinRM, you may do so by using the template variable {{.WinRMPassword}}.
|
||||
For example:
|
||||
|
||||
``` json
|
||||
"elevated_user": "Administrator",
|
||||
"elevated_password": "{{.WinRMPassword}}",
|
||||
```
|
||||
|
||||
- `remote_path` (string) - The path where the script will be uploaded to in
|
||||
the machine. This defaults to "c:/Windows/Temp/script.ps1". This value must
|
||||
|
|
Loading…
Reference in New Issue