packer/rpc: Support Artifacts

This commit is contained in:
Mitchell Hashimoto 2013-05-21 22:10:21 -07:00
parent 55d9cd2124
commit 53c3d330e4
7 changed files with 135 additions and 4 deletions

View File

@ -19,10 +19,11 @@ func (tb *TestBuilder) Prepare(config interface{}) error {
return nil
}
func (tb *TestBuilder) Run(ui Ui, h Hook) {
func (tb *TestBuilder) Run(ui Ui, h Hook) Artifact {
tb.runCalled = true
tb.runHook = h
tb.runUi = ui
return nil
}
func testBuild() Build {

View File

@ -11,5 +11,5 @@ package packer
// Run is where the actual build should take place. It takes a Build and a Ui.
type Builder interface {
Prepare(config interface{}) error
Run(ui Ui, hook Hook)
Run(ui Ui, hook Hook) Artifact
}

62
packer/rpc/artifact.go Normal file
View File

@ -0,0 +1,62 @@
package rpc
import (
"github.com/mitchellh/packer/packer"
"net/rpc"
)
// An implementation of packer.Artifact where the artifact is actually
// available over an RPC connection.
type artifact struct {
client *rpc.Client
}
// ArtifactServer wraps a packer.Artifact implementation and makes it
// exportable as part of a Golang RPC server.
type ArtifactServer struct {
artifact packer.Artifact
}
func Artifact(client *rpc.Client) *artifact {
return &artifact{client}
}
func (a *artifact) BuilderId() (result string) {
a.client.Call("Artifact.BuilderId", new(interface{}), &result)
return
}
func (a *artifact) Files() (result []string) {
a.client.Call("Artifact.Files", new(interface{}), &result)
return
}
func (a *artifact) Id() (result string) {
a.client.Call("Artifact.Id", new(interface{}), &result)
return
}
func (a *artifact) String() (result string) {
a.client.Call("Artifact.String", new(interface{}), &result)
return
}
func (s *ArtifactServer) BuilderId(args *interface{}, reply *string) error {
*reply = s.artifact.BuilderId()
return nil
}
func (s *ArtifactServer) Files(args *interface{}, reply *[]string) error {
*reply = s.artifact.Files()
return nil
}
func (s *ArtifactServer) Id(args *interface{}, reply *string) error {
*reply = s.artifact.Id()
return nil
}
func (s *ArtifactServer) String(args *interface{}, reply *string) error {
*reply = s.artifact.String()
return nil
}

View File

@ -0,0 +1,58 @@
package rpc
import (
"cgl.tideland.biz/asserts"
"github.com/mitchellh/packer/packer"
"net/rpc"
"testing"
)
type testArtifact struct{}
func (testArtifact) BuilderId() string {
return "bid"
}
func (testArtifact) Files() []string {
return []string{"a", "b"}
}
func (testArtifact) Id() string {
return "id"
}
func (testArtifact) String() string {
return "string"
}
func TestArtifactRPC(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
// Create the interface to test
a := new(testArtifact)
// Start the server
server := rpc.NewServer()
RegisterArtifact(server, a)
address := serveSingleConn(server)
// Create the client over RPC and run some methods to verify it works
client, err := rpc.Dial("tcp", address)
assert.Nil(err, "should be able to connect")
aClient := Artifact(client)
// Test
assert.Equal(aClient.BuilderId(), "bid", "should have correct builder ID")
assert.Equal(aClient.Files(), []string{"a", "b"}, "should have correct builder ID")
assert.Equal(aClient.Id(), "id", "should have correct builder ID")
assert.Equal(aClient.String(), "string", "should have correct builder ID")
}
func TestArtifact_Implements(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
var r packer.Artifact
a := Artifact(nil)
assert.Implementor(a, &r, "should be an Artifact")
}

View File

@ -38,7 +38,7 @@ func (b *builder) Prepare(config interface{}) (err error) {
return
}
func (b *builder) Run(ui packer.Ui, hook packer.Hook) {
func (b *builder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
// Create and start the server for the Build and UI
// TODO: Error handling
server := rpc.NewServer()
@ -47,6 +47,9 @@ func (b *builder) Run(ui packer.Ui, hook packer.Hook) {
args := &BuilderRunArgs{serveSingleConn(server)}
b.client.Call("Builder.Run", args, new(interface{}))
// TODO: artifact
return nil
}
func (b *BuilderServer) Prepare(args *BuilderPrepareArgs, reply *error) error {

View File

@ -21,10 +21,11 @@ func (b *testBuilder) Prepare(config interface{}) error {
return nil
}
func (b *testBuilder) Run(ui packer.Ui, hook packer.Hook) {
func (b *testBuilder) Run(ui packer.Ui, hook packer.Hook) packer.Artifact {
b.runCalled = true
b.runHook = hook
b.runUi = ui
return nil
}
func TestBuilderRPC(t *testing.T) {

View File

@ -5,6 +5,12 @@ import (
"net/rpc"
)
// Registers the appropriate endpoint on an RPC server to serve an
// Artifact.
func RegisterArtifact(s *rpc.Server, a packer.Artifact) {
s.RegisterName("Artifact", &ArtifactServer{a})
}
// Registers the appropriate endpoint on an RPC server to serve a
// Packer Build.
func RegisterBuild(s *rpc.Server, b packer.Build) {