From ad4371342f32765fd7d2cd6ed42c39de4db23d75 Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Tue, 2 Sep 2025 11:28:25 +0200 Subject: [PATCH] track partial expanded action invocations through deferred action invocation like we do it for resources just simpler because we don't have layered addrs maps --- internal/addrs/partial_expanded.go | 10 ++ .../command/jsonplan/action_invocations.go | 95 ---------- internal/command/jsonplan/plan.go | 8 - internal/plans/action_invocation.go | 164 ------------------ internal/plans/deferring.go | 50 ------ internal/plans/deferring/deferred.go | 43 +---- internal/plans/plan.go | 15 +- internal/terraform/context_plan.go | 24 --- .../terraform/context_plan_actions_test.go | 17 +- .../node_action_trigger_partialexp.go | 8 +- 10 files changed, 27 insertions(+), 407 deletions(-) diff --git a/internal/addrs/partial_expanded.go b/internal/addrs/partial_expanded.go index 673f226525..057025c69d 100644 --- a/internal/addrs/partial_expanded.go +++ b/internal/addrs/partial_expanded.go @@ -924,6 +924,16 @@ func (a *AbsAction) UnexpandedAction(action Action) PartialExpandedAction { } } +// UnknownActionInstance returns an [AbsActionInstance] that represents the +// same action as the receiver but with all instance keys replaced with a +// wildcard value. +func (per PartialExpandedAction) UnknownActionInstance() AbsActionInstance { + return AbsActionInstance{ + Module: per.module.UnknownModuleInstance(), + Action: per.action.Instance(WildcardKey), + } +} + func (pea PartialExpandedAction) String() string { moduleAddr := pea.module.String() if len(moduleAddr) != 0 { diff --git a/internal/command/jsonplan/action_invocations.go b/internal/command/jsonplan/action_invocations.go index 364a9da84f..9f15db30ef 100644 --- a/internal/command/jsonplan/action_invocations.go +++ b/internal/command/jsonplan/action_invocations.go @@ -234,98 +234,3 @@ func MarshalDeferredActionInvocations(dais []*plans.DeferredActionInvocationSrc, } return deferredInvocations, nil } - -func MarshalDeferredPartialActionInvocations(dais []*plans.DeferredPartialExpandedActionInvocationSrc, schemas *terraform.Schemas) ([]DeferredActionInvocation, error) { - var deferredInvocations []DeferredActionInvocation - - for _, daiSrc := range dais { - ai, err := MarshalPartialActionInvocation(daiSrc.ActionInvocationInstanceSrc, schemas) - if err != nil { - return nil, err - } - - dai := DeferredActionInvocation{ - ActionInvocation: ai, - } - switch daiSrc.DeferredReason { - case providers.DeferredReasonInstanceCountUnknown: - dai.Reason = DeferredReasonInstanceCountUnknown - case providers.DeferredReasonResourceConfigUnknown: - dai.Reason = DeferredReasonResourceConfigUnknown - case providers.DeferredReasonProviderConfigUnknown: - dai.Reason = DeferredReasonProviderConfigUnknown - case providers.DeferredReasonAbsentPrereq: - dai.Reason = DeferredReasonAbsentPrereq - case providers.DeferredReasonDeferredPrereq: - dai.Reason = DeferredReasonDeferredPrereq - default: - // If we find a reason we don't know about, we'll just mark it as - // unknown. This is a bit of a safety net to ensure that we don't - // break if new reasons are introduced in future versions of the - // provider protocol. - dai.Reason = DeferredReasonUnknown - } - - deferredInvocations = append(deferredInvocations, dai) - } - return deferredInvocations, nil -} - -func MarshalPartialActionInvocation(action *plans.PartialExpandedActionInvocationInstanceSrc, schemas *terraform.Schemas) (ActionInvocation, error) { - ai := ActionInvocation{ - Address: action.Addr.String(), - Type: action.Addr.ConfigAction().Action.Type, - Name: action.Addr.ConfigAction().Action.Name, - ProviderName: action.ProviderAddr.Provider.String(), - } - schema := schemas.ActionTypeConfig( - action.ProviderAddr.Provider, - action.Addr.ConfigAction().Action.Type, - ) - if schema.ConfigSchema == nil { - return ai, fmt.Errorf("no schema found for %s (in provider %s)", action.Addr.ConfigAction().Action.Type, action.ProviderAddr.Provider) - } - - actionDec, err := action.Decode(&schema) - if err != nil { - return ai, fmt.Errorf("failed to decode action %s: %w", action.Addr, err) - } - - switch at := action.ActionTrigger.(type) { - case plans.PartialLifecycleActionTrigger: - ai.LifecycleActionTrigger = &LifecycleActionTrigger{ - TriggeringResourceAddress: at.TriggeringResourceAddr.String(), - ActionTriggerEvent: at.TriggerEvent().String(), - ActionTriggerBlockIndex: at.ActionTriggerBlockIndex, - ActionsListIndex: at.ActionsListIndex, - } - default: - return ai, fmt.Errorf("unsupported action trigger type: %T", at) - } - - if actionDec.ConfigValue != cty.NilVal { - _, pvms := actionDec.ConfigValue.UnmarkDeepWithPaths() - sensitivePaths, otherMarks := marks.PathsWithMark(pvms, marks.Sensitive) - ephemeralPaths, otherMarks := marks.PathsWithMark(otherMarks, marks.Ephemeral) - if len(ephemeralPaths) > 0 { - return ai, fmt.Errorf("action %s has ephemeral config values, which are not supported in action invocations", action.Addr) - } - if len(otherMarks) > 0 { - return ai, fmt.Errorf("action %s has config values with unsupported marks: %v", action.Addr, otherMarks) - } - - configValue := actionDec.ConfigValue - if !configValue.IsWhollyKnown() { - configValue = omitUnknowns(actionDec.ConfigValue) - } - cs := jsonstate.SensitiveAsBool(marks.MarkPaths(configValue, marks.Sensitive, sensitivePaths)) - configSensitive, err := ctyjson.Marshal(cs, cs.Type()) - if err != nil { - return ai, err - } - - ai.ConfigValues = marshalConfigValues(configValue) - ai.ConfigSensitive = configSensitive - } - return ai, nil -} diff --git a/internal/command/jsonplan/plan.go b/internal/command/jsonplan/plan.go index 637b0ed4ed..62f9d8c641 100644 --- a/internal/command/jsonplan/plan.go +++ b/internal/command/jsonplan/plan.go @@ -320,14 +320,6 @@ func Marshal( } } - if p.DeferredPartialActionInvocations != nil { - deferredPartialActionInvocations, err := MarshalDeferredPartialActionInvocations(p.DeferredPartialActionInvocations, schemas) - if err != nil { - return nil, fmt.Errorf("error in marshaling deferred partial action invocations: %s", err) - } - output.DeferredActionInvocations = append(output.DeferredActionInvocations, deferredPartialActionInvocations...) - } - // output.OutputChanges if output.OutputChanges, err = MarshalOutputChanges(p.Changes); err != nil { return nil, fmt.Errorf("error in marshaling output changes: %s", err) diff --git a/internal/plans/action_invocation.go b/internal/plans/action_invocation.go index d50c71d09b..d28e5e6094 100644 --- a/internal/plans/action_invocation.go +++ b/internal/plans/action_invocation.go @@ -180,167 +180,3 @@ func (ai *ActionInvocationInstance) DeepCopy() *ActionInvocationInstance { ret := *ai return &ret } - -// PartialActionTrigger is the equivalent of ActionTrigger but allows the -// triggering address to be only partially expanded. This is used during earlier -// phases of planning when (for example) count/for_each expansions are not yet -// fully resolved. -type PartialActionTrigger interface { - partialActionTriggerSigil() - - TriggerEvent() configs.ActionTriggerEvent - - String() string - - Equals(other PartialActionTrigger) bool -} - -// PartialLifecycleActionTrigger is the partial-expanded form of -// LifecycleActionTrigger. It differs only in that it stores a partial-expanded -// resource instance address for the triggering resource. -type PartialLifecycleActionTrigger struct { - TriggeringResourceAddr addrs.PartialExpandedResource - ActionTriggerEvent configs.ActionTriggerEvent - ActionTriggerBlockIndex int - ActionsListIndex int -} - -func (t PartialLifecycleActionTrigger) partialActionTriggerSigil() {} - -func (t PartialLifecycleActionTrigger) TriggerEvent() configs.ActionTriggerEvent { - return t.ActionTriggerEvent -} - -func (t PartialLifecycleActionTrigger) String() string { - return t.TriggeringResourceAddr.String() -} - -func (t PartialLifecycleActionTrigger) Equals(other PartialActionTrigger) bool { - o, ok := other.(*PartialLifecycleActionTrigger) - if !ok { - return false - } - pomt, tIsPartial := t.TriggeringResourceAddr.PartialExpandedModule() - pemo, oIsPartial := o.TriggeringResourceAddr.PartialExpandedModule() - - if tIsPartial != oIsPartial { - return false - } - - return pomt.MatchesPartial(pemo) && t.TriggeringResourceAddr.Resource().Equal(o.TriggeringResourceAddr.Resource()) && - t.ActionTriggerEvent == o.ActionTriggerEvent && - t.ActionTriggerBlockIndex == o.ActionTriggerBlockIndex && - t.ActionsListIndex == o.ActionsListIndex -} - -var _ PartialActionTrigger = (*PartialLifecycleActionTrigger)(nil) - -// PartialExpandedActionInvocationInstance mirrors ActionInvocationInstance -// but keeps the action and/or trigger resource addresses in a -// partial-expanded form until all dynamic expansions (count, for_each, etc.) -// are resolved. -type PartialExpandedActionInvocationInstance struct { - Addr addrs.PartialExpandedAction - ActionTrigger PartialActionTrigger - ProviderAddr addrs.AbsProviderConfig - ConfigValue cty.Value -} - -// DeepCopy creates a defensive copy of the partial-expanded invocation. -func (pii *PartialExpandedActionInvocationInstance) DeepCopy() *PartialExpandedActionInvocationInstance { - if pii == nil { - return pii - } - ret := *pii - return &ret -} - -// Equals compares two partial-expanded invocation instances. -func (pii *PartialExpandedActionInvocationInstance) Equals(other *PartialExpandedActionInvocationInstance) bool { - if pii == nil || other == nil { - return pii == other - } - // We compare the (partial) action address and the trigger (which may also - // embed a partial address). - addrEqual := pii.Addr.Equal(other.Addr) - triggerEqual := false - if pii.ActionTrigger == nil && other.ActionTrigger == nil { - triggerEqual = true - } else if pii.ActionTrigger != nil && other.ActionTrigger != nil { - triggerEqual = pii.ActionTrigger.Equals(other.ActionTrigger) - } - return addrEqual && triggerEqual -} - -type PartialExpandedActionInvocationInstanceSrc struct { - Addr addrs.PartialExpandedAction - ActionTrigger PartialActionTrigger - ProviderAddr addrs.AbsProviderConfig - ConfigValue DynamicValue - SensitiveConfigPaths []cty.Path -} - -// Encode produces a variant of the receiver that has its config value -// serialized so it can be written to a plan file while action and trigger -// addresses are still in their partial-expanded form. Pass the implied type -// of the corresponding action schema for correct operation. -func (pii *PartialExpandedActionInvocationInstance) Encode(schema *providers.ActionSchema) (*PartialExpandedActionInvocationInstanceSrc, error) { - ret := &PartialExpandedActionInvocationInstanceSrc{ - Addr: pii.Addr, - ActionTrigger: pii.ActionTrigger, - ProviderAddr: pii.ProviderAddr, - } - - if pii.ConfigValue != cty.NilVal { - ty := cty.DynamicPseudoType - if schema != nil { - ty = schema.ConfigSchema.ImpliedType() - } - - unmarkedConfigValue, pvms := pii.ConfigValue.UnmarkDeepWithPaths() - sensitivePaths, otherMarks := marks.PathsWithMark(pvms, marks.Sensitive) - if len(otherMarks) > 0 { - return nil, fmt.Errorf("%s: error serializing partial-expanded action invocation with unexpected marks on config value: %#v. This is a bug in Terraform.", tfdiags.FormatCtyPath(otherMarks[0].Path), otherMarks[0].Marks) - } - - var err error - ret.ConfigValue, err = NewDynamicValue(unmarkedConfigValue, ty) - ret.SensitiveConfigPaths = sensitivePaths - if err != nil { - return nil, err - } - } - - return ret, nil -} - -// Decode produces an in-memory form of the serialized partial-expanded action -// invocation instance using the provided schema to infer the original config -// value type. -func (src *PartialExpandedActionInvocationInstanceSrc) Decode(schema *providers.ActionSchema) (*PartialExpandedActionInvocationInstance, error) { - ret := &PartialExpandedActionInvocationInstance{ - Addr: src.Addr, - ActionTrigger: src.ActionTrigger, - ProviderAddr: src.ProviderAddr, - } - - if src.ConfigValue != nil { - ty := cty.DynamicPseudoType - if schema != nil { - ty = schema.ConfigSchema.ImpliedType() - } - - val, err := src.ConfigValue.Decode(ty) - if err != nil { - return nil, err - } - - if len(src.SensitiveConfigPaths) > 0 { - val = marks.MarkPaths(val, marks.Sensitive, src.SensitiveConfigPaths) - } - - ret.ConfigValue = val - } - - return ret, nil -} diff --git a/internal/plans/deferring.go b/internal/plans/deferring.go index ec6a38b86a..2ead6dee54 100644 --- a/internal/plans/deferring.go +++ b/internal/plans/deferring.go @@ -96,53 +96,3 @@ func (dais *DeferredActionInvocationSrc) Decode(schema *providers.ActionSchema) ActionInvocationInstance: instance, }, nil } - -// DeferredPartialExpandedActionInvocation tracks information about an action -// invocation that has been deferred for some reason, where the underlying -// ActionInvocationInstance contains a partially expanded address (and -// LifecycleActionTrigger). -type DeferredPartialExpandedActionInvocation struct { - // DeferredReason is the reason why this action invocation was deferred. - DeferredReason providers.DeferredReason - - // ActionInvocationInstance is the (partially expanded) instance of the action - // invocation that was deferred. Its Addr (and any embedded - // LifecycleActionTrigger addresses) are partial. - ActionInvocationInstance *PartialExpandedActionInvocationInstance -} - -func (dai *DeferredPartialExpandedActionInvocation) Encode(schema *providers.ActionSchema) (*DeferredPartialExpandedActionInvocationSrc, error) { - src, err := dai.ActionInvocationInstance.Encode(schema) - if err != nil { - return nil, err - } - - return &DeferredPartialExpandedActionInvocationSrc{ - DeferredReason: dai.DeferredReason, - ActionInvocationInstanceSrc: src, - }, nil -} - -// DeferredPartialExpandedActionInvocationSrc is the serialized form of -// DeferredPartialExpandedActionInvocation. -type DeferredPartialExpandedActionInvocationSrc struct { - // DeferredReason is the reason why this action invocation was deferred. - DeferredReason providers.DeferredReason - - // ActionInvocationInstanceSrc is the (partially expanded) instance of the - // action invocation that was deferred. Its Addr (and any embedded - // LifecycleActionTrigger addresses) are partial. - ActionInvocationInstanceSrc *PartialExpandedActionInvocationInstanceSrc -} - -func (dais *DeferredPartialExpandedActionInvocationSrc) Decode(schema *providers.ActionSchema) (*DeferredPartialExpandedActionInvocation, error) { - instance, err := dais.ActionInvocationInstanceSrc.Decode(schema) - if err != nil { - return nil, err - } - - return &DeferredPartialExpandedActionInvocation{ - DeferredReason: dais.DeferredReason, - ActionInvocationInstance: instance, - }, nil -} diff --git a/internal/plans/deferring/deferred.go b/internal/plans/deferring/deferred.go index c50a6722b4..e5d89122a6 100644 --- a/internal/plans/deferring/deferred.go +++ b/internal/plans/deferring/deferred.go @@ -136,19 +136,6 @@ type Deferred struct { // instance should be considered deferred. partialExpandedActionsDeferred addrs.Map[addrs.ConfigAction, addrs.Map[addrs.PartialExpandedAction, providers.DeferredReason]] - // partialExpandedActionInvocationsDeferred tracks action invocation evaluations - // whose concrete action instance addresses could not yet be fully determined - // (for example because the action block contains for_each / count style - // expressions, or references values that depend on other deferred changes). - // - // Each element mirrors (in a more lightweight form) the information we - // retain for fully-expanded deferred action invocations, but is specific - // to the partially-expanded (wildcard / unknown) address space. Once the - // address space becomes concrete in a subsequent planning round the - // corresponding concrete action invocations will either be planned or - // recorded in actionInvocationDeferred instead. - partialExpandedActionInvocationsDeferred []*plans.DeferredPartialExpandedActionInvocation - // partialExpandedModulesDeferred tracks all of the partial-expanded module // prefixes we were notified about. // @@ -180,7 +167,6 @@ func NewDeferred(enabled bool) *Deferred { partialExpandedDataSourcesDeferred: addrs.MakeMap[addrs.ConfigResource, addrs.Map[addrs.PartialExpandedResource, *plans.DeferredResourceInstanceChange]](), partialExpandedEphemeralResourceDeferred: addrs.MakeMap[addrs.ConfigResource, addrs.Map[addrs.PartialExpandedResource, *plans.DeferredResourceInstanceChange]](), partialExpandedActionsDeferred: addrs.MakeMap[addrs.ConfigAction, addrs.Map[addrs.PartialExpandedAction, providers.DeferredReason]](), - partialExpandedActionInvocationsDeferred: []*plans.DeferredPartialExpandedActionInvocation{}, partialExpandedModulesDeferred: addrs.MakeSet[addrs.PartialExpandedModule](), } } @@ -222,11 +208,6 @@ func (d *Deferred) GetDeferredActionInvocations() []*plans.DeferredActionInvocat return d.actionInvocationDeferred } -// GetDeferredPartialActionInvocations returns a list of all deferred partial action invocations. -func (d *Deferred) GetDeferredPartialActionInvocations() []*plans.DeferredPartialExpandedActionInvocation { - return d.partialExpandedActionInvocationsDeferred -} - // SetExternalDependencyDeferred modifies a freshly-constructed [Deferred] // so that it will consider all resource instances as needing their actions // deferred, even if there's no other reason to do that. @@ -268,8 +249,7 @@ func (d *Deferred) HaveAnyDeferrals() bool { d.partialExpandedDataSourcesDeferred.Len() != 0 || d.partialExpandedEphemeralResourceDeferred.Len() != 0 || d.partialExpandedActionsDeferred.Len() != 0 || - len(d.partialExpandedModulesDeferred) != 0 || - len(d.partialExpandedActionInvocationsDeferred) != 0) + len(d.partialExpandedModulesDeferred) != 0) } // GetDeferredResourceInstanceValue returns the deferred value for the given @@ -749,27 +729,6 @@ func (d *Deferred) ReportActionDeferred(addr addrs.AbsActionInstance, reason pro configMap.Put(addr, reason) } -func (d *Deferred) ReportPartialActionInvocationDeferred(ai plans.PartialExpandedActionInvocationInstance, reason providers.DeferredReason) { - d.mu.Lock() - defer d.mu.Unlock() - - // Check if the action invocation is already deferred - for _, deferred := range d.partialExpandedActionInvocationsDeferred { - if deferred.ActionInvocationInstance.Equals(&ai) { - // This indicates a bug in the caller, since our graph walk should - // ensure that we visit and evaluate each distinct action invocation - // only once. - panic(fmt.Sprintf("duplicate deferral report for action %s invoked by %s", ai.Addr.String(), ai.ActionTrigger.TriggerEvent().String())) - } - } - - d.partialExpandedActionInvocationsDeferred = append(d.partialExpandedActionInvocationsDeferred, &plans.DeferredPartialExpandedActionInvocation{ - ActionInvocationInstance: &ai, - DeferredReason: reason, - }) - -} - // ShouldDeferActionInvocation returns true if there is a reason to defer the action invocation instance // We want to defer an action invocation if // a) the resource was deferred diff --git a/internal/plans/plan.go b/internal/plans/plan.go index 51db276764..42a1ba4851 100644 --- a/internal/plans/plan.go +++ b/internal/plans/plan.go @@ -66,14 +66,13 @@ type Plan struct { VariableMarks map[string][]cty.PathValueMarks ApplyTimeVariables collections.Set[string] - Changes *ChangesSrc - DriftedResources []*ResourceInstanceChangeSrc - DeferredResources []*DeferredResourceInstanceChangeSrc - DeferredActionInvocations []*DeferredActionInvocationSrc - DeferredPartialActionInvocations []*DeferredPartialExpandedActionInvocationSrc - TargetAddrs []addrs.Targetable - ActionTargetAddrs []addrs.Targetable - ForceReplaceAddrs []addrs.AbsResourceInstance + Changes *ChangesSrc + DriftedResources []*ResourceInstanceChangeSrc + DeferredResources []*DeferredResourceInstanceChangeSrc + DeferredActionInvocations []*DeferredActionInvocationSrc + TargetAddrs []addrs.Targetable + ActionTargetAddrs []addrs.Targetable + ForceReplaceAddrs []addrs.AbsResourceInstance Backend Backend StateStore StateStore diff --git a/internal/terraform/context_plan.go b/internal/terraform/context_plan.go index f7cf1cc31d..cf1ea9a196 100644 --- a/internal/terraform/context_plan.go +++ b/internal/terraform/context_plan.go @@ -885,10 +885,6 @@ func (c *Context) planWalk(config *configs.Config, prevRunState *states.State, o deferredActionInvocations, deferredActionInvocationsDiags := c.deferredActionInvocations(schemas, walker.Deferrals.GetDeferredActionInvocations()) diags = diags.Append(deferredActionInvocationsDiags) plan.DeferredActionInvocations = deferredActionInvocations - - deferredPartialActionInvocations, deferredPartialActionInvocationsDiags := c.deferredPartialActionInvocations(schemas, walker.Deferrals.GetDeferredPartialActionInvocations()) - diags = diags.Append(deferredPartialActionInvocationsDiags) - plan.DeferredPartialActionInvocations = deferredPartialActionInvocations } // Our final rulings on whether the plan is "complete" and "applyable". @@ -977,26 +973,6 @@ func (c *Context) deferredActionInvocations(schemas *Schemas, deferrals []*plans return deferredActionInvocations, diags } -func (c *Context) deferredPartialActionInvocations(schemas *Schemas, deferrals []*plans.DeferredPartialExpandedActionInvocation) ([]*plans.DeferredPartialExpandedActionInvocationSrc, tfdiags.Diagnostics) { - var deferredPartialActionInvocations []*plans.DeferredPartialExpandedActionInvocationSrc - var diags tfdiags.Diagnostics - for _, deferral := range deferrals { - schema := schemas.ActionTypeConfig(deferral.ActionInvocationInstance.ProviderAddr.Provider, deferral.ActionInvocationInstance.Addr.ConfigAction().Action.Type) - deferralSrc, err := deferral.Encode(&schema) - if err != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - "Failed to prepare deferred partial action invocation for plan", - fmt.Sprintf("The deferred partial action invocation %q could not be serialized to store in the plan: %s.", deferral.ActionInvocationInstance.Addr, err))) - continue - } - - deferredPartialActionInvocations = append(deferredPartialActionInvocations, deferralSrc) - } - - return deferredPartialActionInvocations, diags -} - func (c *Context) planGraph(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*Graph, walkOperation, tfdiags.Diagnostics) { var externalProviderConfigs map[addrs.RootProviderConfig]providers.Interface if opts != nil { diff --git a/internal/terraform/context_plan_actions_test.go b/internal/terraform/context_plan_actions_test.go index e3d699ea87..39389f1bff 100644 --- a/internal/terraform/context_plan_actions_test.go +++ b/internal/terraform/context_plan_actions_test.go @@ -2912,14 +2912,10 @@ resource "other_object" "a" { t.Fatalf("expected 0 planned action invocations, got %d", got) } - if got := len(p.DeferredActionInvocations); got != 0 { - t.Fatalf("expected 0 deferred action invocations, got %d", got) - } - - if got := len(p.DeferredPartialActionInvocations); got != 1 { + if got := len(p.DeferredActionInvocations); got != 1 { t.Fatalf("expected 1 deferred action invocations, got %d", got) } - ac, err := p.DeferredPartialActionInvocations[0].Decode(&unlinkedActionSchema) + ac, err := p.DeferredActionInvocations[0].Decode(&unlinkedActionSchema) if err != nil { t.Fatalf("error decoding action invocation: %s", err) } @@ -2990,15 +2986,12 @@ resource "other_object" "a" { if len(p.Changes.ActionInvocations) != 0 { t.Fatalf("expected 0 planned action invocations, got %d", len(p.Changes.ActionInvocations)) } - if got := len(p.DeferredActionInvocations); got != 0 { - t.Fatalf("expected 0 deferred action invocations, got %d", got) - } - if len(p.DeferredPartialActionInvocations) != 1 { - t.Fatalf("expected 1 deferred partial action invocations, got %d", len(p.DeferredPartialActionInvocations)) + if len(p.DeferredActionInvocations) != 1 { + t.Fatalf("expected 1 deferred partial action invocations, got %d", len(p.DeferredActionInvocations)) } - ac, err := p.DeferredPartialActionInvocations[0].Decode(&unlinkedActionSchema) + ac, err := p.DeferredActionInvocations[0].Decode(&unlinkedActionSchema) if err != nil { t.Fatalf("error decoding action invocation: %s", err) } diff --git a/internal/terraform/node_action_trigger_partialexp.go b/internal/terraform/node_action_trigger_partialexp.go index c18d52efb7..de1b408879 100644 --- a/internal/terraform/node_action_trigger_partialexp.go +++ b/internal/terraform/node_action_trigger_partialexp.go @@ -114,11 +114,11 @@ func (n *NodeActionTriggerPartialExpanded) Execute(ctx EvalContext, op walkOpera return diags } - ctx.Deferrals().ReportPartialActionInvocationDeferred(plans.PartialExpandedActionInvocationInstance{ - Addr: n.addr, + ctx.Deferrals().ReportActionInvocationDeferred(plans.ActionInvocationInstance{ + Addr: n.addr.UnknownActionInstance(), ProviderAddr: n.resolvedProvider, - ActionTrigger: plans.PartialLifecycleActionTrigger{ - TriggeringResourceAddr: n.lifecycleActionTrigger.resourceAddress, + ActionTrigger: &plans.LifecycleActionTrigger{ + TriggeringResourceAddr: n.lifecycleActionTrigger.resourceAddress.UnknownResourceInstance(), ActionTriggerEvent: *triggeringEvent, ActionTriggerBlockIndex: n.lifecycleActionTrigger.actionTriggerBlockIndex, ActionsListIndex: n.lifecycleActionTrigger.actionListIndex,