Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
packer
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kristopher Ruzic
packer
Commits
040ff070
Commit
040ff070
authored
Jun 14, 2015
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
provisioner/powershell
parent
cf570a71
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1234 additions
and
0 deletions
+1234
-0
plugin/provisioner-powershell/main.go
plugin/provisioner-powershell/main.go
+15
-0
provisioner/powershell/elevated.go
provisioner/powershell/elevated.go
+87
-0
provisioner/powershell/powershell.go
provisioner/powershell/powershell.go
+17
-0
provisioner/powershell/provisioner.go
provisioner/powershell/provisioner.go
+459
-0
provisioner/powershell/provisioner_test.go
provisioner/powershell/provisioner_test.go
+656
-0
No files found.
plugin/provisioner-powershell/main.go
0 → 100644
View file @
040ff070
package
main
import
(
"github.com/mitchellh/packer/packer/plugin"
"github.com/mitchellh/packer/provisioner/powershell"
)
func
main
()
{
server
,
err
:=
plugin
.
Server
()
if
err
!=
nil
{
panic
(
err
)
}
server
.
RegisterProvisioner
(
new
(
powershell
.
Provisioner
))
server
.
Serve
()
}
provisioner/powershell/elevated.go
0 → 100644
View file @
040ff070
package
powershell
import
(
"text/template"
)
type
elevatedOptions
struct
{
User
string
Password
string
TaskName
string
TaskDescription
string
EncodedCommand
string
}
var
elevatedTemplate
=
template
.
Must
(
template
.
New
(
"ElevatedCommand"
)
.
Parse
(
`
$name = "{{.TaskName}}"
$log = "$env:TEMP\$name.out"
$s = New-Object -ComObject "Schedule.Service"
$s.Connect()
$t = $s.NewTask($null)
$t.XmlText = @'
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Description>{{.TaskDescription}}</Description>
</RegistrationInfo>
<Principals>
<Principal id="Author">
<UserId>{{.User}}</UserId>
<LogonType>Password</LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>false</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT24H</ExecutionTimeLimit>
<Priority>4</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>cmd</Command>
<Arguments>/c powershell.exe -EncodedCommand {{.EncodedCommand}} > %TEMP%\{{.TaskName}}.out 2>&1</Arguments>
</Exec>
</Actions>
</Task>
'@
$f = $s.GetFolder("\")
$f.RegisterTaskDefinition($name, $t, 6, "{{.User}}", "{{.Password}}", 1, $null) | Out-Null
$t = $f.GetTask("\$name")
$t.Run($null) | Out-Null
$timeout = 10
$sec = 0
while ((!($t.state -eq 4)) -and ($sec -lt $timeout)) {
Start-Sleep -s 1
$sec++
}
function SlurpOutput($l) {
if (Test-Path $log) {
Get-Content $log | select -skip $l | ForEach {
$l += 1
Write-Host "$_"
}
}
return $l
}
$line = 0
do {
Start-Sleep -m 100
$line = SlurpOutput $line
} while (!($t.state -eq 3))
$result = $t.LastTaskResult
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($s) | Out-Null
exit $result`
))
provisioner/powershell/powershell.go
0 → 100644
View file @
040ff070
package
powershell
import
(
"encoding/base64"
)
func
powershellEncode
(
buffer
[]
byte
)
string
{
// 2 byte chars to make PowerShell happy
wideCmd
:=
""
for
_
,
b
:=
range
buffer
{
wideCmd
+=
string
(
b
)
+
"
\x00
"
}
// Base64 encode the command
input
:=
[]
uint8
(
wideCmd
)
return
base64
.
StdEncoding
.
EncodeToString
(
input
)
}
provisioner/powershell/provisioner.go
0 → 100644
View file @
040ff070
// This package implements a provisioner for Packer that executes
// shell scripts within the remote machine.
package
powershell
import
(
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"sort"
"strings"
"time"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/common/uuid"
"github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
)
const
DefaultRemotePath
=
"c:/Windows/Temp/script.ps1"
var
retryableSleep
=
2
*
time
.
Second
type
Config
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
// If true, the script contains binary and line endings will not be
// converted from Windows to Unix-style.
Binary
bool
// An inline script to execute. Multiple strings are all executed
// in the context of a single shell.
Inline
[]
string
// The local path of the shell script to upload and execute.
Script
string
// An array of multiple scripts to run.
Scripts
[]
string
// An array of environment variables that will be injected before
// your command(s) are executed.
Vars
[]
string
`mapstructure:"environment_vars"`
// The remote path where the local shell script will be uploaded to.
// This should be set to a writable file that is in a pre-existing directory.
RemotePath
string
`mapstructure:"remote_path"`
// The command used to execute the script. The '{{ .Path }}' variable
// should be used to specify where the script goes, {{ .Vars }}
// can be used to inject the environment_vars into the environment.
ExecuteCommand
string
`mapstructure:"execute_command"`
// The command used to execute the elevated script. The '{{ .Path }}' variable
// should be used to specify where the script goes, {{ .Vars }}
// can be used to inject the environment_vars into the environment.
ElevatedExecuteCommand
string
`mapstructure:"elevated_execute_command"`
// The timeout for retrying to start the process. Until this timeout
// is reached, if the provisioner can't start a process, it retries.
// This can be set high to allow for reboots.
StartRetryTimeout
time
.
Duration
`mapstructure:"start_retry_timeout"`
// This is used in the template generation to format environment variables
// inside the `ExecuteCommand` template.
EnvVarFormat
string
// This is used in the template generation to format environment variables
// inside the `ElevatedExecuteCommand` template.
ElevatedEnvVarFormat
string
`mapstructure:"elevated_env_var_format"`
// 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"`
// Valid Exit Codes - 0 is not always the only valid error code!
// See http://www.symantec.com/connect/articles/windows-system-error-codes-exit-codes-description for examples
// such as 3010 - "The requested operation is successful. Changes will not be effective until the system is rebooted."
ValidExitCodes
[]
int
`mapstructure:"valid_exit_codes"`
ctx
interpolate
.
Context
}
type
Provisioner
struct
{
config
Config
communicator
packer
.
Communicator
}
type
ExecuteCommandTemplate
struct
{
Vars
string
Path
string
}
func
(
p
*
Provisioner
)
Prepare
(
raws
...
interface
{})
error
{
err
:=
config
.
Decode
(
&
p
.
config
,
&
config
.
DecodeOpts
{
Interpolate
:
true
,
InterpolateFilter
:
&
interpolate
.
RenderFilter
{
Exclude
:
[]
string
{
"execute_command"
,
},
},
},
raws
...
)
if
err
!=
nil
{
return
err
}
if
p
.
config
.
EnvVarFormat
==
""
{
p
.
config
.
EnvVarFormat
=
`$env:%s=\"%s\"; `
}
if
p
.
config
.
ElevatedEnvVarFormat
==
""
{
p
.
config
.
ElevatedEnvVarFormat
=
`$env:%s="%s"; `
}
if
p
.
config
.
ExecuteCommand
==
""
{
p
.
config
.
ExecuteCommand
=
`powershell "& { {{.Vars}}{{.Path}}; exit $LastExitCode}"`
}
if
p
.
config
.
ElevatedExecuteCommand
==
""
{
p
.
config
.
ElevatedExecuteCommand
=
`{{.Vars}}{{.Path}}`
}
if
p
.
config
.
Inline
!=
nil
&&
len
(
p
.
config
.
Inline
)
==
0
{
p
.
config
.
Inline
=
nil
}
if
p
.
config
.
StartRetryTimeout
==
0
{
p
.
config
.
StartRetryTimeout
=
5
*
time
.
Minute
}
if
p
.
config
.
RemotePath
==
""
{
p
.
config
.
RemotePath
=
DefaultRemotePath
}
if
p
.
config
.
Scripts
==
nil
{
p
.
config
.
Scripts
=
make
([]
string
,
0
)
}
if
p
.
config
.
Vars
==
nil
{
p
.
config
.
Vars
=
make
([]
string
,
0
)
}
if
p
.
config
.
ValidExitCodes
==
nil
{
p
.
config
.
ValidExitCodes
=
[]
int
{
0
}
}
var
errs
error
if
p
.
config
.
Script
!=
""
&&
len
(
p
.
config
.
Scripts
)
>
0
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errors
.
New
(
"Only one of script or scripts can be specified."
))
}
if
p
.
config
.
ElevatedUser
!=
""
&&
p
.
config
.
ElevatedPassword
==
""
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errors
.
New
(
"Must supply an 'elevated_password' if 'elevated_user' provided"
))
}
if
p
.
config
.
ElevatedUser
==
""
&&
p
.
config
.
ElevatedPassword
!=
""
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errors
.
New
(
"Must supply an 'elevated_user' if 'elevated_password' provided"
))
}
if
p
.
config
.
Script
!=
""
{
p
.
config
.
Scripts
=
[]
string
{
p
.
config
.
Script
}
}
if
len
(
p
.
config
.
Scripts
)
==
0
&&
p
.
config
.
Inline
==
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errors
.
New
(
"Either a script file or inline script must be specified."
))
}
else
if
len
(
p
.
config
.
Scripts
)
>
0
&&
p
.
config
.
Inline
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errors
.
New
(
"Only a script file or an inline script can be specified, not both."
))
}
for
_
,
path
:=
range
p
.
config
.
Scripts
{
if
_
,
err
:=
os
.
Stat
(
path
);
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Bad script '%s': %s"
,
path
,
err
))
}
}
// Do a check for bad environment variables, such as '=foo', 'foobar'
for
_
,
kv
:=
range
p
.
config
.
Vars
{
vs
:=
strings
.
SplitN
(
kv
,
"="
,
2
)
if
len
(
vs
)
!=
2
||
vs
[
0
]
==
""
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Environment variable not in format 'key=value': %s"
,
kv
))
}
}
if
errs
!=
nil
{
return
errs
}
return
nil
}
// Takes the inline scripts, concatenates them
// into a temporary file and returns a string containing the location
// of said file.
func
extractScript
(
p
*
Provisioner
)
(
string
,
error
)
{
temp
,
err
:=
ioutil
.
TempFile
(
os
.
TempDir
(),
"packer-powershell-provisioner"
)
if
err
!=
nil
{
return
""
,
err
}
defer
temp
.
Close
()
writer
:=
bufio
.
NewWriter
(
temp
)
for
_
,
command
:=
range
p
.
config
.
Inline
{
log
.
Printf
(
"Found command: %s"
,
command
)
if
_
,
err
:=
writer
.
WriteString
(
command
+
"
\n
"
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error preparing shell script: %s"
,
err
)
}
}
if
err
:=
writer
.
Flush
();
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error preparing shell script: %s"
,
err
)
}
return
temp
.
Name
(),
nil
}
func
(
p
*
Provisioner
)
Provision
(
ui
packer
.
Ui
,
comm
packer
.
Communicator
)
error
{
ui
.
Say
(
fmt
.
Sprintf
(
"Provisioning with Powershell..."
))
p
.
communicator
=
comm
scripts
:=
make
([]
string
,
len
(
p
.
config
.
Scripts
))
copy
(
scripts
,
p
.
config
.
Scripts
)
// Build our variables up by adding in the build name and builder type
envVars
:=
make
([]
string
,
len
(
p
.
config
.
Vars
)
+
2
)
envVars
[
0
]
=
"PACKER_BUILD_NAME="
+
p
.
config
.
PackerBuildName
envVars
[
1
]
=
"PACKER_BUILDER_TYPE="
+
p
.
config
.
PackerBuilderType
copy
(
envVars
,
p
.
config
.
Vars
)
if
p
.
config
.
Inline
!=
nil
{
temp
,
err
:=
extractScript
(
p
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Unable to extract inline scripts into a file: %s"
,
err
))
}
scripts
=
append
(
scripts
,
temp
)
}
for
_
,
path
:=
range
scripts
{
ui
.
Say
(
fmt
.
Sprintf
(
"Provisioning with shell script: %s"
,
path
))
log
.
Printf
(
"Opening %s for reading"
,
path
)
f
,
err
:=
os
.
Open
(
path
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error opening shell script: %s"
,
err
)
}
defer
f
.
Close
()
command
,
err
:=
p
.
createCommandText
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error processing command: %s"
,
err
)
}
// Upload the file and run the command. Do this in the context of
// a single retryable function so that we don't end up with
// the case that the upload succeeded, a restart is initiated,
// and then the command is executed but the file doesn't exist
// any longer.
var
cmd
*
packer
.
RemoteCmd
err
=
p
.
retryable
(
func
()
error
{
if
_
,
err
:=
f
.
Seek
(
0
,
0
);
err
!=
nil
{
return
err
}
if
err
:=
comm
.
Upload
(
p
.
config
.
RemotePath
,
f
,
nil
);
err
!=
nil
{
return
fmt
.
Errorf
(
"Error uploading script: %s"
,
err
)
}
cmd
=
&
packer
.
RemoteCmd
{
Command
:
command
}
return
cmd
.
StartWithUi
(
comm
,
ui
)
})
if
err
!=
nil
{
return
err
}
// Close the original file since we copied it
f
.
Close
()
// Check exit code against allowed codes (likely just 0)
validExitCode
:=
false
for
_
,
v
:=
range
p
.
config
.
ValidExitCodes
{
if
cmd
.
ExitStatus
==
v
{
validExitCode
=
true
}
}
if
!
validExitCode
{
return
fmt
.
Errorf
(
"Script exited with non-zero exit status: %d. Allowed exit codes are: %s"
,
cmd
.
ExitStatus
,
p
.
config
.
ValidExitCodes
)
}
}
return
nil
}
func
(
p
*
Provisioner
)
Cancel
()
{
// Just hard quit. It isn't a big deal if what we're doing keeps
// running on the other side.
os
.
Exit
(
0
)
}
// retryable will retry the given function over and over until a
// non-error is returned.
func
(
p
*
Provisioner
)
retryable
(
f
func
()
error
)
error
{
startTimeout
:=
time
.
After
(
p
.
config
.
StartRetryTimeout
)
for
{
var
err
error
if
err
=
f
();
err
==
nil
{
return
nil
}
// Create an error and log it
err
=
fmt
.
Errorf
(
"Retryable error: %s"
,
err
)
log
.
Printf
(
err
.
Error
())
// Check if we timed out, otherwise we retry. It is safe to
// retry since the only error case above is if the command
// failed to START.
select
{
case
<-
startTimeout
:
return
err
default
:
time
.
Sleep
(
retryableSleep
)
}
}
}
func
(
p
*
Provisioner
)
createFlattenedEnvVars
(
elevated
bool
)
(
flattened
string
,
err
error
)
{
flattened
=
""
envVars
:=
make
(
map
[
string
]
string
)
// Always available Packer provided env vars
envVars
[
"PACKER_BUILD_NAME"
]
=
p
.
config
.
PackerBuildName
envVars
[
"PACKER_BUILDER_TYPE"
]
=
p
.
config
.
PackerBuilderType
// Split vars into key/value components
for
_
,
envVar
:=
range
p
.
config
.
Vars
{
keyValue
:=
strings
.
Split
(
envVar
,
"="
)
if
len
(
keyValue
)
!=
2
{
err
=
errors
.
New
(
"Shell provisioner environment variables must be in key=value format"
)
return
}
envVars
[
keyValue
[
0
]]
=
keyValue
[
1
]
}
// Create a list of env var keys in sorted order
var
keys
[]
string
for
k
:=
range
envVars
{
keys
=
append
(
keys
,
k
)
}
sort
.
Strings
(
keys
)
format
:=
p
.
config
.
EnvVarFormat
if
elevated
{
format
=
p
.
config
.
ElevatedEnvVarFormat
}
// Re-assemble vars using OS specific format pattern and flatten
for
_
,
key
:=
range
keys
{
flattened
+=
fmt
.
Sprintf
(
format
,
key
,
envVars
[
key
])
}
return
}
func
(
p
*
Provisioner
)
createCommandText
()
(
command
string
,
err
error
)
{
// Create environment variables to set before executing the command
flattenedEnvVars
,
err
:=
p
.
createFlattenedEnvVars
(
false
)
if
err
!=
nil
{
return
""
,
err
}
p
.
config
.
ctx
.
Data
=
&
ExecuteCommandTemplate
{
Vars
:
flattenedEnvVars
,
Path
:
p
.
config
.
RemotePath
,
}
command
,
err
=
interpolate
.
Render
(
p
.
config
.
ExecuteCommand
,
&
p
.
config
.
ctx
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error processing command: %s"
,
err
)
}
// Return the interpolated command
if
p
.
config
.
ElevatedUser
==
""
{
return
command
,
nil
}
// Can't double escape the env vars, lets create shiny new ones
flattenedEnvVars
,
err
=
p
.
createFlattenedEnvVars
(
true
)
p
.
config
.
ctx
.
Data
=
&
ExecuteCommandTemplate
{
Vars
:
flattenedEnvVars
,
Path
:
p
.
config
.
RemotePath
,
}
command
,
err
=
interpolate
.
Render
(
p
.
config
.
ExecuteCommand
,
&
p
.
config
.
ctx
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error processing command: %s"
,
err
)
}
// OK so we need an elevated shell runner to wrap our command, this is going to have its own path
// generate the script and update the command runner in the process
path
,
err
:=
p
.
generateElevatedRunner
(
command
)
// Return the path to the elevated shell wrapper
command
=
fmt
.
Sprintf
(
"powershell -executionpolicy bypass -file
\"
%s
\"
"
,
path
)
return
}
func
(
p
*
Provisioner
)
generateElevatedRunner
(
command
string
)
(
uploadedPath
string
,
err
error
)
{
log
.
Printf
(
"Building elevated command wrapper for: %s"
,
command
)
// generate command
var
buffer
bytes
.
Buffer
err
=
elevatedTemplate
.
Execute
(
&
buffer
,
elevatedOptions
{
User
:
p
.
config
.
ElevatedUser
,
Password
:
p
.
config
.
ElevatedPassword
,
TaskDescription
:
"Packer elevated task"
,
TaskName
:
fmt
.
Sprintf
(
"packer-%s"
,
uuid
.
TimeOrderedUUID
()),
EncodedCommand
:
powershellEncode
([]
byte
(
command
+
"; exit $LASTEXITCODE"
)),
})
if
err
!=
nil
{
fmt
.
Printf
(
"Error creating elevated template: %s"
,
err
)
return
""
,
err
}
tmpFile
,
err
:=
ioutil
.
TempFile
(
os
.
TempDir
(),
"packer-elevated-shell.ps1"
)
writer
:=
bufio
.
NewWriter
(
tmpFile
)
if
_
,
err
:=
writer
.
WriteString
(
string
(
buffer
.
Bytes
()));
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error preparing elevated shell script: %s"
,
err
)
}
if
err
:=
writer
.
Flush
();
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error preparing elevated shell script: %s"
,
err
)
}
tmpFile
.
Close
()
f
,
err
:=
os
.
Open
(
tmpFile
.
Name
())
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error opening temporary elevated shell script: %s"
,
err
)
}
defer
f
.
Close
()
uuid
:=
uuid
.
TimeOrderedUUID
()
path
:=
fmt
.
Sprintf
(
`${env:TEMP}\packer-elevated-shell-%s.ps1`
,
uuid
)
log
.
Printf
(
"Uploading elevated shell wrapper for command [%s] to [%s] from [%s]"
,
command
,
path
,
tmpFile
.
Name
())
err
=
p
.
communicator
.
Upload
(
path
,
f
,
nil
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"Error preparing elevated shell script: %s"
,
err
)
}
// CMD formatted Path required for this op
path
=
fmt
.
Sprintf
(
"%s-%s.ps1"
,
"%TEMP%
\\
packer-elevated-shell"
,
uuid
)
return
path
,
err
}
provisioner/powershell/provisioner_test.go
0 → 100644
View file @
040ff070
package
powershell
import
(
"bytes"
"errors"
"fmt"
"io/ioutil"
//"log"
"os"
"regexp"
"strings"
"testing"
"time"
"github.com/mitchellh/packer/packer"
)
func
testConfig
()
map
[
string
]
interface
{}
{
return
map
[
string
]
interface
{}{
"inline"
:
[]
interface
{}{
"foo"
,
"bar"
},
}
}
func
init
()
{
//log.SetOutput(ioutil.Discard)
}
func
TestProvisionerPrepare_extractScript
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
p
:=
new
(
Provisioner
)
_
=
p
.
Prepare
(
config
)
file
,
err
:=
extractScript
(
p
)
if
err
!=
nil
{
t
.
Fatalf
(
"Should not be error: %s"
,
err
)
}
t
.
Logf
(
"File: %s"
,
file
)
if
strings
.
Index
(
file
,
os
.
TempDir
())
!=
0
{
t
.
Fatalf
(
"Temp file should reside in %s. File location: %s"
,
os
.
TempDir
(),
file
)
}
// File contents should contain 2 lines concatenated by newlines: foo\nbar
readFile
,
err
:=
ioutil
.
ReadFile
(
file
)
expectedContents
:=
"foo
\n
bar
\n
"
s
:=
string
(
readFile
[
:
])
if
s
!=
expectedContents
{
t
.
Fatalf
(
"Expected generated inlineScript to equal '%s', got '%s'"
,
expectedContents
,
s
)
}
}
func
TestProvisioner_Impl
(
t
*
testing
.
T
)
{
var
raw
interface
{}
raw
=
&
Provisioner
{}
if
_
,
ok
:=
raw
.
(
packer
.
Provisioner
);
!
ok
{
t
.
Fatalf
(
"must be a Provisioner"
)
}
}
func
TestProvisionerPrepare_Defaults
(
t
*
testing
.
T
)
{
var
p
Provisioner
config
:=
testConfig
()
err
:=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
if
p
.
config
.
RemotePath
!=
DefaultRemotePath
{
t
.
Errorf
(
"unexpected remote path: %s"
,
p
.
config
.
RemotePath
)
}
if
p
.
config
.
ElevatedUser
!=
""
{
t
.
Error
(
"expected elevated_user to be empty"
)
}
if
p
.
config
.
ElevatedPassword
!=
""
{
t
.
Error
(
"expected elevated_password to be empty"
)
}
if
p
.
config
.
ExecuteCommand
!=
"powershell
\"
& { {{.Vars}}{{.Path}}; exit $LastExitCode}
\"
"
{
t
.
Fatalf
(
"Default command should be powershell
\"
& { {{.Vars}}{{.Path}}; exit $LastExitCode}
\"
, but got %s"
,
p
.
config
.
ExecuteCommand
)
}
if
p
.
config
.
ElevatedExecuteCommand
!=
"{{.Vars}}{{.Path}}"
{
t
.
Fatalf
(
"Default command should be powershell {{.Vars}}{{.Path}}, but got %s"
,
p
.
config
.
ElevatedExecuteCommand
)
}
if
p
.
config
.
ValidExitCodes
==
nil
{
t
.
Fatalf
(
"ValidExitCodes should not be nil"
)
}
if
p
.
config
.
ValidExitCodes
!=
nil
{
expCodes
:=
[]
int
{
0
}
for
i
,
v
:=
range
p
.
config
.
ValidExitCodes
{
if
v
!=
expCodes
[
i
]
{
t
.
Fatalf
(
"Expected ValidExitCodes don't match actual"
)
}
}
}
if
p
.
config
.
ElevatedEnvVarFormat
!=
`$env:%s="%s"; `
{
t
.
Fatalf
(
"Default command should be powershell
\"
{{.Vars}}{{.Path}}
\"
, but got %s"
,
p
.
config
.
ElevatedEnvVarFormat
)
}
}
func
TestProvisionerPrepare_Config
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
config
[
"elevated_user"
]
=
"{{user `user`}}"
config
[
"elevated_password"
]
=
"{{user `password`}}"
config
[
packer
.
UserVariablesConfigKey
]
=
map
[
string
]
string
{
"user"
:
"myusername"
,
"password"
:
"mypassword"
,
}
var
p
Provisioner
err
:=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
if
p
.
config
.
ElevatedUser
!=
"myusername"
{
t
.
Fatalf
(
"Expected 'myusername' for key `elevated_user`: %s"
,
p
.
config
.
ElevatedUser
)
}
if
p
.
config
.
ElevatedPassword
!=
"mypassword"
{
t
.
Fatalf
(
"Expected 'mypassword' for key `elevated_password`: %s"
,
p
.
config
.
ElevatedPassword
)
}
}
func
TestProvisionerPrepare_InvalidKey
(
t
*
testing
.
T
)
{
var
p
Provisioner
config
:=
testConfig
()
// Add a random key
config
[
"i_should_not_be_valid"
]
=
true
err
:=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
}
func
TestProvisionerPrepare_Elevated
(
t
*
testing
.
T
)
{
var
p
Provisioner
config
:=
testConfig
()
// Add a random key
config
[
"elevated_user"
]
=
"vagrant"
err
:=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error (only provided elevated_user)"
)
}
config
[
"elevated_password"
]
=
"vagrant"
err
=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatal
(
"should not have error"
)
}
}
func
TestProvisionerPrepare_Script
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
delete
(
config
,
"inline"
)
config
[
"script"
]
=
"/this/should/not/exist"
p
:=
new
(
Provisioner
)
err
:=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
// Test with a good one
tf
,
err
:=
ioutil
.
TempFile
(
""
,
"packer"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error tempfile: %s"
,
err
)
}
defer
os
.
Remove
(
tf
.
Name
())
config
[
"script"
]
=
tf
.
Name
()
p
=
new
(
Provisioner
)
err
=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error: %s"
,
err
)
}
}
func
TestProvisionerPrepare_ScriptAndInline
(
t
*
testing
.
T
)
{
var
p
Provisioner
config
:=
testConfig
()
delete
(
config
,
"inline"
)
delete
(
config
,
"script"
)
err
:=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
// Test with both
tf
,
err
:=
ioutil
.
TempFile
(
""
,
"packer"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error tempfile: %s"
,
err
)
}
defer
os
.
Remove
(
tf
.
Name
())
config
[
"inline"
]
=
[]
interface
{}{
"foo"
}
config
[
"script"
]
=
tf
.
Name
()
err
=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
}
func
TestProvisionerPrepare_ScriptAndScripts
(
t
*
testing
.
T
)
{
var
p
Provisioner
config
:=
testConfig
()
// Test with both
tf
,
err
:=
ioutil
.
TempFile
(
""
,
"packer"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error tempfile: %s"
,
err
)
}
defer
os
.
Remove
(
tf
.
Name
())
config
[
"inline"
]
=
[]
interface
{}{
"foo"
}
config
[
"scripts"
]
=
[]
string
{
tf
.
Name
()}
err
=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
}
func
TestProvisionerPrepare_Scripts
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
delete
(
config
,
"inline"
)
config
[
"scripts"
]
=
[]
string
{}
p
:=
new
(
Provisioner
)
err
:=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
// Test with a good one
tf
,
err
:=
ioutil
.
TempFile
(
""
,
"packer"
)
if
err
!=
nil
{
t
.
Fatalf
(
"error tempfile: %s"
,
err
)
}
defer
os
.
Remove
(
tf
.
Name
())
config
[
"scripts"
]
=
[]
string
{
tf
.
Name
()}
p
=
new
(
Provisioner
)
err
=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error: %s"
,
err
)
}
}
func
TestProvisionerPrepare_EnvironmentVars
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
// Test with a bad case
config
[
"environment_vars"
]
=
[]
string
{
"badvar"
,
"good=var"
}
p
:=
new
(
Provisioner
)
err
:=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
// Test with a trickier case
config
[
"environment_vars"
]
=
[]
string
{
"=bad"
}
p
=
new
(
Provisioner
)
err
=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
// Test with a good case
// Note: baz= is a real env variable, just empty
config
[
"environment_vars"
]
=
[]
string
{
"FOO=bar"
,
"baz="
}
p
=
new
(
Provisioner
)
err
=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error: %s"
,
err
)
}
}
func
TestProvisionerQuote_EnvironmentVars
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
config
[
"environment_vars"
]
=
[]
string
{
"keyone=valueone"
,
"keytwo=value
\n
two"
,
"keythree='valuethree'"
,
"keyfour='value
\n
four'"
}
p
:=
new
(
Provisioner
)
p
.
Prepare
(
config
)
expectedValue
:=
"keyone=valueone"
if
p
.
config
.
Vars
[
0
]
!=
expectedValue
{
t
.
Fatalf
(
"%s should be equal to %s"
,
p
.
config
.
Vars
[
0
],
expectedValue
)
}
expectedValue
=
"keytwo=value
\n
two"
if
p
.
config
.
Vars
[
1
]
!=
expectedValue
{
t
.
Fatalf
(
"%s should be equal to %s"
,
p
.
config
.
Vars
[
1
],
expectedValue
)
}
expectedValue
=
"keythree='valuethree'"
if
p
.
config
.
Vars
[
2
]
!=
expectedValue
{
t
.
Fatalf
(
"%s should be equal to %s"
,
p
.
config
.
Vars
[
2
],
expectedValue
)
}
expectedValue
=
"keyfour='value
\n
four'"
if
p
.
config
.
Vars
[
3
]
!=
expectedValue
{
t
.
Fatalf
(
"%s should be equal to %s"
,
p
.
config
.
Vars
[
3
],
expectedValue
)
}
}
func
testUi
()
*
packer
.
BasicUi
{
return
&
packer
.
BasicUi
{
Reader
:
new
(
bytes
.
Buffer
),
Writer
:
new
(
bytes
.
Buffer
),
ErrorWriter
:
new
(
bytes
.
Buffer
),
}
}
func
testObjects
()
(
packer
.
Ui
,
packer
.
Communicator
)
{
ui
:=
testUi
()
return
ui
,
new
(
packer
.
MockCommunicator
)
}
func
TestProvisionerProvision_ValidExitCodes
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
delete
(
config
,
"inline"
)
// Defaults provided by Packer
config
[
"remote_path"
]
=
"c:/Windows/Temp/inlineScript.bat"
config
[
"inline"
]
=
[]
string
{
"whoami"
}
ui
:=
testUi
()
p
:=
new
(
Provisioner
)
// Defaults provided by Packer
p
.
config
.
PackerBuildName
=
"vmware"
p
.
config
.
PackerBuilderType
=
"iso"
p
.
config
.
ValidExitCodes
=
[]
int
{
0
,
200
}
comm
:=
new
(
packer
.
MockCommunicator
)
comm
.
StartExitStatus
=
200
p
.
Prepare
(
config
)
err
:=
p
.
Provision
(
ui
,
comm
)
if
err
!=
nil
{
t
.
Fatal
(
"should not have error"
)
}
}
func
TestProvisionerProvision_InvalidExitCodes
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
delete
(
config
,
"inline"
)
// Defaults provided by Packer
config
[
"remote_path"
]
=
"c:/Windows/Temp/inlineScript.bat"
config
[
"inline"
]
=
[]
string
{
"whoami"
}
ui
:=
testUi
()
p
:=
new
(
Provisioner
)
// Defaults provided by Packer
p
.
config
.
PackerBuildName
=
"vmware"
p
.
config
.
PackerBuilderType
=
"iso"
p
.
config
.
ValidExitCodes
=
[]
int
{
0
,
200
}
comm
:=
new
(
packer
.
MockCommunicator
)
comm
.
StartExitStatus
=
201
// Invalid!
p
.
Prepare
(
config
)
err
:=
p
.
Provision
(
ui
,
comm
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
}
func
TestProvisionerProvision_Inline
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
delete
(
config
,
"inline"
)
// Defaults provided by Packer
config
[
"remote_path"
]
=
"c:/Windows/Temp/inlineScript.bat"
config
[
"inline"
]
=
[]
string
{
"whoami"
}
ui
:=
testUi
()
p
:=
new
(
Provisioner
)
// Defaults provided by Packer
p
.
config
.
PackerBuildName
=
"vmware"
p
.
config
.
PackerBuilderType
=
"iso"
comm
:=
new
(
packer
.
MockCommunicator
)
p
.
Prepare
(
config
)
err
:=
p
.
Provision
(
ui
,
comm
)
if
err
!=
nil
{
t
.
Fatal
(
"should not have error"
)
}
expectedCommand
:=
`powershell "& { $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode}"`
// Should run the command without alteration
if
comm
.
StartCmd
.
Command
!=
expectedCommand
{
t
.
Fatalf
(
"Expect command to be: %s, got %s"
,
expectedCommand
,
comm
.
StartCmd
.
Command
)
}
envVars
:=
make
([]
string
,
2
)
envVars
[
0
]
=
"FOO=BAR"
envVars
[
1
]
=
"BAR=BAZ"
config
[
"environment_vars"
]
=
envVars
config
[
"remote_path"
]
=
"c:/Windows/Temp/inlineScript.bat"
p
.
Prepare
(
config
)
err
=
p
.
Provision
(
ui
,
comm
)
if
err
!=
nil
{
t
.
Fatal
(
"should not have error"
)
}
expectedCommand
=
`powershell "& { $env:BAR=\"BAZ\"; $env:FOO=\"BAR\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode}"`
// Should run the command without alteration
if
comm
.
StartCmd
.
Command
!=
expectedCommand
{
t
.
Fatalf
(
"Expect command to be: %s, got: %s"
,
expectedCommand
,
comm
.
StartCmd
.
Command
)
}
}
func
TestProvisionerProvision_Scripts
(
t
*
testing
.
T
)
{
tempFile
,
_
:=
ioutil
.
TempFile
(
""
,
"packer"
)
defer
os
.
Remove
(
tempFile
.
Name
())
config
:=
testConfig
()
delete
(
config
,
"inline"
)
config
[
"scripts"
]
=
[]
string
{
tempFile
.
Name
()}
config
[
"packer_build_name"
]
=
"foobuild"
config
[
"packer_builder_type"
]
=
"footype"
ui
:=
testUi
()
p
:=
new
(
Provisioner
)
comm
:=
new
(
packer
.
MockCommunicator
)
p
.
Prepare
(
config
)
err
:=
p
.
Provision
(
ui
,
comm
)
if
err
!=
nil
{
t
.
Fatal
(
"should not have error"
)
}
//powershell -Command "$env:PACKER_BUILDER_TYPE=''"; powershell -Command "$env:PACKER_BUILD_NAME='foobuild'"; powershell -Command c:/Windows/Temp/script.ps1
expectedCommand
:=
`powershell "& { $env:PACKER_BUILDER_TYPE=\"footype\"; $env:PACKER_BUILD_NAME=\"foobuild\"; c:/Windows/Temp/script.ps1; exit $LastExitCode}"`
// Should run the command without alteration
if
comm
.
StartCmd
.
Command
!=
expectedCommand
{
t
.
Fatalf
(
"Expect command to be %s NOT %s"
,
expectedCommand
,
comm
.
StartCmd
.
Command
)
}
}
func
TestProvisionerProvision_ScriptsWithEnvVars
(
t
*
testing
.
T
)
{
tempFile
,
_
:=
ioutil
.
TempFile
(
""
,
"packer"
)
config
:=
testConfig
()
ui
:=
testUi
()
defer
os
.
Remove
(
tempFile
.
Name
())
delete
(
config
,
"inline"
)
config
[
"scripts"
]
=
[]
string
{
tempFile
.
Name
()}
config
[
"packer_build_name"
]
=
"foobuild"
config
[
"packer_builder_type"
]
=
"footype"
// Env vars - currently should not effect them
envVars
:=
make
([]
string
,
2
)
envVars
[
0
]
=
"FOO=BAR"
envVars
[
1
]
=
"BAR=BAZ"
config
[
"environment_vars"
]
=
envVars
p
:=
new
(
Provisioner
)
comm
:=
new
(
packer
.
MockCommunicator
)
p
.
Prepare
(
config
)
err
:=
p
.
Provision
(
ui
,
comm
)
if
err
!=
nil
{
t
.
Fatal
(
"should not have error"
)
}
expectedCommand
:=
`powershell "& { $env:BAR=\"BAZ\"; $env:FOO=\"BAR\"; $env:PACKER_BUILDER_TYPE=\"footype\"; $env:PACKER_BUILD_NAME=\"foobuild\"; c:/Windows/Temp/script.ps1; exit $LastExitCode}"`
// Should run the command without alteration
if
comm
.
StartCmd
.
Command
!=
expectedCommand
{
t
.
Fatalf
(
"Expect command to be %s NOT %s"
,
expectedCommand
,
comm
.
StartCmd
.
Command
)
}
}
func
TestProvisionerProvision_UISlurp
(
t
*
testing
.
T
)
{
// UI should be called n times
// UI should receive following messages / output
}
func
TestProvisioner_createFlattenedElevatedEnvVars_windows
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
p
:=
new
(
Provisioner
)
err
:=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error preparing config: %s"
,
err
)
}
// Defaults provided by Packer
p
.
config
.
PackerBuildName
=
"vmware"
p
.
config
.
PackerBuilderType
=
"iso"
// no user env var
flattenedEnvVars
,
err
:=
p
.
createFlattenedEnvVars
(
true
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error creating flattened env vars: %s"
,
err
)
}
if
flattenedEnvVars
!=
"$env:PACKER_BUILDER_TYPE=
\"
iso
\"
; $env:PACKER_BUILD_NAME=
\"
vmware
\"
; "
{
t
.
Fatalf
(
"unexpected flattened env vars: %s"
,
flattenedEnvVars
)
}
// single user env var
p
.
config
.
Vars
=
[]
string
{
"FOO=bar"
}
flattenedEnvVars
,
err
=
p
.
createFlattenedEnvVars
(
true
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error creating flattened env vars: %s"
,
err
)
}
if
flattenedEnvVars
!=
"$env:FOO=
\"
bar
\"
; $env:PACKER_BUILDER_TYPE=
\"
iso
\"
; $env:PACKER_BUILD_NAME=
\"
vmware
\"
; "
{
t
.
Fatalf
(
"unexpected flattened env vars: %s"
,
flattenedEnvVars
)
}
// multiple user env vars
p
.
config
.
Vars
=
[]
string
{
"FOO=bar"
,
"BAZ=qux"
}
flattenedEnvVars
,
err
=
p
.
createFlattenedEnvVars
(
true
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error creating flattened env vars: %s"
,
err
)
}
if
flattenedEnvVars
!=
"$env:BAZ=
\"
qux
\"
; $env:FOO=
\"
bar
\"
; $env:PACKER_BUILDER_TYPE=
\"
iso
\"
; $env:PACKER_BUILD_NAME=
\"
vmware
\"
; "
{
t
.
Fatalf
(
"unexpected flattened env vars: %s"
,
flattenedEnvVars
)
}
}
func
TestProvisioner_createFlattenedEnvVars_windows
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
p
:=
new
(
Provisioner
)
err
:=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error preparing config: %s"
,
err
)
}
// Defaults provided by Packer
p
.
config
.
PackerBuildName
=
"vmware"
p
.
config
.
PackerBuilderType
=
"iso"
// no user env var
flattenedEnvVars
,
err
:=
p
.
createFlattenedEnvVars
(
false
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error creating flattened env vars: %s"
,
err
)
}
if
flattenedEnvVars
!=
"$env:PACKER_BUILDER_TYPE=
\\\"
iso
\\\"
; $env:PACKER_BUILD_NAME=
\\\"
vmware
\\\"
; "
{
t
.
Fatalf
(
"unexpected flattened env vars: %s"
,
flattenedEnvVars
)
}
// single user env var
p
.
config
.
Vars
=
[]
string
{
"FOO=bar"
}
flattenedEnvVars
,
err
=
p
.
createFlattenedEnvVars
(
false
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error creating flattened env vars: %s"
,
err
)
}
if
flattenedEnvVars
!=
"$env:FOO=
\\\"
bar
\\\"
; $env:PACKER_BUILDER_TYPE=
\\\"
iso
\\\"
; $env:PACKER_BUILD_NAME=
\\\"
vmware
\\\"
; "
{
t
.
Fatalf
(
"unexpected flattened env vars: %s"
,
flattenedEnvVars
)
}
// multiple user env vars
p
.
config
.
Vars
=
[]
string
{
"FOO=bar"
,
"BAZ=qux"
}
flattenedEnvVars
,
err
=
p
.
createFlattenedEnvVars
(
false
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error creating flattened env vars: %s"
,
err
)
}
if
flattenedEnvVars
!=
"$env:BAZ=
\\\"
qux
\\\"
; $env:FOO=
\\\"
bar
\\\"
; $env:PACKER_BUILDER_TYPE=
\\\"
iso
\\\"
; $env:PACKER_BUILD_NAME=
\\\"
vmware
\\\"
; "
{
t
.
Fatalf
(
"unexpected flattened env vars: %s"
,
flattenedEnvVars
)
}
}
func
TestProvision_createCommandText
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
p
:=
new
(
Provisioner
)
comm
:=
new
(
packer
.
MockCommunicator
)
p
.
communicator
=
comm
_
=
p
.
Prepare
(
config
)
// Non-elevated
cmd
,
_
:=
p
.
createCommandText
()
if
cmd
!=
"powershell
\"
& { $env:PACKER_BUILDER_TYPE=
\\\"\\\"
; $env:PACKER_BUILD_NAME=
\\\"\\\"
; c:/Windows/Temp/script.ps1; exit $LastExitCode}
\"
"
{
t
.
Fatalf
(
"Got unexpected non-elevated 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
)
if
!
matched
{
t
.
Fatalf
(
"Got unexpected elevated command: %s"
,
cmd
)
}
}
func
TestProvision_generateElevatedShellRunner
(
t
*
testing
.
T
)
{
// Non-elevated
config
:=
testConfig
()
p
:=
new
(
Provisioner
)
p
.
Prepare
(
config
)
comm
:=
new
(
packer
.
MockCommunicator
)
p
.
communicator
=
comm
path
,
err
:=
p
.
generateElevatedRunner
(
"whoami"
)
if
err
!=
nil
{
t
.
Fatalf
(
"Did not expect error: %s"
,
err
.
Error
())
}
if
comm
.
UploadCalled
!=
true
{
t
.
Fatalf
(
"Should have uploaded file"
)
}
matched
,
_
:=
regexp
.
MatchString
(
"%TEMP%(.{1})packer-elevated-shell.*"
,
path
)
if
!
matched
{
t
.
Fatalf
(
"Got unexpected file: %s"
,
path
)
}
}
func
TestRetryable
(
t
*
testing
.
T
)
{
config
:=
testConfig
()
count
:=
0
retryMe
:=
func
()
error
{
t
.
Logf
(
"RetryMe, attempt number %d"
,
count
)
if
count
==
2
{
return
nil
}
count
++
return
errors
.
New
(
fmt
.
Sprintf
(
"Still waiting %d more times..."
,
2
-
count
))
}
retryableSleep
=
50
*
time
.
Millisecond
p
:=
new
(
Provisioner
)
p
.
config
.
StartRetryTimeout
=
155
*
time
.
Millisecond
err
:=
p
.
Prepare
(
config
)
err
=
p
.
retryable
(
retryMe
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error retrying funuction"
)
}
count
=
0
p
.
config
.
StartRetryTimeout
=
10
*
time
.
Millisecond
err
=
p
.
Prepare
(
config
)
err
=
p
.
retryable
(
retryMe
)
if
err
==
nil
{
t
.
Fatalf
(
"should have error retrying funuction"
)
}
}
func
TestCancel
(
t
*
testing
.
T
)
{
// Don't actually call Cancel() as it performs an os.Exit(0)
// which kills the 'go test' tool
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment