Merge pull request #32207 from hashicorp/jbardin/destroy-plan-state

Ensure destroy plan contains valid state values
This commit is contained in:
James Bardin 2022-11-17 14:18:17 -05:00 committed by GitHub
commit 62a8b9ef1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 14 deletions

View File

@ -325,7 +325,6 @@ func (c *Context) refreshOnlyPlan(config *configs.Config, prevRunState *states.S
func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*plans.Plan, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
pendingPlan := &plans.Plan{}
if opts.Mode != plans.DestroyMode {
panic(fmt.Sprintf("called Context.destroyPlan with %s", opts.Mode))
@ -373,18 +372,17 @@ func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State
return nil, diags
}
// insert the refreshed state into the destroy plan result, and ignore
// the changes recorded from the refresh.
pendingPlan.PriorState = refreshPlan.PriorState.DeepCopy()
pendingPlan.PrevRunState = refreshPlan.PrevRunState.DeepCopy()
log.Printf("[TRACE] Context.destroyPlan: now _really_ creating a destroy plan")
// We'll use the refreshed state -- which is the "prior state" from
// the perspective of this "pending plan" -- as the starting state
// the perspective of this "destroy plan" -- as the starting state
// for our destroy-plan walk, so it can take into account if we
// detected during refreshing that anything was already deleted outside
// of Terraform.
priorState = pendingPlan.PriorState
priorState = refreshPlan.PriorState.DeepCopy()
// The refresh plan may have upgraded state for some resources, make
// sure we store the new version.
prevRunState = refreshPlan.PrevRunState.DeepCopy()
log.Printf("[TRACE] Context.destroyPlan: now _really_ creating a destroy plan")
}
destroyPlan, walkDiags := c.planWalk(config, priorState, opts)
@ -394,10 +392,10 @@ func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State
}
if !opts.SkipRefresh {
// If we didn't skip refreshing then we want the previous run state
// prior state to be the one we originally fed into the c.plan call
// above, not the refreshed version we used for the destroy walk.
destroyPlan.PrevRunState = pendingPlan.PrevRunState
// If we didn't skip refreshing then we want the previous run state to
// be the one we originally fed into the c.refreshOnlyPlan call above,
// not the refreshed version we used for the destroy planWalk.
destroyPlan.PrevRunState = prevRunState
}
relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, destroyPlan)

View File

@ -3676,11 +3676,19 @@ output "out" {
},
})
_, diags := ctx.Plan(m, state, &PlanOpts{
plan, diags := ctx.Plan(m, state, &PlanOpts{
Mode: plans.DestroyMode,
})
assertNoErrors(t, diags)
// ensure that the given states are valid and can be serialized
if plan.PrevRunState == nil {
t.Fatal("nil plan.PrevRunState")
}
if plan.PriorState == nil {
t.Fatal("nil plan.PriorState")
}
}
// A deposed instances which no longer exists during ReadResource creates NoOp