Commit e5a7fc6b authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer: Provisioner/Hook can have errors returned

parent 5a9a993c
...@@ -12,7 +12,7 @@ const HookProvision = "packer_provision" ...@@ -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 // in. In addition to that, the Hook is given access to a UI so that it can
// output things to the user. // output things to the user.
type Hook interface { type Hook interface {
Run(string, Ui, Communicator, interface{}) Run(string, Ui, Communicator, interface{}) error
} }
// A Hook implementation that dispatches based on an internal mapping. // A Hook implementation that dispatches based on an internal mapping.
...@@ -23,14 +23,18 @@ type DispatchHook struct { ...@@ -23,14 +23,18 @@ type DispatchHook struct {
// Runs the hook with the given name by dispatching it to the proper // 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 // hooks if a mapping exists. If a mapping doesn't exist, then nothing
// happens. // 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] hooks, ok := h.Mapping[name]
if !ok { if !ok {
// No hooks for that name. No problem. // No hooks for that name. No problem.
return return nil
} }
for _, hook := range hooks { for _, hook := range hooks {
hook.Run(name, ui, comm, data) if err := hook.Run(name, ui, comm, data); err != nil {
return err
}
} }
return nil
} }
...@@ -13,12 +13,13 @@ type TestHook struct { ...@@ -13,12 +13,13 @@ type TestHook struct {
runUi Ui 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.runCalled = true
t.runComm = comm t.runComm = comm
t.runData = data t.runData = data
t.runName = name t.runName = name
t.runUi = ui t.runUi = ui
return nil
} }
func TestDispatchHook_Implements(t *testing.T) { func TestDispatchHook_Implements(t *testing.T) {
......
...@@ -10,13 +10,13 @@ type cmdHook struct { ...@@ -10,13 +10,13 @@ type cmdHook struct {
client *Client 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() { defer func() {
r := recover() r := recover()
c.checkExit(r, nil) 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()) { func (c *cmdHook) checkExit(p interface{}, cb func()) {
......
...@@ -8,7 +8,9 @@ import ( ...@@ -8,7 +8,9 @@ import (
type helperHook byte 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) { func TestHook_NoExist(t *testing.T) {
c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")}) c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")})
......
...@@ -19,13 +19,13 @@ func (c *cmdProvisioner) Prepare(configs ...interface{}) error { ...@@ -19,13 +19,13 @@ func (c *cmdProvisioner) Prepare(configs ...interface{}) error {
return c.p.Prepare(configs...) 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() { defer func() {
r := recover() r := recover()
c.checkExit(r, nil) c.checkExit(r, nil)
}() }()
c.p.Provision(ui, comm) return c.p.Provision(ui, comm)
} }
func (c *cmdProvisioner) checkExit(p interface{}, cb func()) { func (c *cmdProvisioner) checkExit(p interface{}, cb func()) {
......
...@@ -12,7 +12,9 @@ func (helperProvisioner) Prepare(...interface{}) error { ...@@ -12,7 +12,9 @@ func (helperProvisioner) Prepare(...interface{}) error {
return nil 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) { func TestProvisioner_NoExist(t *testing.T) {
c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")}) c := NewClient(&ClientConfig{Cmd: exec.Command("i-should-not-exist")})
......
...@@ -12,7 +12,7 @@ type Provisioner interface { ...@@ -12,7 +12,7 @@ type Provisioner interface {
// given to communicate with the user, and a communicator is given that // given to communicate with the user, and a communicator is given that
// is guaranteed to be connected to some machine so that provisioning // is guaranteed to be connected to some machine so that provisioning
// can be done. // can be done.
Provision(Ui, Communicator) Provision(Ui, Communicator) error
} }
// A Hook implementation that runs the given provisioners. // A Hook implementation that runs the given provisioners.
...@@ -23,8 +23,12 @@ type ProvisionHook struct { ...@@ -23,8 +23,12 @@ type ProvisionHook struct {
} }
// Runs the provisioners in order. // 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 { for _, p := range h.Provisioners {
p.Provision(ui, comm) if err := p.Provision(ui, comm); err != nil {
return err
}
} }
return nil
} }
...@@ -14,8 +14,9 @@ func (t *TestProvisioner) Prepare(configs ...interface{}) error { ...@@ -14,8 +14,9 @@ func (t *TestProvisioner) Prepare(configs ...interface{}) error {
return nil return nil
} }
func (t *TestProvisioner) Provision(Ui, Communicator) { func (t *TestProvisioner) Provision(Ui, Communicator) error {
t.provCalled = true t.provCalled = true
return nil
} }
func TestProvisionHook_Impl(t *testing.T) { func TestProvisionHook_Impl(t *testing.T) {
......
...@@ -27,15 +27,14 @@ func Hook(client *rpc.Client) *hook { ...@@ -27,15 +27,14 @@ func Hook(client *rpc.Client) *hook {
return &hook{client} 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() server := rpc.NewServer()
RegisterCommunicator(server, comm) RegisterCommunicator(server, comm)
RegisterUi(server, ui) RegisterUi(server, ui)
address := serveSingleConn(server) address := serveSingleConn(server)
args := &HookRunArgs{name, data, address} args := &HookRunArgs{name, data, address}
h.client.Call("Hook.Run", args, new(interface{})) return h.client.Call("Hook.Run", args, new(interface{}))
return
} }
func (h *HookServer) Run(args *HookRunArgs, reply *interface{}) error { func (h *HookServer) Run(args *HookRunArgs, reply *interface{}) error {
...@@ -44,7 +43,9 @@ func (h *HookServer) Run(args *HookRunArgs, reply *interface{}) error { ...@@ -44,7 +43,9 @@ func (h *HookServer) Run(args *HookRunArgs, reply *interface{}) error {
return err 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 *reply = nil
return nil return nil
......
...@@ -12,8 +12,9 @@ type testHook struct { ...@@ -12,8 +12,9 @@ type testHook struct {
runUi packer.Ui 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 h.runCalled = true
return nil
} }
func TestHookRPC(t *testing.T) { func TestHookRPC(t *testing.T) {
......
...@@ -37,14 +37,14 @@ func (p *provisioner) Prepare(configs ...interface{}) (err error) { ...@@ -37,14 +37,14 @@ func (p *provisioner) Prepare(configs ...interface{}) (err error) {
return 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 // TODO: Error handling
server := rpc.NewServer() server := rpc.NewServer()
RegisterCommunicator(server, comm) RegisterCommunicator(server, comm)
RegisterUi(server, ui) RegisterUi(server, ui)
args := &ProvisionerProvisionArgs{serveSingleConn(server)} 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 { func (p *ProvisionerServer) Prepare(args *ProvisionerPrepareArgs, reply *error) error {
...@@ -65,6 +65,9 @@ func (p *ProvisionerServer) Provision(args *ProvisionerProvisionArgs, reply *int ...@@ -65,6 +65,9 @@ func (p *ProvisionerServer) Provision(args *ProvisionerProvisionArgs, reply *int
comm := Communicator(client) comm := Communicator(client)
ui := &Ui{client} ui := &Ui{client}
p.p.Provision(ui, comm) if err := p.p.Provision(ui, comm); err != nil {
return NewBasicError(err)
}
return nil return nil
} }
...@@ -21,10 +21,11 @@ func (p *testProvisioner) Prepare(configs ...interface{}) error { ...@@ -21,10 +21,11 @@ func (p *testProvisioner) Prepare(configs ...interface{}) error {
return nil 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.provCalled = true
p.provComm = comm p.provComm = comm
p.provUi = ui p.provUi = ui
return nil
} }
func TestProvisionerRPC(t *testing.T) { func TestProvisionerRPC(t *testing.T) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment