From f40fdde708bacccff8a26d0577b0a6da65276fa6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 20 Jan 2017 20:21:12 -0800 Subject: [PATCH] terraform: PostProvision hook gets the error from the provision step --- terraform/context_apply_test.go | 40 +++++++++++++++++++++++++++++++++ terraform/eval_apply.go | 18 ++++++++------- terraform/hook.go | 4 ++-- terraform/hook_mock.go | 4 +++- terraform/hook_stop.go | 2 +- 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 0a483fe61..a96ac1a98 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -4043,6 +4043,46 @@ aws_instance.foo: } } +// Verify that a normal provisioner with on_failure "continue" records +// the error with the hook. +func TestContext2Apply_provisionerFailContinueHook(t *testing.T) { + h := new(MockHook) + m := testModule(t, "apply-provisioner-fail-continue") + p := testProvider("aws") + pr := testProvisioner() + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { + return fmt.Errorf("provisioner error") + } + + ctx := testContext2(t, &ContextOpts{ + Module: m, + Hooks: []Hook{h}, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + Provisioners: map[string]ResourceProvisionerFactory{ + "shell": testProvisionerFuncFixed(pr), + }, + }) + + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + if _, err := ctx.Apply(); err != nil { + t.Fatalf("err: %s", err) + } + + if !h.PostProvisionCalled { + t.Fatal("PostProvision not called") + } + if h.PostProvisionErrorArg == nil { + t.Fatal("should have error") + } +} + func TestContext2Apply_provisionerDestroy(t *testing.T) { m := testModule(t, "apply-provisioner-destroy") p := testProvider("aws") diff --git a/terraform/eval_apply.go b/terraform/eval_apply.go index fee44d37a..21c9ff832 100644 --- a/terraform/eval_apply.go +++ b/terraform/eval_apply.go @@ -307,6 +307,13 @@ func (n *EvalApplyProvisioners) apply(ctx EvalContext, provs []*config.Provision // Invoke the Provisioner output := CallbackUIOutput{OutputFn: outputFn} applyErr := provisioner.Apply(&output, state, provConfig) + + // Call post hook + hookErr := ctx.Hook(func(h Hook) (HookAction, error) { + return h.PostProvision(n.Info, prov.Type, applyErr) + }) + + // Handle the error before we deal with the hook if applyErr != nil { // Determine failure behavior switch prov.OnFailure { @@ -320,14 +327,9 @@ func (n *EvalApplyProvisioners) apply(ctx EvalContext, provs []*config.Provision } } - { - // Call post hook - err := ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostProvision(n.Info, prov.Type) - }) - if err != nil { - return err - } + // Deal with the hook + if hookErr != nil { + return hookErr } } diff --git a/terraform/hook.go b/terraform/hook.go index 81a68842f..ab11e8ee0 100644 --- a/terraform/hook.go +++ b/terraform/hook.go @@ -42,7 +42,7 @@ type Hook interface { PreProvisionResource(*InstanceInfo, *InstanceState) (HookAction, error) PostProvisionResource(*InstanceInfo, *InstanceState) (HookAction, error) PreProvision(*InstanceInfo, string) (HookAction, error) - PostProvision(*InstanceInfo, string) (HookAction, error) + PostProvision(*InstanceInfo, string, error) (HookAction, error) ProvisionOutput(*InstanceInfo, string, string) // PreRefresh and PostRefresh are called before and after a single @@ -92,7 +92,7 @@ func (*NilHook) PreProvision(*InstanceInfo, string) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostProvision(*InstanceInfo, string) (HookAction, error) { +func (*NilHook) PostProvision(*InstanceInfo, string, error) (HookAction, error) { return HookActionContinue, nil } diff --git a/terraform/hook_mock.go b/terraform/hook_mock.go index b0bb94e57..0e4640067 100644 --- a/terraform/hook_mock.go +++ b/terraform/hook_mock.go @@ -55,6 +55,7 @@ type MockHook struct { PostProvisionCalled bool PostProvisionInfo *InstanceInfo PostProvisionProvisionerId string + PostProvisionErrorArg error PostProvisionReturn HookAction PostProvisionError error @@ -170,13 +171,14 @@ func (h *MockHook) PreProvision(n *InstanceInfo, provId string) (HookAction, err return h.PreProvisionReturn, h.PreProvisionError } -func (h *MockHook) PostProvision(n *InstanceInfo, provId string) (HookAction, error) { +func (h *MockHook) PostProvision(n *InstanceInfo, provId string, err error) (HookAction, error) { h.Lock() defer h.Unlock() h.PostProvisionCalled = true h.PostProvisionInfo = n h.PostProvisionProvisionerId = provId + h.PostProvisionErrorArg = err return h.PostProvisionReturn, h.PostProvisionError } diff --git a/terraform/hook_stop.go b/terraform/hook_stop.go index 4c9bbb7b3..104d0098a 100644 --- a/terraform/hook_stop.go +++ b/terraform/hook_stop.go @@ -38,7 +38,7 @@ func (h *stopHook) PreProvision(*InstanceInfo, string) (HookAction, error) { return h.hook() } -func (h *stopHook) PostProvision(*InstanceInfo, string) (HookAction, error) { +func (h *stopHook) PostProvision(*InstanceInfo, string, error) (HookAction, error) { return h.hook() }