diff --git a/internal/terraform/node_resource_abstract_instance.go b/internal/terraform/node_resource_abstract_instance.go index 47cad41787..ad4366984f 100644 --- a/internal/terraform/node_resource_abstract_instance.go +++ b/internal/terraform/node_resource_abstract_instance.go @@ -368,8 +368,9 @@ func (n *NodeAbstractResourceInstance) writeResourceInstanceStateImpl(ctx EvalCo } // planDestroy returns a plain destroy diff. -func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState *states.ResourceInstanceObject, deposedKey states.DeposedKey) (*plans.ResourceInstanceChange, tfdiags.Diagnostics) { +func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState *states.ResourceInstanceObject, deposedKey states.DeposedKey) (*plans.ResourceInstanceChange, *providers.Deferred, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics + var deferred *providers.Deferred var plan *plans.ResourceInstanceChange absAddr := n.Addr @@ -400,7 +401,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState }, ProviderAddr: n.ResolvedProvider, } - return noop, nil + return noop, deferred, nil } unmarkedPriorVal, _ := currentState.Value.UnmarkDeep() @@ -411,13 +412,13 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState provider, _, err := getProvider(ctx, n.ResolvedProvider) if err != nil { - return plan, diags.Append(err) + return plan, deferred, diags.Append(err) } metaConfigVal, metaDiags := n.providerMetas(ctx) diags = diags.Append(metaDiags) if diags.HasErrors() { - return plan, diags + return plan, deferred, diags } var resp providers.PlanResourceChangeResponse @@ -441,6 +442,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState ProviderMeta: metaConfigVal, DeferralAllowed: ctx.Deferrals().DeferralAllowed(), }) + deferred = resp.Deferred // We may not have a config for all destroys, but we want to reference // it in the diagnostics if we do. @@ -449,19 +451,11 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState } diags = diags.Append(resp.Diagnostics) if diags.HasErrors() { - return plan, diags + return plan, deferred, diags } if resp.Deferred != nil { - ctx.Deferrals().ReportResourceInstanceDeferred(n.Addr, resp.Deferred.Reason, &plans.ResourceInstanceChange{ - Addr: n.Addr, - Change: plans.Change{ - Action: plans.Delete, - Before: unmarkedPriorVal, - After: resp.PlannedState, - }, - }) - return plan, diags + return plan, deferred, diags } // Check that the provider returned a null value here, since that is the @@ -475,7 +469,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState n.ResolvedProvider.Provider, n.Addr), ), ) - return plan, diags + return plan, deferred, diags } } @@ -493,7 +487,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState ProviderAddr: n.ResolvedProvider, } - return plan, diags + return plan, deferred, diags } // planForget returns a Forget change. diff --git a/internal/terraform/node_resource_destroy_deposed.go b/internal/terraform/node_resource_destroy_deposed.go index 9cd958d8e2..c844c5ab9a 100644 --- a/internal/terraform/node_resource_destroy_deposed.go +++ b/internal/terraform/node_resource_destroy_deposed.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform/internal/dag" "github.com/hashicorp/terraform/internal/instances" "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/tfdiags" ) @@ -161,15 +162,26 @@ func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walk } var change *plans.ResourceInstanceChange var pDiags tfdiags.Diagnostics + var deferred *providers.Deferred if forget { change, pDiags = n.planForget(ctx, state, n.DeposedKey) } else { - change, pDiags = n.planDestroy(ctx, state, n.DeposedKey) + change, deferred, pDiags = n.planDestroy(ctx, state, n.DeposedKey) } diags = diags.Append(pDiags) if diags.HasErrors() { return diags } + if deferred != nil { + ctx.Deferrals().ReportResourceInstanceDeferred(n.Addr, deferred.Reason, &plans.ResourceInstanceChange{ + Addr: n.Addr, + Change: plans.Change{ + Action: plans.Delete, + Before: state.Value, + }, + }) + return diags + } // NOTE: We don't check prevent_destroy for deposed objects, even // though we would do so here for a "current" object, because @@ -275,12 +287,23 @@ func (n *NodeDestroyDeposedResourceInstanceObject) Execute(ctx EvalContext, op w return diags } - change, destroyPlanDiags := n.planDestroy(ctx, state, n.DeposedKey) + change, deferred, destroyPlanDiags := n.planDestroy(ctx, state, n.DeposedKey) diags = diags.Append(destroyPlanDiags) if diags.HasErrors() { return diags } + if deferred != nil { + ctx.Deferrals().ReportResourceInstanceDeferred(n.Addr, deferred.Reason, &plans.ResourceInstanceChange{ + Addr: n.Addr, + Change: plans.Change{ + Action: plans.Delete, + Before: state.Value, + }, + }) + return diags + } + // Call pre-apply hook diags = diags.Append(n.preApplyHook(ctx, change)) if diags.HasErrors() { diff --git a/internal/terraform/node_resource_plan_destroy.go b/internal/terraform/node_resource_plan_destroy.go index 51cfd64c09..98734a2e76 100644 --- a/internal/terraform/node_resource_plan_destroy.go +++ b/internal/terraform/node_resource_plan_destroy.go @@ -90,12 +90,23 @@ func (n *NodePlanDestroyableResourceInstance) managedResourceExecute(ctx EvalCon } } - change, destroyPlanDiags := n.planDestroy(ctx, state, "") + change, deferred, destroyPlanDiags := n.planDestroy(ctx, state, "") diags = diags.Append(destroyPlanDiags) if diags.HasErrors() { return diags } + if deferred != nil { + ctx.Deferrals().ReportResourceInstanceDeferred(n.Addr, deferred.Reason, &plans.ResourceInstanceChange{ + Addr: n.Addr, + Change: plans.Change{ + Action: plans.Delete, + Before: state.Value, + }, + }) + return diags + } + // We intentionally write the change before the subsequent checks, because // all of the checks below this point are for problems caused by the // context surrounding the change, rather than the change itself, and diff --git a/internal/terraform/node_resource_plan_orphan.go b/internal/terraform/node_resource_plan_orphan.go index 6b009f37d7..ba028a086f 100644 --- a/internal/terraform/node_resource_plan_orphan.go +++ b/internal/terraform/node_resource_plan_orphan.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/tfdiags" ) @@ -164,13 +165,22 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon } var change *plans.ResourceInstanceChange var pDiags tfdiags.Diagnostics + var deferred *providers.Deferred if forget { change, pDiags = n.planForget(ctx, oldState, "") diags = diags.Append(pDiags) } else { - change, pDiags = n.planDestroy(ctx, oldState, "") + change, deferred, pDiags = n.planDestroy(ctx, oldState, "") diags = diags.Append(pDiags) - if diags.HasErrors() { + + if deferred != nil { + ctx.Deferrals().ReportResourceInstanceDeferred(n.Addr, deferred.Reason, &plans.ResourceInstanceChange{ + Addr: n.Addr, + Change: plans.Change{ + Action: plans.Delete, + Before: oldState.Value, + }, + }) return diags } } @@ -181,10 +191,7 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon // We might be able to offer an approximate reason for why we are // planning to delete this object. (This is best-effort; we might // sometimes not have a reason.) - // The change can be nil in case of deferred destroys. - if change != nil { - change.ActionReason = n.deleteActionReason(ctx) - } + change.ActionReason = n.deleteActionReason(ctx) // We intentionally write the change before the subsequent checks, because // all of the checks below this point are for problems caused by the