diff options
author | Alex Pilon <apilon@hashicorp.com> | 2019-02-22 18:24:37 -0500 |
---|---|---|
committer | Alex Pilon <apilon@hashicorp.com> | 2019-02-22 18:24:37 -0500 |
commit | 15c0b25d011f37e7c20aeca9eaf461f78285b8d9 (patch) | |
tree | 255c250a5c9d4801c74092d33b7337d8c14438ff /vendor/github.com/hashicorp/terraform/config/loader_hcl2.go | |
parent | 07971ca38143c5faf951d152fba370ddcbe26ad5 (diff) | |
download | terraform-provider-statuscake-15c0b25d011f37e7c20aeca9eaf461f78285b8d9.tar.gz terraform-provider-statuscake-15c0b25d011f37e7c20aeca9eaf461f78285b8d9.tar.zst terraform-provider-statuscake-15c0b25d011f37e7c20aeca9eaf461f78285b8d9.zip |
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
Updated via: go get github.com/hashicorp/terraform@sdk-v0.11-with-go-modules and go mod tidy
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config/loader_hcl2.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/config/loader_hcl2.go | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/loader_hcl2.go b/vendor/github.com/hashicorp/terraform/config/loader_hcl2.go new file mode 100644 index 0000000..4f9f129 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/config/loader_hcl2.go | |||
@@ -0,0 +1,473 @@ | |||
1 | package config | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "sort" | ||
6 | "strings" | ||
7 | |||
8 | gohcl2 "github.com/hashicorp/hcl2/gohcl" | ||
9 | hcl2 "github.com/hashicorp/hcl2/hcl" | ||
10 | hcl2parse "github.com/hashicorp/hcl2/hclparse" | ||
11 | "github.com/hashicorp/terraform/config/hcl2shim" | ||
12 | "github.com/zclconf/go-cty/cty" | ||
13 | ) | ||
14 | |||
15 | // hcl2Configurable is an implementation of configurable that knows | ||
16 | // how to turn a HCL Body into a *Config object. | ||
17 | type hcl2Configurable struct { | ||
18 | SourceFilename string | ||
19 | Body hcl2.Body | ||
20 | } | ||
21 | |||
22 | // hcl2Loader is a wrapper around a HCL parser that provides a fileLoaderFunc. | ||
23 | type hcl2Loader struct { | ||
24 | Parser *hcl2parse.Parser | ||
25 | } | ||
26 | |||
27 | // For the moment we'll just have a global loader since we don't have anywhere | ||
28 | // better to stash this. | ||
29 | // TODO: refactor the loader API so that it uses some sort of object we can | ||
30 | // stash the parser inside. | ||
31 | var globalHCL2Loader = newHCL2Loader() | ||
32 | |||
33 | // newHCL2Loader creates a new hcl2Loader containing a new HCL Parser. | ||
34 | // | ||
35 | // HCL parsers retain information about files that are loaded to aid in | ||
36 | // producing diagnostic messages, so all files within a single configuration | ||
37 | // should be loaded with the same parser to ensure the availability of | ||
38 | // full diagnostic information. | ||
39 | func newHCL2Loader() hcl2Loader { | ||
40 | return hcl2Loader{ | ||
41 | Parser: hcl2parse.NewParser(), | ||
42 | } | ||
43 | } | ||
44 | |||
45 | // loadFile is a fileLoaderFunc that knows how to read a HCL2 file and turn it | ||
46 | // into a hcl2Configurable. | ||
47 | func (l hcl2Loader) loadFile(filename string) (configurable, []string, error) { | ||
48 | var f *hcl2.File | ||
49 | var diags hcl2.Diagnostics | ||
50 | if strings.HasSuffix(filename, ".json") { | ||
51 | f, diags = l.Parser.ParseJSONFile(filename) | ||
52 | } else { | ||
53 | f, diags = l.Parser.ParseHCLFile(filename) | ||
54 | } | ||
55 | if diags.HasErrors() { | ||
56 | // Return diagnostics as an error; callers may type-assert this to | ||
57 | // recover the original diagnostics, if it doesn't end up wrapped | ||
58 | // in another error. | ||
59 | return nil, nil, diags | ||
60 | } | ||
61 | |||
62 | return &hcl2Configurable{ | ||
63 | SourceFilename: filename, | ||
64 | Body: f.Body, | ||
65 | }, nil, nil | ||
66 | } | ||
67 | |||
68 | func (t *hcl2Configurable) Config() (*Config, error) { | ||
69 | config := &Config{} | ||
70 | |||
71 | // these structs are used only for the initial shallow decoding; we'll | ||
72 | // expand this into the main, public-facing config structs afterwards. | ||
73 | type atlas struct { | ||
74 | Name string `hcl:"name"` | ||
75 | Include *[]string `hcl:"include"` | ||
76 | Exclude *[]string `hcl:"exclude"` | ||
77 | } | ||
78 | type provider struct { | ||
79 | Name string `hcl:"name,label"` | ||
80 | Alias *string `hcl:"alias,attr"` | ||
81 | Version *string `hcl:"version,attr"` | ||
82 | Config hcl2.Body `hcl:",remain"` | ||
83 | } | ||
84 | type module struct { | ||
85 | Name string `hcl:"name,label"` | ||
86 | Source string `hcl:"source,attr"` | ||
87 | Version *string `hcl:"version,attr"` | ||
88 | Providers *map[string]string `hcl:"providers,attr"` | ||
89 | Config hcl2.Body `hcl:",remain"` | ||
90 | } | ||
91 | type resourceLifecycle struct { | ||
92 | CreateBeforeDestroy *bool `hcl:"create_before_destroy,attr"` | ||
93 | PreventDestroy *bool `hcl:"prevent_destroy,attr"` | ||
94 | IgnoreChanges *[]string `hcl:"ignore_changes,attr"` | ||
95 | } | ||
96 | type connection struct { | ||
97 | Config hcl2.Body `hcl:",remain"` | ||
98 | } | ||
99 | type provisioner struct { | ||
100 | Type string `hcl:"type,label"` | ||
101 | |||
102 | When *string `hcl:"when,attr"` | ||
103 | OnFailure *string `hcl:"on_failure,attr"` | ||
104 | |||
105 | Connection *connection `hcl:"connection,block"` | ||
106 | Config hcl2.Body `hcl:",remain"` | ||
107 | } | ||
108 | type managedResource struct { | ||
109 | Type string `hcl:"type,label"` | ||
110 | Name string `hcl:"name,label"` | ||
111 | |||
112 | CountExpr hcl2.Expression `hcl:"count,attr"` | ||
113 | Provider *string `hcl:"provider,attr"` | ||
114 | DependsOn *[]string `hcl:"depends_on,attr"` | ||
115 | |||
116 | Lifecycle *resourceLifecycle `hcl:"lifecycle,block"` | ||
117 | Provisioners []provisioner `hcl:"provisioner,block"` | ||
118 | Connection *connection `hcl:"connection,block"` | ||
119 | |||
120 | Config hcl2.Body `hcl:",remain"` | ||
121 | } | ||
122 | type dataResource struct { | ||
123 | Type string `hcl:"type,label"` | ||
124 | Name string `hcl:"name,label"` | ||
125 | |||
126 | CountExpr hcl2.Expression `hcl:"count,attr"` | ||
127 | Provider *string `hcl:"provider,attr"` | ||
128 | DependsOn *[]string `hcl:"depends_on,attr"` | ||
129 | |||
130 | Config hcl2.Body `hcl:",remain"` | ||
131 | } | ||
132 | type variable struct { | ||
133 | Name string `hcl:"name,label"` | ||
134 | |||
135 | DeclaredType *string `hcl:"type,attr"` | ||
136 | Default *cty.Value `hcl:"default,attr"` | ||
137 | Description *string `hcl:"description,attr"` | ||
138 | Sensitive *bool `hcl:"sensitive,attr"` | ||
139 | } | ||
140 | type output struct { | ||
141 | Name string `hcl:"name,label"` | ||
142 | |||
143 | ValueExpr hcl2.Expression `hcl:"value,attr"` | ||
144 | DependsOn *[]string `hcl:"depends_on,attr"` | ||
145 | Description *string `hcl:"description,attr"` | ||
146 | Sensitive *bool `hcl:"sensitive,attr"` | ||
147 | } | ||
148 | type locals struct { | ||
149 | Definitions hcl2.Attributes `hcl:",remain"` | ||
150 | } | ||
151 | type backend struct { | ||
152 | Type string `hcl:"type,label"` | ||
153 | Config hcl2.Body `hcl:",remain"` | ||
154 | } | ||
155 | type terraform struct { | ||
156 | RequiredVersion *string `hcl:"required_version,attr"` | ||
157 | Backend *backend `hcl:"backend,block"` | ||
158 | } | ||
159 | type topLevel struct { | ||
160 | Atlas *atlas `hcl:"atlas,block"` | ||
161 | Datas []dataResource `hcl:"data,block"` | ||
162 | Modules []module `hcl:"module,block"` | ||
163 | Outputs []output `hcl:"output,block"` | ||
164 | Providers []provider `hcl:"provider,block"` | ||
165 | Resources []managedResource `hcl:"resource,block"` | ||
166 | Terraform *terraform `hcl:"terraform,block"` | ||
167 | Variables []variable `hcl:"variable,block"` | ||
168 | Locals []*locals `hcl:"locals,block"` | ||
169 | } | ||
170 | |||
171 | var raw topLevel | ||
172 | diags := gohcl2.DecodeBody(t.Body, nil, &raw) | ||
173 | if diags.HasErrors() { | ||
174 | // Do some minimal decoding to see if we can at least get the | ||
175 | // required Terraform version, which might help explain why we | ||
176 | // couldn't parse the rest. | ||
177 | if raw.Terraform != nil && raw.Terraform.RequiredVersion != nil { | ||
178 | config.Terraform = &Terraform{ | ||
179 | RequiredVersion: *raw.Terraform.RequiredVersion, | ||
180 | } | ||
181 | } | ||
182 | |||
183 | // We return the diags as an implementation of error, which the | ||
184 | // caller than then type-assert if desired to recover the individual | ||
185 | // diagnostics. | ||
186 | // FIXME: The current API gives us no way to return warnings in the | ||
187 | // absense of any errors. | ||
188 | return config, diags | ||
189 | } | ||
190 | |||
191 | if raw.Terraform != nil { | ||
192 | var reqdVersion string | ||
193 | var backend *Backend | ||
194 | |||
195 | if raw.Terraform.RequiredVersion != nil { | ||
196 | reqdVersion = *raw.Terraform.RequiredVersion | ||
197 | } | ||
198 | if raw.Terraform.Backend != nil { | ||
199 | backend = new(Backend) | ||
200 | backend.Type = raw.Terraform.Backend.Type | ||
201 | |||
202 | // We don't permit interpolations or nested blocks inside the | ||
203 | // backend config, so we can decode the config early here and | ||
204 | // get direct access to the values, which is important for the | ||
205 | // config hashing to work as expected. | ||
206 | var config map[string]string | ||
207 | configDiags := gohcl2.DecodeBody(raw.Terraform.Backend.Config, nil, &config) | ||
208 | diags = append(diags, configDiags...) | ||
209 | |||
210 | raw := make(map[string]interface{}, len(config)) | ||
211 | for k, v := range config { | ||
212 | raw[k] = v | ||
213 | } | ||
214 | |||
215 | var err error | ||
216 | backend.RawConfig, err = NewRawConfig(raw) | ||
217 | if err != nil { | ||
218 | diags = append(diags, &hcl2.Diagnostic{ | ||
219 | Severity: hcl2.DiagError, | ||
220 | Summary: "Invalid backend configuration", | ||
221 | Detail: fmt.Sprintf("Error in backend configuration: %s", err), | ||
222 | }) | ||
223 | } | ||
224 | } | ||
225 | |||
226 | config.Terraform = &Terraform{ | ||
227 | RequiredVersion: reqdVersion, | ||
228 | Backend: backend, | ||
229 | } | ||
230 | } | ||
231 | |||
232 | if raw.Atlas != nil { | ||
233 | var include, exclude []string | ||
234 | if raw.Atlas.Include != nil { | ||
235 | include = *raw.Atlas.Include | ||
236 | } | ||
237 | if raw.Atlas.Exclude != nil { | ||
238 | exclude = *raw.Atlas.Exclude | ||
239 | } | ||
240 | config.Atlas = &AtlasConfig{ | ||
241 | Name: raw.Atlas.Name, | ||
242 | Include: include, | ||
243 | Exclude: exclude, | ||
244 | } | ||
245 | } | ||
246 | |||
247 | for _, rawM := range raw.Modules { | ||
248 | m := &Module{ | ||
249 | Name: rawM.Name, | ||
250 | Source: rawM.Source, | ||
251 | RawConfig: NewRawConfigHCL2(rawM.Config), | ||
252 | } | ||
253 | |||
254 | if rawM.Version != nil { | ||
255 | m.Version = *rawM.Version | ||
256 | } | ||
257 | |||
258 | if rawM.Providers != nil { | ||
259 | m.Providers = *rawM.Providers | ||
260 | } | ||
261 | |||
262 | config.Modules = append(config.Modules, m) | ||
263 | } | ||
264 | |||
265 | for _, rawV := range raw.Variables { | ||
266 | v := &Variable{ | ||
267 | Name: rawV.Name, | ||
268 | } | ||
269 | if rawV.DeclaredType != nil { | ||
270 | v.DeclaredType = *rawV.DeclaredType | ||
271 | } | ||
272 | if rawV.Default != nil { | ||
273 | v.Default = hcl2shim.ConfigValueFromHCL2(*rawV.Default) | ||
274 | } | ||
275 | if rawV.Description != nil { | ||
276 | v.Description = *rawV.Description | ||
277 | } | ||
278 | |||
279 | config.Variables = append(config.Variables, v) | ||
280 | } | ||
281 | |||
282 | for _, rawO := range raw.Outputs { | ||
283 | o := &Output{ | ||
284 | Name: rawO.Name, | ||
285 | } | ||
286 | |||
287 | if rawO.Description != nil { | ||
288 | o.Description = *rawO.Description | ||
289 | } | ||
290 | if rawO.DependsOn != nil { | ||
291 | o.DependsOn = *rawO.DependsOn | ||
292 | } | ||
293 | if rawO.Sensitive != nil { | ||
294 | o.Sensitive = *rawO.Sensitive | ||
295 | } | ||
296 | |||
297 | // The result is expected to be a map like map[string]interface{}{"value": something}, | ||
298 | // so we'll fake that with our hcl2shim.SingleAttrBody shim. | ||
299 | o.RawConfig = NewRawConfigHCL2(hcl2shim.SingleAttrBody{ | ||
300 | Name: "value", | ||
301 | Expr: rawO.ValueExpr, | ||
302 | }) | ||
303 | |||
304 | config.Outputs = append(config.Outputs, o) | ||
305 | } | ||
306 | |||
307 | for _, rawR := range raw.Resources { | ||
308 | r := &Resource{ | ||
309 | Mode: ManagedResourceMode, | ||
310 | Type: rawR.Type, | ||
311 | Name: rawR.Name, | ||
312 | } | ||
313 | if rawR.Lifecycle != nil { | ||
314 | var l ResourceLifecycle | ||
315 | if rawR.Lifecycle.CreateBeforeDestroy != nil { | ||
316 | l.CreateBeforeDestroy = *rawR.Lifecycle.CreateBeforeDestroy | ||
317 | } | ||
318 | if rawR.Lifecycle.PreventDestroy != nil { | ||
319 | l.PreventDestroy = *rawR.Lifecycle.PreventDestroy | ||
320 | } | ||
321 | if rawR.Lifecycle.IgnoreChanges != nil { | ||
322 | l.IgnoreChanges = *rawR.Lifecycle.IgnoreChanges | ||
323 | } | ||
324 | r.Lifecycle = l | ||
325 | } | ||
326 | if rawR.Provider != nil { | ||
327 | r.Provider = *rawR.Provider | ||
328 | } | ||
329 | if rawR.DependsOn != nil { | ||
330 | r.DependsOn = *rawR.DependsOn | ||
331 | } | ||
332 | |||
333 | var defaultConnInfo *RawConfig | ||
334 | if rawR.Connection != nil { | ||
335 | defaultConnInfo = NewRawConfigHCL2(rawR.Connection.Config) | ||
336 | } | ||
337 | |||
338 | for _, rawP := range rawR.Provisioners { | ||
339 | p := &Provisioner{ | ||
340 | Type: rawP.Type, | ||
341 | } | ||
342 | |||
343 | switch { | ||
344 | case rawP.When == nil: | ||
345 | p.When = ProvisionerWhenCreate | ||
346 | case *rawP.When == "create": | ||
347 | p.When = ProvisionerWhenCreate | ||
348 | case *rawP.When == "destroy": | ||
349 | p.When = ProvisionerWhenDestroy | ||
350 | default: | ||
351 | p.When = ProvisionerWhenInvalid | ||
352 | } | ||
353 | |||
354 | switch { | ||
355 | case rawP.OnFailure == nil: | ||
356 | p.OnFailure = ProvisionerOnFailureFail | ||
357 | case *rawP.When == "fail": | ||
358 | p.OnFailure = ProvisionerOnFailureFail | ||
359 | case *rawP.When == "continue": | ||
360 | p.OnFailure = ProvisionerOnFailureContinue | ||
361 | default: | ||
362 | p.OnFailure = ProvisionerOnFailureInvalid | ||
363 | } | ||
364 | |||
365 | if rawP.Connection != nil { | ||
366 | p.ConnInfo = NewRawConfigHCL2(rawP.Connection.Config) | ||
367 | } else { | ||
368 | p.ConnInfo = defaultConnInfo | ||
369 | } | ||
370 | |||
371 | p.RawConfig = NewRawConfigHCL2(rawP.Config) | ||
372 | |||
373 | r.Provisioners = append(r.Provisioners, p) | ||
374 | } | ||
375 | |||
376 | // The old loader records the count expression as a weird RawConfig with | ||
377 | // a single-element map inside. Since the rest of the world is assuming | ||
378 | // that, we'll mimic it here. | ||
379 | { | ||
380 | countBody := hcl2shim.SingleAttrBody{ | ||
381 | Name: "count", | ||
382 | Expr: rawR.CountExpr, | ||
383 | } | ||
384 | |||
385 | r.RawCount = NewRawConfigHCL2(countBody) | ||
386 | r.RawCount.Key = "count" | ||
387 | } | ||
388 | |||
389 | r.RawConfig = NewRawConfigHCL2(rawR.Config) | ||
390 | |||
391 | config.Resources = append(config.Resources, r) | ||
392 | |||
393 | } | ||
394 | |||
395 | for _, rawR := range raw.Datas { | ||
396 | r := &Resource{ | ||
397 | Mode: DataResourceMode, | ||
398 | Type: rawR.Type, | ||
399 | Name: rawR.Name, | ||
400 | } | ||
401 | |||
402 | if rawR.Provider != nil { | ||
403 | r.Provider = *rawR.Provider | ||
404 | } | ||
405 | if rawR.DependsOn != nil { | ||
406 | r.DependsOn = *rawR.DependsOn | ||
407 | } | ||
408 | |||
409 | // The old loader records the count expression as a weird RawConfig with | ||
410 | // a single-element map inside. Since the rest of the world is assuming | ||
411 | // that, we'll mimic it here. | ||
412 | { | ||
413 | countBody := hcl2shim.SingleAttrBody{ | ||
414 | Name: "count", | ||
415 | Expr: rawR.CountExpr, | ||
416 | } | ||
417 | |||
418 | r.RawCount = NewRawConfigHCL2(countBody) | ||
419 | r.RawCount.Key = "count" | ||
420 | } | ||
421 | |||
422 | r.RawConfig = NewRawConfigHCL2(rawR.Config) | ||
423 | |||
424 | config.Resources = append(config.Resources, r) | ||
425 | } | ||
426 | |||
427 | for _, rawP := range raw.Providers { | ||
428 | p := &ProviderConfig{ | ||
429 | Name: rawP.Name, | ||
430 | } | ||
431 | |||
432 | if rawP.Alias != nil { | ||
433 | p.Alias = *rawP.Alias | ||
434 | } | ||
435 | if rawP.Version != nil { | ||
436 | p.Version = *rawP.Version | ||
437 | } | ||
438 | |||
439 | // The result is expected to be a map like map[string]interface{}{"value": something}, | ||
440 | // so we'll fake that with our hcl2shim.SingleAttrBody shim. | ||
441 | p.RawConfig = NewRawConfigHCL2(rawP.Config) | ||
442 | |||
443 | config.ProviderConfigs = append(config.ProviderConfigs, p) | ||
444 | } | ||
445 | |||
446 | for _, rawL := range raw.Locals { | ||
447 | names := make([]string, 0, len(rawL.Definitions)) | ||
448 | for n := range rawL.Definitions { | ||
449 | names = append(names, n) | ||
450 | } | ||
451 | sort.Strings(names) | ||
452 | for _, n := range names { | ||
453 | attr := rawL.Definitions[n] | ||
454 | l := &Local{ | ||
455 | Name: n, | ||
456 | RawConfig: NewRawConfigHCL2(hcl2shim.SingleAttrBody{ | ||
457 | Name: "value", | ||
458 | Expr: attr.Expr, | ||
459 | }), | ||
460 | } | ||
461 | config.Locals = append(config.Locals, l) | ||
462 | } | ||
463 | } | ||
464 | |||
465 | // FIXME: The current API gives us no way to return warnings in the | ||
466 | // absense of any errors. | ||
467 | var err error | ||
468 | if diags.HasErrors() { | ||
469 | err = diags | ||
470 | } | ||
471 | |||
472 | return config, err | ||
473 | } | ||