diff --git a/internal/terraform/context_apply_action_test.go b/internal/terraform/context_apply_action_test.go index a4edafdd3c..c8d81129a3 100644 --- a/internal/terraform/context_apply_action_test.go +++ b/internal/terraform/context_apply_action_test.go @@ -5,6 +5,7 @@ package terraform import ( "path/filepath" + "sync" "testing" "github.com/google/go-cmp/cmp" @@ -2563,7 +2564,7 @@ lifecycle { InvokeActionFn: invokeActionFn, } - hookCapture := actionHookCapture{} + hookCapture := newActionHookCapture() ctx := testContext2(t, &ContextOpts{ Providers: map[addrs.Provider]providers.Factory{ addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider), @@ -2654,10 +2655,17 @@ lifecycle { var _ Hook = (*actionHookCapture)(nil) type actionHookCapture struct { + mu *sync.Mutex startActionHooks []HookActionIdentity completeActionHooks []HookActionIdentity } +func newActionHookCapture() actionHookCapture { + return actionHookCapture{ + mu: &sync.Mutex{}, + } +} + func (a *actionHookCapture) PreApply(HookResourceIdentity, addrs.DeposedKey, plans.Action, cty.Value, cty.Value) (HookAction, error) { return HookActionContinue, nil } @@ -2741,6 +2749,8 @@ func (a *actionHookCapture) PostListQuery(HookResourceIdentity, plans.QueryResul } func (a *actionHookCapture) StartAction(identity HookActionIdentity) (HookAction, error) { + a.mu.Lock() + defer a.mu.Unlock() a.startActionHooks = append(a.startActionHooks, identity) return HookActionContinue, nil } @@ -2750,6 +2760,8 @@ func (a *actionHookCapture) ProgressAction(HookActionIdentity, string) (HookActi } func (a *actionHookCapture) CompleteAction(identity HookActionIdentity, _ error) (HookAction, error) { + a.mu.Lock() + defer a.mu.Unlock() a.completeActionHooks = append(a.completeActionHooks, identity) return HookActionContinue, nil } diff --git a/internal/terraform/node_action_trigger_instance_apply.go b/internal/terraform/node_action_trigger_instance_apply.go index eb631ee4c8..103b52efc2 100644 --- a/internal/terraform/node_action_trigger_instance_apply.go +++ b/internal/terraform/node_action_trigger_instance_apply.go @@ -136,9 +136,12 @@ func (n *nodeActionTriggerApplyInstance) Execute(ctx EvalContext, wo walkOperati ActionTrigger: ai.ActionTrigger, } - ctx.Hook(func(h Hook) (HookAction, error) { + diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { return h.StartAction(hookIdentity) - }) + })) + if diags.HasErrors() { + return diags + } // We don't want to send the marks, but all marks are okay in the context // of an action invocation. We can't reuse our ephemeral free value from @@ -153,9 +156,9 @@ func (n *nodeActionTriggerApplyInstance) Execute(ctx EvalContext, wo walkOperati respDiags := n.AddSubjectToDiagnostics(resp.Diagnostics) diags = diags.Append(respDiags) if respDiags.HasErrors() { - ctx.Hook(func(h Hook) (HookAction, error) { + diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { return h.CompleteAction(hookIdentity, respDiags.Err()) - }) + })) return diags } @@ -163,18 +166,24 @@ func (n *nodeActionTriggerApplyInstance) Execute(ctx EvalContext, wo walkOperati for event := range resp.Events { switch ev := event.(type) { case providers.InvokeActionEvent_Progress: - ctx.Hook(func(h Hook) (HookAction, error) { + diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { return h.ProgressAction(hookIdentity, ev.Message) - }) + })) + if diags.HasErrors() { + return diags + } case providers.InvokeActionEvent_Completed: // Enhance the diagnostics diags = diags.Append(n.AddSubjectToDiagnostics(ev.Diagnostics)) - ctx.Hook(func(h Hook) (HookAction, error) { + diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { return h.CompleteAction(hookIdentity, ev.Diagnostics.Err()) - }) + })) if ev.Diagnostics.HasErrors() { return diags } + if diags.HasErrors() { + return diags + } default: panic(fmt.Sprintf("unexpected action event type %T", ev)) }