]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
107c1cdb ND |
4 | "github.com/hashicorp/terraform/addrs" |
5 | "github.com/hashicorp/terraform/configs" | |
bae9f6d2 | 6 | "github.com/hashicorp/terraform/dag" |
107c1cdb ND |
7 | "github.com/hashicorp/terraform/plans" |
8 | "github.com/hashicorp/terraform/states" | |
9 | "github.com/hashicorp/terraform/tfdiags" | |
bae9f6d2 JC |
10 | ) |
11 | ||
12 | // ApplyGraphBuilder implements GraphBuilder and is responsible for building | |
13 | // a graph for applying a Terraform diff. | |
14 | // | |
15 | // Because the graph is built from the diff (vs. the config or state), | |
16 | // this helps ensure that the apply-time graph doesn't modify any resources | |
17 | // that aren't explicitly in the diff. There are other scenarios where the | |
18 | // diff can be deviated, so this is just one layer of protection. | |
19 | type ApplyGraphBuilder struct { | |
107c1cdb ND |
20 | // Config is the configuration tree that the diff was built from. |
21 | Config *configs.Config | |
bae9f6d2 | 22 | |
107c1cdb ND |
23 | // Changes describes the changes that we need apply. |
24 | Changes *plans.Changes | |
bae9f6d2 JC |
25 | |
26 | // State is the current state | |
107c1cdb | 27 | State *states.State |
bae9f6d2 | 28 | |
107c1cdb ND |
29 | // Components is a factory for the plug-in components (providers and |
30 | // provisioners) available for use. | |
31 | Components contextComponentFactory | |
bae9f6d2 | 32 | |
107c1cdb ND |
33 | // Schemas is the repository of schemas we will draw from to analyse |
34 | // the configuration. | |
35 | Schemas *Schemas | |
bae9f6d2 JC |
36 | |
37 | // Targets are resources to target. This is only required to make sure | |
38 | // unnecessary outputs aren't included in the apply graph. The plan | |
39 | // builder successfully handles targeting resources. In the future, | |
40 | // outputs should go into the diff so that this is unnecessary. | |
107c1cdb | 41 | Targets []addrs.Targetable |
bae9f6d2 JC |
42 | |
43 | // DisableReduce, if true, will not reduce the graph. Great for testing. | |
44 | DisableReduce bool | |
45 | ||
46 | // Destroy, if true, represents a pure destroy operation | |
47 | Destroy bool | |
48 | ||
49 | // Validate will do structural validation of the graph. | |
50 | Validate bool | |
51 | } | |
52 | ||
53 | // See GraphBuilder | |
107c1cdb | 54 | func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { |
bae9f6d2 JC |
55 | return (&BasicGraphBuilder{ |
56 | Steps: b.Steps(), | |
57 | Validate: b.Validate, | |
58 | Name: "ApplyGraphBuilder", | |
59 | }).Build(path) | |
60 | } | |
61 | ||
62 | // See GraphBuilder | |
63 | func (b *ApplyGraphBuilder) Steps() []GraphTransformer { | |
64 | // Custom factory for creating providers. | |
65 | concreteProvider := func(a *NodeAbstractProvider) dag.Vertex { | |
66 | return &NodeApplyableProvider{ | |
67 | NodeAbstractProvider: a, | |
68 | } | |
69 | } | |
70 | ||
71 | concreteResource := func(a *NodeAbstractResource) dag.Vertex { | |
72 | return &NodeApplyableResource{ | |
73 | NodeAbstractResource: a, | |
74 | } | |
75 | } | |
76 | ||
107c1cdb ND |
77 | concreteOrphanResource := func(a *NodeAbstractResource) dag.Vertex { |
78 | return &NodeDestroyResource{ | |
79 | NodeAbstractResource: a, | |
80 | } | |
81 | } | |
82 | ||
83 | concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { | |
84 | return &NodeApplyableResourceInstance{ | |
85 | NodeAbstractResourceInstance: a, | |
86 | } | |
87 | } | |
88 | ||
bae9f6d2 | 89 | steps := []GraphTransformer{ |
107c1cdb ND |
90 | // Creates all the resources represented in the config. During apply, |
91 | // we use this just to ensure that the whole-resource metadata is | |
92 | // updated to reflect things such as whether the count argument is | |
93 | // set in config, or which provider configuration manages each resource. | |
94 | &ConfigTransformer{ | |
bae9f6d2 | 95 | Concrete: concreteResource, |
107c1cdb ND |
96 | Config: b.Config, |
97 | }, | |
bae9f6d2 | 98 | |
107c1cdb ND |
99 | // Creates all the resource instances represented in the diff, along |
100 | // with dependency edges against the whole-resource nodes added by | |
101 | // ConfigTransformer above. | |
102 | &DiffTransformer{ | |
103 | Concrete: concreteResourceInstance, | |
104 | State: b.State, | |
105 | Changes: b.Changes, | |
106 | }, | |
107 | ||
108 | // Creates extra cleanup nodes for any entire resources that are | |
109 | // no longer present in config, so we can make sure we clean up the | |
110 | // leftover empty resource states after the instances have been | |
111 | // destroyed. | |
112 | // (We don't track this particular type of change in the plan because | |
113 | // it's just cleanup of our own state object, and so doesn't effect | |
114 | // any real remote objects or consumable outputs.) | |
115 | &OrphanResourceTransformer{ | |
116 | Concrete: concreteOrphanResource, | |
117 | Config: b.Config, | |
118 | State: b.State, | |
bae9f6d2 JC |
119 | }, |
120 | ||
121 | // Create orphan output nodes | |
107c1cdb | 122 | &OrphanOutputTransformer{Config: b.Config, State: b.State}, |
bae9f6d2 JC |
123 | |
124 | // Attach the configuration to any resources | |
107c1cdb | 125 | &AttachResourceConfigTransformer{Config: b.Config}, |
bae9f6d2 JC |
126 | |
127 | // Attach the state | |
128 | &AttachStateTransformer{State: b.State}, | |
129 | ||
bae9f6d2 | 130 | // Destruction ordering |
107c1cdb ND |
131 | &DestroyEdgeTransformer{ |
132 | Config: b.Config, | |
133 | State: b.State, | |
134 | Schemas: b.Schemas, | |
135 | }, | |
bae9f6d2 JC |
136 | GraphTransformIf( |
137 | func() bool { return !b.Destroy }, | |
107c1cdb ND |
138 | &CBDEdgeTransformer{ |
139 | Config: b.Config, | |
140 | State: b.State, | |
141 | Schemas: b.Schemas, | |
142 | }, | |
bae9f6d2 JC |
143 | ), |
144 | ||
145 | // Provisioner-related transformations | |
107c1cdb | 146 | &MissingProvisionerTransformer{Provisioners: b.Components.ResourceProvisioners()}, |
bae9f6d2 JC |
147 | &ProvisionerTransformer{}, |
148 | ||
149 | // Add root variables | |
107c1cdb | 150 | &RootVariableTransformer{Config: b.Config}, |
bae9f6d2 | 151 | |
15c0b25d | 152 | // Add the local values |
107c1cdb | 153 | &LocalTransformer{Config: b.Config}, |
15c0b25d | 154 | |
bae9f6d2 | 155 | // Add the outputs |
107c1cdb | 156 | &OutputTransformer{Config: b.Config}, |
bae9f6d2 JC |
157 | |
158 | // Add module variables | |
107c1cdb ND |
159 | &ModuleVariableTransformer{Config: b.Config}, |
160 | ||
161 | // add providers | |
162 | TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config), | |
bae9f6d2 | 163 | |
15c0b25d | 164 | // Remove modules no longer present in the config |
107c1cdb ND |
165 | &RemovedModuleTransformer{Config: b.Config, State: b.State}, |
166 | ||
167 | // Must attach schemas before ReferenceTransformer so that we can | |
168 | // analyze the configuration to find references. | |
169 | &AttachSchemaTransformer{Schemas: b.Schemas}, | |
15c0b25d | 170 | |
bae9f6d2 JC |
171 | // Connect references so ordering is correct |
172 | &ReferenceTransformer{}, | |
173 | ||
15c0b25d AP |
174 | // Handle destroy time transformations for output and local values. |
175 | // Reverse the edges from outputs and locals, so that | |
176 | // interpolations don't fail during destroy. | |
177 | // Create a destroy node for outputs to remove them from the state. | |
178 | // Prune unreferenced values, which may have interpolations that can't | |
179 | // be resolved. | |
180 | GraphTransformIf( | |
181 | func() bool { return b.Destroy }, | |
182 | GraphTransformMulti( | |
183 | &DestroyValueReferenceTransformer{}, | |
184 | &DestroyOutputTransformer{}, | |
185 | &PruneUnusedValuesTransformer{}, | |
186 | ), | |
187 | ), | |
188 | ||
bae9f6d2 | 189 | // Add the node to fix the state count boundaries |
107c1cdb ND |
190 | &CountBoundaryTransformer{ |
191 | Config: b.Config, | |
192 | }, | |
bae9f6d2 JC |
193 | |
194 | // Target | |
195 | &TargetsTransformer{Targets: b.Targets}, | |
196 | ||
197 | // Close opened plugin connections | |
198 | &CloseProviderTransformer{}, | |
199 | &CloseProvisionerTransformer{}, | |
200 | ||
201 | // Single root | |
202 | &RootTransformer{}, | |
203 | } | |
204 | ||
205 | if !b.DisableReduce { | |
206 | // Perform the transitive reduction to make our graph a bit | |
207 | // more sane if possible (it usually is possible). | |
208 | steps = append(steps, &TransitiveReductionTransformer{}) | |
209 | } | |
210 | ||
211 | return steps | |
212 | } |