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
77976760
Commit
77976760
authored
Jun 20, 2013
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
provisioner/shell: can specify multiple scripts to provision with
parent
ac088bee
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
135 additions
and
72 deletions
+135
-72
provisioner/shell/provisioner.go
provisioner/shell/provisioner.go
+88
-71
provisioner/shell/provisioner_test.go
provisioner/shell/provisioner_test.go
+47
-1
No files found.
provisioner/shell/provisioner.go
View file @
77976760
...
...
@@ -28,6 +28,9 @@ type config struct {
// The local path of the shell script to upload and execute.
Path
string
// An array of multiple scripts to run.
Scripts
[]
string
// 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"`
...
...
@@ -64,17 +67,29 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
p
.
config
.
RemotePath
=
DefaultRemotePath
}
if
p
.
config
.
Scripts
==
nil
{
p
.
config
.
Scripts
=
make
([]
string
,
0
)
}
errs
:=
make
([]
error
,
0
)
if
p
.
config
.
Path
==
""
&&
p
.
config
.
Inline
==
nil
{
errs
=
append
(
errs
,
errors
.
New
(
"Either a path or inline script must be specified."
))
}
else
if
p
.
config
.
Path
!=
""
&&
p
.
config
.
Inline
!=
nil
{
errs
=
append
(
errs
,
errors
.
New
(
"Only a path or an inline script can be specified, not both."
))
if
p
.
config
.
Path
!=
""
&&
len
(
p
.
config
.
Scripts
)
>
0
{
errs
=
append
(
errs
,
errors
.
New
(
"Only one of path or scripts can be specified."
))
}
if
p
.
config
.
Path
!=
""
{
if
_
,
err
:=
os
.
Stat
(
p
.
config
.
Path
);
err
!=
nil
{
errs
=
append
(
errs
,
fmt
.
Errorf
(
"Bad script path: %s"
,
err
))
p
.
config
.
Scripts
=
[]
string
{
p
.
config
.
Path
}
}
if
len
(
p
.
config
.
Scripts
)
==
0
&&
p
.
config
.
Inline
==
nil
{
errs
=
append
(
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
=
append
(
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
=
append
(
errs
,
fmt
.
Errorf
(
"Bad script '%s': %s"
,
path
,
err
))
}
}
...
...
@@ -86,7 +101,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}
func
(
p
*
Provisioner
)
Provision
(
ui
packer
.
Ui
,
comm
packer
.
Communicator
)
{
path
:=
p
.
config
.
Path
scripts
:=
make
([]
string
,
len
(
p
.
config
.
Scripts
))
// If we have an inline script, then turn that into a temporary
// shell script and use that.
...
...
@@ -99,7 +114,7 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) {
defer
os
.
Remove
(
tf
.
Name
())
// Set the path to the temporary file
path
=
tf
.
Name
(
)
scripts
=
append
(
scripts
,
tf
.
Name
()
)
// Write our contents to it
writer
:=
bufio
.
NewWriter
(
tf
)
...
...
@@ -118,75 +133,77 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) {
tf
.
Close
()
}
ui
.
Say
(
fmt
.
Sprintf
(
"Provisioning with shell script: %s"
,
path
))
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
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error opening shell script: %s"
,
err
))
return
}
log
.
Printf
(
"Opening %s for reading"
,
path
)
f
,
err
:=
os
.
Open
(
path
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error opening shell script: %s"
,
err
))
return
}
log
.
Printf
(
"Uploading %s => %s"
,
path
,
p
.
config
.
RemotePath
)
err
=
comm
.
Upload
(
p
.
config
.
RemotePath
,
f
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error uploading shell script: %s"
,
err
))
return
}
log
.
Printf
(
"Uploading %s => %s"
,
path
,
p
.
config
.
RemotePath
)
err
=
comm
.
Upload
(
p
.
config
.
RemotePath
,
f
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error uploading shell script: %s"
,
err
))
return
}
// Compile the command
var
command
bytes
.
Buffer
t
:=
template
.
Must
(
template
.
New
(
"command"
)
.
Parse
(
p
.
config
.
ExecuteCommand
))
t
.
Execute
(
&
command
,
&
ExecuteCommandTemplate
{
p
.
config
.
RemotePath
})
// Setup the remote command
stdout_r
,
stdout_w
:=
io
.
Pipe
()
stderr_r
,
stderr_w
:=
io
.
Pipe
()
var
cmd
packer
.
RemoteCmd
cmd
.
Command
=
command
.
String
()
cmd
.
Stdout
=
stdout_w
cmd
.
Stderr
=
stderr_w
log
.
Printf
(
"Executing command: %s"
,
cmd
.
Command
)
err
=
comm
.
Start
(
&
cmd
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Failed executing command: %s"
,
err
))
return
}
// Compile the command
var
command
bytes
.
Buffer
t
:=
template
.
Must
(
template
.
New
(
"command"
)
.
Parse
(
p
.
config
.
ExecuteCommand
))
t
.
Execute
(
&
command
,
&
ExecuteCommandTemplate
{
p
.
config
.
RemotePath
})
// Setup the remote command
stdout_r
,
stdout_w
:=
io
.
Pipe
()
stderr_r
,
stderr_w
:=
io
.
Pipe
()
var
cmd
packer
.
RemoteCmd
cmd
.
Command
=
command
.
String
()
cmd
.
Stdout
=
stdout_w
cmd
.
Stderr
=
stderr_w
exitChan
:=
make
(
chan
int
,
1
)
stdoutChan
:=
iochan
.
DelimReader
(
stdout_r
,
'\n'
)
stderrChan
:=
iochan
.
DelimReader
(
stderr_r
,
'\n'
)
go
func
()
{
defer
stdout_w
.
Close
()
defer
stderr_w
.
Close
()
cmd
.
Wait
()
exitChan
<-
cmd
.
ExitStatus
}()
OutputLoop
:
for
{
select
{
case
output
:=
<-
stderrChan
:
ui
.
Message
(
strings
.
TrimSpace
(
output
))
case
output
:=
<-
stdoutChan
:
ui
.
Message
(
strings
.
TrimSpace
(
output
))
case
exitStatus
:=
<-
exitChan
:
log
.
Printf
(
"shell provisioner exited with status %d"
,
exitStatus
)
break
OutputLoop
log
.
Printf
(
"Executing command: %s"
,
cmd
.
Command
)
err
=
comm
.
Start
(
&
cmd
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Failed executing command: %s"
,
err
))
return
}
}
// Make sure we finish off stdout/stderr because we may have gotten
// a message from the exit channel first.
for
output
:=
range
stdoutChan
{
ui
.
Message
(
output
)
}
exitChan
:=
make
(
chan
int
,
1
)
stdoutChan
:=
iochan
.
DelimReader
(
stdout_r
,
'\n'
)
stderrChan
:=
iochan
.
DelimReader
(
stderr_r
,
'\n'
)
go
func
()
{
defer
stdout_w
.
Close
()
defer
stderr_w
.
Close
()
cmd
.
Wait
()
exitChan
<-
cmd
.
ExitStatus
}()
OutputLoop
:
for
{
select
{
case
output
:=
<-
stderrChan
:
ui
.
Message
(
strings
.
TrimSpace
(
output
))
case
output
:=
<-
stdoutChan
:
ui
.
Message
(
strings
.
TrimSpace
(
output
))
case
exitStatus
:=
<-
exitChan
:
log
.
Printf
(
"shell provisioner exited with status %d"
,
exitStatus
)
break
OutputLoop
}
}
for
output
:=
range
stderrChan
{
ui
.
Message
(
output
)
// Make sure we finish off stdout/stderr because we may have gotten
// a message from the exit channel first.
for
output
:=
range
stdoutChan
{
ui
.
Message
(
output
)
}
for
output
:=
range
stderrChan
{
ui
.
Message
(
output
)
}
}
}
provisioner/shell/provisioner_test.go
View file @
77976760
...
...
@@ -36,11 +36,11 @@ func TestProvisionerPrepare_Defaults(t *testing.T) {
}
func
TestProvisionerPrepare_Path
(
t
*
testing
.
T
)
{
var
p
Provisioner
config
:=
testConfig
()
delete
(
config
,
"inline"
)
config
[
"path"
]
=
"/this/should/not/exist"
p
:=
new
(
Provisioner
)
err
:=
p
.
Prepare
(
config
)
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
...
...
@@ -54,6 +54,7 @@ func TestProvisionerPrepare_Path(t *testing.T) {
defer
os
.
Remove
(
tf
.
Name
())
config
[
"path"
]
=
tf
.
Name
()
p
=
new
(
Provisioner
)
err
=
p
.
Prepare
(
config
)
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error: %s"
,
err
)
...
...
@@ -85,3 +86,48 @@ func TestProvisionerPrepare_PathAndInline(t *testing.T) {
t
.
Fatal
(
"should have error"
)
}
}
func
TestProvisionerPrepare_PathAndScripts
(
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
)
}
}
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