mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
use the PlanGraphBuilder for destroy
Rather than maintain a separate graph builder for destroy, use the normal plan graph with some extra options. Utilize the same pattern as the validate graph for now, where we take the normal plan graph builder and inject a new concrete function for the destroy nodes.
This commit is contained in:
parent
77d13808d5
commit
8fed14fc59
@ -574,7 +574,7 @@ func (c *Context) planGraph(config *configs.Config, prevRunState *states.State,
|
|||||||
}).Build(addrs.RootModuleInstance)
|
}).Build(addrs.RootModuleInstance)
|
||||||
return graph, walkPlan, diags
|
return graph, walkPlan, diags
|
||||||
case plans.DestroyMode:
|
case plans.DestroyMode:
|
||||||
graph, diags := (&DestroyPlanGraphBuilder{
|
graph, diags := DestroyPlanGraphBuilder(&PlanGraphBuilder{
|
||||||
Config: config,
|
Config: config,
|
||||||
State: prevRunState,
|
State: prevRunState,
|
||||||
RootVariableValues: opts.SetVariables,
|
RootVariableValues: opts.SetVariables,
|
||||||
|
@ -1,115 +1,17 @@
|
|||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/terraform/internal/addrs"
|
|
||||||
"github.com/hashicorp/terraform/internal/configs"
|
|
||||||
"github.com/hashicorp/terraform/internal/dag"
|
"github.com/hashicorp/terraform/internal/dag"
|
||||||
"github.com/hashicorp/terraform/internal/states"
|
|
||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DestroyPlanGraphBuilder implements GraphBuilder and is responsible for
|
func DestroyPlanGraphBuilder(p *PlanGraphBuilder) GraphBuilder {
|
||||||
// planning a pure-destroy.
|
p.ConcreteResourceInstance = func(a *NodeAbstractResourceInstance) dag.Vertex {
|
||||||
//
|
|
||||||
// Planning a pure destroy operation is simple because we can ignore most
|
|
||||||
// ordering configuration and simply reverse the state. This graph mainly
|
|
||||||
// exists for targeting, because we need to walk the destroy dependencies to
|
|
||||||
// ensure we plan the required resources. Without the requirement for
|
|
||||||
// targeting, the plan could theoretically be created directly from the state.
|
|
||||||
type DestroyPlanGraphBuilder struct {
|
|
||||||
// Config is the configuration tree to build the plan from.
|
|
||||||
Config *configs.Config
|
|
||||||
|
|
||||||
// State is the current state
|
|
||||||
State *states.State
|
|
||||||
|
|
||||||
// RootVariableValues are the raw input values for root input variables
|
|
||||||
// given by the caller, which we'll resolve into final values as part
|
|
||||||
// of the plan walk.
|
|
||||||
RootVariableValues InputValues
|
|
||||||
|
|
||||||
// Plugins is a library of plug-in components (providers and
|
|
||||||
// provisioners) available for use.
|
|
||||||
Plugins *contextPlugins
|
|
||||||
|
|
||||||
// Targets are resources to target
|
|
||||||
Targets []addrs.Targetable
|
|
||||||
|
|
||||||
// If set, skipRefresh will cause us stop skip refreshing any existing
|
|
||||||
// resource instances as part of our planning. This will cause us to fail
|
|
||||||
// to detect if an object has already been deleted outside of Terraform.
|
|
||||||
skipRefresh bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// See GraphBuilder
|
|
||||||
func (b *DestroyPlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
|
|
||||||
return (&BasicGraphBuilder{
|
|
||||||
Steps: b.Steps(),
|
|
||||||
Name: "DestroyPlanGraphBuilder",
|
|
||||||
}).Build(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// See GraphBuilder
|
|
||||||
func (b *DestroyPlanGraphBuilder) Steps() []GraphTransformer {
|
|
||||||
concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex {
|
|
||||||
return &NodePlanDestroyableResourceInstance{
|
return &NodePlanDestroyableResourceInstance{
|
||||||
NodeAbstractResourceInstance: a,
|
NodeAbstractResourceInstance: a,
|
||||||
skipRefresh: b.skipRefresh,
|
skipRefresh: p.skipRefresh,
|
||||||
}
|
|
||||||
}
|
|
||||||
concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
|
|
||||||
return &NodePlanDeposedResourceInstanceObject{
|
|
||||||
NodeAbstractResourceInstance: a,
|
|
||||||
DeposedKey: key,
|
|
||||||
skipRefresh: b.skipRefresh,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p.destroy = true
|
||||||
|
|
||||||
concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
|
return p
|
||||||
return &NodeApplyableProvider{
|
|
||||||
NodeAbstractProvider: a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
steps := []GraphTransformer{
|
|
||||||
// Creates nodes for the resource instances tracked in the state.
|
|
||||||
&StateTransformer{
|
|
||||||
ConcreteCurrent: concreteResourceInstance,
|
|
||||||
ConcreteDeposed: concreteResourceInstanceDeposed,
|
|
||||||
State: b.State,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Create the delete changes for root module outputs.
|
|
||||||
&OutputTransformer{
|
|
||||||
Config: b.Config,
|
|
||||||
Destroy: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Attach the state
|
|
||||||
&AttachStateTransformer{State: b.State},
|
|
||||||
|
|
||||||
// Attach the configuration to any resources
|
|
||||||
&AttachResourceConfigTransformer{Config: b.Config},
|
|
||||||
|
|
||||||
transformProviders(concreteProvider, b.Config),
|
|
||||||
|
|
||||||
// Destruction ordering. We require this only so that
|
|
||||||
// targeting below will prune the correct things.
|
|
||||||
&DestroyEdgeTransformer{
|
|
||||||
Config: b.Config,
|
|
||||||
State: b.State,
|
|
||||||
},
|
|
||||||
|
|
||||||
&TargetsTransformer{Targets: b.Targets},
|
|
||||||
|
|
||||||
// Close opened plugin connections
|
|
||||||
&CloseProviderTransformer{},
|
|
||||||
|
|
||||||
// Close the root module
|
|
||||||
&CloseRootModuleTransformer{},
|
|
||||||
|
|
||||||
&TransitiveReductionTransformer{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return steps
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/internal/addrs"
|
"github.com/hashicorp/terraform/internal/addrs"
|
||||||
"github.com/hashicorp/terraform/internal/configs"
|
"github.com/hashicorp/terraform/internal/configs"
|
||||||
"github.com/hashicorp/terraform/internal/dag"
|
"github.com/hashicorp/terraform/internal/dag"
|
||||||
@ -60,10 +58,13 @@ type PlanGraphBuilder struct {
|
|||||||
CustomConcrete bool
|
CustomConcrete bool
|
||||||
ConcreteProvider ConcreteProviderNodeFunc
|
ConcreteProvider ConcreteProviderNodeFunc
|
||||||
ConcreteResource ConcreteResourceNodeFunc
|
ConcreteResource ConcreteResourceNodeFunc
|
||||||
|
ConcreteResourceInstance ConcreteResourceInstanceNodeFunc
|
||||||
ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc
|
ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc
|
||||||
|
ConcreteResourceInstanceDeposed ConcreteResourceInstanceDeposedNodeFunc
|
||||||
ConcreteModule ConcreteModuleNodeFunc
|
ConcreteModule ConcreteModuleNodeFunc
|
||||||
|
|
||||||
once sync.Once
|
// destroy is set to true when create a full destroy plan.
|
||||||
|
destroy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// See GraphBuilder
|
// See GraphBuilder
|
||||||
@ -76,36 +77,32 @@ func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Dia
|
|||||||
|
|
||||||
// See GraphBuilder
|
// See GraphBuilder
|
||||||
func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
||||||
b.once.Do(b.init)
|
b.init()
|
||||||
|
|
||||||
concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
|
|
||||||
return &NodePlanDeposedResourceInstanceObject{
|
|
||||||
NodeAbstractResourceInstance: a,
|
|
||||||
DeposedKey: key,
|
|
||||||
|
|
||||||
skipRefresh: b.skipRefresh,
|
|
||||||
skipPlanChanges: b.skipPlanChanges,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
steps := []GraphTransformer{
|
steps := []GraphTransformer{
|
||||||
// Creates all the resources represented in the config
|
// Creates all the resources represented in the config
|
||||||
&ConfigTransformer{
|
&ConfigTransformer{
|
||||||
Concrete: b.ConcreteResource,
|
Concrete: b.ConcreteResource,
|
||||||
Config: b.Config,
|
Config: b.Config,
|
||||||
|
destroyPlan: b.destroy,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Add dynamic values
|
// Add dynamic values
|
||||||
&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
|
&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
|
||||||
&ModuleVariableTransformer{Config: b.Config},
|
&ModuleVariableTransformer{Config: b.Config},
|
||||||
&LocalTransformer{Config: b.Config},
|
&LocalTransformer{Config: b.Config},
|
||||||
&OutputTransformer{Config: b.Config, RefreshOnly: b.skipPlanChanges},
|
&OutputTransformer{
|
||||||
|
Config: b.Config,
|
||||||
|
RefreshOnly: b.skipPlanChanges,
|
||||||
|
destroyPlan: b.destroy,
|
||||||
|
},
|
||||||
|
|
||||||
// Add orphan resources
|
// Add orphan resources
|
||||||
&OrphanResourceInstanceTransformer{
|
&OrphanResourceInstanceTransformer{
|
||||||
Concrete: b.ConcreteResourceOrphan,
|
Concrete: b.ConcreteResourceOrphan,
|
||||||
State: b.State,
|
State: b.State,
|
||||||
Config: b.Config,
|
Config: b.Config,
|
||||||
|
destroyPlan: b.destroy,
|
||||||
},
|
},
|
||||||
|
|
||||||
// We also need nodes for any deposed instance objects present in the
|
// We also need nodes for any deposed instance objects present in the
|
||||||
@ -113,7 +110,8 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
|||||||
// skips creating nodes for _current_ objects, since ConfigTransformer
|
// skips creating nodes for _current_ objects, since ConfigTransformer
|
||||||
// created nodes that will do that during DynamicExpand.)
|
// created nodes that will do that during DynamicExpand.)
|
||||||
&StateTransformer{
|
&StateTransformer{
|
||||||
ConcreteDeposed: concreteResourceInstanceDeposed,
|
ConcreteCurrent: b.ConcreteResourceInstance,
|
||||||
|
ConcreteDeposed: b.ConcreteResourceInstanceDeposed,
|
||||||
State: b.State,
|
State: b.State,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -141,15 +139,18 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
|||||||
// objects that can belong to modules.
|
// objects that can belong to modules.
|
||||||
&ModuleExpansionTransformer{Concrete: b.ConcreteModule, Config: b.Config},
|
&ModuleExpansionTransformer{Concrete: b.ConcreteModule, Config: b.Config},
|
||||||
|
|
||||||
// Connect so that the references are ready for targeting. We'll
|
|
||||||
// have to connect again later for providers and so on.
|
|
||||||
&ReferenceTransformer{},
|
&ReferenceTransformer{},
|
||||||
|
|
||||||
&AttachDependenciesTransformer{},
|
&AttachDependenciesTransformer{},
|
||||||
|
|
||||||
// Make sure data sources are aware of any depends_on from the
|
// Make sure data sources are aware of any depends_on from the
|
||||||
// configuration
|
// configuration
|
||||||
&attachDataResourceDependsOnTransformer{},
|
&attachDataResourceDependsOnTransformer{},
|
||||||
|
|
||||||
|
// DestroyEdgeTransformer is only required during a plan so that the
|
||||||
|
// TargetsTransformer can determine which nodes to keep in the graph.
|
||||||
|
&DestroyEdgeTransformer{},
|
||||||
|
|
||||||
// Target
|
// Target
|
||||||
&TargetsTransformer{Targets: b.Targets},
|
&TargetsTransformer{Targets: b.Targets},
|
||||||
|
|
||||||
@ -199,4 +200,15 @@ func (b *PlanGraphBuilder) init() {
|
|||||||
skipPlanChanges: b.skipPlanChanges,
|
skipPlanChanges: b.skipPlanChanges,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.ConcreteResourceInstanceDeposed = func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
|
||||||
|
return &NodePlanDeposedResourceInstanceObject{
|
||||||
|
NodeAbstractResourceInstance: a,
|
||||||
|
DeposedKey: key,
|
||||||
|
|
||||||
|
skipRefresh: b.skipRefresh,
|
||||||
|
skipPlanChanges: b.skipPlanChanges,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user