Commit a21fe8c4 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer/rpc: Exited fields now work over RPC

parent ea4171f1
package rpc package rpc
import ( import (
"encoding/gob"
"errors" "errors"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"io" "io"
"log" "log"
"net" "net"
"net/rpc" "net/rpc"
"time"
) )
// An implementation of packer.Communicator where the communicator is actually // An implementation of packer.Communicator where the communicator is actually
...@@ -21,11 +23,16 @@ type CommunicatorServer struct { ...@@ -21,11 +23,16 @@ type CommunicatorServer struct {
c packer.Communicator c packer.Communicator
} }
type CommandFinished struct {
ExitStatus int
}
type CommunicatorStartArgs struct { type CommunicatorStartArgs struct {
Command string Command string
StdinAddress string StdinAddress string
StdoutAddress string StdoutAddress string
StderrAddress string StderrAddress string
ResponseAddress string
} }
type CommunicatorDownloadArgs struct { type CommunicatorDownloadArgs struct {
...@@ -64,6 +71,30 @@ func (c *communicator) Start(cmd *packer.RemoteCmd) (err error) { ...@@ -64,6 +71,30 @@ func (c *communicator) Start(cmd *packer.RemoteCmd) (err error) {
go serveSingleCopy("stderr", stderrL, cmd.Stderr, nil) go serveSingleCopy("stderr", stderrL, cmd.Stderr, nil)
} }
responseL := netListenerInRange(portRangeMin, portRangeMax)
args.ResponseAddress = responseL.Addr().String()
go func() {
defer responseL.Close()
conn, err := responseL.Accept()
if err != nil {
log.Panic(err)
}
defer conn.Close()
decoder := gob.NewDecoder(conn)
var finished CommandFinished
if err := decoder.Decode(&finished); err != nil {
log.Panic(err)
}
cmd.ExitStatus = finished.ExitStatus
cmd.Exited = true
}()
err = c.client.Call("Communicator.Start", &args, new(interface{})) err = c.client.Call("Communicator.Start", &args, new(interface{}))
return return
} }
...@@ -149,8 +180,30 @@ func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface ...@@ -149,8 +180,30 @@ func (c *CommunicatorServer) Start(args *CommunicatorStartArgs, reply *interface
cmd.Stderr = stderrC cmd.Stderr = stderrC
} }
// Connect to the response address so we can write our result to it
// when ready.
responseC, err := net.Dial("tcp", args.ResponseAddress)
if err != nil {
return err
}
responseWriter := gob.NewEncoder(responseC)
// Start the actual command // Start the actual command
err = c.c.Start(&cmd) err = c.c.Start(&cmd)
// Start a goroutine to spin and wait for the process to actual
// exit. When it does, report it back to caller...
go func() {
defer responseC.Close()
for !cmd.Exited {
time.Sleep(50 * time.Millisecond)
}
responseWriter.Encode(&CommandFinished{cmd.ExitStatus})
}()
return return
} }
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"io" "io"
"net/rpc" "net/rpc"
"testing" "testing"
"time"
) )
type testCommunicator struct { type testCommunicator struct {
...@@ -95,7 +96,19 @@ func TestCommunicatorRPC(t *testing.T) { ...@@ -95,7 +96,19 @@ func TestCommunicatorRPC(t *testing.T) {
assert.Equal(data, "infoo\n", "should be correct stdin") assert.Equal(data, "infoo\n", "should be correct stdin")
// Test that we can get the exit status properly // Test that we can get the exit status properly
// TODO c.startCmd.ExitStatus = 42
c.startCmd.Exited = true
for i := 0; i < 5; i++ {
if cmd.Exited {
assert.Equal(cmd.ExitStatus, 42, "should have proper exit status")
break
}
time.Sleep(50 * time.Millisecond)
}
assert.True(cmd.Exited, "should have exited")
// Test that we can upload things // Test that we can upload things
uploadR, uploadW := io.Pipe() uploadR, uploadW := io.Pipe()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment