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,
75 &OutputTransformer{Module: b.Module},
77 // Add orphan resources
78 &OrphanResourceTransformer{
79 Concrete: b.ConcreteResourceOrphan,
84 // Attach the configuration to any resources
85 &AttachResourceConfigTransformer{Module: b.Module},
88 &AttachStateTransformer{State: b.State},
91 &RootVariableTransformer{Module: b.Module},
93 // Create all the providers
94 &MissingProviderTransformer{Providers: b.Providers, Concrete: b.ConcreteProvider},
95 &ProviderTransformer{},
96 &DisableProviderTransformer{},
97 &ParentProviderTransformer{},
98 &AttachProviderConfigTransformer{Module: b.Module},
100 // Provisioner-related transformations. Only add these if requested.
102 func() bool { return b.Provisioners != nil },
104 &MissingProvisionerTransformer{Provisioners: b.Provisioners},
105 &ProvisionerTransformer{},
109 // Add module variables
110 &ModuleVariableTransformer{Module: b.Module},
112 // Connect so that the references are ready for targeting. We'll
113 // have to connect again later for providers and so on.
114 &ReferenceTransformer{},
116 // Add the node to fix the state count boundaries
117 &CountBoundaryTransformer{},
123 // Resource nodes from config have not yet been expanded for
124 // "count", so we must apply targeting without indices. Exact
125 // targeting will be dealt with later when these resources
130 // Close opened plugin connections
131 &CloseProviderTransformer{},
132 &CloseProvisionerTransformer{},
138 if !b.DisableReduce {
139 // Perform the transitive reduction to make our graph a bit
140 // more sane if possible (it usually is possible).
141 steps = append(steps, &TransitiveReductionTransformer{})
147 func (b *PlanGraphBuilder) init() {
148 // Do nothing if the user requests customizing the fields
149 if b.CustomConcrete {
153 b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
154 return &NodeApplyableProvider{
155 NodeAbstractProvider: a,
159 b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
160 return &NodePlannableResource{
161 NodeAbstractCountResource: &NodeAbstractCountResource{
162 NodeAbstractResource: a,
167 b.ConcreteResourceOrphan = func(a *NodeAbstractResource) dag.Vertex {
168 return &NodePlannableResourceOrphan{
169 NodeAbstractResource: a,