4 "github.com/hashicorp/terraform/config/module"
5 "github.com/hashicorp/terraform/dag"
8 // ApplyGraphBuilder implements GraphBuilder and is responsible for building
9 // a graph for applying a Terraform diff.
11 // Because the graph is built from the diff (vs. the config or state),
12 // this helps ensure that the apply-time graph doesn't modify any resources
13 // that aren't explicitly in the diff. There are other scenarios where the
14 // diff can be deviated, so this is just one layer of protection.
15 type ApplyGraphBuilder struct {
16 // Module is the root module for the graph to build.
19 // Diff is the diff to apply.
22 // State is the current state
25 // Providers is the list of providers supported.
28 // Provisioners is the list of provisioners supported.
31 // Targets are resources to target. This is only required to make sure
32 // unnecessary outputs aren't included in the apply graph. The plan
33 // builder successfully handles targeting resources. In the future,
34 // outputs should go into the diff so that this is unnecessary.
37 // DisableReduce, if true, will not reduce the graph. Great for testing.
40 // Destroy, if true, represents a pure destroy operation
43 // Validate will do structural validation of the graph.
48 func (b *ApplyGraphBuilder) Build(path []string) (*Graph, error) {
49 return (&BasicGraphBuilder{
52 Name: "ApplyGraphBuilder",
57 func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
58 // Custom factory for creating providers.
59 concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
60 return &NodeApplyableProvider{
61 NodeAbstractProvider: a,
65 concreteResource := func(a *NodeAbstractResource) dag.Vertex {
66 return &NodeApplyableResource{
67 NodeAbstractResource: a,
71 steps := []GraphTransformer{
72 // Creates all the nodes represented in the diff.
74 Concrete: concreteResource,
81 // Create orphan output nodes
82 &OrphanOutputTransformer{Module: b.Module, State: b.State},
84 // Attach the configuration to any resources
85 &AttachResourceConfigTransformer{Module: b.Module},
88 &AttachStateTransformer{State: b.State},
90 // Create all the providers
91 &MissingProviderTransformer{Providers: b.Providers, Concrete: concreteProvider},
92 &ProviderTransformer{},
93 &DisableProviderTransformer{},
94 &ParentProviderTransformer{},
95 &AttachProviderConfigTransformer{Module: b.Module},
97 // Destruction ordering
98 &DestroyEdgeTransformer{Module: b.Module, State: b.State},
100 func() bool { return !b.Destroy },
101 &CBDEdgeTransformer{Module: b.Module, State: b.State},
104 // Provisioner-related transformations
105 &MissingProvisionerTransformer{Provisioners: b.Provisioners},
106 &ProvisionerTransformer{},
108 // Add root variables
109 &RootVariableTransformer{Module: b.Module},
112 &OutputTransformer{Module: b.Module},
114 // Add module variables
115 &ModuleVariableTransformer{Module: b.Module},
117 // Connect references so ordering is correct
118 &ReferenceTransformer{},
120 // Add the node to fix the state count boundaries
121 &CountBoundaryTransformer{},
124 &TargetsTransformer{Targets: b.Targets},
126 // Close opened plugin connections
127 &CloseProviderTransformer{},
128 &CloseProvisionerTransformer{},
134 if !b.DisableReduce {
135 // Perform the transitive reduction to make our graph a bit
136 // more sane if possible (it usually is possible).
137 steps = append(steps, &TransitiveReductionTransformer{})