packer/plugin: Much more robust subprocess starting

This commit is contained in:
Mitchell Hashimoto 2013-05-05 16:25:32 -07:00
parent 86f1fbe925
commit 0cc3a5f918
4 changed files with 49 additions and 33 deletions

View File

@ -10,19 +10,10 @@ import (
"time"
)
type processCommand struct {
cmd *exec.Cmd
}
func (c *processCommand) Run(e packer.Environment, args []string) int {
return 0
}
func (c *processCommand) Synopsis() string {
func Command(cmd *exec.Cmd) packer.Command {
out := new(bytes.Buffer)
c.cmd.Stdout = out
c.cmd.Start()
defer c.cmd.Process.Kill()
cmd.Stdout = out
cmd.Start()
// TODO: timeout
// TODO: check that command is even running
@ -37,13 +28,10 @@ func (c *processCommand) Synopsis() string {
time.Sleep(10 * time.Millisecond)
}
client, _ := rpc.Dial("tcp", address)
defer client.Close()
client, err := rpc.Dial("tcp", address)
if err != nil {
panic(err)
}
realCommand := packrpc.Command(client)
return realCommand.Synopsis()
}
func Command(cmd *exec.Cmd) packer.Command {
return &processCommand{cmd}
return packrpc.Command(client)
}

View File

@ -6,26 +6,42 @@ package plugin
import (
"fmt"
"github.com/mitchellh/packer/packer"
"net"
"net/rpc"
"os"
packrpc "github.com/mitchellh/packer/packer/rpc"
)
// This serves the plugin by starting the RPC server and serving requests.
// This function never returns.
func serve(server *packrpc.Server) {
// Start up the server
server.Start()
// This serves a single RPC connection on the given RPC server on
// a random port.
func serve(server *rpc.Server) (err error) {
listener, err := net.Listen("tcp", ":2345")
if err != nil {
return
}
defer listener.Close()
// Output the address to stdout
fmt.Println(server.Address())
fmt.Println(":2345")
os.Stdout.Sync()
// Never return, wait on a channel that never gets a message
<-make(chan bool)
// Accept a connection
conn, err := listener.Accept()
if err != nil {
return
}
// Serve a single connection
server.ServeConn(conn)
return
}
// Serves a command from a plugin.
func ServeCommand(command packer.Command) {
server := packrpc.NewServer()
server.RegisterCommand(command)
serve(server)
server := rpc.NewServer()
packrpc.RegisterCommand(server, command)
if err := serve(server); err != nil {
panic(err)
}
}

View File

@ -31,12 +31,20 @@ func Command(client *rpc.Client) *ClientCommand {
func (c *ClientCommand) Run(env packer.Environment, args []string) (result int) {
// TODO: Environment
rpcArgs := &CommandRunArgs{nil, args}
c.client.Call("Command.Run", rpcArgs, &result)
err := c.client.Call("Command.Run", rpcArgs, &result)
if err != nil {
panic(err)
}
return
}
func (c *ClientCommand) Synopsis() (result string) {
c.client.Call("Command.Synopsis", CommandSynopsisArgs(0), &result)
err := c.client.Call("Command.Synopsis", CommandSynopsisArgs(0), &result)
if err != nil {
panic(err)
}
return
}

View File

@ -7,6 +7,10 @@ import (
"net/rpc"
)
func RegisterCommand(s *rpc.Server, c packer.Command) {
s.RegisterName("Command", &ServerCommand{c})
}
// A Server is a Golang RPC server that has helper methods for automatically
// setting up the endpoints for Packer interfaces.
type Server struct {