Merge pull request #5872 from DanHam/ps-combined
PowerShell - Combined and updated PR's 5515 and 5376
This commit is contained in:
commit
a0c1f4e59d
|
@ -34,6 +34,7 @@ func init() {
|
|||
"amazon-shutdown_behavior": new(FixerAmazonShutdownBehavior),
|
||||
"amazon-enhanced-networking": new(FixerAmazonEnhancedNetworking),
|
||||
"docker-email": new(FixerDockerEmail),
|
||||
"powershell-escapes": new(FixerPowerShellEscapes),
|
||||
}
|
||||
|
||||
FixerOrder = []string{
|
||||
|
@ -51,5 +52,6 @@ func init() {
|
|||
"amazon-shutdown_behavior",
|
||||
"amazon-enhanced-networking",
|
||||
"docker-email",
|
||||
"powershell-escapes",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package fix
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FixerPowerShellEscapes removes the PowerShell escape character from user
|
||||
// environment variables and elevated username and password strings
|
||||
type FixerPowerShellEscapes struct{}
|
||||
|
||||
func (FixerPowerShellEscapes) Fix(input map[string]interface{}) (map[string]interface{}, error) {
|
||||
type template struct {
|
||||
Provisioners []interface{}
|
||||
}
|
||||
|
||||
var psUnescape = strings.NewReplacer(
|
||||
"`$", "$",
|
||||
"`\"", "\"",
|
||||
"``", "`",
|
||||
"`'", "'",
|
||||
)
|
||||
|
||||
// Decode the input into our structure, if we can
|
||||
var tpl template
|
||||
if err := mapstructure.WeakDecode(input, &tpl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, raw := range tpl.Provisioners {
|
||||
var provisioners map[string]interface{}
|
||||
if err := mapstructure.Decode(raw, &provisioners); err != nil {
|
||||
// Ignore errors, could be a non-map
|
||||
continue
|
||||
}
|
||||
|
||||
if ok := provisioners["type"] == "powershell"; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := provisioners["elevated_user"]; ok {
|
||||
provisioners["elevated_user"] = psUnescape.Replace(provisioners["elevated_user"].(string))
|
||||
}
|
||||
if _, ok := provisioners["elevated_password"]; ok {
|
||||
provisioners["elevated_password"] = psUnescape.Replace(provisioners["elevated_password"].(string))
|
||||
}
|
||||
if raw, ok := provisioners["environment_vars"]; ok {
|
||||
var env_vars []string
|
||||
if err := mapstructure.Decode(raw, &env_vars); err != nil {
|
||||
continue
|
||||
}
|
||||
env_vars_unescaped := make([]interface{}, len(env_vars))
|
||||
for j, env_var := range env_vars {
|
||||
env_vars_unescaped[j] = psUnescape.Replace(env_var)
|
||||
}
|
||||
// Replace with unescaped environment variables
|
||||
provisioners["environment_vars"] = env_vars_unescaped
|
||||
}
|
||||
|
||||
// Write all changes back to template
|
||||
tpl.Provisioners[i] = provisioners
|
||||
}
|
||||
|
||||
if len(tpl.Provisioners) > 0 {
|
||||
input["provisioners"] = tpl.Provisioners
|
||||
}
|
||||
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (FixerPowerShellEscapes) Synopsis() string {
|
||||
return `Removes PowerShell escapes from user env vars and elevated username and password strings`
|
||||
}
|
|
@ -24,6 +24,13 @@ import (
|
|||
|
||||
var retryableSleep = 2 * time.Second
|
||||
|
||||
var psEscape = strings.NewReplacer(
|
||||
"$", "`$",
|
||||
"\"", "`\"",
|
||||
"`", "``",
|
||||
"'", "`'",
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
|
||||
|
@ -113,7 +120,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
|||
}
|
||||
|
||||
if p.config.EnvVarFormat == "" {
|
||||
p.config.EnvVarFormat = `$env:%s=\"%s\"; `
|
||||
p.config.EnvVarFormat = `$env:%s="%s"; `
|
||||
}
|
||||
|
||||
if p.config.ElevatedEnvVarFormat == "" {
|
||||
|
@ -121,7 +128,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
|||
}
|
||||
|
||||
if p.config.ExecuteCommand == "" {
|
||||
p.config.ExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }"`
|
||||
p.config.ExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}';exit $LastExitCode }"`
|
||||
}
|
||||
|
||||
if p.config.ElevatedExecuteCommand == "" {
|
||||
|
@ -331,6 +338,19 @@ func (p *Provisioner) retryable(f func() error) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Enviroment variables required within the remote environment are uploaded within a PS script and
|
||||
// then enabled by 'dot sourcing' the script immediately prior to execution of the main command
|
||||
func (p *Provisioner) prepareEnvVars(elevated bool) (envVarPath string, err error) {
|
||||
// Collate all required env vars into a plain string with required formatting applied
|
||||
flattenedEnvVars := p.createFlattenedEnvVars(elevated)
|
||||
// Create a powershell script on the target build fs containing the flattened env vars
|
||||
envVarPath, err = p.uploadEnvVars(flattenedEnvVars)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string) {
|
||||
flattened = ""
|
||||
envVars := make(map[string]string)
|
||||
|
@ -346,7 +366,13 @@ func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string) {
|
|||
// Split vars into key/value components
|
||||
for _, envVar := range p.config.Vars {
|
||||
keyValue := strings.SplitN(envVar, "=", 2)
|
||||
envVars[keyValue[0]] = keyValue[1]
|
||||
// Escape chars special to PS in each env var value
|
||||
escapedEnvVarValue := psEscape.Replace(keyValue[1])
|
||||
if escapedEnvVarValue != keyValue[1] {
|
||||
log.Printf("Env var %s converted to %s after escaping chars special to PS", keyValue[1],
|
||||
escapedEnvVarValue)
|
||||
}
|
||||
envVars[keyValue[0]] = escapedEnvVarValue
|
||||
}
|
||||
|
||||
// Create a list of env var keys in sorted order
|
||||
|
@ -367,6 +393,19 @@ func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string) {
|
|||
return
|
||||
}
|
||||
|
||||
func (p *Provisioner) uploadEnvVars(flattenedEnvVars string) (envVarPath string, err error) {
|
||||
// Upload all env vars to a powershell script on the target build file system
|
||||
envVarReader := strings.NewReader(flattenedEnvVars)
|
||||
uuid := uuid.TimeOrderedUUID()
|
||||
envVarPath = fmt.Sprintf(`${env:SYSTEMROOT}\Temp\packer-env-vars-%s.ps1`, uuid)
|
||||
log.Printf("Uploading env vars to %s", envVarPath)
|
||||
err = p.communicator.Upload(envVarPath, envVarReader, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error uploading ps script containing env vars: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Provisioner) createCommandText() (command string, err error) {
|
||||
// Return the interpolated command
|
||||
if p.config.ElevatedUser == "" {
|
||||
|
@ -377,12 +416,15 @@ func (p *Provisioner) createCommandText() (command string, err error) {
|
|||
}
|
||||
|
||||
func (p *Provisioner) createCommandTextNonPrivileged() (command string, err error) {
|
||||
// Create environment variables to set before executing the command
|
||||
flattenedEnvVars := p.createFlattenedEnvVars(false)
|
||||
// Prepare everything needed to enable the required env vars within the remote environment
|
||||
envVarPath, err := p.prepareEnvVars(false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
p.config.ctx.Data = &ExecuteCommandTemplate{
|
||||
Vars: flattenedEnvVars,
|
||||
Path: p.config.RemotePath,
|
||||
Vars: envVarPath,
|
||||
}
|
||||
command, err = interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
|
||||
|
||||
|
@ -395,17 +437,10 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro
|
|||
}
|
||||
|
||||
func (p *Provisioner) createCommandTextPrivileged() (command string, err error) {
|
||||
// Can't double escape the env vars, lets create shiny new ones
|
||||
flattenedEnvVars := p.createFlattenedEnvVars(true)
|
||||
// Need to create a mini ps1 script containing all of the environment variables we want;
|
||||
// we'll be dot-sourcing this later
|
||||
envVarReader := strings.NewReader(flattenedEnvVars)
|
||||
uuid := uuid.TimeOrderedUUID()
|
||||
envVarPath := fmt.Sprintf(`${env:SYSTEMROOT}\Temp\packer-env-vars-%s.ps1`, uuid)
|
||||
log.Printf("Uploading env vars to %s", envVarPath)
|
||||
err = p.communicator.Upload(envVarPath, envVarReader, nil)
|
||||
// Prepare everything needed to enable the required env vars within the remote environment
|
||||
envVarPath, err := p.prepareEnvVars(true)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error preparing elevated powershell script: %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
p.config.ctx.Data = &ExecuteCommandTemplate{
|
||||
|
@ -458,13 +493,26 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin
|
|||
}
|
||||
escapedCommand := buffer.String()
|
||||
log.Printf("Command [%s] converted to [%s] for use in XML string", command, escapedCommand)
|
||||
|
||||
buffer.Reset()
|
||||
|
||||
// Escape chars special to PowerShell in the ElevatedUser string
|
||||
escapedElevatedUser := psEscape.Replace(p.config.ElevatedUser)
|
||||
if escapedElevatedUser != p.config.ElevatedUser {
|
||||
log.Printf("Elevated user %s converted to %s after escaping chars special to PowerShell",
|
||||
p.config.ElevatedUser, escapedElevatedUser)
|
||||
}
|
||||
|
||||
// Escape chars special to PowerShell in the ElevatedPassword string
|
||||
escapedElevatedPassword := psEscape.Replace(p.config.ElevatedPassword)
|
||||
if escapedElevatedPassword != p.config.ElevatedPassword {
|
||||
log.Printf("Elevated password %s converted to %s after escaping chars special to PowerShell",
|
||||
p.config.ElevatedPassword, escapedElevatedPassword)
|
||||
}
|
||||
|
||||
// Generate command
|
||||
err = elevatedTemplate.Execute(&buffer, elevatedOptions{
|
||||
User: p.config.ElevatedUser,
|
||||
Password: p.config.ElevatedPassword,
|
||||
User: escapedElevatedUser,
|
||||
Password: escapedElevatedPassword,
|
||||
TaskName: taskName,
|
||||
TaskDescription: "Packer elevated task",
|
||||
LogFile: logFile,
|
||||
|
|
|
@ -79,8 +79,8 @@ func TestProvisionerPrepare_Defaults(t *testing.T) {
|
|||
t.Error("expected elevated_password to be empty")
|
||||
}
|
||||
|
||||
if p.config.ExecuteCommand != `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }"` {
|
||||
t.Fatalf(`Default command should be 'powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }"', but got '%s'`, p.config.ExecuteCommand)
|
||||
if p.config.ExecuteCommand != `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}';exit $LastExitCode }"` {
|
||||
t.Fatalf(`Default command should be 'powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}';exit $LastExitCode }"', but got '%s'`, p.config.ExecuteCommand)
|
||||
}
|
||||
|
||||
if p.config.ElevatedExecuteCommand != `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` {
|
||||
|
@ -403,7 +403,7 @@ func TestProvisionerProvision_Inline(t *testing.T) {
|
|||
ui := testUi()
|
||||
p := new(Provisioner)
|
||||
|
||||
// Defaults provided by Packer
|
||||
// Defaults provided by Packer - env vars should not appear in cmd
|
||||
p.config.PackerBuildName = "vmware"
|
||||
p.config.PackerBuilderType = "iso"
|
||||
comm := new(packer.MockCommunicator)
|
||||
|
@ -413,11 +413,14 @@ func TestProvisionerProvision_Inline(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
expectedCommand := `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; &'c:/Windows/Temp/inlineScript.ps1';exit $LastExitCode }"`
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command)
|
||||
cmd := comm.StartCmd.Command
|
||||
re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){\$ProgressPreference='SilentlyContinue'};\. \${env:SYSTEMROOT}\\Temp\\packer-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/inlineScript.ps1';exit \$LastExitCode }"`)
|
||||
matched := re.MatchString(cmd)
|
||||
if !matched {
|
||||
t.Fatalf("Got unexpected command: %s", cmd)
|
||||
}
|
||||
|
||||
// User supplied env vars should not change things
|
||||
envVars := make([]string, 2)
|
||||
envVars[0] = "FOO=BAR"
|
||||
envVars[1] = "BAR=BAZ"
|
||||
|
@ -430,9 +433,11 @@ func TestProvisionerProvision_Inline(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
expectedCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:BAR=\"BAZ\"; $env:FOO=\"BAR\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; &'c:/Windows/Temp/inlineScript.ps1';exit $LastExitCode }"`
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command)
|
||||
cmd = comm.StartCmd.Command
|
||||
re = regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){\$ProgressPreference='SilentlyContinue'};\. \${env:SYSTEMROOT}\\Temp\\packer-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/inlineScript.ps1';exit \$LastExitCode }"`)
|
||||
matched = re.MatchString(cmd)
|
||||
if !matched {
|
||||
t.Fatalf("Got unexpected command: %s", cmd)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,11 +460,12 @@ func TestProvisionerProvision_Scripts(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
expectedCommand := `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:PACKER_BUILDER_TYPE=\"footype\"; $env:PACKER_BUILD_NAME=\"foobuild\"; &'c:/Windows/Temp/script.ps1';exit $LastExitCode }"`
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command)
|
||||
cmd := comm.StartCmd.Command
|
||||
re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){\$ProgressPreference='SilentlyContinue'};\. \${env:SYSTEMROOT}\\Temp\\packer-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/script.ps1';exit \$LastExitCode }"`)
|
||||
matched := re.MatchString(cmd)
|
||||
if !matched {
|
||||
t.Fatalf("Got unexpected command: %s", cmd)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) {
|
||||
|
@ -488,9 +494,11 @@ func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
expectedCommand := `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:BAR=\"BAZ\"; $env:FOO=\"BAR\"; $env:PACKER_BUILDER_TYPE=\"footype\"; $env:PACKER_BUILD_NAME=\"foobuild\"; &'c:/Windows/Temp/script.ps1';exit $LastExitCode }"`
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command)
|
||||
cmd := comm.StartCmd.Command
|
||||
re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){\$ProgressPreference='SilentlyContinue'};\. \${env:SYSTEMROOT}\\Temp\\packer-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/script.ps1';exit \$LastExitCode }"`)
|
||||
matched := re.MatchString(cmd)
|
||||
if !matched {
|
||||
t.Fatalf("Got unexpected command: %s", cmd)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,6 +518,12 @@ func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) {
|
|||
{"FOO=bar", "BAZ=qux"}, // Multiple user env vars
|
||||
{"FOO=bar=baz"}, // User env var with value containing equals
|
||||
{"FOO==bar"}, // User env var with value starting with equals
|
||||
// Test escaping of characters special to PowerShell
|
||||
{"FOO=bar$baz"}, // User env var with value containing dollar
|
||||
{"FOO=bar\"baz"}, // User env var with value containing a double quote
|
||||
{"FOO=bar'baz"}, // User env var with value containing a single quote
|
||||
{"FOO=bar`baz"}, // User env var with value containing a backtick
|
||||
|
||||
}
|
||||
expected := []string{
|
||||
`$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
|
@ -517,6 +531,10 @@ func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) {
|
|||
`$env:BAZ="qux"; $env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
`$env:FOO="bar=baz"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
`$env:FOO="=bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
"$env:FOO=\"bar`$baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
"$env:FOO=\"bar`\"baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
"$env:FOO=\"bar`'baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
"$env:FOO=\"bar``baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
}
|
||||
|
||||
p := new(Provisioner)
|
||||
|
@ -545,13 +563,22 @@ func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
|
|||
{"FOO=bar", "BAZ=qux"}, // Multiple user env vars
|
||||
{"FOO=bar=baz"}, // User env var with value containing equals
|
||||
{"FOO==bar"}, // User env var with value starting with equals
|
||||
// Test escaping of characters special to PowerShell
|
||||
{"FOO=bar$baz"}, // User env var with value containing dollar
|
||||
{"FOO=bar\"baz"}, // User env var with value containing a double quote
|
||||
{"FOO=bar'baz"}, // User env var with value containing a single quote
|
||||
{"FOO=bar`baz"}, // User env var with value containing a backtick
|
||||
}
|
||||
expected := []string{
|
||||
`$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `,
|
||||
`$env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `,
|
||||
`$env:BAZ=\"qux\"; $env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `,
|
||||
`$env:FOO=\"bar=baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `,
|
||||
`$env:FOO=\"=bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `,
|
||||
`$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
`$env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
`$env:BAZ="qux"; $env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
`$env:FOO="bar=baz"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
`$env:FOO="=bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `,
|
||||
"$env:FOO=\"bar`$baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
"$env:FOO=\"bar`\"baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
"$env:FOO=\"bar`'baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
"$env:FOO=\"bar``baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ",
|
||||
}
|
||||
|
||||
p := new(Provisioner)
|
||||
|
@ -571,7 +598,6 @@ func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestProvision_createCommandText(t *testing.T) {
|
||||
|
||||
config := testConfig()
|
||||
config["remote_path"] = "c:/Windows/Temp/script.ps1"
|
||||
p := new(Provisioner)
|
||||
|
@ -586,22 +612,46 @@ func TestProvision_createCommandText(t *testing.T) {
|
|||
// Non-elevated
|
||||
cmd, _ := p.createCommandText()
|
||||
|
||||
expectedCommand := `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; &'c:/Windows/Temp/script.ps1';exit $LastExitCode }"`
|
||||
|
||||
if cmd != expectedCommand {
|
||||
t.Fatalf("Expected Non-elevated command: %s, got %s", expectedCommand, cmd)
|
||||
re := regexp.MustCompile(`powershell -executionpolicy bypass "& { if \(Test-Path variable:global:ProgressPreference\){\$ProgressPreference='SilentlyContinue'};\. \${env:SYSTEMROOT}\\Temp\\packer-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1; &'c:/Windows/Temp/script.ps1';exit \$LastExitCode }"`)
|
||||
matched := re.MatchString(cmd)
|
||||
if !matched {
|
||||
t.Fatalf("Got unexpected command: %s", cmd)
|
||||
}
|
||||
|
||||
// Elevated
|
||||
p.config.ElevatedUser = "vagrant"
|
||||
p.config.ElevatedPassword = "vagrant"
|
||||
cmd, _ = p.createCommandText()
|
||||
matched, _ := regexp.MatchString("powershell -executionpolicy bypass -file \"%TEMP%(.{1})packer-elevated-shell.*", cmd)
|
||||
re = regexp.MustCompile(`powershell -executionpolicy bypass -file "%TEMP%\\packer-elevated-shell-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1"`)
|
||||
matched = re.MatchString(cmd)
|
||||
if !matched {
|
||||
t.Fatalf("Got unexpected elevated command: %s", cmd)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvision_uploadEnvVars(t *testing.T) {
|
||||
p := new(Provisioner)
|
||||
comm := new(packer.MockCommunicator)
|
||||
p.communicator = comm
|
||||
|
||||
flattenedEnvVars := `$env:PACKER_BUILDER_TYPE="footype"; $env:PACKER_BUILD_NAME="foobuild";`
|
||||
|
||||
envVarPath, err := p.uploadEnvVars(flattenedEnvVars)
|
||||
if err != nil {
|
||||
t.Fatalf("Did not expect error: %s", err.Error())
|
||||
}
|
||||
|
||||
if comm.UploadCalled != true {
|
||||
t.Fatalf("Failed to upload env var file")
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`\${env:SYSTEMROOT}\\Temp\\packer-env-vars-[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}\.ps1`)
|
||||
matched := re.MatchString(envVarPath)
|
||||
if !matched {
|
||||
t.Fatalf("Got unexpected path for env var file: %s", envVarPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvision_generateElevatedShellRunner(t *testing.T) {
|
||||
|
||||
// Non-elevated
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
description: |
|
||||
The shell Packer provisioner provisions machines built by Packer using shell
|
||||
scripts. Shell provisioning is the easiest way to get software installed and
|
||||
configured on a machine.
|
||||
The PowerShell Packer provisioner runs PowerShell scripts on Windows
|
||||
machines.
|
||||
It assumes that the communicator in use is WinRM.
|
||||
layout: docs
|
||||
page_title: 'PowerShell - Provisioners'
|
||||
sidebar_current: 'docs-provisioners-powershell'
|
||||
|
@ -29,20 +29,21 @@ The example below is fully functional.
|
|||
## Configuration Reference
|
||||
|
||||
The reference of available configuration options is listed below. The only
|
||||
required element is either "inline" or "script". Every other option is optional.
|
||||
required element is either "inline" or "script". Every other option is
|
||||
optional.
|
||||
|
||||
Exactly *one* of the following is required:
|
||||
|
||||
- `inline` (array of strings) - This is an array of commands to execute. The
|
||||
commands are concatenated by newlines and turned into a single file, so they
|
||||
are all executed within the same context. This allows you to change
|
||||
commands are concatenated by newlines and turned into a single file, so
|
||||
they are all executed within the same context. This allows you to change
|
||||
directories in one command and use something in the directory in the next
|
||||
and so on. Inline scripts are the easiest way to pull off simple tasks
|
||||
within the machine.
|
||||
|
||||
- `script` (string) - The path to a script to upload and execute in
|
||||
the machine. This path can be absolute or relative. If it is relative, it is
|
||||
relative to the working directory when Packer is executed.
|
||||
the machine. This path can be absolute or relative. If it is relative, it
|
||||
is relative to the working directory when Packer is executed.
|
||||
|
||||
- `scripts` (array of strings) - An array of scripts to execute. The scripts
|
||||
will be uploaded and executed in the order specified. Each script is
|
||||
|
@ -51,12 +52,12 @@ Exactly *one* of the following is required:
|
|||
|
||||
Optional parameters:
|
||||
|
||||
- `binary` (boolean) - If true, specifies that the script(s) are binary files,
|
||||
and Packer should therefore not convert Windows line endings to Unix line
|
||||
endings (if there are any). By default this is false.
|
||||
- `binary` (boolean) - If true, specifies that the script(s) are binary
|
||||
files, and Packer should therefore not convert Windows line endings to Unix
|
||||
line endings (if there are any). By default this is false.
|
||||
|
||||
- `elevated_execute_command` (string) - The command to use to execute the elevated
|
||||
script. By default this is as follows:
|
||||
- `elevated_execute_command` (string) - The command to use to execute the
|
||||
elevated script. By default this is as follows:
|
||||
|
||||
``` powershell
|
||||
powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"
|
||||
|
@ -65,32 +66,34 @@ Optional parameters:
|
|||
The value of this is treated as [configuration
|
||||
template](/docs/templates/engine.html). There are two
|
||||
available variables: `Path`, which is the path to the script to run, and
|
||||
`Vars`, which is the location of a temp file containing the list of `environment_vars`, if configured.
|
||||
`Vars`, which is the location of a temp file containing the list of
|
||||
`environment_vars`, if configured.
|
||||
|
||||
- `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.
|
||||
Packer injects some environmental variables by default into the
|
||||
environment, as well, which are covered in the section below.
|
||||
|
||||
- `execute_command` (string) - The command to use to execute the script. By
|
||||
default this is as follows:
|
||||
|
||||
``` powershell
|
||||
powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }"
|
||||
powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"
|
||||
```
|
||||
|
||||
The value of this is treated as [configuration
|
||||
template](/docs/templates/engine.html). There are two
|
||||
available variables: `Path`, which is the path to the script to run, and
|
||||
`Vars`, which is the list of `environment_vars`, if configured.
|
||||
`Vars`, which is the location of a temp file containing the list of
|
||||
`environment_vars`, if configured.
|
||||
|
||||
- `elevated_user` and `elevated_password` (string) - If specified, the
|
||||
PowerShell script will be run with elevated privileges using the given
|
||||
Windows user.
|
||||
|
||||
- `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 be a
|
||||
writable location and any parent directories must already exist.
|
||||
the machine. This defaults to "c:/Windows/Temp/script.ps1". This value must
|
||||
be a writable location and any parent directories must already exist.
|
||||
|
||||
- `start_retry_timeout` (string) - The amount of time to attempt to *start*
|
||||
the remote process. By default this is "5m" or 5 minutes. This setting
|
||||
|
@ -111,9 +114,10 @@ commonly useful environmental variables:
|
|||
This is most useful when Packer is making multiple builds and you want to
|
||||
distinguish them slightly from a common provisioning script.
|
||||
|
||||
- `PACKER_BUILDER_TYPE` is the type of the builder that was used to create the
|
||||
machine that the script is running on. This is useful if you want to run
|
||||
only certain parts of the script on systems built with certain builders.
|
||||
- `PACKER_BUILDER_TYPE` is the type of the builder that was used to create
|
||||
the machine that the script is running on. This is useful if you want to
|
||||
run only certain parts of the script on systems built with certain
|
||||
builders.
|
||||
|
||||
- `PACKER_HTTP_ADDR` If using a builder that provides an http server for file
|
||||
transfer (such as hyperv, parallels, qemu, virtualbox, and vmware), this
|
||||
|
@ -121,3 +125,101 @@ commonly useful environmental variables:
|
|||
download large files over http. This may be useful if you're experiencing
|
||||
slower speeds using the default file provisioner. A file provisioner using
|
||||
the `winrm` communicator may experience these types of difficulties.
|
||||
|
||||
## Packer's Handling of Characters Special to PowerShell
|
||||
|
||||
The escape character in PowerShell is the `backtick`, also sometimes
|
||||
referred to as the `grave accent`. When, and when not, to escape characters
|
||||
special to PowerShell is probably best demonstrated with a series of examples.
|
||||
|
||||
### When To Escape...
|
||||
|
||||
Users need to deal with escaping characters special to PowerShell when they
|
||||
appear *directly* in commands used in the `inline` PowerShell provisioner and
|
||||
when they appear *directly* in the users own scripts.
|
||||
Note that where double quotes appear within double quotes, the addition of
|
||||
a backslash escape is required for the JSON template to be parsed correctly.
|
||||
|
||||
``` json
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "powershell",
|
||||
"inline": [
|
||||
"Write-Host \"A literal dollar `$ must be escaped\"",
|
||||
"Write-Host \"A literal backtick `` must be escaped\"",
|
||||
"Write-Host \"Here `\"double quotes`\" must be escaped\"",
|
||||
"Write-Host \"Here `'single quotes`' don`'t really need to be\"",
|
||||
"Write-Host \"escaped... but it doesn`'t hurt to do so.\"",
|
||||
]
|
||||
},
|
||||
```
|
||||
|
||||
The above snippet should result in the following output on the Packer console:
|
||||
|
||||
```
|
||||
==> amazon-ebs: Provisioning with Powershell...
|
||||
==> amazon-ebs: Provisioning with powershell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner508190439
|
||||
amazon-ebs: A literal dollar $ must be escaped
|
||||
amazon-ebs: A literal backtick ` must be escaped
|
||||
amazon-ebs: Here "double quotes" must be escaped
|
||||
amazon-ebs: Here 'single quotes' don't really need to be
|
||||
amazon-ebs: escaped... but it doesn't hurt to do so.
|
||||
```
|
||||
|
||||
### When Not To Escape...
|
||||
|
||||
Special characters appearing in user environment variable values and in the
|
||||
`elevated_user` and `elevated_password` fields will be automatically
|
||||
dealt with for the user. There is no need to use escapes in these instances.
|
||||
|
||||
``` json
|
||||
{
|
||||
"variables": {
|
||||
"psvar": "My$tring"
|
||||
},
|
||||
...
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "powershell",
|
||||
"elevated_user": "Administrator",
|
||||
"elevated_password": "Super$3cr3t!",
|
||||
"inline": "Write-Output \"The dollar in the elevated_password is interpreted correctly\""
|
||||
},
|
||||
{
|
||||
"type": "powershell",
|
||||
"environment_vars": [
|
||||
"VAR1=A$Dollar",
|
||||
"VAR2=A`Backtick",
|
||||
"VAR3=A'SingleQuote",
|
||||
"VAR4=A\"DoubleQuote",
|
||||
"VAR5={{user `psvar`}}"
|
||||
],
|
||||
"inline": [
|
||||
"Write-Output \"In the following examples the special character is interpreted correctly:\"",
|
||||
"Write-Output \"The dollar in VAR1: $Env:VAR1\"",
|
||||
"Write-Output \"The backtick in VAR2: $Env:VAR2\"",
|
||||
"Write-Output \"The single quote in VAR3: $Env:VAR3\"",
|
||||
"Write-Output \"The double quote in VAR4: $Env:VAR4\"",
|
||||
"Write-Output \"The dollar in VAR5 (expanded from a user var): $Env:VAR5\""
|
||||
]
|
||||
}
|
||||
]
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The above snippet should result in the following output on the Packer console:
|
||||
|
||||
```
|
||||
==> amazon-ebs: Provisioning with Powershell...
|
||||
==> amazon-ebs: Provisioning with powershell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner961728919
|
||||
amazon-ebs: The dollar in the elevated_password is interpreted correctly
|
||||
==> amazon-ebs: Provisioning with Powershell...
|
||||
==> amazon-ebs: Provisioning with powershell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner142826554
|
||||
amazon-ebs: In the following examples the special character is interpreted correctly:
|
||||
amazon-ebs: The dollar in VAR1: A$Dollar
|
||||
amazon-ebs: The backtick in VAR2: A`Backtick
|
||||
amazon-ebs: The single quote in VAR3: A'SingleQuote
|
||||
amazon-ebs: The double quote in VAR4: A"DoubleQuote
|
||||
amazon-ebs: The dollar in VAR5 (expanded from a user var): My$tring
|
||||
```
|
||||
|
|
|
@ -448,14 +448,19 @@ variables we will set in our build template; copy the contents into your own
|
|||
`sample_script.ps1` and provide the path to it in your build template:
|
||||
|
||||
```powershell
|
||||
Write-Host "PACKER_BUILD_NAME is automatically set for you, " -NoNewline
|
||||
Write-Host "or you can set it in your builder variables; " -NoNewline
|
||||
Write-Host "PACKER_BUILD_NAME is an env var Packer automatically sets for you."
|
||||
Write-Host "...or you can set it in your builder variables."
|
||||
Write-Host "The default for this builder is:" $Env:PACKER_BUILD_NAME
|
||||
|
||||
Write-Host "Use backticks as the escape character when required in powershell:"
|
||||
Write-Host "The PowerShell provisioner will automatically escape characters"
|
||||
Write-Host "considered special to PowerShell when it encounters them in"
|
||||
Write-Host "your environment variables or in the PowerShell elevated"
|
||||
Write-Host "username/password fields."
|
||||
Write-Host "For example, VAR1 from our config is:" $Env:VAR1
|
||||
Write-Host "Likewise, VAR2 is:" $Env:VAR2
|
||||
Write-Host "Finally, VAR3 is:" $Env:VAR3
|
||||
Write-Host "VAR3 is:" $Env:VAR3
|
||||
Write-Host "Finally, VAR4 is:" $Env:VAR4
|
||||
Write-Host "None of the special characters needed escaping in the template"
|
||||
```
|
||||
|
||||
Finally, we need to create the actual [build template](
|
||||
|
@ -514,7 +519,12 @@ customize and control the build process:
|
|||
{
|
||||
"type": "powershell",
|
||||
"environment_vars": ["DEVOPS_LIFE_IMPROVER=PACKER"],
|
||||
"inline": "Write-Host \"HELLO NEW USER; WELCOME TO $Env:DEVOPS_LIFE_IMPROVER\""
|
||||
"inline": [
|
||||
"Write-Host \"HELLO NEW USER; WELCOME TO $Env:DEVOPS_LIFE_IMPROVER\"",
|
||||
"Write-Host \"You need to use backtick escapes when using\"",
|
||||
"Write-Host \"characters such as DOLLAR`$ directly in a command\"",
|
||||
"Write-Host \"or in your own scripts.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "windows-restart"
|
||||
|
@ -523,9 +533,10 @@ customize and control the build process:
|
|||
"script": "./sample_script.ps1",
|
||||
"type": "powershell",
|
||||
"environment_vars": [
|
||||
"VAR1=A`$Dollar",
|
||||
"VAR2=A``Backtick",
|
||||
"VAR3=A`'SingleQuote"
|
||||
"VAR1=A$Dollar",
|
||||
"VAR2=A`Backtick",
|
||||
"VAR3=A'SingleQuote",
|
||||
"VAR4=A\"DoubleQuote"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -550,39 +561,49 @@ You should see output like this:
|
|||
```
|
||||
amazon-ebs output will be in this color.
|
||||
|
||||
==> amazon-ebs: Prevalidating AMI Name: packer-demo-1507933843
|
||||
amazon-ebs: Found Image ID: ami-23d93c59
|
||||
==> amazon-ebs: Creating temporary keypair: packer_59e13e94-203a-1bca-5327-bebf0d5ad15a
|
||||
==> amazon-ebs: Creating temporary security group for this instance: packer_59e13ea9-3220-8dab-29c0-ed7f71e221a1
|
||||
==> amazon-ebs: Prevalidating AMI Name: packer-demo-1518111383
|
||||
amazon-ebs: Found Image ID: ami-013e197b
|
||||
==> amazon-ebs: Creating temporary keypair: packer_5a7c8a97-f27f-6708-cc3c-6ab9b4688b13
|
||||
==> amazon-ebs: Creating temporary security group for this instance: packer_5a7c8ab5-444c-13f2-0aa1-18d124cdb975
|
||||
==> amazon-ebs: Authorizing access to port 5985 from 0.0.0.0/0 in the temporary security group...
|
||||
==> amazon-ebs: Launching a source AWS instance...
|
||||
==> amazon-ebs: Adding tags to source instance
|
||||
amazon-ebs: Adding tag: "Name": "Packer Builder"
|
||||
amazon-ebs: Instance ID: i-0349406ac85f02166
|
||||
==> amazon-ebs: Waiting for instance (i-0349406ac85f02166) to become ready...
|
||||
amazon-ebs: Instance ID: i-0c8c808a3b945782a
|
||||
==> amazon-ebs: Waiting for instance (i-0c8c808a3b945782a) to become ready...
|
||||
==> amazon-ebs: Skipping waiting for password since WinRM password set...
|
||||
==> amazon-ebs: Waiting for WinRM to become available...
|
||||
amazon-ebs: WinRM connected.
|
||||
==> amazon-ebs: Connected to WinRM!
|
||||
==> amazon-ebs: Provisioning with Powershell...
|
||||
==> amazon-ebs: Provisioning with powershell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner175214995
|
||||
==> amazon-ebs: Provisioning with powershell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner943573503
|
||||
amazon-ebs: HELLO NEW USER; WELCOME TO PACKER
|
||||
amazon-ebs: You need to use backtick escapes when using
|
||||
amazon-ebs: characters such as DOLLAR$ directly in a command
|
||||
amazon-ebs: or in your own scripts.
|
||||
==> amazon-ebs: Restarting Machine
|
||||
==> amazon-ebs: Waiting for machine to restart...
|
||||
amazon-ebs: WIN-TEM0TDL751M restarted.
|
||||
amazon-ebs: WIN-NI8N45RPJ23 restarted.
|
||||
==> amazon-ebs: Machine successfully restarted, moving on
|
||||
==> amazon-ebs: Provisioning with Powershell...
|
||||
==> amazon-ebs: Provisioning with powershell script: ./sample_script.ps1
|
||||
amazon-ebs: PACKER_BUILD_NAME is automatically set for you, or you can set it in your builder variables; The default for this builder is: amazon-ebs
|
||||
amazon-ebs: Use backticks as the escape character when required in powershell:
|
||||
amazon-ebs: PACKER_BUILD_NAME is an env var Packer automatically sets for you.
|
||||
amazon-ebs: ...or you can set it in your builder variables.
|
||||
amazon-ebs: The default for this builder is: amazon-ebs
|
||||
amazon-ebs: The PowerShell provisioner will automatically escape characters
|
||||
amazon-ebs: considered special to PowerShell when it encounters them in
|
||||
amazon-ebs: your environment variables or in the PowerShell elevated
|
||||
amazon-ebs: username/password fields.
|
||||
amazon-ebs: For example, VAR1 from our config is: A$Dollar
|
||||
amazon-ebs: Likewise, VAR2 is: A`Backtick
|
||||
amazon-ebs: Finally, VAR3 is: A'SingleQuote
|
||||
amazon-ebs: VAR3 is: A'SingleQuote
|
||||
amazon-ebs: Finally, VAR4 is: A"DoubleQuote
|
||||
amazon-ebs: None of the special characters needed escaping in the template
|
||||
==> amazon-ebs: Stopping the source instance...
|
||||
amazon-ebs: Stopping instance, attempt 1
|
||||
==> amazon-ebs: Waiting for the instance to stop...
|
||||
==> amazon-ebs: Creating the AMI: packer-demo-1507933843
|
||||
amazon-ebs: AMI: ami-100fc56a
|
||||
==> amazon-ebs: Creating the AMI: packer-demo-1518111383
|
||||
amazon-ebs: AMI: ami-f0060c8a
|
||||
==> amazon-ebs: Waiting for AMI to become ready...
|
||||
==> amazon-ebs: Terminating the source AWS instance...
|
||||
==> amazon-ebs: Cleaning up any extra volumes...
|
||||
|
@ -593,7 +614,7 @@ Build 'amazon-ebs' finished.
|
|||
|
||||
==> Builds finished. The artifacts of successful builds are:
|
||||
--> amazon-ebs: AMIs were created:
|
||||
us-east-1: ami-100fc56a
|
||||
us-east-1: ami-f0060c8a
|
||||
```
|
||||
|
||||
And if you navigate to your EC2 dashboard you should see your shiny new AMI
|
||||
|
|
Loading…
Reference in New Issue