packer: Provisioner/Hook can have errors returned

This commit is contained in:
Mitchell Hashimoto 2013-06-26 17:50:25 -07:00
parent 5a9a993c32
commit e5a7fc6b0a
12 changed files with 44 additions and 24 deletions

View File

@ -12,7 +12,7 @@ const HookProvision = "packer_provision"
// in. In addition to that, the Hook is given access to a UI so that it can
// output things to the user.
type Hook interface {
Run(string, Ui, Communicator, interface{})
Run(string, Ui, Communicator, interface{}) error
}
// A Hook implementation that dispatches based on an internal mapping.
@ -23,14 +23,18 @@ type DispatchHook struct {
// Runs the hook with the given name by dispatching it to the proper
// hooks if a mapping exists. If a mapping doesn't exist, then nothing
// happens.
func (h *DispatchHook) Run(name string, ui Ui, comm Communicator, data interface{}) {
func (h *DispatchHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
hooks, ok := h.Mapping[name]
if !ok {
// No hooks for that name. No problem.
return
return nil
}
for _, hook := range hooks {
hook.Run(name, ui, comm, data)
if err := hook.Run(name, ui, comm, data); err != nil {
return err
}
}
return nil
}

View File

@ -13,12 +13,13 @@ type TestHook struct {
runUi Ui
}
func (t *TestHook) Run(name string, ui Ui, comm Communicator, data interface{}) {
func (t *TestHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
t.runCalled = true
t.runComm = comm
t.runData = data
t.runName = name
t.runUi = ui
return nil
}
func TestDispatchHook_Implements(t *testing.T) {

View File

@ -10,13 +10,13 @@ type cmdHook struct {
client *Client
}
func (c *cmdHook) Run(name string, ui packer.Ui, comm packer.Communicator, data interface{}) {
func (c *cmdHook) Run(name string, ui packer.Ui, comm packer.Communicator, data interface{}) error {
defer func() {
r := recover()
c.checkExit(r, nil)
}()
c.hook.Run(name, ui, comm, data)
return c.hook.Run(name, ui, comm, data)
}
func (c *cmdHook) checkExit(p interface{}, cb func()) {

View File

@ -8,7 +8,9 @@ import (
type helperHook byte
func (helperHook) Run(string, packer.Ui, packer.Communicator, interface{}) {}
func (helperHook) Run(string, packer.Ui, packer.Communicator, interface{}) error {
return nil
}
func TestHook_NoExist(t *testing.T) {
c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")})

View File

@ -19,13 +19,13 @@ func (c *cmdProvisioner) Prepare(configs ...interface{}) error {
return c.p.Prepare(configs...)
}
func (c *cmdProvisioner) Provision(ui packer.Ui, comm packer.Communicator) {
func (c *cmdProvisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
defer func() {
r := recover()
c.checkExit(r, nil)
}()
c.p.Provision(ui, comm)
return c.p.Provision(ui, comm)
}
func (c *cmdProvisioner) checkExit(p interface{}, cb func()) {

View File

@ -12,7 +12,9 @@ func (helperProvisioner) Prepare(...interface{}) error {
return nil
}
func (helperProvisioner) Provision(packer.Ui, packer.Communicator) {}
func (helperProvisioner) Provision(packer.Ui, packer.Communicator) error {
return nil
}
func TestProvisioner_NoExist(t *testing.T) {
c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")})

View File

@ -12,7 +12,7 @@ type Provisioner interface {
// given to communicate with the user, and a communicator is given that
// is guaranteed to be connected to some machine so that provisioning
// can be done.
Provision(Ui, Communicator)
Provision(Ui, Communicator) error
}
// A Hook implementation that runs the given provisioners.
@ -23,8 +23,12 @@ type ProvisionHook struct {
}
// Runs the provisioners in order.
func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interface{}) {
func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interface{}) error {
for _, p := range h.Provisioners {
p.Provision(ui, comm)
if err := p.Provision(ui, comm); err != nil {
return err
}
}
return nil
}

View File

@ -14,8 +14,9 @@ func (t *TestProvisioner) Prepare(configs ...interface{}) error {
return nil
}
func (t *TestProvisioner) Provision(Ui, Communicator) {
func (t *TestProvisioner) Provision(Ui, Communicator) error {
t.provCalled = true
return nil
}
func TestProvisionHook_Impl(t *testing.T) {

View File

@ -27,15 +27,14 @@ func Hook(client *rpc.Client) *hook {
return &hook{client}
}
func (h *hook) Run(name string, ui packer.Ui, comm packer.Communicator, data interface{}) {
func (h *hook) Run(name string, ui packer.Ui, comm packer.Communicator, data interface{}) error {
server := rpc.NewServer()
RegisterCommunicator(server, comm)
RegisterUi(server, ui)
address := serveSingleConn(server)
args := &HookRunArgs{name, data, address}
h.client.Call("Hook.Run", args, new(interface{}))
return
return h.client.Call("Hook.Run", args, new(interface{}))
}
func (h *HookServer) Run(args *HookRunArgs, reply *interface{}) error {
@ -44,7 +43,9 @@ func (h *HookServer) Run(args *HookRunArgs, reply *interface{}) error {
return err
}
h.hook.Run(args.Name, &Ui{client}, Communicator(client), args.Data)
if err := h.hook.Run(args.Name, &Ui{client}, Communicator(client), args.Data); err != nil {
return NewBasicError(err)
}
*reply = nil
return nil

View File

@ -12,8 +12,9 @@ type testHook struct {
runUi packer.Ui
}
func (h *testHook) Run(name string, ui packer.Ui, comm packer.Communicator, data interface{}) {
func (h *testHook) Run(name string, ui packer.Ui, comm packer.Communicator, data interface{}) error {
h.runCalled = true
return nil
}
func TestHookRPC(t *testing.T) {

View File

@ -37,14 +37,14 @@ func (p *provisioner) Prepare(configs ...interface{}) (err error) {
return
}
func (p *provisioner) Provision(ui packer.Ui, comm packer.Communicator) {
func (p *provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
// TODO: Error handling
server := rpc.NewServer()
RegisterCommunicator(server, comm)
RegisterUi(server, ui)
args := &ProvisionerProvisionArgs{serveSingleConn(server)}
p.client.Call("Provisioner.Provision", args, new(interface{}))
return p.client.Call("Provisioner.Provision", args, new(interface{}))
}
func (p *ProvisionerServer) Prepare(args *ProvisionerPrepareArgs, reply *error) error {
@ -65,6 +65,9 @@ func (p *ProvisionerServer) Provision(args *ProvisionerProvisionArgs, reply *int
comm := Communicator(client)
ui := &Ui{client}
p.p.Provision(ui, comm)
if err := p.p.Provision(ui, comm); err != nil {
return NewBasicError(err)
}
return nil
}

View File

@ -21,10 +21,11 @@ func (p *testProvisioner) Prepare(configs ...interface{}) error {
return nil
}
func (p *testProvisioner) Provision(ui packer.Ui, comm packer.Communicator) {
func (p *testProvisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
p.provCalled = true
p.provComm = comm
p.provUi = ui
return nil
}
func TestProvisionerRPC(t *testing.T) {