6 "github.com/hashicorp/terraform/addrs"
7 "github.com/hashicorp/terraform/configs"
8 "github.com/hashicorp/terraform/dag"
9 "github.com/hashicorp/terraform/states"
10 "github.com/hashicorp/terraform/tfdiags"
13 // PlanGraphBuilder implements GraphBuilder and is responsible for building
14 // a graph for planning (creating a Terraform Diff).
16 // The primary difference between this graph and others:
18 // * Based on the config since it represents the target state
20 // * Ignores lifecycle options since no lifecycle events occur here. This
21 // simplifies the graph significantly since complex transforms such as
22 // create-before-destroy can be completely ignored.
24 type PlanGraphBuilder struct {
25 // Config is the configuration tree to build a plan from.
26 Config *configs.Config
28 // State is the current state
31 // Components is a factory for the plug-in components (providers and
32 // provisioners) available for use.
33 Components contextComponentFactory
35 // Schemas is the repository of schemas we will draw from to analyse
39 // Targets are resources to target
40 Targets []addrs.Targetable
42 // DisableReduce, if true, will not reduce the graph. Great for testing.
45 // Validate will do structural validation of the graph.
48 // CustomConcrete can be set to customize the node types created
49 // for various parts of the plan. This is useful in order to customize
52 ConcreteProvider ConcreteProviderNodeFunc
53 ConcreteResource ConcreteResourceNodeFunc
54 ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc
60 func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
61 return (&BasicGraphBuilder{
64 Name: "PlanGraphBuilder",
69 func (b *PlanGraphBuilder) Steps() []GraphTransformer {
72 concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
73 return &NodePlanDeposedResourceInstanceObject{
74 NodeAbstractResourceInstance: a,
79 steps := []GraphTransformer{
80 // Creates all the resources represented in the config
82 Concrete: b.ConcreteResource,
86 // Add the local values
87 &LocalTransformer{Config: b.Config},
90 &OutputTransformer{Config: b.Config},
92 // Add orphan resources
93 &OrphanResourceInstanceTransformer{
94 Concrete: b.ConcreteResourceOrphan,
99 // We also need nodes for any deposed instance objects present in the
100 // state, so we can plan to destroy them. (This intentionally
101 // skips creating nodes for _current_ objects, since ConfigTransformer
102 // created nodes that will do that during DynamicExpand.)
104 ConcreteDeposed: concreteResourceInstanceDeposed,
108 // Create orphan output nodes
109 &OrphanOutputTransformer{
114 // Attach the configuration to any resources
115 &AttachResourceConfigTransformer{Config: b.Config},
118 &AttachStateTransformer{State: b.State},
120 // Add root variables
121 &RootVariableTransformer{Config: b.Config},
123 &MissingProvisionerTransformer{Provisioners: b.Components.ResourceProvisioners()},
124 &ProvisionerTransformer{},
126 // Add module variables
127 &ModuleVariableTransformer{
131 TransformProviders(b.Components.ResourceProviders(), b.ConcreteProvider, b.Config),
133 // Remove modules no longer present in the config
134 &RemovedModuleTransformer{Config: b.Config, State: b.State},
136 // Must attach schemas before ReferenceTransformer so that we can
137 // analyze the configuration to find references.
138 &AttachSchemaTransformer{Schemas: b.Schemas},
140 // Connect so that the references are ready for targeting. We'll
141 // have to connect again later for providers and so on.
142 &ReferenceTransformer{},
144 // Add the node to fix the state count boundaries
145 &CountBoundaryTransformer{
153 // Resource nodes from config have not yet been expanded for
154 // "count", so we must apply targeting without indices. Exact
155 // targeting will be dealt with later when these resources
160 // Detect when create_before_destroy must be forced on for a particular
161 // node due to dependency edges, to avoid graph cycles during apply.
162 &ForcedCBDTransformer{},
164 // Close opened plugin connections
165 &CloseProviderTransformer{},
166 &CloseProvisionerTransformer{},
172 if !b.DisableReduce {
173 // Perform the transitive reduction to make our graph a bit
174 // more sane if possible (it usually is possible).
175 steps = append(steps, &TransitiveReductionTransformer{})
181 func (b *PlanGraphBuilder) init() {
182 // Do nothing if the user requests customizing the fields
183 if b.CustomConcrete {
187 b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
188 return &NodeApplyableProvider{
189 NodeAbstractProvider: a,
193 b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
194 return &NodePlannableResource{
195 NodeAbstractResource: a,
199 b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex {
200 return &NodePlannableResourceInstanceOrphan{
201 NodeAbstractResourceInstance: a,