Skip to content

Commit 3db3ed0

Browse files
committed
ensure destroy plan contains valid state values
Some prior refactors left the detroyPlan method a bit confusing, and ran into a case where the previous run state could be returned as nil. Get rid of the no longer used pendingPlan value, and track the prior and prev states directly, making sure we always have a value for both.
1 parent 3ea704e commit 3db3ed0

File tree

2 files changed

+20
-14
lines changed

2 files changed

+20
-14
lines changed

internal/terraform/context_plan.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,6 @@ func (c *Context) refreshOnlyPlan(config *configs.Config, prevRunState *states.S
325325

326326
func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) {
327327
var diags tfdiags.Diagnostics
328-
pendingPlan := &plans.Plan{}
329328

330329
if opts.Mode != plans.DestroyMode {
331330
panic(fmt.Sprintf("called Context.destroyPlan with %s", opts.Mode))
@@ -373,18 +372,17 @@ func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State
373372
return nil, diags
374373
}
375374

376-
// insert the refreshed state into the destroy plan result, and ignore
377-
// the changes recorded from the refresh.
378-
pendingPlan.PriorState = refreshPlan.PriorState.DeepCopy()
379-
pendingPlan.PrevRunState = refreshPlan.PrevRunState.DeepCopy()
380-
log.Printf("[TRACE] Context.destroyPlan: now _really_ creating a destroy plan")
381-
382375
// We'll use the refreshed state -- which is the "prior state" from
383-
// the perspective of this "pending plan" -- as the starting state
376+
// the perspective of this "destroy plan" -- as the starting state
384377
// for our destroy-plan walk, so it can take into account if we
385378
// detected during refreshing that anything was already deleted outside
386379
// of Terraform.
387-
priorState = pendingPlan.PriorState
380+
priorState = refreshPlan.PriorState.DeepCopy()
381+
382+
// The refresh plan may have upgraded state for some resources, make
383+
// sure we store the new version.
384+
prevRunState = refreshPlan.PrevRunState.DeepCopy()
385+
log.Printf("[TRACE] Context.destroyPlan: now _really_ creating a destroy plan")
388386
}
389387

390388
destroyPlan, walkDiags := c.planWalk(config, priorState, opts)
@@ -394,10 +392,10 @@ func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State
394392
}
395393

396394
if !opts.SkipRefresh {
397-
// If we didn't skip refreshing then we want the previous run state
398-
// prior state to be the one we originally fed into the c.plan call
399-
// above, not the refreshed version we used for the destroy walk.
400-
destroyPlan.PrevRunState = pendingPlan.PrevRunState
395+
// If we didn't skip refreshing then we want the previous run state to
396+
// be the one we originally fed into the c.refreshOnlyPlan call above,
397+
// not the refreshed version we used for the destroy planWalk.
398+
destroyPlan.PrevRunState = prevRunState
401399
}
402400

403401
relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, destroyPlan)

internal/terraform/context_plan2_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3676,11 +3676,19 @@ output "out" {
36763676
},
36773677
})
36783678

3679-
_, diags := ctx.Plan(m, state, &PlanOpts{
3679+
plan, diags := ctx.Plan(m, state, &PlanOpts{
36803680
Mode: plans.DestroyMode,
36813681
})
36823682

36833683
assertNoErrors(t, diags)
3684+
3685+
// ensure that the given states are valid and can be serialized
3686+
if plan.PrevRunState == nil {
3687+
t.Fatal("nil plan.PrevRunState")
3688+
}
3689+
if plan.PriorState == nil {
3690+
t.Fatal("nil plan.PriorState")
3691+
}
36843692
}
36853693

36863694
// A deposed instances which no longer exists during ReadResource creates NoOp

0 commit comments

Comments
 (0)