6 "github.com/hashicorp/terraform/config/module"
7 "github.com/hashicorp/terraform/dag"
10 // PlanGraphBuilder implements GraphBuilder and is responsible for building
11 // a graph for planning (creating a Terraform Diff).
13 // The primary difference between this graph and others:
15 // * Based on the config since it represents the target state
17 // * Ignores lifecycle options since no lifecycle events occur here. This
18 // simplifies the graph significantly since complex transforms such as
19 // create-before-destroy can be completely ignored.
21 type PlanGraphBuilder struct {
22 // Module is the root module for the graph to build.
25 // State is the current state
28 // Providers is the list of providers supported.
31 // Provisioners is the list of provisioners supported.
34 // Targets are resources to target
37 // DisableReduce, if true, will not reduce the graph. Great for testing.
40 // Validate will do structural validation of the graph.
43 // CustomConcrete can be set to customize the node types created
44 // for various parts of the plan. This is useful in order to customize
47 ConcreteProvider ConcreteProviderNodeFunc
48 ConcreteResource ConcreteResourceNodeFunc
49 ConcreteResourceOrphan ConcreteResourceNodeFunc
55 func (b *PlanGraphBuilder) Build(path []string) (*Graph, error) {
56 return (&BasicGraphBuilder{
59 Name: "PlanGraphBuilder",
64 func (b *PlanGraphBuilder) Steps() []GraphTransformer {
67 steps := []GraphTransformer{
68 // Creates all the resources represented in the config
70 Concrete: b.ConcreteResource,
74 // Add the local values
75 &LocalTransformer{Module: b.Module},
78 &OutputTransformer{Module: b.Module},
80 // Add orphan resources
81 &OrphanResourceTransformer{
82 Concrete: b.ConcreteResourceOrphan,
87 // Create orphan output nodes
88 &OrphanOutputTransformer{
93 // Attach the configuration to any resources
94 &AttachResourceConfigTransformer{Module: b.Module},
97 &AttachStateTransformer{State: b.State},
100 &RootVariableTransformer{Module: b.Module},
102 TransformProviders(b.Providers, b.ConcreteProvider, b.Module),
104 // Provisioner-related transformations. Only add these if requested.
106 func() bool { return b.Provisioners != nil },
108 &MissingProvisionerTransformer{Provisioners: b.Provisioners},
109 &ProvisionerTransformer{},
113 // Add module variables
114 &ModuleVariableTransformer{
118 // Remove modules no longer present in the config
119 &RemovedModuleTransformer{Module: b.Module, State: b.State},
121 // Connect so that the references are ready for targeting. We'll
122 // have to connect again later for providers and so on.
123 &ReferenceTransformer{},
125 // Add the node to fix the state count boundaries
126 &CountBoundaryTransformer{},
132 // Resource nodes from config have not yet been expanded for
133 // "count", so we must apply targeting without indices. Exact
134 // targeting will be dealt with later when these resources
139 // Close opened plugin connections
140 &CloseProviderTransformer{},
141 &CloseProvisionerTransformer{},
147 if !b.DisableReduce {
148 // Perform the transitive reduction to make our graph a bit
149 // more sane if possible (it usually is possible).
150 steps = append(steps, &TransitiveReductionTransformer{})
156 func (b *PlanGraphBuilder) init() {
157 // Do nothing if the user requests customizing the fields
158 if b.CustomConcrete {
162 b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
163 return &NodeApplyableProvider{
164 NodeAbstractProvider: a,
168 b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
169 return &NodePlannableResource{
170 NodeAbstractCountResource: &NodeAbstractCountResource{
171 NodeAbstractResource: a,
176 b.ConcreteResourceOrphan = func(a *NodeAbstractResource) dag.Vertex {
177 return &NodePlannableResourceOrphan{
178 NodeAbstractResource: a,