]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | "log" | |
6 | ||
7 | "github.com/hashicorp/terraform/config" | |
8 | ) | |
9 | ||
10 | // EvalDeleteOutput is an EvalNode implementation that deletes an output | |
11 | // from the state. | |
12 | type EvalDeleteOutput struct { | |
13 | Name string | |
14 | } | |
15 | ||
16 | // TODO: test | |
17 | func (n *EvalDeleteOutput) Eval(ctx EvalContext) (interface{}, error) { | |
18 | state, lock := ctx.State() | |
19 | if state == nil { | |
20 | return nil, nil | |
21 | } | |
22 | ||
23 | // Get a write lock so we can access this instance | |
24 | lock.Lock() | |
25 | defer lock.Unlock() | |
26 | ||
27 | // Look for the module state. If we don't have one, create it. | |
28 | mod := state.ModuleByPath(ctx.Path()) | |
29 | if mod == nil { | |
30 | return nil, nil | |
31 | } | |
32 | ||
33 | delete(mod.Outputs, n.Name) | |
34 | ||
35 | return nil, nil | |
36 | } | |
37 | ||
38 | // EvalWriteOutput is an EvalNode implementation that writes the output | |
39 | // for the given name to the current state. | |
40 | type EvalWriteOutput struct { | |
41 | Name string | |
42 | Sensitive bool | |
43 | Value *config.RawConfig | |
15c0b25d AP |
44 | // ContinueOnErr allows interpolation to fail during Input |
45 | ContinueOnErr bool | |
bae9f6d2 JC |
46 | } |
47 | ||
48 | // TODO: test | |
49 | func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) { | |
15c0b25d AP |
50 | // This has to run before we have a state lock, since interpolation also |
51 | // reads the state | |
bae9f6d2 | 52 | cfg, err := ctx.Interpolate(n.Value, nil) |
15c0b25d | 53 | // handle the error after we have the module from the state |
bae9f6d2 JC |
54 | |
55 | state, lock := ctx.State() | |
56 | if state == nil { | |
57 | return nil, fmt.Errorf("cannot write state to nil state") | |
58 | } | |
59 | ||
60 | // Get a write lock so we can access this instance | |
61 | lock.Lock() | |
62 | defer lock.Unlock() | |
bae9f6d2 JC |
63 | // Look for the module state. If we don't have one, create it. |
64 | mod := state.ModuleByPath(ctx.Path()) | |
65 | if mod == nil { | |
66 | mod = state.AddModule(ctx.Path()) | |
67 | } | |
68 | ||
15c0b25d AP |
69 | // handling the interpolation error |
70 | if err != nil { | |
71 | if n.ContinueOnErr || flagWarnOutputErrors { | |
72 | log.Printf("[ERROR] Output interpolation %q failed: %s", n.Name, err) | |
73 | // if we're continuing, make sure the output is included, and | |
74 | // marked as unknown | |
75 | mod.Outputs[n.Name] = &OutputState{ | |
76 | Type: "string", | |
77 | Value: config.UnknownVariableValue, | |
78 | } | |
79 | return nil, EvalEarlyExitError{} | |
80 | } | |
81 | return nil, err | |
82 | } | |
83 | ||
bae9f6d2 JC |
84 | // Get the value from the config |
85 | var valueRaw interface{} = config.UnknownVariableValue | |
86 | if cfg != nil { | |
87 | var ok bool | |
88 | valueRaw, ok = cfg.Get("value") | |
89 | if !ok { | |
90 | valueRaw = "" | |
91 | } | |
92 | if cfg.IsComputed("value") { | |
93 | valueRaw = config.UnknownVariableValue | |
94 | } | |
95 | } | |
96 | ||
97 | switch valueTyped := valueRaw.(type) { | |
98 | case string: | |
99 | mod.Outputs[n.Name] = &OutputState{ | |
100 | Type: "string", | |
101 | Sensitive: n.Sensitive, | |
102 | Value: valueTyped, | |
103 | } | |
104 | case []interface{}: | |
105 | mod.Outputs[n.Name] = &OutputState{ | |
106 | Type: "list", | |
107 | Sensitive: n.Sensitive, | |
108 | Value: valueTyped, | |
109 | } | |
110 | case map[string]interface{}: | |
111 | mod.Outputs[n.Name] = &OutputState{ | |
112 | Type: "map", | |
113 | Sensitive: n.Sensitive, | |
114 | Value: valueTyped, | |
115 | } | |
116 | case []map[string]interface{}: | |
117 | // an HCL map is multi-valued, so if this was read out of a config the | |
118 | // map may still be in a slice. | |
119 | if len(valueTyped) == 1 { | |
120 | mod.Outputs[n.Name] = &OutputState{ | |
121 | Type: "map", | |
122 | Sensitive: n.Sensitive, | |
123 | Value: valueTyped[0], | |
124 | } | |
125 | break | |
126 | } | |
127 | return nil, fmt.Errorf("output %s type (%T) with %d values not valid for type map", | |
128 | n.Name, valueTyped, len(valueTyped)) | |
129 | default: | |
130 | return nil, fmt.Errorf("output %s is not a valid type (%T)\n", n.Name, valueTyped) | |
131 | } | |
132 | ||
133 | return nil, nil | |
134 | } |