]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
4 | "sync" | |
5 | ||
107c1cdb ND |
6 | "github.com/hashicorp/terraform/addrs" |
7 | "github.com/hashicorp/terraform/configs" | |
bae9f6d2 | 8 | "github.com/hashicorp/terraform/dag" |
107c1cdb ND |
9 | "github.com/hashicorp/terraform/states" |
10 | "github.com/hashicorp/terraform/tfdiags" | |
bae9f6d2 JC |
11 | ) |
12 | ||
13 | // PlanGraphBuilder implements GraphBuilder and is responsible for building | |
14 | // a graph for planning (creating a Terraform Diff). | |
15 | // | |
16 | // The primary difference between this graph and others: | |
17 | // | |
18 | // * Based on the config since it represents the target state | |
19 | // | |
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. | |
23 | // | |
24 | type PlanGraphBuilder struct { | |
107c1cdb ND |
25 | // Config is the configuration tree to build a plan from. |
26 | Config *configs.Config | |
bae9f6d2 JC |
27 | |
28 | // State is the current state | |
107c1cdb | 29 | State *states.State |
bae9f6d2 | 30 | |
107c1cdb ND |
31 | // Components is a factory for the plug-in components (providers and |
32 | // provisioners) available for use. | |
33 | Components contextComponentFactory | |
bae9f6d2 | 34 | |
107c1cdb ND |
35 | // Schemas is the repository of schemas we will draw from to analyse |
36 | // the configuration. | |
37 | Schemas *Schemas | |
bae9f6d2 JC |
38 | |
39 | // Targets are resources to target | |
107c1cdb | 40 | Targets []addrs.Targetable |
bae9f6d2 JC |
41 | |
42 | // DisableReduce, if true, will not reduce the graph. Great for testing. | |
43 | DisableReduce bool | |
44 | ||
45 | // Validate will do structural validation of the graph. | |
46 | Validate bool | |
47 | ||
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 | |
50 | // the plan behavior. | |
51 | CustomConcrete bool | |
52 | ConcreteProvider ConcreteProviderNodeFunc | |
53 | ConcreteResource ConcreteResourceNodeFunc | |
107c1cdb | 54 | ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc |
bae9f6d2 JC |
55 | |
56 | once sync.Once | |
57 | } | |
58 | ||
59 | // See GraphBuilder | |
107c1cdb | 60 | func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { |
bae9f6d2 JC |
61 | return (&BasicGraphBuilder{ |
62 | Steps: b.Steps(), | |
63 | Validate: b.Validate, | |
64 | Name: "PlanGraphBuilder", | |
65 | }).Build(path) | |
66 | } | |
67 | ||
68 | // See GraphBuilder | |
69 | func (b *PlanGraphBuilder) Steps() []GraphTransformer { | |
70 | b.once.Do(b.init) | |
71 | ||
107c1cdb ND |
72 | concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex { |
73 | return &NodePlanDeposedResourceInstanceObject{ | |
74 | NodeAbstractResourceInstance: a, | |
75 | DeposedKey: key, | |
76 | } | |
77 | } | |
78 | ||
bae9f6d2 JC |
79 | steps := []GraphTransformer{ |
80 | // Creates all the resources represented in the config | |
81 | &ConfigTransformer{ | |
82 | Concrete: b.ConcreteResource, | |
107c1cdb | 83 | Config: b.Config, |
bae9f6d2 JC |
84 | }, |
85 | ||
15c0b25d | 86 | // Add the local values |
107c1cdb | 87 | &LocalTransformer{Config: b.Config}, |
15c0b25d | 88 | |
bae9f6d2 | 89 | // Add the outputs |
107c1cdb | 90 | &OutputTransformer{Config: b.Config}, |
bae9f6d2 JC |
91 | |
92 | // Add orphan resources | |
107c1cdb | 93 | &OrphanResourceInstanceTransformer{ |
bae9f6d2 JC |
94 | Concrete: b.ConcreteResourceOrphan, |
95 | State: b.State, | |
107c1cdb ND |
96 | Config: b.Config, |
97 | }, | |
98 | ||
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.) | |
103 | &StateTransformer{ | |
104 | ConcreteDeposed: concreteResourceInstanceDeposed, | |
105 | State: b.State, | |
bae9f6d2 JC |
106 | }, |
107 | ||
15c0b25d AP |
108 | // Create orphan output nodes |
109 | &OrphanOutputTransformer{ | |
107c1cdb | 110 | Config: b.Config, |
15c0b25d AP |
111 | State: b.State, |
112 | }, | |
113 | ||
bae9f6d2 | 114 | // Attach the configuration to any resources |
107c1cdb | 115 | &AttachResourceConfigTransformer{Config: b.Config}, |
bae9f6d2 JC |
116 | |
117 | // Attach the state | |
118 | &AttachStateTransformer{State: b.State}, | |
119 | ||
120 | // Add root variables | |
107c1cdb | 121 | &RootVariableTransformer{Config: b.Config}, |
bae9f6d2 | 122 | |
107c1cdb ND |
123 | &MissingProvisionerTransformer{Provisioners: b.Components.ResourceProvisioners()}, |
124 | &ProvisionerTransformer{}, | |
bae9f6d2 JC |
125 | |
126 | // Add module variables | |
15c0b25d | 127 | &ModuleVariableTransformer{ |
107c1cdb | 128 | Config: b.Config, |
15c0b25d AP |
129 | }, |
130 | ||
107c1cdb ND |
131 | TransformProviders(b.Components.ResourceProviders(), b.ConcreteProvider, b.Config), |
132 | ||
15c0b25d | 133 | // Remove modules no longer present in the config |
107c1cdb ND |
134 | &RemovedModuleTransformer{Config: b.Config, State: b.State}, |
135 | ||
136 | // Must attach schemas before ReferenceTransformer so that we can | |
137 | // analyze the configuration to find references. | |
138 | &AttachSchemaTransformer{Schemas: b.Schemas}, | |
bae9f6d2 JC |
139 | |
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{}, | |
143 | ||
144 | // Add the node to fix the state count boundaries | |
107c1cdb ND |
145 | &CountBoundaryTransformer{ |
146 | Config: b.Config, | |
147 | }, | |
bae9f6d2 JC |
148 | |
149 | // Target | |
c680a8e1 RS |
150 | &TargetsTransformer{ |
151 | Targets: b.Targets, | |
152 | ||
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 | |
156 | // DynamicExpand. | |
157 | IgnoreIndices: true, | |
158 | }, | |
bae9f6d2 | 159 | |
107c1cdb ND |
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{}, | |
163 | ||
bae9f6d2 JC |
164 | // Close opened plugin connections |
165 | &CloseProviderTransformer{}, | |
166 | &CloseProvisionerTransformer{}, | |
167 | ||
168 | // Single root | |
169 | &RootTransformer{}, | |
170 | } | |
171 | ||
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{}) | |
176 | } | |
177 | ||
178 | return steps | |
179 | } | |
180 | ||
181 | func (b *PlanGraphBuilder) init() { | |
182 | // Do nothing if the user requests customizing the fields | |
183 | if b.CustomConcrete { | |
184 | return | |
185 | } | |
186 | ||
187 | b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex { | |
188 | return &NodeApplyableProvider{ | |
189 | NodeAbstractProvider: a, | |
190 | } | |
191 | } | |
192 | ||
193 | b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex { | |
194 | return &NodePlannableResource{ | |
107c1cdb | 195 | NodeAbstractResource: a, |
bae9f6d2 JC |
196 | } |
197 | } | |
198 | ||
107c1cdb ND |
199 | b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex { |
200 | return &NodePlannableResourceInstanceOrphan{ | |
201 | NodeAbstractResourceInstance: a, | |
bae9f6d2 JC |
202 | } |
203 | } | |
204 | } |