From 53c3d330e4ea2a95438338e8226b5bf79864ac09 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 21 May 2013 22:10:21 -0700 Subject: [PATCH] packer/rpc: Support Artifacts --- packer/build_test.go | 3 +- packer/builder.go | 2 +- packer/rpc/artifact.go | 62 +++++++++++++++++++++++++++++++++++++ packer/rpc/artifact_test.go | 58 ++++++++++++++++++++++++++++++++++ packer/rpc/builder.go | 5 ++- packer/rpc/builder_test.go | 3 +- packer/rpc/server.go | 6 ++++ 7 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 packer/rpc/artifact.go create mode 100644 packer/rpc/artifact_test.go diff --git a/packer/build_test.go b/packer/build_test.go index 4f33a2dce..a5d656292 100644 --- a/packer/build_test.go +++ b/packer/build_test.go @@ -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 { diff --git a/packer/builder.go b/packer/builder.go index 1c1a739a5..e48eea0a4 100644 --- a/packer/builder.go +++ b/packer/builder.go @@ -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 } diff --git a/packer/rpc/artifact.go b/packer/rpc/artifact.go new file mode 100644 index 000000000..64b0ef3da --- /dev/null +++ b/packer/rpc/artifact.go @@ -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 +} diff --git a/packer/rpc/artifact_test.go b/packer/rpc/artifact_test.go new file mode 100644 index 000000000..e665d384f --- /dev/null +++ b/packer/rpc/artifact_test.go @@ -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") +} diff --git a/packer/rpc/builder.go b/packer/rpc/builder.go index c4d79704b..dd23c7dbf 100644 --- a/packer/rpc/builder.go +++ b/packer/rpc/builder.go @@ -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 { diff --git a/packer/rpc/builder_test.go b/packer/rpc/builder_test.go index 07eb26994..de12bddbb 100644 --- a/packer/rpc/builder_test.go +++ b/packer/rpc/builder_test.go @@ -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) { diff --git a/packer/rpc/server.go b/packer/rpc/server.go index c050ccb9e..8b4e519fb 100644 --- a/packer/rpc/server.go +++ b/packer/rpc/server.go @@ -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) {