aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go
diff options
context:
space:
mode:
authorJake Champlin <jake.champlin.27@gmail.com>2017-06-06 12:40:07 -0400
committerJake Champlin <jake.champlin.27@gmail.com>2017-06-06 12:40:07 -0400
commitbae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch)
treeca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/github.com/hashicorp/terraform/terraform/eval_apply.go
parent254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff)
downloadterraform-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.go359
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 @@
1package terraform
2
3import (
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.
14type 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
25func (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
98type EvalApplyPre struct {
99 Info *InstanceInfo
100 State **InstanceState
101 Diff **InstanceDiff
102}
103
104// TODO: test
105func (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
129type EvalApplyPost struct {
130 Info *InstanceInfo
131 State **InstanceState
132 Error *error
133}
134
135// TODO: test
136func (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.
157type 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
170func (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.
236func (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
256func (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}