]>
Commit | Line | Data |
---|---|---|
1 | package terraform | |
2 | ||
3 | import ( | |
4 | "sync" | |
5 | ||
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" | |
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 { | |
25 | // Config is the configuration tree to build a plan from. | |
26 | Config *configs.Config | |
27 | ||
28 | // State is the current state | |
29 | State *states.State | |
30 | ||
31 | // Components is a factory for the plug-in components (providers and | |
32 | // provisioners) available for use. | |
33 | Components contextComponentFactory | |
34 | ||
35 | // Schemas is the repository of schemas we will draw from to analyse | |
36 | // the configuration. | |
37 | Schemas *Schemas | |
38 | ||
39 | // Targets are resources to target | |
40 | Targets []addrs.Targetable | |
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 | |
54 | ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc | |
55 | ||
56 | once sync.Once | |
57 | } | |
58 | ||
59 | // See GraphBuilder | |
60 | func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { | |
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 | ||
72 | concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex { | |
73 | return &NodePlanDeposedResourceInstanceObject{ | |
74 | NodeAbstractResourceInstance: a, | |
75 | DeposedKey: key, | |
76 | } | |
77 | } | |
78 | ||
79 | steps := []GraphTransformer{ | |
80 | // Creates all the resources represented in the config | |
81 | &ConfigTransformer{ | |
82 | Concrete: b.ConcreteResource, | |
83 | Config: b.Config, | |
84 | }, | |
85 | ||
86 | // Add the local values | |
87 | &LocalTransformer{Config: b.Config}, | |
88 | ||
89 | // Add the outputs | |
90 | &OutputTransformer{Config: b.Config}, | |
91 | ||
92 | // Add orphan resources | |
93 | &OrphanResourceInstanceTransformer{ | |
94 | Concrete: b.ConcreteResourceOrphan, | |
95 | State: b.State, | |
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, | |
106 | }, | |
107 | ||
108 | // Create orphan output nodes | |
109 | &OrphanOutputTransformer{ | |
110 | Config: b.Config, | |
111 | State: b.State, | |
112 | }, | |
113 | ||
114 | // Attach the configuration to any resources | |
115 | &AttachResourceConfigTransformer{Config: b.Config}, | |
116 | ||
117 | // Attach the state | |
118 | &AttachStateTransformer{State: b.State}, | |
119 | ||
120 | // Add root variables | |
121 | &RootVariableTransformer{Config: b.Config}, | |
122 | ||
123 | &MissingProvisionerTransformer{Provisioners: b.Components.ResourceProvisioners()}, | |
124 | &ProvisionerTransformer{}, | |
125 | ||
126 | // Add module variables | |
127 | &ModuleVariableTransformer{ | |
128 | Config: b.Config, | |
129 | }, | |
130 | ||
131 | TransformProviders(b.Components.ResourceProviders(), b.ConcreteProvider, b.Config), | |
132 | ||
133 | // Remove modules no longer present in the config | |
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}, | |
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 | |
145 | &CountBoundaryTransformer{ | |
146 | Config: b.Config, | |
147 | }, | |
148 | ||
149 | // Target | |
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 | }, | |
159 | ||
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 | ||
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{ | |
195 | NodeAbstractResource: a, | |
196 | } | |
197 | } | |
198 | ||
199 | b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex { | |
200 | return &NodePlannableResourceInstanceOrphan{ | |
201 | NodeAbstractResourceInstance: a, | |
202 | } | |
203 | } | |
204 | } |