diff --git a/internal/plans/changes_sync.go b/internal/plans/changes_sync.go index c346474708..18a2e9ff68 100644 --- a/internal/plans/changes_sync.go +++ b/internal/plans/changes_sync.go @@ -239,8 +239,9 @@ func (cs *ChangesSync) RemoveOutputChange(addr addrs.AbsOutputValue) { } } -// GetActionInvocation -func (cs *ChangesSync) GetActionInvocation(addr addrs.AbsActionInstance) *ActionInvocationInstance { +// GetActionInvocation gets an action invocation based on the action address, the triggering +// resource address, the action trigger block index, and the action list index. +func (cs *ChangesSync) GetActionInvocation(addr addrs.AbsActionInstance, triggeringResourceAddr addrs.AbsResourceInstance, triggerBlockIndex, actionListIndex int) *ActionInvocationInstance { if cs == nil { panic("GetActionInvocation on nil ChangesSync") } @@ -248,7 +249,7 @@ func (cs *ChangesSync) GetActionInvocation(addr addrs.AbsActionInstance) *Action defer cs.lock.Unlock() for _, a := range cs.changes.ActionInvocations { - if a.Addr.Equal(addr) { + if a.Addr.Equal(addr) && a.TriggeringResourceAddr.Equal(triggeringResourceAddr) && a.ActionTriggerBlockIndex == triggerBlockIndex && a.ActionsListIndex == actionListIndex { return a } } diff --git a/internal/terraform/node_action_apply.go b/internal/terraform/node_action_apply.go index 47a6423359..7cdd23b78c 100644 --- a/internal/terraform/node_action_apply.go +++ b/internal/terraform/node_action_apply.go @@ -46,8 +46,21 @@ func invokeActions(ctx EvalContext, actionInvocations []*plans.ActionInvocationI var diags tfdiags.Diagnostics // First we order the action invocations by their trigger block index and events list index. // This way we have the correct order of execution. - orderedActionInvocations := make([]*plans.ActionInvocationInstanceSrc, len(actionInvocations)) - copy(orderedActionInvocations, actionInvocations) + orderedActionInvocations := make([]*plans.ActionInvocationInstance, 0, len(actionInvocations)) + for _, invocation := range actionInvocations { + ai := ctx.Changes().GetActionInvocation(invocation.Addr, invocation.TriggeringResourceAddr, invocation.ActionTriggerBlockIndex, invocation.ActionsListIndex) + + if ai == nil { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + fmt.Sprintf("Failed to find action invocation instance %s in changes.", ai.Addr), + fmt.Sprintf("The action invocation instance %s was not found in the changes for %s.", ai.Addr, ai.TriggeringResourceAddr.String()), + )) + return diags + } + + orderedActionInvocations = append(orderedActionInvocations, ai) + } sort.Slice(orderedActionInvocations, func(i, j int) bool { if orderedActionInvocations[i].ActionTriggerBlockIndex == orderedActionInvocations[j].ActionTriggerBlockIndex { return orderedActionInvocations[i].ActionsListIndex < orderedActionInvocations[j].ActionsListIndex @@ -100,20 +113,11 @@ func invokeActions(ctx EvalContext, actionInvocations []*plans.ActionInvocationI return diags } - ais, err := ai.Decode(&actionSchema) - if err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - fmt.Sprintf("Failed to decode action data for %s", ai.Addr), - err.Error(), - )) - } - // We don't want to send the marks, but all marks are okay in the context of an action invocation. unmarkedConfigValue, _ := actionData.ConfigValue.UnmarkDeep() // Validate that what we planned matches the action data we have. - errs := objchange.AssertObjectCompatible(actionSchema.ConfigSchema, ais.ConfigValue, unmarkedConfigValue) + errs := objchange.AssertObjectCompatible(actionSchema.ConfigSchema, ai.ConfigValue, unmarkedConfigValue) for _, err := range errs { diags = diags.Append(tfdiags.Sourceless( tfdiags.Error,