mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
prune unused nodes from a destroy plan graph
We may need to prune nodes from a full destroy plan graph which cannot be evaluated if there is no current state. Add missing method to nodeExpandPlannableResource to ensure planned resource are handled correctly when pruning nodes.
This commit is contained in:
parent
4153685bfe
commit
aedd95a1ee
@ -3518,3 +3518,44 @@ resource "test_object" "b" {
|
||||
t.Fatalf("no cycle error found:\n got: %s\n", msg)
|
||||
}
|
||||
}
|
||||
|
||||
// plan a destroy with no state where configuration could fail to evaluate
|
||||
// expansion indexes.
|
||||
func TestContext2Plan_emptyDestroy(t *testing.T) {
|
||||
m := testModuleInline(t, map[string]string{
|
||||
"main.tf": `
|
||||
locals {
|
||||
enable = true
|
||||
value = local.enable ? module.example[0].out : null
|
||||
}
|
||||
|
||||
module "example" {
|
||||
count = local.enable ? 1 : 0
|
||||
source = "./example"
|
||||
}
|
||||
`,
|
||||
"example/main.tf": `
|
||||
resource "test_resource" "x" {
|
||||
}
|
||||
|
||||
output "out" {
|
||||
value = test_resource.x
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
p := testProvider("test")
|
||||
state := states.NewState()
|
||||
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
|
||||
_, diags := ctx.Plan(m, state, &PlanOpts{
|
||||
Mode: plans.DestroyMode,
|
||||
})
|
||||
|
||||
assertNoErrors(t, diags)
|
||||
}
|
||||
|
@ -170,6 +170,10 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
||||
// TargetsTransformer can determine which nodes to keep in the graph.
|
||||
&DestroyEdgeTransformer{},
|
||||
|
||||
&pruneUnusedNodesTransformer{
|
||||
skip: b.Operation != walkPlanDestroy,
|
||||
},
|
||||
|
||||
// Target
|
||||
&TargetsTransformer{Targets: b.Targets},
|
||||
|
||||
|
@ -53,12 +53,16 @@ var (
|
||||
_ GraphNodeAttachResourceConfig = (*nodeExpandPlannableResource)(nil)
|
||||
_ GraphNodeAttachDependencies = (*nodeExpandPlannableResource)(nil)
|
||||
_ GraphNodeTargetable = (*nodeExpandPlannableResource)(nil)
|
||||
_ graphNodeExpandsInstances = (*nodeExpandPlannableResource)(nil)
|
||||
)
|
||||
|
||||
func (n *nodeExpandPlannableResource) Name() string {
|
||||
return n.NodeAbstractResource.Name() + " (expand)"
|
||||
}
|
||||
|
||||
func (n *nodeExpandPlannableResource) expandsInstances() {
|
||||
}
|
||||
|
||||
// GraphNodeAttachDependencies
|
||||
func (n *nodeExpandPlannableResource) AttachDependencies(deps []addrs.ConfigResource) {
|
||||
n.dependencies = deps
|
||||
|
@ -170,9 +170,18 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
|
||||
// closers also need to disable their use of expansion if the module itself is
|
||||
// no longer present.
|
||||
type pruneUnusedNodesTransformer struct {
|
||||
// The plan graph builder will skip this transformer except during a full
|
||||
// destroy. Planing normally involves all nodes, but during a destroy plan
|
||||
// we may need to prune things which are in the configuration but do not
|
||||
// exist in state to evaluate.
|
||||
skip bool
|
||||
}
|
||||
|
||||
func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error {
|
||||
if t.skip {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We need a reverse depth first walk of modules, processing them in order
|
||||
// from the leaf modules to the root. This allows us to remove unneeded
|
||||
// dependencies from child modules, freeing up nodes in the parent module
|
||||
|
Loading…
Reference in New Issue
Block a user