diff --git a/packer/hook.go b/packer/hook.go index c86380b2e..4a79222f4 100644 --- a/packer/hook.go +++ b/packer/hook.go @@ -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 } diff --git a/packer/hook_test.go b/packer/hook_test.go index 62ebbdac3..e43dfd1fd 100644 --- a/packer/hook_test.go +++ b/packer/hook_test.go @@ -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) { diff --git a/packer/plugin/hook.go b/packer/plugin/hook.go index 61695d098..fd45585ea 100644 --- a/packer/plugin/hook.go +++ b/packer/plugin/hook.go @@ -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()) { diff --git a/packer/plugin/hook_test.go b/packer/plugin/hook_test.go index f705853df..e6880e616 100644 --- a/packer/plugin/hook_test.go +++ b/packer/plugin/hook_test.go @@ -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")}) diff --git a/packer/plugin/provisioner.go b/packer/plugin/provisioner.go index 2bfa72405..66033b9d3 100644 --- a/packer/plugin/provisioner.go +++ b/packer/plugin/provisioner.go @@ -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()) { diff --git a/packer/plugin/provisioner_test.go b/packer/plugin/provisioner_test.go index 2917cd55d..4a665411c 100644 --- a/packer/plugin/provisioner_test.go +++ b/packer/plugin/provisioner_test.go @@ -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")}) diff --git a/packer/provisioner.go b/packer/provisioner.go index cfd2ffbd1..99a0a2ac2 100644 --- a/packer/provisioner.go +++ b/packer/provisioner.go @@ -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 } diff --git a/packer/provisioner_test.go b/packer/provisioner_test.go index 5eba77743..1db8b55bc 100644 --- a/packer/provisioner_test.go +++ b/packer/provisioner_test.go @@ -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) { diff --git a/packer/rpc/hook.go b/packer/rpc/hook.go index c39dd1fd3..27840f080 100644 --- a/packer/rpc/hook.go +++ b/packer/rpc/hook.go @@ -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 diff --git a/packer/rpc/hook_test.go b/packer/rpc/hook_test.go index 8e94e5a0f..fcc2aea7a 100644 --- a/packer/rpc/hook_test.go +++ b/packer/rpc/hook_test.go @@ -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) { diff --git a/packer/rpc/provisioner.go b/packer/rpc/provisioner.go index 5236a0033..dbe366e56 100644 --- a/packer/rpc/provisioner.go +++ b/packer/rpc/provisioner.go @@ -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 } diff --git a/packer/rpc/provisioner_test.go b/packer/rpc/provisioner_test.go index bf027be99..56b3b80c4 100644 --- a/packer/rpc/provisioner_test.go +++ b/packer/rpc/provisioner_test.go @@ -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) {