]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/config/raw_config.go
f8498d85cebca599ca3175311bb9ecd25367a408
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / config / raw_config.go
1 package config
2
3 import (
4 "bytes"
5 "encoding/gob"
6 "sync"
7
8 "github.com/hashicorp/hil"
9 "github.com/hashicorp/hil/ast"
10 "github.com/mitchellh/copystructure"
11 "github.com/mitchellh/reflectwalk"
12 )
13
14 // UnknownVariableValue is a sentinel value that can be used
15 // to denote that the value of a variable is unknown at this time.
16 // RawConfig uses this information to build up data about
17 // unknown keys.
18 const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
19
20 // RawConfig is a structure that holds a piece of configuration
21 // where the overall structure is unknown since it will be used
22 // to configure a plugin or some other similar external component.
23 //
24 // RawConfigs can be interpolated with variables that come from
25 // other resources, user variables, etc.
26 //
27 // RawConfig supports a query-like interface to request
28 // information from deep within the structure.
29 type RawConfig struct {
30 Key string
31 Raw map[string]interface{}
32 Interpolations []ast.Node
33 Variables map[string]InterpolatedVariable
34
35 lock sync.Mutex
36 config map[string]interface{}
37 unknownKeys []string
38 }
39
40 // NewRawConfig creates a new RawConfig structure and populates the
41 // publicly readable struct fields.
42 func NewRawConfig(raw map[string]interface{}) (*RawConfig, error) {
43 result := &RawConfig{Raw: raw}
44 if err := result.init(); err != nil {
45 return nil, err
46 }
47
48 return result, nil
49 }
50
51 // RawMap returns a copy of the RawConfig.Raw map.
52 func (r *RawConfig) RawMap() map[string]interface{} {
53 r.lock.Lock()
54 defer r.lock.Unlock()
55
56 m := make(map[string]interface{})
57 for k, v := range r.Raw {
58 m[k] = v
59 }
60 return m
61 }
62
63 // Copy returns a copy of this RawConfig, uninterpolated.
64 func (r *RawConfig) Copy() *RawConfig {
65 if r == nil {
66 return nil
67 }
68
69 r.lock.Lock()
70 defer r.lock.Unlock()
71
72 newRaw := make(map[string]interface{})
73 for k, v := range r.Raw {
74 newRaw[k] = v
75 }
76
77 result, err := NewRawConfig(newRaw)
78 if err != nil {
79 panic("copy failed: " + err.Error())
80 }
81
82 result.Key = r.Key
83 return result
84 }
85
86 // Value returns the value of the configuration if this configuration
87 // has a Key set. If this does not have a Key set, nil will be returned.
88 func (r *RawConfig) Value() interface{} {
89 if c := r.Config(); c != nil {
90 if v, ok := c[r.Key]; ok {
91 return v
92 }
93 }
94
95 r.lock.Lock()
96 defer r.lock.Unlock()
97 return r.Raw[r.Key]
98 }
99
100 // Config returns the entire configuration with the variables
101 // interpolated from any call to Interpolate.
102 //
103 // If any interpolated variables are unknown (value set to
104 // UnknownVariableValue), the first non-container (map, slice, etc.) element
105 // will be removed from the config. The keys of unknown variables
106 // can be found using the UnknownKeys function.
107 //
108 // By pruning out unknown keys from the configuration, the raw
109 // structure will always successfully decode into its ultimate
110 // structure using something like mapstructure.
111 func (r *RawConfig) Config() map[string]interface{} {
112 r.lock.Lock()
113 defer r.lock.Unlock()
114 return r.config
115 }
116
117 // Interpolate uses the given mapping of variable values and uses
118 // those as the values to replace any variables in this raw
119 // configuration.
120 //
121 // Any prior calls to Interpolate are replaced with this one.
122 //
123 // If a variable key is missing, this will panic.
124 func (r *RawConfig) Interpolate(vs map[string]ast.Variable) error {
125 r.lock.Lock()
126 defer r.lock.Unlock()
127
128 config := langEvalConfig(vs)
129 return r.interpolate(func(root ast.Node) (interface{}, error) {
130 // None of the variables we need are computed, meaning we should
131 // be able to properly evaluate.
132 result, err := hil.Eval(root, config)
133 if err != nil {
134 return "", err
135 }
136
137 return result.Value, nil
138 })
139 }
140
141 // Merge merges another RawConfig into this one (overriding any conflicting
142 // values in this config) and returns a new config. The original config
143 // is not modified.
144 func (r *RawConfig) Merge(other *RawConfig) *RawConfig {
145 r.lock.Lock()
146 defer r.lock.Unlock()
147
148 // Merge the raw configurations
149 raw := make(map[string]interface{})
150 for k, v := range r.Raw {
151 raw[k] = v
152 }
153 for k, v := range other.Raw {
154 raw[k] = v
155 }
156
157 // Create the result
158 result, err := NewRawConfig(raw)
159 if err != nil {
160 panic(err)
161 }
162
163 // Merge the interpolated results
164 result.config = make(map[string]interface{})
165 for k, v := range r.config {
166 result.config[k] = v
167 }
168 for k, v := range other.config {
169 result.config[k] = v
170 }
171
172 // Build the unknown keys
173 if len(r.unknownKeys) > 0 || len(other.unknownKeys) > 0 {
174 unknownKeys := make(map[string]struct{})
175 for _, k := range r.unknownKeys {
176 unknownKeys[k] = struct{}{}
177 }
178 for _, k := range other.unknownKeys {
179 unknownKeys[k] = struct{}{}
180 }
181
182 result.unknownKeys = make([]string, 0, len(unknownKeys))
183 for k, _ := range unknownKeys {
184 result.unknownKeys = append(result.unknownKeys, k)
185 }
186 }
187
188 return result
189 }
190
191 func (r *RawConfig) init() error {
192 r.lock.Lock()
193 defer r.lock.Unlock()
194
195 r.config = r.Raw
196 r.Interpolations = nil
197 r.Variables = nil
198
199 fn := func(node ast.Node) (interface{}, error) {
200 r.Interpolations = append(r.Interpolations, node)
201 vars, err := DetectVariables(node)
202 if err != nil {
203 return "", err
204 }
205
206 for _, v := range vars {
207 if r.Variables == nil {
208 r.Variables = make(map[string]InterpolatedVariable)
209 }
210
211 r.Variables[v.FullKey()] = v
212 }
213
214 return "", nil
215 }
216
217 walker := &interpolationWalker{F: fn}
218 if err := reflectwalk.Walk(r.Raw, walker); err != nil {
219 return err
220 }
221
222 return nil
223 }
224
225 func (r *RawConfig) interpolate(fn interpolationWalkerFunc) error {
226 config, err := copystructure.Copy(r.Raw)
227 if err != nil {
228 return err
229 }
230 r.config = config.(map[string]interface{})
231
232 w := &interpolationWalker{F: fn, Replace: true}
233 err = reflectwalk.Walk(r.config, w)
234 if err != nil {
235 return err
236 }
237
238 r.unknownKeys = w.unknownKeys
239 return nil
240 }
241
242 func (r *RawConfig) merge(r2 *RawConfig) *RawConfig {
243 if r == nil && r2 == nil {
244 return nil
245 }
246
247 if r == nil {
248 r = &RawConfig{}
249 }
250
251 rawRaw, err := copystructure.Copy(r.Raw)
252 if err != nil {
253 panic(err)
254 }
255
256 raw := rawRaw.(map[string]interface{})
257 if r2 != nil {
258 for k, v := range r2.Raw {
259 raw[k] = v
260 }
261 }
262
263 result, err := NewRawConfig(raw)
264 if err != nil {
265 panic(err)
266 }
267
268 return result
269 }
270
271 // UnknownKeys returns the keys of the configuration that are unknown
272 // because they had interpolated variables that must be computed.
273 func (r *RawConfig) UnknownKeys() []string {
274 r.lock.Lock()
275 defer r.lock.Unlock()
276 return r.unknownKeys
277 }
278
279 // See GobEncode
280 func (r *RawConfig) GobDecode(b []byte) error {
281 var data gobRawConfig
282 err := gob.NewDecoder(bytes.NewReader(b)).Decode(&data)
283 if err != nil {
284 return err
285 }
286
287 r.Key = data.Key
288 r.Raw = data.Raw
289
290 return r.init()
291 }
292
293 // GobEncode is a custom Gob encoder to use so that we only include the
294 // raw configuration. Interpolated variables and such are lost and the
295 // tree of interpolated variables is recomputed on decode, since it is
296 // referentially transparent.
297 func (r *RawConfig) GobEncode() ([]byte, error) {
298 r.lock.Lock()
299 defer r.lock.Unlock()
300
301 data := gobRawConfig{
302 Key: r.Key,
303 Raw: r.Raw,
304 }
305
306 var buf bytes.Buffer
307 if err := gob.NewEncoder(&buf).Encode(data); err != nil {
308 return nil, err
309 }
310
311 return buf.Bytes(), nil
312 }
313
314 type gobRawConfig struct {
315 Key string
316 Raw map[string]interface{}
317 }
318
319 // langEvalConfig returns the evaluation configuration we use to execute.
320 func langEvalConfig(vs map[string]ast.Variable) *hil.EvalConfig {
321 funcMap := make(map[string]ast.Function)
322 for k, v := range Funcs() {
323 funcMap[k] = v
324 }
325 funcMap["lookup"] = interpolationFuncLookup(vs)
326 funcMap["keys"] = interpolationFuncKeys(vs)
327 funcMap["values"] = interpolationFuncValues(vs)
328
329 return &hil.EvalConfig{
330 GlobalScope: &ast.BasicScope{
331 VarMap: vs,
332 FuncMap: funcMap,
333 },
334 }
335 }