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
2799cccf
Commit
2799cccf
authored
May 12, 2013
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
packer: Waiting for a remote command and setting the exit status
parent
88a018bf
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
58 additions
and
4 deletions
+58
-4
packer/communicator.go
packer/communicator.go
+23
-1
packer/rpc/communicator.go
packer/rpc/communicator.go
+23
-3
packer/rpc/communicator_test.go
packer/rpc/communicator_test.go
+12
-0
No files found.
packer/communicator.go
View file @
2799cccf
package
packer
import
"io"
import
(
"io"
"time"
)
// A Communicator is the interface used to communicate with the machine
// that exists that will eventually be packaged into an image. Communicators
...
...
@@ -16,9 +19,28 @@ type Communicator interface {
// This struct contains some information about the remote command being
// executed and can be used to wait for it to complete.
//
// Stdin, Stdout, Stderr are readers and writers to varios IO streams for
// the remote command.
//
// Exited is false until Wait is called. It can be used to check if Wait
// has already been called.
//
// ExitStatus is the exit code of the remote process. It is only available
// once Wait is called.
type
RemoteCommand
struct
{
Stdin
io
.
Writer
Stdout
io
.
Reader
Stderr
io
.
Reader
Exited
bool
ExitStatus
int
}
// Wait waits for the command to exit.
func
(
r
*
RemoteCommand
)
Wait
()
{
// Busy wait on being exited. We put a sleep to be kind to the
// Go scheduler, and because we don't really need smaller granularity.
for
!
r
.
Exited
{
time
.
Sleep
(
10
*
time
.
Millisecond
)
}
}
packer/rpc/communicator.go
View file @
2799cccf
...
...
@@ -31,7 +31,7 @@ type CommunicatorStartResponse struct {
StdinAddress
string
StdoutAddress
string
StderrAddress
string
ExitStatus
Address
string
RemoteCommand
Address
string
}
func
Communicator
(
client
*
rpc
.
Client
)
*
communicator
{
...
...
@@ -62,14 +62,28 @@ func (c *communicator) Start(cmd string) (rc *packer.RemoteCommand, err error) {
return
}
// Connect to the RPC server for the remote command
client
,
err
:=
rpc
.
Dial
(
"tcp"
,
response
.
RemoteCommandAddress
)
if
err
!=
nil
{
return
}
// Build the response object using the streams we created
rc
=
&
packer
.
RemoteCommand
{
stdinC
,
stdoutC
,
stderrC
,
0
,
false
,
-
1
,
}
// In a goroutine, we wait for the process to exit, then we set
// that it has exited.
go
func
()
{
client
.
Call
(
"RemoteCommand.Wait"
,
new
(
interface
{}),
&
rc
.
ExitStatus
)
rc
.
Exited
=
true
}()
return
}
...
...
@@ -99,7 +113,7 @@ func (c *CommunicatorServer) Start(cmd *string, reply *CommunicatorStartResponse
// For the exit status, we use a simple RPC Server that serves
// some of the RemoteComand methods.
server
:=
rpc
.
NewServer
()
//
server.RegisterName("RemoteCommand", &RemoteCommandServer{command})
server
.
RegisterName
(
"RemoteCommand"
,
&
RemoteCommandServer
{
command
})
*
reply
=
CommunicatorStartResponse
{
stdinL
.
Addr
()
.
String
(),
...
...
@@ -111,6 +125,12 @@ func (c *CommunicatorServer) Start(cmd *string, reply *CommunicatorStartResponse
return
}
func
(
rc
*
RemoteCommandServer
)
Wait
(
args
*
interface
{},
reply
*
int
)
error
{
rc
.
rc
.
Wait
()
*
reply
=
rc
.
rc
.
ExitStatus
return
nil
}
func
serveSingleCopy
(
name
string
,
l
net
.
Listener
,
dst
io
.
Writer
,
src
io
.
Reader
)
{
defer
l
.
Close
()
...
...
packer/rpc/communicator_test.go
View file @
2799cccf
...
...
@@ -16,6 +16,8 @@ type testCommunicator struct {
startIn
*
io
.
PipeReader
startOut
*
io
.
PipeWriter
startErr
*
io
.
PipeWriter
startExited
*
bool
startExitStatus
*
int
}
func
(
t
*
testCommunicator
)
Start
(
cmd
string
)
(
*
packer
.
RemoteCommand
,
error
)
{
...
...
@@ -33,9 +35,13 @@ func (t *testCommunicator) Start(cmd string) (*packer.RemoteCommand, error) {
stdin
,
stdout
,
stderr
,
false
,
0
,
}
t
.
startExited
=
&
rc
.
Exited
t
.
startExitStatus
=
&
rc
.
ExitStatus
return
rc
,
nil
}
...
...
@@ -83,6 +89,12 @@ func TestCommunicatorRPC(t *testing.T) {
data
,
err
=
bufIn
.
ReadString
(
'\n'
)
assert
.
Nil
(
err
,
"should have no problem reading stdin"
)
assert
.
Equal
(
data
,
"infoo
\n
"
,
"should be correct stdin"
)
// Test that we can get the exit status properly
*
c
.
startExitStatus
=
42
*
c
.
startExited
=
true
rc
.
Wait
()
assert
.
Equal
(
rc
.
ExitStatus
,
42
,
"should have proper exit status"
)
}
func
TestCommunicator_ImplementsCommunicator
(
t
*
testing
.
T
)
{
...
...
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