packer/rpc: Support provisioners
This commit is contained in:
parent
638e191186
commit
92a4f27868
|
@ -59,6 +59,22 @@ func (e *Environment) Hook(name string) (h packer.Hook, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Environment) Provisioner(name string) (p packer.Provisioner, err error) {
|
||||||
|
var reply string
|
||||||
|
err = e.client.Call("Environment.Provisioner", name, &reply)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := rpc.Dial("tcp", reply)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p = Provisioner(client)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Environment) Ui() packer.Ui {
|
func (e *Environment) Ui() packer.Ui {
|
||||||
var reply string
|
var reply string
|
||||||
e.client.Call("Environment.Ui", new(interface{}), &reply)
|
e.client.Call("Environment.Ui", new(interface{}), &reply)
|
||||||
|
@ -101,6 +117,19 @@ func (e *EnvironmentServer) Hook(name *string, reply *string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *EnvironmentServer) Provisioner(name *string, reply *string) error {
|
||||||
|
prov, err := e.env.Provisioner(*name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
server := rpc.NewServer()
|
||||||
|
RegisterProvisioner(server, prov)
|
||||||
|
|
||||||
|
*reply = serveSingleConn(server)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *EnvironmentServer) Ui(args *interface{}, reply *string) error {
|
func (e *EnvironmentServer) Ui(args *interface{}, reply *string) error {
|
||||||
ui := e.env.Ui()
|
ui := e.env.Ui()
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ type testEnvironment struct {
|
||||||
cliArgs []string
|
cliArgs []string
|
||||||
hookCalled bool
|
hookCalled bool
|
||||||
hookName string
|
hookName string
|
||||||
|
provCalled bool
|
||||||
|
provName string
|
||||||
uiCalled bool
|
uiCalled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +40,12 @@ func (e *testEnvironment) Hook(name string) (packer.Hook, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *testEnvironment) Provisioner(name string) (packer.Provisioner, error) {
|
||||||
|
e.provCalled = true
|
||||||
|
e.provName = name
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *testEnvironment) Ui() packer.Ui {
|
func (e *testEnvironment) Ui() packer.Ui {
|
||||||
e.uiCalled = true
|
e.uiCalled = true
|
||||||
return testEnvUi
|
return testEnvUi
|
||||||
|
@ -74,6 +82,11 @@ func TestEnvironmentRPC(t *testing.T) {
|
||||||
assert.Equal(e.cliArgs, cliArgs, "args should match")
|
assert.Equal(e.cliArgs, cliArgs, "args should match")
|
||||||
assert.Equal(result, 42, "result shuld be 42")
|
assert.Equal(result, 42, "result shuld be 42")
|
||||||
|
|
||||||
|
// Test Provisioner
|
||||||
|
_, _ = eClient.Provisioner("foo")
|
||||||
|
assert.True(e.provCalled, "provisioner should be called")
|
||||||
|
assert.Equal(e.provName, "foo", "should have proper name")
|
||||||
|
|
||||||
// Test Ui
|
// Test Ui
|
||||||
ui := eClient.Ui()
|
ui := eClient.Ui()
|
||||||
assert.True(e.uiCalled, "Ui should've been called")
|
assert.True(e.uiCalled, "Ui should've been called")
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"net/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An implementation of packer.Provisioner where the provisioner is actually
|
||||||
|
// executed over an RPC connection.
|
||||||
|
type provisioner struct {
|
||||||
|
client *rpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProvisionerServer wraps a packer.Provisioner implementation and makes it
|
||||||
|
// exportable as part of a Golang RPC server.
|
||||||
|
type ProvisionerServer struct {
|
||||||
|
p packer.Provisioner
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProvisionerPrepareArgs struct {
|
||||||
|
Config interface{}
|
||||||
|
RPCAddress string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProvisionerProvisionArgs struct {
|
||||||
|
RPCAddress string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Provisioner(client *rpc.Client) *provisioner {
|
||||||
|
return &provisioner{client}
|
||||||
|
}
|
||||||
|
func (p *provisioner) Prepare(config interface{}, ui packer.Ui) {
|
||||||
|
// TODO: Error handling
|
||||||
|
server := rpc.NewServer()
|
||||||
|
RegisterUi(server, ui)
|
||||||
|
|
||||||
|
args := &ProvisionerPrepareArgs{config, serveSingleConn(server)}
|
||||||
|
p.client.Call("Provisioner.Prepare", args, new(interface{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *provisioner) Provision(ui packer.Ui, comm packer.Communicator) {
|
||||||
|
// TODO: Error handling
|
||||||
|
server := rpc.NewServer()
|
||||||
|
RegisterCommunicator(server, comm)
|
||||||
|
RegisterUi(server, ui)
|
||||||
|
|
||||||
|
args := &ProvisionerProvisionArgs{serveSingleConn(server)}
|
||||||
|
p.client.Call("Provisioner.Provision", args, new(interface{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProvisionerServer) Prepare(args *ProvisionerPrepareArgs, reply *interface{}) error {
|
||||||
|
client, err := rpc.Dial("tcp", args.RPCAddress)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ui := &Ui{client}
|
||||||
|
|
||||||
|
p.p.Prepare(args.Config, ui)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProvisionerServer) Provision(args *ProvisionerProvisionArgs, reply *interface{}) error {
|
||||||
|
client, err := rpc.Dial("tcp", args.RPCAddress)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
comm := Communicator(client)
|
||||||
|
ui := &Ui{client}
|
||||||
|
|
||||||
|
p.p.Provision(ui, comm)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cgl.tideland.biz/asserts"
|
||||||
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"net/rpc"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testProvisioner struct {
|
||||||
|
prepareCalled bool
|
||||||
|
prepareConfig interface{}
|
||||||
|
prepareUi packer.Ui
|
||||||
|
provCalled bool
|
||||||
|
provComm packer.Communicator
|
||||||
|
provUi packer.Ui
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *testProvisioner) Prepare(config interface{}, ui packer.Ui) {
|
||||||
|
p.prepareCalled = true
|
||||||
|
p.prepareConfig = config
|
||||||
|
p.prepareUi = ui
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *testProvisioner) Provision(ui packer.Ui, comm packer.Communicator) {
|
||||||
|
p.provCalled = true
|
||||||
|
p.provComm = comm
|
||||||
|
p.provUi = ui
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvisionerRPC(t *testing.T) {
|
||||||
|
assert := asserts.NewTestingAsserts(t, true)
|
||||||
|
|
||||||
|
// Create the interface to test
|
||||||
|
p := new(testProvisioner)
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
server := rpc.NewServer()
|
||||||
|
RegisterProvisioner(server, p)
|
||||||
|
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")
|
||||||
|
|
||||||
|
// Test Prepare
|
||||||
|
config := 42
|
||||||
|
ui := &testUi{}
|
||||||
|
pClient := Provisioner(client)
|
||||||
|
pClient.Prepare(config, ui)
|
||||||
|
assert.True(p.prepareCalled, "prepare should be called")
|
||||||
|
assert.Equal(p.prepareConfig, 42, "prepare should be called with right arg")
|
||||||
|
|
||||||
|
p.prepareUi.Say("foo")
|
||||||
|
assert.True(ui.sayCalled, "say should be called")
|
||||||
|
|
||||||
|
// Test Provision
|
||||||
|
ui = &testUi{}
|
||||||
|
comm := &testCommunicator{}
|
||||||
|
pClient.Provision(ui, comm)
|
||||||
|
assert.True(p.provCalled, "provision should be called")
|
||||||
|
|
||||||
|
p.provUi.Say("foo")
|
||||||
|
assert.True(ui.sayCalled, "say should be called")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvisioner_Implements(t *testing.T) {
|
||||||
|
assert := asserts.NewTestingAsserts(t, true)
|
||||||
|
|
||||||
|
var r packer.Provisioner
|
||||||
|
p := Provisioner(nil)
|
||||||
|
|
||||||
|
assert.Implementor(p, &r, "should be a provisioner")
|
||||||
|
}
|
|
@ -47,6 +47,11 @@ func RegisterHook(s *rpc.Server, hook packer.Hook) {
|
||||||
s.RegisterName("Hook", &HookServer{hook})
|
s.RegisterName("Hook", &HookServer{hook})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Registers the appropriate endpoint on an RPC server to serve a packer.Provisioner
|
||||||
|
func RegisterProvisioner(s *rpc.Server, p packer.Provisioner) {
|
||||||
|
s.RegisterName("Provisioner", &ProvisionerServer{p})
|
||||||
|
}
|
||||||
|
|
||||||
// Registers the appropriate endpoint on an RPC server to serve a
|
// Registers the appropriate endpoint on an RPC server to serve a
|
||||||
// Packer UI
|
// Packer UI
|
||||||
func RegisterUi(s *rpc.Server, ui packer.Ui) {
|
func RegisterUi(s *rpc.Server, ui packer.Ui) {
|
||||||
|
|
Loading…
Reference in New Issue