]>
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 | |
44 | } | |
45 | ||
46 | // TODO: test | |
47 | func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) { | |
48 | cfg, err := ctx.Interpolate(n.Value, nil) | |
49 | if err != nil { | |
50 | // Log error but continue anyway | |
51 | log.Printf("[WARN] Output interpolation %q failed: %s", n.Name, err) | |
52 | } | |
53 | ||
54 | state, lock := ctx.State() | |
55 | if state == nil { | |
56 | return nil, fmt.Errorf("cannot write state to nil state") | |
57 | } | |
58 | ||
59 | // Get a write lock so we can access this instance | |
60 | lock.Lock() | |
61 | defer lock.Unlock() | |
62 | ||
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 | ||
69 | // Get the value from the config | |
70 | var valueRaw interface{} = config.UnknownVariableValue | |
71 | if cfg != nil { | |
72 | var ok bool | |
73 | valueRaw, ok = cfg.Get("value") | |
74 | if !ok { | |
75 | valueRaw = "" | |
76 | } | |
77 | if cfg.IsComputed("value") { | |
78 | valueRaw = config.UnknownVariableValue | |
79 | } | |
80 | } | |
81 | ||
82 | switch valueTyped := valueRaw.(type) { | |
83 | case string: | |
84 | mod.Outputs[n.Name] = &OutputState{ | |
85 | Type: "string", | |
86 | Sensitive: n.Sensitive, | |
87 | Value: valueTyped, | |
88 | } | |
89 | case []interface{}: | |
90 | mod.Outputs[n.Name] = &OutputState{ | |
91 | Type: "list", | |
92 | Sensitive: n.Sensitive, | |
93 | Value: valueTyped, | |
94 | } | |
95 | case map[string]interface{}: | |
96 | mod.Outputs[n.Name] = &OutputState{ | |
97 | Type: "map", | |
98 | Sensitive: n.Sensitive, | |
99 | Value: valueTyped, | |
100 | } | |
101 | case []map[string]interface{}: | |
102 | // an HCL map is multi-valued, so if this was read out of a config the | |
103 | // map may still be in a slice. | |
104 | if len(valueTyped) == 1 { | |
105 | mod.Outputs[n.Name] = &OutputState{ | |
106 | Type: "map", | |
107 | Sensitive: n.Sensitive, | |
108 | Value: valueTyped[0], | |
109 | } | |
110 | break | |
111 | } | |
112 | return nil, fmt.Errorf("output %s type (%T) with %d values not valid for type map", | |
113 | n.Name, valueTyped, len(valueTyped)) | |
114 | default: | |
115 | return nil, fmt.Errorf("output %s is not a valid type (%T)\n", n.Name, valueTyped) | |
116 | } | |
117 | ||
118 | return nil, nil | |
119 | } |