]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/eval_output.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / eval_output.go
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
4 "fmt"
5 "log"
6
107c1cdb
ND
7 "github.com/hashicorp/hcl2/hcl"
8 "github.com/zclconf/go-cty/cty"
9
10 "github.com/hashicorp/terraform/addrs"
11 "github.com/hashicorp/terraform/plans"
12 "github.com/hashicorp/terraform/states"
bae9f6d2
JC
13)
14
15// EvalDeleteOutput is an EvalNode implementation that deletes an output
16// from the state.
17type EvalDeleteOutput struct {
107c1cdb 18 Addr addrs.OutputValue
bae9f6d2
JC
19}
20
21// TODO: test
22func (n *EvalDeleteOutput) Eval(ctx EvalContext) (interface{}, error) {
107c1cdb 23 state := ctx.State()
bae9f6d2
JC
24 if state == nil {
25 return nil, nil
26 }
27
107c1cdb 28 state.RemoveOutputValue(n.Addr.Absolute(ctx.Path()))
bae9f6d2
JC
29 return nil, nil
30}
31
32// EvalWriteOutput is an EvalNode implementation that writes the output
33// for the given name to the current state.
34type EvalWriteOutput struct {
107c1cdb 35 Addr addrs.OutputValue
bae9f6d2 36 Sensitive bool
107c1cdb 37 Expr hcl.Expression
15c0b25d
AP
38 // ContinueOnErr allows interpolation to fail during Input
39 ContinueOnErr bool
bae9f6d2
JC
40}
41
42// TODO: test
43func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
107c1cdb
ND
44 addr := n.Addr.Absolute(ctx.Path())
45
46 // This has to run before we have a state lock, since evaluation also
15c0b25d 47 // reads the state
107c1cdb
ND
48 val, diags := ctx.EvaluateExpr(n.Expr, cty.DynamicPseudoType, nil)
49 // We'll handle errors below, after we have loaded the module.
bae9f6d2 50
107c1cdb 51 state := ctx.State()
bae9f6d2 52 if state == nil {
107c1cdb 53 return nil, nil
bae9f6d2
JC
54 }
55
107c1cdb 56 changes := ctx.Changes() // may be nil, if we're not working on a changeset
bae9f6d2 57
15c0b25d 58 // handling the interpolation error
107c1cdb 59 if diags.HasErrors() {
15c0b25d 60 if n.ContinueOnErr || flagWarnOutputErrors {
107c1cdb 61 log.Printf("[ERROR] Output interpolation %q failed: %s", n.Addr.Name, diags.Err())
15c0b25d 62 // if we're continuing, make sure the output is included, and
107c1cdb
ND
63 // marked as unknown. If the evaluator was able to find a type
64 // for the value in spite of the error then we'll use it.
65 n.setValue(addr, state, changes, cty.UnknownVal(val.Type()))
15c0b25d
AP
66 return nil, EvalEarlyExitError{}
67 }
107c1cdb 68 return nil, diags.Err()
15c0b25d
AP
69 }
70
107c1cdb
ND
71 n.setValue(addr, state, changes, val)
72
73 return nil, nil
74}
75
76func (n *EvalWriteOutput) setValue(addr addrs.AbsOutputValue, state *states.SyncState, changes *plans.ChangesSync, val cty.Value) {
77 if val.IsKnown() && !val.IsNull() {
78 // The state itself doesn't represent unknown values, so we null them
79 // out here and then we'll save the real unknown value in the planned
80 // changeset below, if we have one on this graph walk.
81 log.Printf("[TRACE] EvalWriteOutput: Saving value for %s in state", addr)
82 stateVal := cty.UnknownAsNull(val)
83 state.SetOutputValue(addr, stateVal, n.Sensitive)
84 } else {
85 log.Printf("[TRACE] EvalWriteOutput: Removing %s from state (it is now null)", addr)
86 state.RemoveOutputValue(addr)
bae9f6d2
JC
87 }
88
107c1cdb
ND
89 // If we also have an active changeset then we'll replicate the value in
90 // there. This is used in preference to the state where present, since it
91 // *is* able to represent unknowns, while the state cannot.
92 if changes != nil {
93 // For the moment we are not properly tracking changes to output
94 // values, and just marking them always as "Create" or "Destroy"
95 // actions. A future release will rework the output lifecycle so we
96 // can track their changes properly, in a similar way to how we work
97 // with resource instances.
98
99 var change *plans.OutputChange
100 if !val.IsNull() {
101 change = &plans.OutputChange{
102 Addr: addr,
bae9f6d2 103 Sensitive: n.Sensitive,
107c1cdb
ND
104 Change: plans.Change{
105 Action: plans.Create,
106 Before: cty.NullVal(cty.DynamicPseudoType),
107 After: val,
108 },
109 }
110 } else {
111 change = &plans.OutputChange{
112 Addr: addr,
113 Sensitive: n.Sensitive,
114 Change: plans.Change{
115 // This is just a weird placeholder delete action since
116 // we don't have an actual prior value to indicate.
117 // FIXME: Generate real planned changes for output values
118 // that include the old values.
119 Action: plans.Delete,
120 Before: cty.NullVal(cty.DynamicPseudoType),
121 After: cty.NullVal(cty.DynamicPseudoType),
122 },
bae9f6d2 123 }
bae9f6d2 124 }
bae9f6d2 125
107c1cdb
ND
126 cs, err := change.Encode()
127 if err != nil {
128 // Should never happen, since we just constructed this right above
129 panic(fmt.Sprintf("planned change for %s could not be encoded: %s", addr, err))
130 }
131 log.Printf("[TRACE] EvalWriteOutput: Saving %s change for %s in changeset", change.Action, addr)
132 changes.RemoveOutputChange(addr) // remove any existing planned change, if present
133 changes.AppendOutputChange(cs) // add the new planned change
134 }
bae9f6d2 135}