diff options
author | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
---|---|---|
committer | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
commit | bae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch) | |
tree | ca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/github.com/hashicorp/terraform/terraform/eval_apply.go | |
parent | 254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff) | |
download | terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.gz terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.zst terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.zip |
Initial transfer of provider code
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/eval_apply.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/eval_apply.go | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go b/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go new file mode 100644 index 0000000..2f6a497 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go | |||
@@ -0,0 +1,359 @@ | |||
1 | package terraform | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "log" | ||
6 | "strconv" | ||
7 | |||
8 | "github.com/hashicorp/go-multierror" | ||
9 | "github.com/hashicorp/terraform/config" | ||
10 | ) | ||
11 | |||
12 | // EvalApply is an EvalNode implementation that writes the diff to | ||
13 | // the full diff. | ||
14 | type EvalApply struct { | ||
15 | Info *InstanceInfo | ||
16 | State **InstanceState | ||
17 | Diff **InstanceDiff | ||
18 | Provider *ResourceProvider | ||
19 | Output **InstanceState | ||
20 | CreateNew *bool | ||
21 | Error *error | ||
22 | } | ||
23 | |||
24 | // TODO: test | ||
25 | func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) { | ||
26 | diff := *n.Diff | ||
27 | provider := *n.Provider | ||
28 | state := *n.State | ||
29 | |||
30 | // If we have no diff, we have nothing to do! | ||
31 | if diff.Empty() { | ||
32 | log.Printf( | ||
33 | "[DEBUG] apply: %s: diff is empty, doing nothing.", n.Info.Id) | ||
34 | return nil, nil | ||
35 | } | ||
36 | |||
37 | // Remove any output values from the diff | ||
38 | for k, ad := range diff.CopyAttributes() { | ||
39 | if ad.Type == DiffAttrOutput { | ||
40 | diff.DelAttribute(k) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | // If the state is nil, make it non-nil | ||
45 | if state == nil { | ||
46 | state = new(InstanceState) | ||
47 | } | ||
48 | state.init() | ||
49 | |||
50 | // Flag if we're creating a new instance | ||
51 | if n.CreateNew != nil { | ||
52 | *n.CreateNew = state.ID == "" && !diff.GetDestroy() || diff.RequiresNew() | ||
53 | } | ||
54 | |||
55 | // With the completed diff, apply! | ||
56 | log.Printf("[DEBUG] apply: %s: executing Apply", n.Info.Id) | ||
57 | state, err := provider.Apply(n.Info, state, diff) | ||
58 | if state == nil { | ||
59 | state = new(InstanceState) | ||
60 | } | ||
61 | state.init() | ||
62 | |||
63 | // Force the "id" attribute to be our ID | ||
64 | if state.ID != "" { | ||
65 | state.Attributes["id"] = state.ID | ||
66 | } | ||
67 | |||
68 | // If the value is the unknown variable value, then it is an error. | ||
69 | // In this case we record the error and remove it from the state | ||
70 | for ak, av := range state.Attributes { | ||
71 | if av == config.UnknownVariableValue { | ||
72 | err = multierror.Append(err, fmt.Errorf( | ||
73 | "Attribute with unknown value: %s", ak)) | ||
74 | delete(state.Attributes, ak) | ||
75 | } | ||
76 | } | ||
77 | |||
78 | // Write the final state | ||
79 | if n.Output != nil { | ||
80 | *n.Output = state | ||
81 | } | ||
82 | |||
83 | // If there are no errors, then we append it to our output error | ||
84 | // if we have one, otherwise we just output it. | ||
85 | if err != nil { | ||
86 | if n.Error != nil { | ||
87 | helpfulErr := fmt.Errorf("%s: %s", n.Info.Id, err.Error()) | ||
88 | *n.Error = multierror.Append(*n.Error, helpfulErr) | ||
89 | } else { | ||
90 | return nil, err | ||
91 | } | ||
92 | } | ||
93 | |||
94 | return nil, nil | ||
95 | } | ||
96 | |||
97 | // EvalApplyPre is an EvalNode implementation that does the pre-Apply work | ||
98 | type EvalApplyPre struct { | ||
99 | Info *InstanceInfo | ||
100 | State **InstanceState | ||
101 | Diff **InstanceDiff | ||
102 | } | ||
103 | |||
104 | // TODO: test | ||
105 | func (n *EvalApplyPre) Eval(ctx EvalContext) (interface{}, error) { | ||
106 | state := *n.State | ||
107 | diff := *n.Diff | ||
108 | |||
109 | // If the state is nil, make it non-nil | ||
110 | if state == nil { | ||
111 | state = new(InstanceState) | ||
112 | } | ||
113 | state.init() | ||
114 | |||
115 | { | ||
116 | // Call post-apply hook | ||
117 | err := ctx.Hook(func(h Hook) (HookAction, error) { | ||
118 | return h.PreApply(n.Info, state, diff) | ||
119 | }) | ||
120 | if err != nil { | ||
121 | return nil, err | ||
122 | } | ||
123 | } | ||
124 | |||
125 | return nil, nil | ||
126 | } | ||
127 | |||
128 | // EvalApplyPost is an EvalNode implementation that does the post-Apply work | ||
129 | type EvalApplyPost struct { | ||
130 | Info *InstanceInfo | ||
131 | State **InstanceState | ||
132 | Error *error | ||
133 | } | ||
134 | |||
135 | // TODO: test | ||
136 | func (n *EvalApplyPost) Eval(ctx EvalContext) (interface{}, error) { | ||
137 | state := *n.State | ||
138 | |||
139 | { | ||
140 | // Call post-apply hook | ||
141 | err := ctx.Hook(func(h Hook) (HookAction, error) { | ||
142 | return h.PostApply(n.Info, state, *n.Error) | ||
143 | }) | ||
144 | if err != nil { | ||
145 | return nil, err | ||
146 | } | ||
147 | } | ||
148 | |||
149 | return nil, *n.Error | ||
150 | } | ||
151 | |||
152 | // EvalApplyProvisioners is an EvalNode implementation that executes | ||
153 | // the provisioners for a resource. | ||
154 | // | ||
155 | // TODO(mitchellh): This should probably be split up into a more fine-grained | ||
156 | // ApplyProvisioner (single) that is looped over. | ||
157 | type EvalApplyProvisioners struct { | ||
158 | Info *InstanceInfo | ||
159 | State **InstanceState | ||
160 | Resource *config.Resource | ||
161 | InterpResource *Resource | ||
162 | CreateNew *bool | ||
163 | Error *error | ||
164 | |||
165 | // When is the type of provisioner to run at this point | ||
166 | When config.ProvisionerWhen | ||
167 | } | ||
168 | |||
169 | // TODO: test | ||
170 | func (n *EvalApplyProvisioners) Eval(ctx EvalContext) (interface{}, error) { | ||
171 | state := *n.State | ||
172 | |||
173 | if n.CreateNew != nil && !*n.CreateNew { | ||
174 | // If we're not creating a new resource, then don't run provisioners | ||
175 | return nil, nil | ||
176 | } | ||
177 | |||
178 | provs := n.filterProvisioners() | ||
179 | if len(provs) == 0 { | ||
180 | // We have no provisioners, so don't do anything | ||
181 | return nil, nil | ||
182 | } | ||
183 | |||
184 | // taint tells us whether to enable tainting. | ||
185 | taint := n.When == config.ProvisionerWhenCreate | ||
186 | |||
187 | if n.Error != nil && *n.Error != nil { | ||
188 | if taint { | ||
189 | state.Tainted = true | ||
190 | } | ||
191 | |||
192 | // We're already tainted, so just return out | ||
193 | return nil, nil | ||
194 | } | ||
195 | |||
196 | { | ||
197 | // Call pre hook | ||
198 | err := ctx.Hook(func(h Hook) (HookAction, error) { | ||
199 | return h.PreProvisionResource(n.Info, state) | ||
200 | }) | ||
201 | if err != nil { | ||
202 | return nil, err | ||
203 | } | ||
204 | } | ||
205 | |||
206 | // If there are no errors, then we append it to our output error | ||
207 | // if we have one, otherwise we just output it. | ||
208 | err := n.apply(ctx, provs) | ||
209 | if err != nil { | ||
210 | if taint { | ||
211 | state.Tainted = true | ||
212 | } | ||
213 | |||
214 | if n.Error != nil { | ||
215 | *n.Error = multierror.Append(*n.Error, err) | ||
216 | } else { | ||
217 | return nil, err | ||
218 | } | ||
219 | } | ||
220 | |||
221 | { | ||
222 | // Call post hook | ||
223 | err := ctx.Hook(func(h Hook) (HookAction, error) { | ||
224 | return h.PostProvisionResource(n.Info, state) | ||
225 | }) | ||
226 | if err != nil { | ||
227 | return nil, err | ||
228 | } | ||
229 | } | ||
230 | |||
231 | return nil, nil | ||
232 | } | ||
233 | |||
234 | // filterProvisioners filters the provisioners on the resource to only | ||
235 | // the provisioners specified by the "when" option. | ||
236 | func (n *EvalApplyProvisioners) filterProvisioners() []*config.Provisioner { | ||
237 | // Fast path the zero case | ||
238 | if n.Resource == nil { | ||
239 | return nil | ||
240 | } | ||
241 | |||
242 | if len(n.Resource.Provisioners) == 0 { | ||
243 | return nil | ||
244 | } | ||
245 | |||
246 | result := make([]*config.Provisioner, 0, len(n.Resource.Provisioners)) | ||
247 | for _, p := range n.Resource.Provisioners { | ||
248 | if p.When == n.When { | ||
249 | result = append(result, p) | ||
250 | } | ||
251 | } | ||
252 | |||
253 | return result | ||
254 | } | ||
255 | |||
256 | func (n *EvalApplyProvisioners) apply(ctx EvalContext, provs []*config.Provisioner) error { | ||
257 | state := *n.State | ||
258 | |||
259 | // Store the original connection info, restore later | ||
260 | origConnInfo := state.Ephemeral.ConnInfo | ||
261 | defer func() { | ||
262 | state.Ephemeral.ConnInfo = origConnInfo | ||
263 | }() | ||
264 | |||
265 | for _, prov := range provs { | ||
266 | // Get the provisioner | ||
267 | provisioner := ctx.Provisioner(prov.Type) | ||
268 | |||
269 | // Interpolate the provisioner config | ||
270 | provConfig, err := ctx.Interpolate(prov.RawConfig.Copy(), n.InterpResource) | ||
271 | if err != nil { | ||
272 | return err | ||
273 | } | ||
274 | |||
275 | // Interpolate the conn info, since it may contain variables | ||
276 | connInfo, err := ctx.Interpolate(prov.ConnInfo.Copy(), n.InterpResource) | ||
277 | if err != nil { | ||
278 | return err | ||
279 | } | ||
280 | |||
281 | // Merge the connection information | ||
282 | overlay := make(map[string]string) | ||
283 | if origConnInfo != nil { | ||
284 | for k, v := range origConnInfo { | ||
285 | overlay[k] = v | ||
286 | } | ||
287 | } | ||
288 | for k, v := range connInfo.Config { | ||
289 | switch vt := v.(type) { | ||
290 | case string: | ||
291 | overlay[k] = vt | ||
292 | case int64: | ||
293 | overlay[k] = strconv.FormatInt(vt, 10) | ||
294 | case int32: | ||
295 | overlay[k] = strconv.FormatInt(int64(vt), 10) | ||
296 | case int: | ||
297 | overlay[k] = strconv.FormatInt(int64(vt), 10) | ||
298 | case float32: | ||
299 | overlay[k] = strconv.FormatFloat(float64(vt), 'f', 3, 32) | ||
300 | case float64: | ||
301 | overlay[k] = strconv.FormatFloat(vt, 'f', 3, 64) | ||
302 | case bool: | ||
303 | overlay[k] = strconv.FormatBool(vt) | ||
304 | default: | ||
305 | overlay[k] = fmt.Sprintf("%v", vt) | ||
306 | } | ||
307 | } | ||
308 | state.Ephemeral.ConnInfo = overlay | ||
309 | |||
310 | { | ||
311 | // Call pre hook | ||
312 | err := ctx.Hook(func(h Hook) (HookAction, error) { | ||
313 | return h.PreProvision(n.Info, prov.Type) | ||
314 | }) | ||
315 | if err != nil { | ||
316 | return err | ||
317 | } | ||
318 | } | ||
319 | |||
320 | // The output function | ||
321 | outputFn := func(msg string) { | ||
322 | ctx.Hook(func(h Hook) (HookAction, error) { | ||
323 | h.ProvisionOutput(n.Info, prov.Type, msg) | ||
324 | return HookActionContinue, nil | ||
325 | }) | ||
326 | } | ||
327 | |||
328 | // Invoke the Provisioner | ||
329 | output := CallbackUIOutput{OutputFn: outputFn} | ||
330 | applyErr := provisioner.Apply(&output, state, provConfig) | ||
331 | |||
332 | // Call post hook | ||
333 | hookErr := ctx.Hook(func(h Hook) (HookAction, error) { | ||
334 | return h.PostProvision(n.Info, prov.Type, applyErr) | ||
335 | }) | ||
336 | |||
337 | // Handle the error before we deal with the hook | ||
338 | if applyErr != nil { | ||
339 | // Determine failure behavior | ||
340 | switch prov.OnFailure { | ||
341 | case config.ProvisionerOnFailureContinue: | ||
342 | log.Printf( | ||
343 | "[INFO] apply: %s [%s]: error during provision, continue requested", | ||
344 | n.Info.Id, prov.Type) | ||
345 | |||
346 | case config.ProvisionerOnFailureFail: | ||
347 | return applyErr | ||
348 | } | ||
349 | } | ||
350 | |||
351 | // Deal with the hook | ||
352 | if hookErr != nil { | ||
353 | return hookErr | ||
354 | } | ||
355 | } | ||
356 | |||
357 | return nil | ||
358 | |||
359 | } | ||