Remote builders
This commit is contained in:
parent
68341e6e8a
commit
c537c304cb
|
@ -0,0 +1,63 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
)
|
||||
|
||||
// An implementation of packer.Builder where the builder is actually executed
|
||||
// over an RPC connection.
|
||||
type Builder struct {
|
||||
client *rpc.Client
|
||||
}
|
||||
|
||||
// BuilderServer wraps a packer.Builder implementation and makes it exportable
|
||||
// as part of a Golang RPC server.
|
||||
type BuilderServer struct {
|
||||
builder packer.Builder
|
||||
}
|
||||
|
||||
type BuilderPrepareArgs struct {
|
||||
Config interface{}
|
||||
}
|
||||
|
||||
type BuilderRunArgs struct {
|
||||
RPCAddress string
|
||||
}
|
||||
|
||||
func (b *Builder) Prepare(config interface{}) {
|
||||
b.client.Call("Builder.Prepare", &BuilderPrepareArgs{config}, new(interface{}))
|
||||
}
|
||||
|
||||
func (b *Builder) Run(build packer.Build, ui packer.Ui) {
|
||||
// Create and start the server for the Build and UI
|
||||
// TODO: Error handling
|
||||
server := NewServer()
|
||||
server.RegisterBuild(build)
|
||||
server.RegisterUi(ui)
|
||||
server.Start()
|
||||
defer server.Stop()
|
||||
|
||||
args := &BuilderRunArgs{server.Address()}
|
||||
b.client.Call("Builder.Run", args, new(interface{}))
|
||||
}
|
||||
|
||||
func (b *BuilderServer) Prepare(args *BuilderPrepareArgs, reply *interface{}) error {
|
||||
b.builder.Prepare(args.Config)
|
||||
*reply = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BuilderServer) Run(args *BuilderRunArgs, reply *interface{}) error {
|
||||
client, err := rpc.Dial("tcp", args.RPCAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
build := &Build{client}
|
||||
ui := &Ui{client}
|
||||
b.builder.Run(build, ui)
|
||||
|
||||
*reply = nil
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"cgl.tideland.biz/asserts"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"net/rpc"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testBuilder struct {
|
||||
prepareCalled bool
|
||||
prepareConfig interface{}
|
||||
runCalled bool
|
||||
runBuild packer.Build
|
||||
runUi packer.Ui
|
||||
}
|
||||
|
||||
func (b *testBuilder) Prepare(config interface{}) {
|
||||
b.prepareCalled = true
|
||||
b.prepareConfig = config
|
||||
}
|
||||
|
||||
func (b *testBuilder) Run(build packer.Build, ui packer.Ui) {
|
||||
b.runCalled = true
|
||||
b.runBuild = build
|
||||
b.runUi = ui
|
||||
}
|
||||
|
||||
func TestBuilderRPC(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
// Create the interface to test
|
||||
b := new(testBuilder)
|
||||
|
||||
// Start the server
|
||||
server := NewServer()
|
||||
server.RegisterBuilder(b)
|
||||
server.Start()
|
||||
defer server.Stop()
|
||||
|
||||
// Create the client over RPC and run some methods to verify it works
|
||||
client, err := rpc.Dial("tcp", server.Address())
|
||||
assert.Nil(err, "should be able to connect")
|
||||
|
||||
// Test Prepare
|
||||
config := 42
|
||||
bClient := &Builder{client}
|
||||
bClient.Prepare(config)
|
||||
assert.True(b.prepareCalled, "prepare should be called")
|
||||
assert.Equal(b.prepareConfig, 42, "prepare should be called with right arg")
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuild(t *testing.T) {
|
||||
assert := asserts.NewTestingAsserts(t, true)
|
||||
|
||||
var realBuilder packer.Builder
|
||||
b := &Builder{nil}
|
||||
|
||||
assert.Implementor(b, &realBuilder, "should be a Builder")
|
||||
}
|
|
@ -29,6 +29,14 @@ func (s *Server) Address() string {
|
|||
return s.listener.Addr().String()
|
||||
}
|
||||
|
||||
func (s *Server) RegisterBuild(b packer.Build) {
|
||||
s.server.RegisterName("Build", &BuildServer{b})
|
||||
}
|
||||
|
||||
func (s *Server) RegisterBuilder(b packer.Builder) {
|
||||
s.server.RegisterName("Builder", &BuilderServer{b})
|
||||
}
|
||||
|
||||
func (s *Server) RegisterUi(ui packer.Ui) {
|
||||
s.server.RegisterName("Ui", &UiServer{ui})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue