aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/config
diff options
context:
space:
mode:
authorAlex Pilon <apilon@hashicorp.com>2019-02-22 18:24:37 -0500
committerAlex Pilon <apilon@hashicorp.com>2019-02-22 18:24:37 -0500
commit15c0b25d011f37e7c20aeca9eaf461f78285b8d9 (patch)
tree255c250a5c9d4801c74092d33b7337d8c14438ff /vendor/github.com/hashicorp/terraform/config
parent07971ca38143c5faf951d152fba370ddcbe26ad5 (diff)
downloadterraform-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')
-rw-r--r--vendor/github.com/hashicorp/terraform/config/append.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/config/config.go396
-rw-r--r--vendor/github.com/hashicorp/terraform/config/config_string.go40
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go97
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/doc.go14
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go92
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go16
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/schema.go107
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2_shim_util.go134
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2shim/single_attr_body.go85
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go246
-rw-r--r--vendor/github.com/hashicorp/terraform/config/import_tree.go54
-rw-r--r--vendor/github.com/hashicorp/terraform/config/interpolate.go55
-rw-r--r--vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go429
-rw-r--r--vendor/github.com/hashicorp/terraform/config/interpolate_walk.go4
-rw-r--r--vendor/github.com/hashicorp/terraform/config/loader.go5
-rw-r--r--vendor/github.com/hashicorp/terraform/config/loader_hcl.go126
-rw-r--r--vendor/github.com/hashicorp/terraform/config/loader_hcl2.go473
-rw-r--r--vendor/github.com/hashicorp/terraform/config/merge.go11
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/get.go20
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/inode.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/module.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/storage.go365
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/testing.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/tree.go314
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/versions.go95
-rw-r--r--vendor/github.com/hashicorp/terraform/config/raw_config.go125
-rw-r--r--vendor/github.com/hashicorp/terraform/config/resource_mode_string.go4
-rw-r--r--vendor/github.com/hashicorp/terraform/config/testing.go2
31 files changed, 3022 insertions, 330 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/append.go b/vendor/github.com/hashicorp/terraform/config/append.go
index 5f4e89e..9d80c42 100644
--- a/vendor/github.com/hashicorp/terraform/config/append.go
+++ b/vendor/github.com/hashicorp/terraform/config/append.go
@@ -82,5 +82,11 @@ func Append(c1, c2 *Config) (*Config, error) {
82 c.Variables = append(c.Variables, c2.Variables...) 82 c.Variables = append(c.Variables, c2.Variables...)
83 } 83 }
84 84
85 if len(c1.Locals) > 0 || len(c2.Locals) > 0 {
86 c.Locals = make([]*Local, 0, len(c1.Locals)+len(c2.Locals))
87 c.Locals = append(c.Locals, c1.Locals...)
88 c.Locals = append(c.Locals, c2.Locals...)
89 }
90
85 return c, nil 91 return c, nil
86} 92}
diff --git a/vendor/github.com/hashicorp/terraform/config/config.go b/vendor/github.com/hashicorp/terraform/config/config.go
index 3f756dc..1772fd7 100644
--- a/vendor/github.com/hashicorp/terraform/config/config.go
+++ b/vendor/github.com/hashicorp/terraform/config/config.go
@@ -8,11 +8,11 @@ import (
8 "strconv" 8 "strconv"
9 "strings" 9 "strings"
10 10
11 "github.com/hashicorp/go-multierror" 11 hcl2 "github.com/hashicorp/hcl2/hcl"
12 "github.com/hashicorp/hil"
13 "github.com/hashicorp/hil/ast" 12 "github.com/hashicorp/hil/ast"
14 "github.com/hashicorp/terraform/helper/hilmapstructure" 13 "github.com/hashicorp/terraform/helper/hilmapstructure"
15 "github.com/hashicorp/terraform/plugin/discovery" 14 "github.com/hashicorp/terraform/plugin/discovery"
15 "github.com/hashicorp/terraform/tfdiags"
16 "github.com/mitchellh/reflectwalk" 16 "github.com/mitchellh/reflectwalk"
17) 17)
18 18
@@ -34,6 +34,7 @@ type Config struct {
34 ProviderConfigs []*ProviderConfig 34 ProviderConfigs []*ProviderConfig
35 Resources []*Resource 35 Resources []*Resource
36 Variables []*Variable 36 Variables []*Variable
37 Locals []*Local
37 Outputs []*Output 38 Outputs []*Output
38 39
39 // The fields below can be filled in by loaders for validation 40 // The fields below can be filled in by loaders for validation
@@ -55,6 +56,8 @@ type AtlasConfig struct {
55type Module struct { 56type Module struct {
56 Name string 57 Name string
57 Source string 58 Source string
59 Version string
60 Providers map[string]string
58 RawConfig *RawConfig 61 RawConfig *RawConfig
59} 62}
60 63
@@ -147,7 +150,7 @@ func (p *Provisioner) Copy() *Provisioner {
147 } 150 }
148} 151}
149 152
150// Variable is a variable defined within the configuration. 153// Variable is a module argument defined within the configuration.
151type Variable struct { 154type Variable struct {
152 Name string 155 Name string
153 DeclaredType string `mapstructure:"type"` 156 DeclaredType string `mapstructure:"type"`
@@ -155,6 +158,12 @@ type Variable struct {
155 Description string 158 Description string
156} 159}
157 160
161// Local is a local value defined within the configuration.
162type Local struct {
163 Name string
164 RawConfig *RawConfig
165}
166
158// Output is an output defined within the configuration. An output is 167// Output is an output defined within the configuration. An output is
159// resulting data that is highlighted by Terraform when finished. An 168// resulting data that is highlighted by Terraform when finished. An
160// output marked Sensitive will be output in a masked form following 169// output marked Sensitive will be output in a masked form following
@@ -222,7 +231,10 @@ func (r *Resource) Count() (int, error) {
222 231
223 v, err := strconv.ParseInt(count, 0, 0) 232 v, err := strconv.ParseInt(count, 0, 0)
224 if err != nil { 233 if err != nil {
225 return 0, err 234 return 0, fmt.Errorf(
235 "cannot parse %q as an integer",
236 count,
237 )
226 } 238 }
227 239
228 return int(v), nil 240 return int(v), nil
@@ -253,7 +265,9 @@ func (r *Resource) ProviderFullName() string {
253// the provider name is inferred from the resource type name. 265// the provider name is inferred from the resource type name.
254func ResourceProviderFullName(resourceType, explicitProvider string) string { 266func ResourceProviderFullName(resourceType, explicitProvider string) string {
255 if explicitProvider != "" { 267 if explicitProvider != "" {
256 return explicitProvider 268 // check for an explicit provider name, or return the original
269 parts := strings.SplitAfter(explicitProvider, "provider.")
270 return parts[len(parts)-1]
257 } 271 }
258 272
259 idx := strings.IndexRune(resourceType, '_') 273 idx := strings.IndexRune(resourceType, '_')
@@ -268,30 +282,35 @@ func ResourceProviderFullName(resourceType, explicitProvider string) string {
268} 282}
269 283
270// Validate does some basic semantic checking of the configuration. 284// Validate does some basic semantic checking of the configuration.
271func (c *Config) Validate() error { 285func (c *Config) Validate() tfdiags.Diagnostics {
272 if c == nil { 286 if c == nil {
273 return nil 287 return nil
274 } 288 }
275 289
276 var errs []error 290 var diags tfdiags.Diagnostics
277 291
278 for _, k := range c.unknownKeys { 292 for _, k := range c.unknownKeys {
279 errs = append(errs, fmt.Errorf( 293 diags = diags.Append(
280 "Unknown root level key: %s", k)) 294 fmt.Errorf("Unknown root level key: %s", k),
295 )
281 } 296 }
282 297
283 // Validate the Terraform config 298 // Validate the Terraform config
284 if tf := c.Terraform; tf != nil { 299 if tf := c.Terraform; tf != nil {
285 errs = append(errs, c.Terraform.Validate()...) 300 errs := c.Terraform.Validate()
301 for _, err := range errs {
302 diags = diags.Append(err)
303 }
286 } 304 }
287 305
288 vars := c.InterpolatedVariables() 306 vars := c.InterpolatedVariables()
289 varMap := make(map[string]*Variable) 307 varMap := make(map[string]*Variable)
290 for _, v := range c.Variables { 308 for _, v := range c.Variables {
291 if _, ok := varMap[v.Name]; ok { 309 if _, ok := varMap[v.Name]; ok {
292 errs = append(errs, fmt.Errorf( 310 diags = diags.Append(fmt.Errorf(
293 "Variable '%s': duplicate found. Variable names must be unique.", 311 "Variable '%s': duplicate found. Variable names must be unique.",
294 v.Name)) 312 v.Name,
313 ))
295 } 314 }
296 315
297 varMap[v.Name] = v 316 varMap[v.Name] = v
@@ -299,17 +318,19 @@ func (c *Config) Validate() error {
299 318
300 for k, _ := range varMap { 319 for k, _ := range varMap {
301 if !NameRegexp.MatchString(k) { 320 if !NameRegexp.MatchString(k) {
302 errs = append(errs, fmt.Errorf( 321 diags = diags.Append(fmt.Errorf(
303 "variable %q: variable name must match regular expresion %s", 322 "variable %q: variable name must match regular expression %s",
304 k, NameRegexp)) 323 k, NameRegexp,
324 ))
305 } 325 }
306 } 326 }
307 327
308 for _, v := range c.Variables { 328 for _, v := range c.Variables {
309 if v.Type() == VariableTypeUnknown { 329 if v.Type() == VariableTypeUnknown {
310 errs = append(errs, fmt.Errorf( 330 diags = diags.Append(fmt.Errorf(
311 "Variable '%s': must be a string or a map", 331 "Variable '%s': must be a string or a map",
312 v.Name)) 332 v.Name,
333 ))
313 continue 334 continue
314 } 335 }
315 336
@@ -330,9 +351,10 @@ func (c *Config) Validate() error {
330 if v.Default != nil { 351 if v.Default != nil {
331 if err := reflectwalk.Walk(v.Default, w); err == nil { 352 if err := reflectwalk.Walk(v.Default, w); err == nil {
332 if interp { 353 if interp {
333 errs = append(errs, fmt.Errorf( 354 diags = diags.Append(fmt.Errorf(
334 "Variable '%s': cannot contain interpolations", 355 "variable %q: default may not contain interpolations",
335 v.Name)) 356 v.Name,
357 ))
336 } 358 }
337 } 359 }
338 } 360 }
@@ -348,10 +370,11 @@ func (c *Config) Validate() error {
348 } 370 }
349 371
350 if _, ok := varMap[uv.Name]; !ok { 372 if _, ok := varMap[uv.Name]; !ok {
351 errs = append(errs, fmt.Errorf( 373 diags = diags.Append(fmt.Errorf(
352 "%s: unknown variable referenced: '%s'. define it with 'variable' blocks", 374 "%s: unknown variable referenced: '%s'; define it with a 'variable' block",
353 source, 375 source,
354 uv.Name)) 376 uv.Name,
377 ))
355 } 378 }
356 } 379 }
357 } 380 }
@@ -362,17 +385,19 @@ func (c *Config) Validate() error {
362 switch v := rawV.(type) { 385 switch v := rawV.(type) {
363 case *CountVariable: 386 case *CountVariable:
364 if v.Type == CountValueInvalid { 387 if v.Type == CountValueInvalid {
365 errs = append(errs, fmt.Errorf( 388 diags = diags.Append(fmt.Errorf(
366 "%s: invalid count variable: %s", 389 "%s: invalid count variable: %s",
367 source, 390 source,
368 v.FullKey())) 391 v.FullKey(),
392 ))
369 } 393 }
370 case *PathVariable: 394 case *PathVariable:
371 if v.Type == PathValueInvalid { 395 if v.Type == PathValueInvalid {
372 errs = append(errs, fmt.Errorf( 396 diags = diags.Append(fmt.Errorf(
373 "%s: invalid path variable: %s", 397 "%s: invalid path variable: %s",
374 source, 398 source,
375 v.FullKey())) 399 v.FullKey(),
400 ))
376 } 401 }
377 } 402 }
378 } 403 }
@@ -380,27 +405,35 @@ func (c *Config) Validate() error {
380 405
381 // Check that providers aren't declared multiple times and that their 406 // Check that providers aren't declared multiple times and that their
382 // version constraints, where present, are syntactically valid. 407 // version constraints, where present, are syntactically valid.
383 providerSet := make(map[string]struct{}) 408 providerSet := make(map[string]bool)
384 for _, p := range c.ProviderConfigs { 409 for _, p := range c.ProviderConfigs {
385 name := p.FullName() 410 name := p.FullName()
386 if _, ok := providerSet[name]; ok { 411 if _, ok := providerSet[name]; ok {
387 errs = append(errs, fmt.Errorf( 412 diags = diags.Append(fmt.Errorf(
388 "provider.%s: declared multiple times, you can only declare a provider once", 413 "provider.%s: multiple configurations present; only one configuration is allowed per provider",
389 name)) 414 name,
415 ))
390 continue 416 continue
391 } 417 }
392 418
393 if p.Version != "" { 419 if p.Version != "" {
394 _, err := discovery.ConstraintStr(p.Version).Parse() 420 _, err := discovery.ConstraintStr(p.Version).Parse()
395 if err != nil { 421 if err != nil {
396 errs = append(errs, fmt.Errorf( 422 diags = diags.Append(&hcl2.Diagnostic{
397 "provider.%s: invalid version constraint %q: %s", 423 Severity: hcl2.DiagError,
398 name, p.Version, err, 424 Summary: "Invalid provider version constraint",
399 )) 425 Detail: fmt.Sprintf(
426 "The value %q given for provider.%s is not a valid version constraint.",
427 p.Version, name,
428 ),
429 // TODO: include a "Subject" source reference in here,
430 // once the config loader is able to retain source
431 // location information.
432 })
400 } 433 }
401 } 434 }
402 435
403 providerSet[name] = struct{}{} 436 providerSet[name] = true
404 } 437 }
405 438
406 // Check that all references to modules are valid 439 // Check that all references to modules are valid
@@ -412,9 +445,10 @@ func (c *Config) Validate() error {
412 if _, ok := dupped[m.Id()]; !ok { 445 if _, ok := dupped[m.Id()]; !ok {
413 dupped[m.Id()] = struct{}{} 446 dupped[m.Id()] = struct{}{}
414 447
415 errs = append(errs, fmt.Errorf( 448 diags = diags.Append(fmt.Errorf(
416 "%s: module repeated multiple times", 449 "module %q: module repeated multiple times",
417 m.Id())) 450 m.Id(),
451 ))
418 } 452 }
419 453
420 // Already seen this module, just skip it 454 // Already seen this module, just skip it
@@ -428,21 +462,23 @@ func (c *Config) Validate() error {
428 "root": m.Source, 462 "root": m.Source,
429 }) 463 })
430 if err != nil { 464 if err != nil {
431 errs = append(errs, fmt.Errorf( 465 diags = diags.Append(fmt.Errorf(
432 "%s: module source error: %s", 466 "module %q: module source error: %s",
433 m.Id(), err)) 467 m.Id(), err,
468 ))
434 } else if len(rc.Interpolations) > 0 { 469 } else if len(rc.Interpolations) > 0 {
435 errs = append(errs, fmt.Errorf( 470 diags = diags.Append(fmt.Errorf(
436 "%s: module source cannot contain interpolations", 471 "module %q: module source cannot contain interpolations",
437 m.Id())) 472 m.Id(),
473 ))
438 } 474 }
439 475
440 // Check that the name matches our regexp 476 // Check that the name matches our regexp
441 if !NameRegexp.Match([]byte(m.Name)) { 477 if !NameRegexp.Match([]byte(m.Name)) {
442 errs = append(errs, fmt.Errorf( 478 diags = diags.Append(fmt.Errorf(
443 "%s: module name can only contain letters, numbers, "+ 479 "module %q: module name must be a letter or underscore followed by only letters, numbers, dashes, and underscores",
444 "dashes, and underscores", 480 m.Id(),
445 m.Id())) 481 ))
446 } 482 }
447 483
448 // Check that the configuration can all be strings, lists or maps 484 // Check that the configuration can all be strings, lists or maps
@@ -466,30 +502,47 @@ func (c *Config) Validate() error {
466 continue 502 continue
467 } 503 }
468 504
469 errs = append(errs, fmt.Errorf( 505 diags = diags.Append(fmt.Errorf(
470 "%s: variable %s must be a string, list or map value", 506 "module %q: argument %s must have a string, list, or map value",
471 m.Id(), k)) 507 m.Id(), k,
508 ))
472 } 509 }
473 510
474 // Check for invalid count variables 511 // Check for invalid count variables
475 for _, v := range m.RawConfig.Variables { 512 for _, v := range m.RawConfig.Variables {
476 switch v.(type) { 513 switch v.(type) {
477 case *CountVariable: 514 case *CountVariable:
478 errs = append(errs, fmt.Errorf( 515 diags = diags.Append(fmt.Errorf(
479 "%s: count variables are only valid within resources", m.Name)) 516 "module %q: count variables are only valid within resources",
517 m.Name,
518 ))
480 case *SelfVariable: 519 case *SelfVariable:
481 errs = append(errs, fmt.Errorf( 520 diags = diags.Append(fmt.Errorf(
482 "%s: self variables are only valid within resources", m.Name)) 521 "module %q: self variables are only valid within resources",
522 m.Name,
523 ))
483 } 524 }
484 } 525 }
485 526
486 // Update the raw configuration to only contain the string values 527 // Update the raw configuration to only contain the string values
487 m.RawConfig, err = NewRawConfig(raw) 528 m.RawConfig, err = NewRawConfig(raw)
488 if err != nil { 529 if err != nil {
489 errs = append(errs, fmt.Errorf( 530 diags = diags.Append(fmt.Errorf(
490 "%s: can't initialize configuration: %s", 531 "%s: can't initialize configuration: %s",
491 m.Id(), err)) 532 m.Id(), err,
533 ))
492 } 534 }
535
536 // check that all named providers actually exist
537 for _, p := range m.Providers {
538 if !providerSet[p] {
539 diags = diags.Append(fmt.Errorf(
540 "module %q: cannot pass non-existent provider %q",
541 m.Name, p,
542 ))
543 }
544 }
545
493 } 546 }
494 dupped = nil 547 dupped = nil
495 548
@@ -503,10 +556,10 @@ func (c *Config) Validate() error {
503 } 556 }
504 557
505 if _, ok := modules[mv.Name]; !ok { 558 if _, ok := modules[mv.Name]; !ok {
506 errs = append(errs, fmt.Errorf( 559 diags = diags.Append(fmt.Errorf(
507 "%s: unknown module referenced: %s", 560 "%s: unknown module referenced: %s",
508 source, 561 source, mv.Name,
509 mv.Name)) 562 ))
510 } 563 }
511 } 564 }
512 } 565 }
@@ -519,9 +572,10 @@ func (c *Config) Validate() error {
519 if _, ok := dupped[r.Id()]; !ok { 572 if _, ok := dupped[r.Id()]; !ok {
520 dupped[r.Id()] = struct{}{} 573 dupped[r.Id()] = struct{}{}
521 574
522 errs = append(errs, fmt.Errorf( 575 diags = diags.Append(fmt.Errorf(
523 "%s: resource repeated multiple times", 576 "%s: resource repeated multiple times",
524 r.Id())) 577 r.Id(),
578 ))
525 } 579 }
526 } 580 }
527 581
@@ -535,53 +589,42 @@ func (c *Config) Validate() error {
535 for _, v := range r.RawCount.Variables { 589 for _, v := range r.RawCount.Variables {
536 switch v.(type) { 590 switch v.(type) {
537 case *CountVariable: 591 case *CountVariable:
538 errs = append(errs, fmt.Errorf( 592 diags = diags.Append(fmt.Errorf(
539 "%s: resource count can't reference count variable: %s", 593 "%s: resource count can't reference count variable: %s",
540 n, 594 n, v.FullKey(),
541 v.FullKey())) 595 ))
542 case *SimpleVariable: 596 case *SimpleVariable:
543 errs = append(errs, fmt.Errorf( 597 diags = diags.Append(fmt.Errorf(
544 "%s: resource count can't reference variable: %s", 598 "%s: resource count can't reference variable: %s",
545 n, 599 n, v.FullKey(),
546 v.FullKey())) 600 ))
547 601
548 // Good 602 // Good
549 case *ModuleVariable: 603 case *ModuleVariable:
550 case *ResourceVariable: 604 case *ResourceVariable:
551 case *TerraformVariable: 605 case *TerraformVariable:
552 case *UserVariable: 606 case *UserVariable:
607 case *LocalVariable:
553 608
554 default: 609 default:
555 errs = append(errs, fmt.Errorf( 610 diags = diags.Append(fmt.Errorf(
556 "Internal error. Unknown type in count var in %s: %T", 611 "Internal error. Unknown type in count var in %s: %T",
557 n, v)) 612 n, v,
613 ))
558 } 614 }
559 } 615 }
560 616
561 // Interpolate with a fixed number to verify that its a number. 617 if !r.RawCount.couldBeInteger() {
562 r.RawCount.interpolate(func(root ast.Node) (interface{}, error) { 618 diags = diags.Append(fmt.Errorf(
563 // Execute the node but transform the AST so that it returns 619 "%s: resource count must be an integer", n,
564 // a fixed value of "5" for all interpolations. 620 ))
565 result, err := hil.Eval(
566 hil.FixedValueTransform(
567 root, &ast.LiteralNode{Value: "5", Typex: ast.TypeString}),
568 nil)
569 if err != nil {
570 return "", err
571 }
572
573 return result.Value, nil
574 })
575 _, err := strconv.ParseInt(r.RawCount.Value().(string), 0, 0)
576 if err != nil {
577 errs = append(errs, fmt.Errorf(
578 "%s: resource count must be an integer",
579 n))
580 } 621 }
581 r.RawCount.init() 622 r.RawCount.init()
582 623
583 // Validate DependsOn 624 // Validate DependsOn
584 errs = append(errs, c.validateDependsOn(n, r.DependsOn, resources, modules)...) 625 for _, err := range c.validateDependsOn(n, r.DependsOn, resources, modules) {
626 diags = diags.Append(err)
627 }
585 628
586 // Verify provisioners 629 // Verify provisioners
587 for _, p := range r.Provisioners { 630 for _, p := range r.Provisioners {
@@ -595,9 +638,10 @@ func (c *Config) Validate() error {
595 } 638 }
596 639
597 if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name { 640 if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
598 errs = append(errs, fmt.Errorf( 641 diags = diags.Append(fmt.Errorf(
599 "%s: connection info cannot contain splat variable "+ 642 "%s: connection info cannot contain splat variable referencing itself",
600 "referencing itself", n)) 643 n,
644 ))
601 break 645 break
602 } 646 }
603 } 647 }
@@ -609,9 +653,10 @@ func (c *Config) Validate() error {
609 } 653 }
610 654
611 if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name { 655 if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
612 errs = append(errs, fmt.Errorf( 656 diags = diags.Append(fmt.Errorf(
613 "%s: connection info cannot contain splat variable "+ 657 "%s: connection info cannot contain splat variable referencing itself",
614 "referencing itself", n)) 658 n,
659 ))
615 break 660 break
616 } 661 }
617 } 662 }
@@ -619,21 +664,24 @@ func (c *Config) Validate() error {
619 // Check for invalid when/onFailure values, though this should be 664 // Check for invalid when/onFailure values, though this should be
620 // picked up by the loader we check here just in case. 665 // picked up by the loader we check here just in case.
621 if p.When == ProvisionerWhenInvalid { 666 if p.When == ProvisionerWhenInvalid {
622 errs = append(errs, fmt.Errorf( 667 diags = diags.Append(fmt.Errorf(
623 "%s: provisioner 'when' value is invalid", n)) 668 "%s: provisioner 'when' value is invalid", n,
669 ))
624 } 670 }
625 if p.OnFailure == ProvisionerOnFailureInvalid { 671 if p.OnFailure == ProvisionerOnFailureInvalid {
626 errs = append(errs, fmt.Errorf( 672 diags = diags.Append(fmt.Errorf(
627 "%s: provisioner 'on_failure' value is invalid", n)) 673 "%s: provisioner 'on_failure' value is invalid", n,
674 ))
628 } 675 }
629 } 676 }
630 677
631 // Verify ignore_changes contains valid entries 678 // Verify ignore_changes contains valid entries
632 for _, v := range r.Lifecycle.IgnoreChanges { 679 for _, v := range r.Lifecycle.IgnoreChanges {
633 if strings.Contains(v, "*") && v != "*" { 680 if strings.Contains(v, "*") && v != "*" {
634 errs = append(errs, fmt.Errorf( 681 diags = diags.Append(fmt.Errorf(
635 "%s: ignore_changes does not support using a partial string "+ 682 "%s: ignore_changes does not support using a partial string together with a wildcard: %s",
636 "together with a wildcard: %s", n, v)) 683 n, v,
684 ))
637 } 685 }
638 } 686 }
639 687
@@ -642,21 +690,24 @@ func (c *Config) Validate() error {
642 "root": r.Lifecycle.IgnoreChanges, 690 "root": r.Lifecycle.IgnoreChanges,
643 }) 691 })
644 if err != nil { 692 if err != nil {
645 errs = append(errs, fmt.Errorf( 693 diags = diags.Append(fmt.Errorf(
646 "%s: lifecycle ignore_changes error: %s", 694 "%s: lifecycle ignore_changes error: %s",
647 n, err)) 695 n, err,
696 ))
648 } else if len(rc.Interpolations) > 0 { 697 } else if len(rc.Interpolations) > 0 {
649 errs = append(errs, fmt.Errorf( 698 diags = diags.Append(fmt.Errorf(
650 "%s: lifecycle ignore_changes cannot contain interpolations", 699 "%s: lifecycle ignore_changes cannot contain interpolations",
651 n)) 700 n,
701 ))
652 } 702 }
653 703
654 // If it is a data source then it can't have provisioners 704 // If it is a data source then it can't have provisioners
655 if r.Mode == DataResourceMode { 705 if r.Mode == DataResourceMode {
656 if _, ok := r.RawConfig.Raw["provisioner"]; ok { 706 if _, ok := r.RawConfig.Raw["provisioner"]; ok {
657 errs = append(errs, fmt.Errorf( 707 diags = diags.Append(fmt.Errorf(
658 "%s: data sources cannot have provisioners", 708 "%s: data sources cannot have provisioners",
659 n)) 709 n,
710 ))
660 } 711 }
661 } 712 }
662 } 713 }
@@ -670,25 +721,50 @@ func (c *Config) Validate() error {
670 721
671 id := rv.ResourceId() 722 id := rv.ResourceId()
672 if _, ok := resources[id]; !ok { 723 if _, ok := resources[id]; !ok {
673 errs = append(errs, fmt.Errorf( 724 diags = diags.Append(fmt.Errorf(
674 "%s: unknown resource '%s' referenced in variable %s", 725 "%s: unknown resource '%s' referenced in variable %s",
675 source, 726 source,
676 id, 727 id,
677 rv.FullKey())) 728 rv.FullKey(),
729 ))
678 continue 730 continue
679 } 731 }
680 } 732 }
681 } 733 }
682 734
735 // Check that all locals are valid
736 {
737 found := make(map[string]struct{})
738 for _, l := range c.Locals {
739 if _, ok := found[l.Name]; ok {
740 diags = diags.Append(fmt.Errorf(
741 "%s: duplicate local. local value names must be unique",
742 l.Name,
743 ))
744 continue
745 }
746 found[l.Name] = struct{}{}
747
748 for _, v := range l.RawConfig.Variables {
749 if _, ok := v.(*CountVariable); ok {
750 diags = diags.Append(fmt.Errorf(
751 "local %s: count variables are only valid within resources", l.Name,
752 ))
753 }
754 }
755 }
756 }
757
683 // Check that all outputs are valid 758 // Check that all outputs are valid
684 { 759 {
685 found := make(map[string]struct{}) 760 found := make(map[string]struct{})
686 for _, o := range c.Outputs { 761 for _, o := range c.Outputs {
687 // Verify the output is new 762 // Verify the output is new
688 if _, ok := found[o.Name]; ok { 763 if _, ok := found[o.Name]; ok {
689 errs = append(errs, fmt.Errorf( 764 diags = diags.Append(fmt.Errorf(
690 "%s: duplicate output. output names must be unique.", 765 "output %q: an output of this name was already defined",
691 o.Name)) 766 o.Name,
767 ))
692 continue 768 continue
693 } 769 }
694 found[o.Name] = struct{}{} 770 found[o.Name] = struct{}{}
@@ -708,9 +784,10 @@ func (c *Config) Validate() error {
708 continue 784 continue
709 } 785 }
710 786
711 errs = append(errs, fmt.Errorf( 787 diags = diags.Append(fmt.Errorf(
712 "%s: value for 'sensitive' must be boolean", 788 "output %q: value for 'sensitive' must be boolean",
713 o.Name)) 789 o.Name,
790 ))
714 continue 791 continue
715 } 792 }
716 if k == "description" { 793 if k == "description" {
@@ -719,27 +796,78 @@ func (c *Config) Validate() error {
719 continue 796 continue
720 } 797 }
721 798
722 errs = append(errs, fmt.Errorf( 799 diags = diags.Append(fmt.Errorf(
723 "%s: value for 'description' must be string", 800 "output %q: value for 'description' must be string",
724 o.Name)) 801 o.Name,
802 ))
725 continue 803 continue
726 } 804 }
727 invalidKeys = append(invalidKeys, k) 805 invalidKeys = append(invalidKeys, k)
728 } 806 }
729 if len(invalidKeys) > 0 { 807 if len(invalidKeys) > 0 {
730 errs = append(errs, fmt.Errorf( 808 diags = diags.Append(fmt.Errorf(
731 "%s: output has invalid keys: %s", 809 "output %q: invalid keys: %s",
732 o.Name, strings.Join(invalidKeys, ", "))) 810 o.Name, strings.Join(invalidKeys, ", "),
811 ))
733 } 812 }
734 if !valueKeyFound { 813 if !valueKeyFound {
735 errs = append(errs, fmt.Errorf( 814 diags = diags.Append(fmt.Errorf(
736 "%s: output is missing required 'value' key", o.Name)) 815 "output %q: missing required 'value' argument", o.Name,
816 ))
737 } 817 }
738 818
739 for _, v := range o.RawConfig.Variables { 819 for _, v := range o.RawConfig.Variables {
740 if _, ok := v.(*CountVariable); ok { 820 if _, ok := v.(*CountVariable); ok {
741 errs = append(errs, fmt.Errorf( 821 diags = diags.Append(fmt.Errorf(
742 "%s: count variables are only valid within resources", o.Name)) 822 "output %q: count variables are only valid within resources",
823 o.Name,
824 ))
825 }
826 }
827
828 // Detect a common mistake of using a "count"ed resource in
829 // an output value without using the splat or index form.
830 // Prior to 0.11 this error was silently ignored, but outputs
831 // now have their errors checked like all other contexts.
832 //
833 // TODO: Remove this in 0.12.
834 for _, v := range o.RawConfig.Variables {
835 rv, ok := v.(*ResourceVariable)
836 if !ok {
837 continue
838 }
839
840 // If the variable seems to be treating the referenced
841 // resource as a singleton (no count specified) then
842 // we'll check to make sure it is indeed a singleton.
843 // It's a warning if not.
844
845 if rv.Multi || rv.Index != 0 {
846 // This reference is treating the resource as a
847 // multi-resource, so the warning doesn't apply.
848 continue
849 }
850
851 for _, r := range c.Resources {
852 if r.Id() != rv.ResourceId() {
853 continue
854 }
855
856 // We test specifically for the raw string "1" here
857 // because we _do_ want to generate this warning if
858 // the user has provided an expression that happens
859 // to return 1 right now, to catch situations where
860 // a count might dynamically be set to something
861 // other than 1 and thus splat syntax is still needed
862 // to be safe.
863 if r.RawCount != nil && r.RawCount.Raw != nil && r.RawCount.Raw["count"] != "1" && rv.Field != "count" {
864 diags = diags.Append(tfdiags.SimpleWarning(fmt.Sprintf(
865 "output %q: must use splat syntax to access %s attribute %q, because it has \"count\" set; use %s.*.%s to obtain a list of the attributes across all instances",
866 o.Name,
867 r.Id(), rv.Field,
868 r.Id(), rv.Field,
869 )))
870 }
743 } 871 }
744 } 872 }
745 } 873 }
@@ -755,17 +883,15 @@ func (c *Config) Validate() error {
755 883
756 for _, v := range rc.Variables { 884 for _, v := range rc.Variables {
757 if _, ok := v.(*SelfVariable); ok { 885 if _, ok := v.(*SelfVariable); ok {
758 errs = append(errs, fmt.Errorf( 886 diags = diags.Append(fmt.Errorf(
759 "%s: cannot contain self-reference %s", source, v.FullKey())) 887 "%s: cannot contain self-reference %s",
888 source, v.FullKey(),
889 ))
760 } 890 }
761 } 891 }
762 } 892 }
763 893
764 if len(errs) > 0 { 894 return diags
765 return &multierror.Error{Errors: errs}
766 }
767
768 return nil
769} 895}
770 896
771// InterpolatedVariables is a helper that returns a mapping of all the interpolated 897// InterpolatedVariables is a helper that returns a mapping of all the interpolated
diff --git a/vendor/github.com/hashicorp/terraform/config/config_string.go b/vendor/github.com/hashicorp/terraform/config/config_string.go
index 0b3abbc..a6933c2 100644
--- a/vendor/github.com/hashicorp/terraform/config/config_string.go
+++ b/vendor/github.com/hashicorp/terraform/config/config_string.go
@@ -143,6 +143,46 @@ func outputsStr(os []*Output) string {
143 result += fmt.Sprintf(" %s: %s\n", kind, str) 143 result += fmt.Sprintf(" %s: %s\n", kind, str)
144 } 144 }
145 } 145 }
146
147 if o.Description != "" {
148 result += fmt.Sprintf(" description\n %s\n", o.Description)
149 }
150 }
151
152 return strings.TrimSpace(result)
153}
154
155func localsStr(ls []*Local) string {
156 ns := make([]string, 0, len(ls))
157 m := make(map[string]*Local)
158 for _, l := range ls {
159 ns = append(ns, l.Name)
160 m[l.Name] = l
161 }
162 sort.Strings(ns)
163
164 result := ""
165 for _, n := range ns {
166 l := m[n]
167
168 result += fmt.Sprintf("%s\n", n)
169
170 if len(l.RawConfig.Variables) > 0 {
171 result += fmt.Sprintf(" vars\n")
172 for _, rawV := range l.RawConfig.Variables {
173 kind := "unknown"
174 str := rawV.FullKey()
175
176 switch rawV.(type) {
177 case *ResourceVariable:
178 kind = "resource"
179 case *UserVariable:
180 kind = "user"
181 }
182
183 result += fmt.Sprintf(" %s: %s\n", kind, str)
184 }
185 }
146 } 186 }
147 187
148 return strings.TrimSpace(result) 188 return strings.TrimSpace(result)
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go b/vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go
new file mode 100644
index 0000000..2b1b0ca
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go
@@ -0,0 +1,97 @@
1package configschema
2
3import (
4 "github.com/hashicorp/hcl2/hcldec"
5 "github.com/zclconf/go-cty/cty"
6)
7
8var mapLabelNames = []string{"key"}
9
10// DecoderSpec returns a hcldec.Spec that can be used to decode a HCL Body
11// using the facilities in the hcldec package.
12//
13// The returned specification is guaranteed to return a value of the same type
14// returned by method ImpliedType, but it may contain null or unknown values if
15// any of the block attributes are defined as optional and/or computed
16// respectively.
17func (b *Block) DecoderSpec() hcldec.Spec {
18 ret := hcldec.ObjectSpec{}
19 if b == nil {
20 return ret
21 }
22
23 for name, attrS := range b.Attributes {
24 switch {
25 case attrS.Computed && attrS.Optional:
26 // In this special case we use an unknown value as a default
27 // to get the intended behavior that the result is computed
28 // unless it has been explicitly set in config.
29 ret[name] = &hcldec.DefaultSpec{
30 Primary: &hcldec.AttrSpec{
31 Name: name,
32 Type: attrS.Type,
33 },
34 Default: &hcldec.LiteralSpec{
35 Value: cty.UnknownVal(attrS.Type),
36 },
37 }
38 case attrS.Computed:
39 ret[name] = &hcldec.LiteralSpec{
40 Value: cty.UnknownVal(attrS.Type),
41 }
42 default:
43 ret[name] = &hcldec.AttrSpec{
44 Name: name,
45 Type: attrS.Type,
46 Required: attrS.Required,
47 }
48 }
49 }
50
51 for name, blockS := range b.BlockTypes {
52 if _, exists := ret[name]; exists {
53 // This indicates an invalid schema, since it's not valid to
54 // define both an attribute and a block type of the same name.
55 // However, we don't raise this here since it's checked by
56 // InternalValidate.
57 continue
58 }
59
60 childSpec := blockS.Block.DecoderSpec()
61
62 switch blockS.Nesting {
63 case NestingSingle:
64 ret[name] = &hcldec.BlockSpec{
65 TypeName: name,
66 Nested: childSpec,
67 Required: blockS.MinItems == 1 && blockS.MaxItems >= 1,
68 }
69 case NestingList:
70 ret[name] = &hcldec.BlockListSpec{
71 TypeName: name,
72 Nested: childSpec,
73 MinItems: blockS.MinItems,
74 MaxItems: blockS.MaxItems,
75 }
76 case NestingSet:
77 ret[name] = &hcldec.BlockSetSpec{
78 TypeName: name,
79 Nested: childSpec,
80 MinItems: blockS.MinItems,
81 MaxItems: blockS.MaxItems,
82 }
83 case NestingMap:
84 ret[name] = &hcldec.BlockMapSpec{
85 TypeName: name,
86 Nested: childSpec,
87 LabelNames: mapLabelNames,
88 }
89 default:
90 // Invalid nesting type is just ignored. It's checked by
91 // InternalValidate.
92 continue
93 }
94 }
95
96 return ret
97}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/doc.go b/vendor/github.com/hashicorp/terraform/config/configschema/doc.go
new file mode 100644
index 0000000..caf8d73
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/configschema/doc.go
@@ -0,0 +1,14 @@
1// Package configschema contains types for describing the expected structure
2// of a configuration block whose shape is not known until runtime.
3//
4// For example, this is used to describe the expected contents of a resource
5// configuration block, which is defined by the corresponding provider plugin
6// and thus not compiled into Terraform core.
7//
8// A configschema primarily describes the shape of configuration, but it is
9// also suitable for use with other structures derived from the configuration,
10// such as the cached state of a resource or a resource diff.
11//
12// This package should not be confused with the package helper/schema, which
13// is the higher-level helper library used to implement providers themselves.
14package configschema
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go b/vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go
new file mode 100644
index 0000000..67324eb
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go
@@ -0,0 +1,21 @@
1package configschema
2
3import (
4 "github.com/hashicorp/hcl2/hcldec"
5 "github.com/zclconf/go-cty/cty"
6)
7
8// ImpliedType returns the cty.Type that would result from decoding a
9// configuration block using the receiving block schema.
10//
11// ImpliedType always returns a result, even if the given schema is
12// inconsistent. Code that creates configschema.Block objects should be
13// tested using the InternalValidate method to detect any inconsistencies
14// that would cause this method to fall back on defaults and assumptions.
15func (b *Block) ImpliedType() cty.Type {
16 if b == nil {
17 return cty.EmptyObject
18 }
19
20 return hcldec.ImpliedType(b.DecoderSpec())
21}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go b/vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go
new file mode 100644
index 0000000..33cbe88
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go
@@ -0,0 +1,92 @@
1package configschema
2
3import (
4 "fmt"
5 "regexp"
6
7 "github.com/zclconf/go-cty/cty"
8
9 multierror "github.com/hashicorp/go-multierror"
10)
11
12var validName = regexp.MustCompile(`^[a-z0-9_]+$`)
13
14// InternalValidate returns an error if the receiving block and its child
15// schema definitions have any consistencies with the documented rules for
16// valid schema.
17//
18// This is intended to be used within unit tests to detect when a given
19// schema is invalid.
20func (b *Block) InternalValidate() error {
21 if b == nil {
22 return fmt.Errorf("top-level block schema is nil")
23 }
24 return b.internalValidate("", nil)
25
26}
27
28func (b *Block) internalValidate(prefix string, err error) error {
29 for name, attrS := range b.Attributes {
30 if attrS == nil {
31 err = multierror.Append(err, fmt.Errorf("%s%s: attribute schema is nil", prefix, name))
32 continue
33 }
34 if !validName.MatchString(name) {
35 err = multierror.Append(err, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
36 }
37 if attrS.Optional == false && attrS.Required == false && attrS.Computed == false {
38 err = multierror.Append(err, fmt.Errorf("%s%s: must set Optional, Required or Computed", prefix, name))
39 }
40 if attrS.Optional && attrS.Required {
41 err = multierror.Append(err, fmt.Errorf("%s%s: cannot set both Optional and Required", prefix, name))
42 }
43 if attrS.Computed && attrS.Required {
44 err = multierror.Append(err, fmt.Errorf("%s%s: cannot set both Computed and Required", prefix, name))
45 }
46 if attrS.Type == cty.NilType {
47 err = multierror.Append(err, fmt.Errorf("%s%s: Type must be set to something other than cty.NilType", prefix, name))
48 }
49 }
50
51 for name, blockS := range b.BlockTypes {
52 if blockS == nil {
53 err = multierror.Append(err, fmt.Errorf("%s%s: block schema is nil", prefix, name))
54 continue
55 }
56
57 if _, isAttr := b.Attributes[name]; isAttr {
58 err = multierror.Append(err, fmt.Errorf("%s%s: name defined as both attribute and child block type", prefix, name))
59 } else if !validName.MatchString(name) {
60 err = multierror.Append(err, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
61 }
62
63 if blockS.MinItems < 0 || blockS.MaxItems < 0 {
64 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must both be greater than zero", prefix, name))
65 }
66
67 switch blockS.Nesting {
68 case NestingSingle:
69 switch {
70 case blockS.MinItems != blockS.MaxItems:
71 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must match in NestingSingle mode", prefix, name))
72 case blockS.MinItems < 0 || blockS.MinItems > 1:
73 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must be set to either 0 or 1 in NestingSingle mode", prefix, name))
74 }
75 case NestingList, NestingSet:
76 if blockS.MinItems > blockS.MaxItems && blockS.MaxItems != 0 {
77 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems must be less than or equal to MaxItems in %s mode", prefix, name, blockS.Nesting))
78 }
79 case NestingMap:
80 if blockS.MinItems != 0 || blockS.MaxItems != 0 {
81 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must both be 0 in NestingMap mode", prefix, name))
82 }
83 default:
84 err = multierror.Append(err, fmt.Errorf("%s%s: invalid nesting mode %s", prefix, name, blockS.Nesting))
85 }
86
87 subPrefix := prefix + name + "."
88 err = blockS.Block.internalValidate(subPrefix, err)
89 }
90
91 return err
92}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go b/vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go
new file mode 100644
index 0000000..6cb9313
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go
@@ -0,0 +1,16 @@
1// Code generated by "stringer -type=NestingMode"; DO NOT EDIT.
2
3package configschema
4
5import "strconv"
6
7const _NestingMode_name = "nestingModeInvalidNestingSingleNestingListNestingSetNestingMap"
8
9var _NestingMode_index = [...]uint8{0, 18, 31, 42, 52, 62}
10
11func (i NestingMode) String() string {
12 if i < 0 || i >= NestingMode(len(_NestingMode_index)-1) {
13 return "NestingMode(" + strconv.FormatInt(int64(i), 10) + ")"
14 }
15 return _NestingMode_name[_NestingMode_index[i]:_NestingMode_index[i+1]]
16}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/schema.go b/vendor/github.com/hashicorp/terraform/config/configschema/schema.go
new file mode 100644
index 0000000..9a8ee55
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/configschema/schema.go
@@ -0,0 +1,107 @@
1package configschema
2
3import (
4 "github.com/zclconf/go-cty/cty"
5)
6
7// Block represents a configuration block.
8//
9// "Block" here is a logical grouping construct, though it happens to map
10// directly onto the physical block syntax of Terraform's native configuration
11// syntax. It may be a more a matter of convention in other syntaxes, such as
12// JSON.
13//
14// When converted to a value, a Block always becomes an instance of an object
15// type derived from its defined attributes and nested blocks
16type Block struct {
17 // Attributes describes any attributes that may appear directly inside
18 // the block.
19 Attributes map[string]*Attribute
20
21 // BlockTypes describes any nested block types that may appear directly
22 // inside the block.
23 BlockTypes map[string]*NestedBlock
24}
25
26// Attribute represents a configuration attribute, within a block.
27type Attribute struct {
28 // Type is a type specification that the attribute's value must conform to.
29 Type cty.Type
30
31 // Required, if set to true, specifies that an omitted or null value is
32 // not permitted.
33 Required bool
34
35 // Optional, if set to true, specifies that an omitted or null value is
36 // permitted. This field conflicts with Required.
37 Optional bool
38
39 // Computed, if set to true, specifies that the value comes from the
40 // provider rather than from configuration. If combined with Optional,
41 // then the config may optionally provide an overridden value.
42 Computed bool
43
44 // Sensitive, if set to true, indicates that an attribute may contain
45 // sensitive information.
46 //
47 // At present nothing is done with this information, but callers are
48 // encouraged to set it where appropriate so that it may be used in the
49 // future to help Terraform mask sensitive information. (Terraform
50 // currently achieves this in a limited sense via other mechanisms.)
51 Sensitive bool
52}
53
54// NestedBlock represents the embedding of one block within another.
55type NestedBlock struct {
56 // Block is the description of the block that's nested.
57 Block
58
59 // Nesting provides the nesting mode for the child block, which determines
60 // how many instances of the block are allowed, how many labels it expects,
61 // and how the resulting data will be converted into a data structure.
62 Nesting NestingMode
63
64 // MinItems and MaxItems set, for the NestingList and NestingSet nesting
65 // modes, lower and upper limits on the number of child blocks allowed
66 // of the given type. If both are left at zero, no limit is applied.
67 //
68 // As a special case, both values can be set to 1 for NestingSingle in
69 // order to indicate that a particular single block is required.
70 //
71 // These fields are ignored for other nesting modes and must both be left
72 // at zero.
73 MinItems, MaxItems int
74}
75
76// NestingMode is an enumeration of modes for nesting blocks inside other
77// blocks.
78type NestingMode int
79
80//go:generate stringer -type=NestingMode
81
82const (
83 nestingModeInvalid NestingMode = iota
84
85 // NestingSingle indicates that only a single instance of a given
86 // block type is permitted, with no labels, and its content should be
87 // provided directly as an object value.
88 NestingSingle
89
90 // NestingList indicates that multiple blocks of the given type are
91 // permitted, with no labels, and that their corresponding objects should
92 // be provided in a list.
93 NestingList
94
95 // NestingSet indicates that multiple blocks of the given type are
96 // permitted, with no labels, and that their corresponding objects should
97 // be provided in a set.
98 NestingSet
99
100 // NestingMap indicates that multiple blocks of the given type are
101 // permitted, each with a single label, and that their corresponding
102 // objects should be provided in a map whose keys are the labels.
103 //
104 // It's an error, therefore, to use the same label value on multiple
105 // blocks.
106 NestingMap
107)
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2_shim_util.go b/vendor/github.com/hashicorp/terraform/config/hcl2_shim_util.go
new file mode 100644
index 0000000..207d105
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2_shim_util.go
@@ -0,0 +1,134 @@
1package config
2
3import (
4 "fmt"
5
6 "github.com/zclconf/go-cty/cty/function/stdlib"
7
8 "github.com/hashicorp/hil/ast"
9 "github.com/hashicorp/terraform/config/hcl2shim"
10
11 hcl2 "github.com/hashicorp/hcl2/hcl"
12 "github.com/zclconf/go-cty/cty"
13 "github.com/zclconf/go-cty/cty/convert"
14 "github.com/zclconf/go-cty/cty/function"
15)
16
17// ---------------------------------------------------------------------------
18// This file contains some helper functions that are used to shim between
19// HCL2 concepts and HCL/HIL concepts, to help us mostly preserve the existing
20// public API that was built around HCL/HIL-oriented approaches.
21// ---------------------------------------------------------------------------
22
23func hcl2InterpolationFuncs() map[string]function.Function {
24 hcl2Funcs := map[string]function.Function{}
25
26 for name, hilFunc := range Funcs() {
27 hcl2Funcs[name] = hcl2InterpolationFuncShim(hilFunc)
28 }
29
30 // Some functions in the old world are dealt with inside langEvalConfig
31 // due to their legacy reliance on direct access to the symbol table.
32 // Since 0.7 they don't actually need it anymore and just ignore it,
33 // so we're cheating a bit here and exploiting that detail by passing nil.
34 hcl2Funcs["lookup"] = hcl2InterpolationFuncShim(interpolationFuncLookup(nil))
35 hcl2Funcs["keys"] = hcl2InterpolationFuncShim(interpolationFuncKeys(nil))
36 hcl2Funcs["values"] = hcl2InterpolationFuncShim(interpolationFuncValues(nil))
37
38 // As a bonus, we'll provide the JSON-handling functions from the cty
39 // function library since its "jsonencode" is more complete (doesn't force
40 // weird type conversions) and HIL's type system can't represent
41 // "jsondecode" at all. The result of jsondecode will eventually be forced
42 // to conform to the HIL type system on exit into the rest of Terraform due
43 // to our shimming right now, but it should be usable for decoding _within_
44 // an expression.
45 hcl2Funcs["jsonencode"] = stdlib.JSONEncodeFunc
46 hcl2Funcs["jsondecode"] = stdlib.JSONDecodeFunc
47
48 return hcl2Funcs
49}
50
51func hcl2InterpolationFuncShim(hilFunc ast.Function) function.Function {
52 spec := &function.Spec{}
53
54 for i, hilArgType := range hilFunc.ArgTypes {
55 spec.Params = append(spec.Params, function.Parameter{
56 Type: hcl2shim.HCL2TypeForHILType(hilArgType),
57 Name: fmt.Sprintf("arg%d", i+1), // HIL args don't have names, so we'll fudge it
58 })
59 }
60
61 if hilFunc.Variadic {
62 spec.VarParam = &function.Parameter{
63 Type: hcl2shim.HCL2TypeForHILType(hilFunc.VariadicType),
64 Name: "varargs", // HIL args don't have names, so we'll fudge it
65 }
66 }
67
68 spec.Type = func(args []cty.Value) (cty.Type, error) {
69 return hcl2shim.HCL2TypeForHILType(hilFunc.ReturnType), nil
70 }
71 spec.Impl = func(args []cty.Value, retType cty.Type) (cty.Value, error) {
72 hilArgs := make([]interface{}, len(args))
73 for i, arg := range args {
74 hilV := hcl2shim.HILVariableFromHCL2Value(arg)
75
76 // Although the cty function system does automatic type conversions
77 // to match the argument types, cty doesn't distinguish int and
78 // float and so we may need to adjust here to ensure that the
79 // wrapped function gets exactly the Go type it was expecting.
80 var wantType ast.Type
81 if i < len(hilFunc.ArgTypes) {
82 wantType = hilFunc.ArgTypes[i]
83 } else {
84 wantType = hilFunc.VariadicType
85 }
86 switch {
87 case hilV.Type == ast.TypeInt && wantType == ast.TypeFloat:
88 hilV.Type = wantType
89 hilV.Value = float64(hilV.Value.(int))
90 case hilV.Type == ast.TypeFloat && wantType == ast.TypeInt:
91 hilV.Type = wantType
92 hilV.Value = int(hilV.Value.(float64))
93 }
94
95 // HIL functions actually expect to have the outermost variable
96 // "peeled" but any nested values (in lists or maps) will
97 // still have their ast.Variable wrapping.
98 hilArgs[i] = hilV.Value
99 }
100
101 hilResult, err := hilFunc.Callback(hilArgs)
102 if err != nil {
103 return cty.DynamicVal, err
104 }
105
106 // Just as on the way in, we get back a partially-peeled ast.Variable
107 // which we need to re-wrap in order to convert it back into what
108 // we're calling a "config value".
109 rv := hcl2shim.HCL2ValueFromHILVariable(ast.Variable{
110 Type: hilFunc.ReturnType,
111 Value: hilResult,
112 })
113
114 return convert.Convert(rv, retType) // if result is unknown we'll force the correct type here
115 }
116 return function.New(spec)
117}
118
119func hcl2EvalWithUnknownVars(expr hcl2.Expression) (cty.Value, hcl2.Diagnostics) {
120 trs := expr.Variables()
121 vars := map[string]cty.Value{}
122 val := cty.DynamicVal
123
124 for _, tr := range trs {
125 name := tr.RootName()
126 vars[name] = val
127 }
128
129 ctx := &hcl2.EvalContext{
130 Variables: vars,
131 Functions: hcl2InterpolationFuncs(),
132 }
133 return expr.Value(ctx)
134}
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/single_attr_body.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/single_attr_body.go
new file mode 100644
index 0000000..19651c8
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/single_attr_body.go
@@ -0,0 +1,85 @@
1package hcl2shim
2
3import (
4 "fmt"
5
6 hcl2 "github.com/hashicorp/hcl2/hcl"
7)
8
9// SingleAttrBody is a weird implementation of hcl2.Body that acts as if
10// it has a single attribute whose value is the given expression.
11//
12// This is used to shim Resource.RawCount and Output.RawConfig to behave
13// more like they do in the old HCL loader.
14type SingleAttrBody struct {
15 Name string
16 Expr hcl2.Expression
17}
18
19var _ hcl2.Body = SingleAttrBody{}
20
21func (b SingleAttrBody) Content(schema *hcl2.BodySchema) (*hcl2.BodyContent, hcl2.Diagnostics) {
22 content, all, diags := b.content(schema)
23 if !all {
24 // This should never happen because this body implementation should only
25 // be used by code that is aware that it's using a single-attr body.
26 diags = append(diags, &hcl2.Diagnostic{
27 Severity: hcl2.DiagError,
28 Summary: "Invalid attribute",
29 Detail: fmt.Sprintf("The correct attribute name is %q.", b.Name),
30 Subject: b.Expr.Range().Ptr(),
31 })
32 }
33 return content, diags
34}
35
36func (b SingleAttrBody) PartialContent(schema *hcl2.BodySchema) (*hcl2.BodyContent, hcl2.Body, hcl2.Diagnostics) {
37 content, all, diags := b.content(schema)
38 var remain hcl2.Body
39 if all {
40 // If the request matched the one attribute we represent, then the
41 // remaining body is empty.
42 remain = hcl2.EmptyBody()
43 } else {
44 remain = b
45 }
46 return content, remain, diags
47}
48
49func (b SingleAttrBody) content(schema *hcl2.BodySchema) (*hcl2.BodyContent, bool, hcl2.Diagnostics) {
50 ret := &hcl2.BodyContent{}
51 all := false
52 var diags hcl2.Diagnostics
53
54 for _, attrS := range schema.Attributes {
55 if attrS.Name == b.Name {
56 attrs, _ := b.JustAttributes()
57 ret.Attributes = attrs
58 all = true
59 } else if attrS.Required {
60 diags = append(diags, &hcl2.Diagnostic{
61 Severity: hcl2.DiagError,
62 Summary: "Missing attribute",
63 Detail: fmt.Sprintf("The attribute %q is required.", attrS.Name),
64 Subject: b.Expr.Range().Ptr(),
65 })
66 }
67 }
68
69 return ret, all, diags
70}
71
72func (b SingleAttrBody) JustAttributes() (hcl2.Attributes, hcl2.Diagnostics) {
73 return hcl2.Attributes{
74 b.Name: {
75 Expr: b.Expr,
76 Name: b.Name,
77 NameRange: b.Expr.Range(),
78 Range: b.Expr.Range(),
79 },
80 }, nil
81}
82
83func (b SingleAttrBody) MissingItemRange() hcl2.Range {
84 return b.Expr.Range()
85}
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
new file mode 100644
index 0000000..0b697a5
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
@@ -0,0 +1,246 @@
1package hcl2shim
2
3import (
4 "fmt"
5 "math/big"
6
7 "github.com/hashicorp/hil/ast"
8 "github.com/zclconf/go-cty/cty"
9)
10
11// UnknownVariableValue is a sentinel value that can be used
12// to denote that the value of a variable is unknown at this time.
13// RawConfig uses this information to build up data about
14// unknown keys.
15const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
16
17// ConfigValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic
18// types library that HCL2 uses) to a value type that matches what would've
19// been produced from the HCL-based interpolator for an equivalent structure.
20//
21// This function will transform a cty null value into a Go nil value, which
22// isn't a possible outcome of the HCL/HIL-based decoder and so callers may
23// need to detect and reject any null values.
24func ConfigValueFromHCL2(v cty.Value) interface{} {
25 if !v.IsKnown() {
26 return UnknownVariableValue
27 }
28 if v.IsNull() {
29 return nil
30 }
31
32 switch v.Type() {
33 case cty.Bool:
34 return v.True() // like HCL.BOOL
35 case cty.String:
36 return v.AsString() // like HCL token.STRING or token.HEREDOC
37 case cty.Number:
38 // We can't match HCL _exactly_ here because it distinguishes between
39 // int and float values, but we'll get as close as we can by using
40 // an int if the number is exactly representable, and a float if not.
41 // The conversion to float will force precision to that of a float64,
42 // which is potentially losing information from the specific number
43 // given, but no worse than what HCL would've done in its own conversion
44 // to float.
45
46 f := v.AsBigFloat()
47 if i, acc := f.Int64(); acc == big.Exact {
48 // if we're on a 32-bit system and the number is too big for 32-bit
49 // int then we'll fall through here and use a float64.
50 const MaxInt = int(^uint(0) >> 1)
51 const MinInt = -MaxInt - 1
52 if i <= int64(MaxInt) && i >= int64(MinInt) {
53 return int(i) // Like HCL token.NUMBER
54 }
55 }
56
57 f64, _ := f.Float64()
58 return f64 // like HCL token.FLOAT
59 }
60
61 if v.Type().IsListType() || v.Type().IsSetType() || v.Type().IsTupleType() {
62 l := make([]interface{}, 0, v.LengthInt())
63 it := v.ElementIterator()
64 for it.Next() {
65 _, ev := it.Element()
66 l = append(l, ConfigValueFromHCL2(ev))
67 }
68 return l
69 }
70
71 if v.Type().IsMapType() || v.Type().IsObjectType() {
72 l := make(map[string]interface{})
73 it := v.ElementIterator()
74 for it.Next() {
75 ek, ev := it.Element()
76 l[ek.AsString()] = ConfigValueFromHCL2(ev)
77 }
78 return l
79 }
80
81 // If we fall out here then we have some weird type that we haven't
82 // accounted for. This should never happen unless the caller is using
83 // capsule types, and we don't currently have any such types defined.
84 panic(fmt.Errorf("can't convert %#v to config value", v))
85}
86
87// HCL2ValueFromConfigValue is the opposite of configValueFromHCL2: it takes
88// a value as would be returned from the old interpolator and turns it into
89// a cty.Value so it can be used within, for example, an HCL2 EvalContext.
90func HCL2ValueFromConfigValue(v interface{}) cty.Value {
91 if v == nil {
92 return cty.NullVal(cty.DynamicPseudoType)
93 }
94 if v == UnknownVariableValue {
95 return cty.DynamicVal
96 }
97
98 switch tv := v.(type) {
99 case bool:
100 return cty.BoolVal(tv)
101 case string:
102 return cty.StringVal(tv)
103 case int:
104 return cty.NumberIntVal(int64(tv))
105 case float64:
106 return cty.NumberFloatVal(tv)
107 case []interface{}:
108 vals := make([]cty.Value, len(tv))
109 for i, ev := range tv {
110 vals[i] = HCL2ValueFromConfigValue(ev)
111 }
112 return cty.TupleVal(vals)
113 case map[string]interface{}:
114 vals := map[string]cty.Value{}
115 for k, ev := range tv {
116 vals[k] = HCL2ValueFromConfigValue(ev)
117 }
118 return cty.ObjectVal(vals)
119 default:
120 // HCL/HIL should never generate anything that isn't caught by
121 // the above, so if we get here something has gone very wrong.
122 panic(fmt.Errorf("can't convert %#v to cty.Value", v))
123 }
124}
125
126func HILVariableFromHCL2Value(v cty.Value) ast.Variable {
127 if v.IsNull() {
128 // Caller should guarantee/check this before calling
129 panic("Null values cannot be represented in HIL")
130 }
131 if !v.IsKnown() {
132 return ast.Variable{
133 Type: ast.TypeUnknown,
134 Value: UnknownVariableValue,
135 }
136 }
137
138 switch v.Type() {
139 case cty.Bool:
140 return ast.Variable{
141 Type: ast.TypeBool,
142 Value: v.True(),
143 }
144 case cty.Number:
145 v := ConfigValueFromHCL2(v)
146 switch tv := v.(type) {
147 case int:
148 return ast.Variable{
149 Type: ast.TypeInt,
150 Value: tv,
151 }
152 case float64:
153 return ast.Variable{
154 Type: ast.TypeFloat,
155 Value: tv,
156 }
157 default:
158 // should never happen
159 panic("invalid return value for configValueFromHCL2")
160 }
161 case cty.String:
162 return ast.Variable{
163 Type: ast.TypeString,
164 Value: v.AsString(),
165 }
166 }
167
168 if v.Type().IsListType() || v.Type().IsSetType() || v.Type().IsTupleType() {
169 l := make([]ast.Variable, 0, v.LengthInt())
170 it := v.ElementIterator()
171 for it.Next() {
172 _, ev := it.Element()
173 l = append(l, HILVariableFromHCL2Value(ev))
174 }
175 // If we were given a tuple then this could actually produce an invalid
176 // list with non-homogenous types, which we expect to be caught inside
177 // HIL just like a user-supplied non-homogenous list would be.
178 return ast.Variable{
179 Type: ast.TypeList,
180 Value: l,
181 }
182 }
183
184 if v.Type().IsMapType() || v.Type().IsObjectType() {
185 l := make(map[string]ast.Variable)
186 it := v.ElementIterator()
187 for it.Next() {
188 ek, ev := it.Element()
189 l[ek.AsString()] = HILVariableFromHCL2Value(ev)
190 }
191 // If we were given an object then this could actually produce an invalid
192 // map with non-homogenous types, which we expect to be caught inside
193 // HIL just like a user-supplied non-homogenous map would be.
194 return ast.Variable{
195 Type: ast.TypeMap,
196 Value: l,
197 }
198 }
199
200 // If we fall out here then we have some weird type that we haven't
201 // accounted for. This should never happen unless the caller is using
202 // capsule types, and we don't currently have any such types defined.
203 panic(fmt.Errorf("can't convert %#v to HIL variable", v))
204}
205
206func HCL2ValueFromHILVariable(v ast.Variable) cty.Value {
207 switch v.Type {
208 case ast.TypeList:
209 vals := make([]cty.Value, len(v.Value.([]ast.Variable)))
210 for i, ev := range v.Value.([]ast.Variable) {
211 vals[i] = HCL2ValueFromHILVariable(ev)
212 }
213 return cty.TupleVal(vals)
214 case ast.TypeMap:
215 vals := make(map[string]cty.Value, len(v.Value.(map[string]ast.Variable)))
216 for k, ev := range v.Value.(map[string]ast.Variable) {
217 vals[k] = HCL2ValueFromHILVariable(ev)
218 }
219 return cty.ObjectVal(vals)
220 default:
221 return HCL2ValueFromConfigValue(v.Value)
222 }
223}
224
225func HCL2TypeForHILType(hilType ast.Type) cty.Type {
226 switch hilType {
227 case ast.TypeAny:
228 return cty.DynamicPseudoType
229 case ast.TypeUnknown:
230 return cty.DynamicPseudoType
231 case ast.TypeBool:
232 return cty.Bool
233 case ast.TypeInt:
234 return cty.Number
235 case ast.TypeFloat:
236 return cty.Number
237 case ast.TypeString:
238 return cty.String
239 case ast.TypeList:
240 return cty.List(cty.DynamicPseudoType)
241 case ast.TypeMap:
242 return cty.Map(cty.DynamicPseudoType)
243 default:
244 return cty.NilType // equilvalent to ast.TypeInvalid
245 }
246}
diff --git a/vendor/github.com/hashicorp/terraform/config/import_tree.go b/vendor/github.com/hashicorp/terraform/config/import_tree.go
index 37ec11a..08cbc77 100644
--- a/vendor/github.com/hashicorp/terraform/config/import_tree.go
+++ b/vendor/github.com/hashicorp/terraform/config/import_tree.go
@@ -1,8 +1,12 @@
1package config 1package config
2 2
3import ( 3import (
4 "bufio"
4 "fmt" 5 "fmt"
5 "io" 6 "io"
7 "os"
8
9 "github.com/hashicorp/errwrap"
6) 10)
7 11
8// configurable is an interface that must be implemented by any configuration 12// configurable is an interface that must be implemented by any configuration
@@ -27,15 +31,52 @@ type importTree struct {
27// imports. 31// imports.
28type fileLoaderFunc func(path string) (configurable, []string, error) 32type fileLoaderFunc func(path string) (configurable, []string, error)
29 33
34// Set this to a non-empty value at link time to enable the HCL2 experiment.
35// This is not currently enabled for release builds.
36//
37// For example:
38// go install -ldflags="-X github.com/hashicorp/terraform/config.enableHCL2Experiment=true" github.com/hashicorp/terraform
39var enableHCL2Experiment = ""
40
30// loadTree takes a single file and loads the entire importTree for that 41// loadTree takes a single file and loads the entire importTree for that
31// file. This function detects what kind of configuration file it is an 42// file. This function detects what kind of configuration file it is an
32// executes the proper fileLoaderFunc. 43// executes the proper fileLoaderFunc.
33func loadTree(root string) (*importTree, error) { 44func loadTree(root string) (*importTree, error) {
34 var f fileLoaderFunc 45 var f fileLoaderFunc
35 switch ext(root) { 46
36 case ".tf", ".tf.json": 47 // HCL2 experiment is currently activated at build time via the linker.
37 f = loadFileHcl 48 // See the comment on this variable for more information.
38 default: 49 if enableHCL2Experiment == "" {
50 // Main-line behavior: always use the original HCL parser
51 switch ext(root) {
52 case ".tf", ".tf.json":
53 f = loadFileHcl
54 default:
55 }
56 } else {
57 // Experimental behavior: use the HCL2 parser if the opt-in comment
58 // is present.
59 switch ext(root) {
60 case ".tf":
61 // We need to sniff the file for the opt-in comment line to decide
62 // if the file is participating in the HCL2 experiment.
63 cf, err := os.Open(root)
64 if err != nil {
65 return nil, err
66 }
67 sc := bufio.NewScanner(cf)
68 for sc.Scan() {
69 if sc.Text() == "#terraform:hcl2" {
70 f = globalHCL2Loader.loadFile
71 }
72 }
73 if f == nil {
74 f = loadFileHcl
75 }
76 case ".tf.json":
77 f = loadFileHcl
78 default:
79 }
39 } 80 }
40 81
41 if f == nil { 82 if f == nil {
@@ -86,10 +127,7 @@ func (t *importTree) Close() error {
86func (t *importTree) ConfigTree() (*configTree, error) { 127func (t *importTree) ConfigTree() (*configTree, error) {
87 config, err := t.Raw.Config() 128 config, err := t.Raw.Config()
88 if err != nil { 129 if err != nil {
89 return nil, fmt.Errorf( 130 return nil, errwrap.Wrapf(fmt.Sprintf("Error loading %s: {{err}}", t.Path), err)
90 "Error loading %s: %s",
91 t.Path,
92 err)
93 } 131 }
94 132
95 // Build our result 133 // Build our result
diff --git a/vendor/github.com/hashicorp/terraform/config/interpolate.go b/vendor/github.com/hashicorp/terraform/config/interpolate.go
index bbb3555..599e5ec 100644
--- a/vendor/github.com/hashicorp/terraform/config/interpolate.go
+++ b/vendor/github.com/hashicorp/terraform/config/interpolate.go
@@ -5,6 +5,8 @@ import (
5 "strconv" 5 "strconv"
6 "strings" 6 "strings"
7 7
8 "github.com/hashicorp/terraform/tfdiags"
9
8 "github.com/hashicorp/hil/ast" 10 "github.com/hashicorp/hil/ast"
9) 11)
10 12
@@ -14,6 +16,21 @@ import (
14// variables can come from: user variables, resources, etc. 16// variables can come from: user variables, resources, etc.
15type InterpolatedVariable interface { 17type InterpolatedVariable interface {
16 FullKey() string 18 FullKey() string
19 SourceRange() tfdiags.SourceRange
20}
21
22// varRange can be embedded into an InterpolatedVariable implementation to
23// implement the SourceRange method.
24type varRange struct {
25 rng tfdiags.SourceRange
26}
27
28func (r varRange) SourceRange() tfdiags.SourceRange {
29 return r.rng
30}
31
32func makeVarRange(rng tfdiags.SourceRange) varRange {
33 return varRange{rng}
17} 34}
18 35
19// CountVariable is a variable for referencing information about 36// CountVariable is a variable for referencing information about
@@ -21,6 +38,7 @@ type InterpolatedVariable interface {
21type CountVariable struct { 38type CountVariable struct {
22 Type CountValueType 39 Type CountValueType
23 key string 40 key string
41 varRange
24} 42}
25 43
26// CountValueType is the type of the count variable that is referenced. 44// CountValueType is the type of the count variable that is referenced.
@@ -37,6 +55,7 @@ type ModuleVariable struct {
37 Name string 55 Name string
38 Field string 56 Field string
39 key string 57 key string
58 varRange
40} 59}
41 60
42// A PathVariable is a variable that references path information about the 61// A PathVariable is a variable that references path information about the
@@ -44,6 +63,7 @@ type ModuleVariable struct {
44type PathVariable struct { 63type PathVariable struct {
45 Type PathValueType 64 Type PathValueType
46 key string 65 key string
66 varRange
47} 67}
48 68
49type PathValueType byte 69type PathValueType byte
@@ -67,6 +87,7 @@ type ResourceVariable struct {
67 Index int // Index for multi-variable: aws_instance.foo.1.id == 1 87 Index int // Index for multi-variable: aws_instance.foo.1.id == 1
68 88
69 key string 89 key string
90 varRange
70} 91}
71 92
72// SelfVariable is a variable that is referencing the same resource 93// SelfVariable is a variable that is referencing the same resource
@@ -75,6 +96,7 @@ type SelfVariable struct {
75 Field string 96 Field string
76 97
77 key string 98 key string
99 varRange
78} 100}
79 101
80// SimpleVariable is an unprefixed variable, which can show up when users have 102// SimpleVariable is an unprefixed variable, which can show up when users have
@@ -82,6 +104,7 @@ type SelfVariable struct {
82// internally. The template_file resource is an example of this. 104// internally. The template_file resource is an example of this.
83type SimpleVariable struct { 105type SimpleVariable struct {
84 Key string 106 Key string
107 varRange
85} 108}
86 109
87// TerraformVariable is a "terraform."-prefixed variable used to access 110// TerraformVariable is a "terraform."-prefixed variable used to access
@@ -89,6 +112,7 @@ type SimpleVariable struct {
89type TerraformVariable struct { 112type TerraformVariable struct {
90 Field string 113 Field string
91 key string 114 key string
115 varRange
92} 116}
93 117
94// A UserVariable is a variable that is referencing a user variable 118// A UserVariable is a variable that is referencing a user variable
@@ -99,6 +123,14 @@ type UserVariable struct {
99 Elem string 123 Elem string
100 124
101 key string 125 key string
126 varRange
127}
128
129// A LocalVariable is a variable that references a local value defined within
130// the current module, via a "locals" block. This looks like "${local.foo}".
131type LocalVariable struct {
132 Name string
133 varRange
102} 134}
103 135
104func NewInterpolatedVariable(v string) (InterpolatedVariable, error) { 136func NewInterpolatedVariable(v string) (InterpolatedVariable, error) {
@@ -112,6 +144,8 @@ func NewInterpolatedVariable(v string) (InterpolatedVariable, error) {
112 return NewTerraformVariable(v) 144 return NewTerraformVariable(v)
113 } else if strings.HasPrefix(v, "var.") { 145 } else if strings.HasPrefix(v, "var.") {
114 return NewUserVariable(v) 146 return NewUserVariable(v)
147 } else if strings.HasPrefix(v, "local.") {
148 return NewLocalVariable(v)
115 } else if strings.HasPrefix(v, "module.") { 149 } else if strings.HasPrefix(v, "module.") {
116 return NewModuleVariable(v) 150 return NewModuleVariable(v)
117 } else if !strings.ContainsRune(v, '.') { 151 } else if !strings.ContainsRune(v, '.') {
@@ -276,7 +310,7 @@ func (v *SelfVariable) GoString() string {
276} 310}
277 311
278func NewSimpleVariable(key string) (*SimpleVariable, error) { 312func NewSimpleVariable(key string) (*SimpleVariable, error) {
279 return &SimpleVariable{key}, nil 313 return &SimpleVariable{Key: key}, nil
280} 314}
281 315
282func (v *SimpleVariable) FullKey() string { 316func (v *SimpleVariable) FullKey() string {
@@ -331,6 +365,25 @@ func (v *UserVariable) GoString() string {
331 return fmt.Sprintf("*%#v", *v) 365 return fmt.Sprintf("*%#v", *v)
332} 366}
333 367
368func NewLocalVariable(key string) (*LocalVariable, error) {
369 name := key[len("local."):]
370 if idx := strings.Index(name, "."); idx > -1 {
371 return nil, fmt.Errorf("Can't use dot (.) attribute access in local.%s; use square bracket indexing", name)
372 }
373
374 return &LocalVariable{
375 Name: name,
376 }, nil
377}
378
379func (v *LocalVariable) FullKey() string {
380 return fmt.Sprintf("local.%s", v.Name)
381}
382
383func (v *LocalVariable) GoString() string {
384 return fmt.Sprintf("*%#v", *v)
385}
386
334// DetectVariables takes an AST root and returns all the interpolated 387// DetectVariables takes an AST root and returns all the interpolated
335// variables that are detected in the AST tree. 388// variables that are detected in the AST tree.
336func DetectVariables(root ast.Node) ([]InterpolatedVariable, error) { 389func DetectVariables(root ast.Node) ([]InterpolatedVariable, error) {
diff --git a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
index a298cf2..421edb0 100644
--- a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
+++ b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
@@ -1,17 +1,23 @@
1package config 1package config
2 2
3import ( 3import (
4 "bytes"
5 "compress/gzip"
4 "crypto/md5" 6 "crypto/md5"
7 "crypto/rsa"
5 "crypto/sha1" 8 "crypto/sha1"
6 "crypto/sha256" 9 "crypto/sha256"
7 "crypto/sha512" 10 "crypto/sha512"
11 "crypto/x509"
8 "encoding/base64" 12 "encoding/base64"
9 "encoding/hex" 13 "encoding/hex"
10 "encoding/json" 14 "encoding/json"
15 "encoding/pem"
11 "fmt" 16 "fmt"
12 "io/ioutil" 17 "io/ioutil"
13 "math" 18 "math"
14 "net" 19 "net"
20 "net/url"
15 "path/filepath" 21 "path/filepath"
16 "regexp" 22 "regexp"
17 "sort" 23 "sort"
@@ -55,59 +61,74 @@ func listVariableValueToStringSlice(values []ast.Variable) ([]string, error) {
55// Funcs is the mapping of built-in functions for configuration. 61// Funcs is the mapping of built-in functions for configuration.
56func Funcs() map[string]ast.Function { 62func Funcs() map[string]ast.Function {
57 return map[string]ast.Function{ 63 return map[string]ast.Function{
58 "basename": interpolationFuncBasename(), 64 "abs": interpolationFuncAbs(),
59 "base64decode": interpolationFuncBase64Decode(), 65 "basename": interpolationFuncBasename(),
60 "base64encode": interpolationFuncBase64Encode(), 66 "base64decode": interpolationFuncBase64Decode(),
61 "base64sha256": interpolationFuncBase64Sha256(), 67 "base64encode": interpolationFuncBase64Encode(),
62 "base64sha512": interpolationFuncBase64Sha512(), 68 "base64gzip": interpolationFuncBase64Gzip(),
63 "bcrypt": interpolationFuncBcrypt(), 69 "base64sha256": interpolationFuncBase64Sha256(),
64 "ceil": interpolationFuncCeil(), 70 "base64sha512": interpolationFuncBase64Sha512(),
65 "chomp": interpolationFuncChomp(), 71 "bcrypt": interpolationFuncBcrypt(),
66 "cidrhost": interpolationFuncCidrHost(), 72 "ceil": interpolationFuncCeil(),
67 "cidrnetmask": interpolationFuncCidrNetmask(), 73 "chomp": interpolationFuncChomp(),
68 "cidrsubnet": interpolationFuncCidrSubnet(), 74 "cidrhost": interpolationFuncCidrHost(),
69 "coalesce": interpolationFuncCoalesce(), 75 "cidrnetmask": interpolationFuncCidrNetmask(),
70 "coalescelist": interpolationFuncCoalesceList(), 76 "cidrsubnet": interpolationFuncCidrSubnet(),
71 "compact": interpolationFuncCompact(), 77 "coalesce": interpolationFuncCoalesce(),
72 "concat": interpolationFuncConcat(), 78 "coalescelist": interpolationFuncCoalesceList(),
73 "contains": interpolationFuncContains(), 79 "compact": interpolationFuncCompact(),
74 "dirname": interpolationFuncDirname(), 80 "concat": interpolationFuncConcat(),
75 "distinct": interpolationFuncDistinct(), 81 "contains": interpolationFuncContains(),
76 "element": interpolationFuncElement(), 82 "dirname": interpolationFuncDirname(),
77 "file": interpolationFuncFile(), 83 "distinct": interpolationFuncDistinct(),
78 "matchkeys": interpolationFuncMatchKeys(), 84 "element": interpolationFuncElement(),
79 "floor": interpolationFuncFloor(), 85 "chunklist": interpolationFuncChunklist(),
80 "format": interpolationFuncFormat(), 86 "file": interpolationFuncFile(),
81 "formatlist": interpolationFuncFormatList(), 87 "filebase64sha256": interpolationFuncMakeFileHash(interpolationFuncBase64Sha256()),
82 "index": interpolationFuncIndex(), 88 "filebase64sha512": interpolationFuncMakeFileHash(interpolationFuncBase64Sha512()),
83 "join": interpolationFuncJoin(), 89 "filemd5": interpolationFuncMakeFileHash(interpolationFuncMd5()),
84 "jsonencode": interpolationFuncJSONEncode(), 90 "filesha1": interpolationFuncMakeFileHash(interpolationFuncSha1()),
85 "length": interpolationFuncLength(), 91 "filesha256": interpolationFuncMakeFileHash(interpolationFuncSha256()),
86 "list": interpolationFuncList(), 92 "filesha512": interpolationFuncMakeFileHash(interpolationFuncSha512()),
87 "log": interpolationFuncLog(), 93 "matchkeys": interpolationFuncMatchKeys(),
88 "lower": interpolationFuncLower(), 94 "flatten": interpolationFuncFlatten(),
89 "map": interpolationFuncMap(), 95 "floor": interpolationFuncFloor(),
90 "max": interpolationFuncMax(), 96 "format": interpolationFuncFormat(),
91 "md5": interpolationFuncMd5(), 97 "formatlist": interpolationFuncFormatList(),
92 "merge": interpolationFuncMerge(), 98 "indent": interpolationFuncIndent(),
93 "min": interpolationFuncMin(), 99 "index": interpolationFuncIndex(),
94 "pathexpand": interpolationFuncPathExpand(), 100 "join": interpolationFuncJoin(),
95 "pow": interpolationFuncPow(), 101 "jsonencode": interpolationFuncJSONEncode(),
96 "uuid": interpolationFuncUUID(), 102 "length": interpolationFuncLength(),
97 "replace": interpolationFuncReplace(), 103 "list": interpolationFuncList(),
98 "sha1": interpolationFuncSha1(), 104 "log": interpolationFuncLog(),
99 "sha256": interpolationFuncSha256(), 105 "lower": interpolationFuncLower(),
100 "sha512": interpolationFuncSha512(), 106 "map": interpolationFuncMap(),
101 "signum": interpolationFuncSignum(), 107 "max": interpolationFuncMax(),
102 "slice": interpolationFuncSlice(), 108 "md5": interpolationFuncMd5(),
103 "sort": interpolationFuncSort(), 109 "merge": interpolationFuncMerge(),
104 "split": interpolationFuncSplit(), 110 "min": interpolationFuncMin(),
105 "substr": interpolationFuncSubstr(), 111 "pathexpand": interpolationFuncPathExpand(),
106 "timestamp": interpolationFuncTimestamp(), 112 "pow": interpolationFuncPow(),
107 "title": interpolationFuncTitle(), 113 "uuid": interpolationFuncUUID(),
108 "trimspace": interpolationFuncTrimSpace(), 114 "replace": interpolationFuncReplace(),
109 "upper": interpolationFuncUpper(), 115 "rsadecrypt": interpolationFuncRsaDecrypt(),
110 "zipmap": interpolationFuncZipMap(), 116 "sha1": interpolationFuncSha1(),
117 "sha256": interpolationFuncSha256(),
118 "sha512": interpolationFuncSha512(),
119 "signum": interpolationFuncSignum(),
120 "slice": interpolationFuncSlice(),
121 "sort": interpolationFuncSort(),
122 "split": interpolationFuncSplit(),
123 "substr": interpolationFuncSubstr(),
124 "timestamp": interpolationFuncTimestamp(),
125 "timeadd": interpolationFuncTimeAdd(),
126 "title": interpolationFuncTitle(),
127 "transpose": interpolationFuncTranspose(),
128 "trimspace": interpolationFuncTrimSpace(),
129 "upper": interpolationFuncUpper(),
130 "urlencode": interpolationFuncURLEncode(),
131 "zipmap": interpolationFuncZipMap(),
111 } 132 }
112} 133}
113 134
@@ -669,6 +690,21 @@ func interpolationFuncFormatList() ast.Function {
669 } 690 }
670} 691}
671 692
693// interpolationFuncIndent indents a multi-line string with the
694// specified number of spaces
695func interpolationFuncIndent() ast.Function {
696 return ast.Function{
697 ArgTypes: []ast.Type{ast.TypeInt, ast.TypeString},
698 ReturnType: ast.TypeString,
699 Callback: func(args []interface{}) (interface{}, error) {
700 spaces := args[0].(int)
701 data := args[1].(string)
702 pad := strings.Repeat(" ", spaces)
703 return strings.Replace(data, "\n", "\n"+pad, -1), nil
704 },
705 }
706}
707
672// interpolationFuncIndex implements the "index" function that allows one to 708// interpolationFuncIndex implements the "index" function that allows one to
673// find the index of a specific element in a list 709// find the index of a specific element in a list
674func interpolationFuncIndex() ast.Function { 710func interpolationFuncIndex() ast.Function {
@@ -823,8 +859,7 @@ func interpolationFuncJoin() ast.Function {
823} 859}
824 860
825// interpolationFuncJSONEncode implements the "jsonencode" function that encodes 861// interpolationFuncJSONEncode implements the "jsonencode" function that encodes
826// a string, list, or map as its JSON representation. For now, values in the 862// a string, list, or map as its JSON representation.
827// list or map may only be strings.
828func interpolationFuncJSONEncode() ast.Function { 863func interpolationFuncJSONEncode() ast.Function {
829 return ast.Function{ 864 return ast.Function{
830 ArgTypes: []ast.Type{ast.TypeAny}, 865 ArgTypes: []ast.Type{ast.TypeAny},
@@ -837,28 +872,36 @@ func interpolationFuncJSONEncode() ast.Function {
837 toEncode = typedArg 872 toEncode = typedArg
838 873
839 case []ast.Variable: 874 case []ast.Variable:
840 // We preallocate the list here. Note that it's important that in
841 // the length 0 case, we have an empty list rather than nil, as
842 // they encode differently.
843 // XXX It would be nice to support arbitrarily nested data here. Is
844 // there an inverse of hil.InterfaceToVariable?
845 strings := make([]string, len(typedArg)) 875 strings := make([]string, len(typedArg))
846 876
847 for i, v := range typedArg { 877 for i, v := range typedArg {
848 if v.Type != ast.TypeString { 878 if v.Type != ast.TypeString {
849 return "", fmt.Errorf("list elements must be strings") 879 variable, _ := hil.InterfaceToVariable(typedArg)
880 toEncode, _ = hil.VariableToInterface(variable)
881
882 jEnc, err := json.Marshal(toEncode)
883 if err != nil {
884 return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode)
885 }
886 return string(jEnc), nil
887
850 } 888 }
851 strings[i] = v.Value.(string) 889 strings[i] = v.Value.(string)
852 } 890 }
853 toEncode = strings 891 toEncode = strings
854 892
855 case map[string]ast.Variable: 893 case map[string]ast.Variable:
856 // XXX It would be nice to support arbitrarily nested data here. Is
857 // there an inverse of hil.InterfaceToVariable?
858 stringMap := make(map[string]string) 894 stringMap := make(map[string]string)
859 for k, v := range typedArg { 895 for k, v := range typedArg {
860 if v.Type != ast.TypeString { 896 if v.Type != ast.TypeString {
861 return "", fmt.Errorf("map values must be strings") 897 variable, _ := hil.InterfaceToVariable(typedArg)
898 toEncode, _ = hil.VariableToInterface(variable)
899
900 jEnc, err := json.Marshal(toEncode)
901 if err != nil {
902 return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode)
903 }
904 return string(jEnc), nil
862 } 905 }
863 stringMap[k] = v.Value.(string) 906 stringMap[k] = v.Value.(string)
864 } 907 }
@@ -1098,6 +1141,56 @@ func interpolationFuncElement() ast.Function {
1098 } 1141 }
1099} 1142}
1100 1143
1144// returns the `list` items chunked by `size`.
1145func interpolationFuncChunklist() ast.Function {
1146 return ast.Function{
1147 ArgTypes: []ast.Type{
1148 ast.TypeList, // inputList
1149 ast.TypeInt, // size
1150 },
1151 ReturnType: ast.TypeList,
1152 Callback: func(args []interface{}) (interface{}, error) {
1153 output := make([]ast.Variable, 0)
1154
1155 values, _ := args[0].([]ast.Variable)
1156 size, _ := args[1].(int)
1157
1158 // errors if size is negative
1159 if size < 0 {
1160 return nil, fmt.Errorf("The size argument must be positive")
1161 }
1162
1163 // if size is 0, returns a list made of the initial list
1164 if size == 0 {
1165 output = append(output, ast.Variable{
1166 Type: ast.TypeList,
1167 Value: values,
1168 })
1169 return output, nil
1170 }
1171
1172 variables := make([]ast.Variable, 0)
1173 chunk := ast.Variable{
1174 Type: ast.TypeList,
1175 Value: variables,
1176 }
1177 l := len(values)
1178 for i, v := range values {
1179 variables = append(variables, v)
1180
1181 // Chunk when index isn't 0, or when reaching the values's length
1182 if (i+1)%size == 0 || (i+1) == l {
1183 chunk.Value = variables
1184 output = append(output, chunk)
1185 variables = make([]ast.Variable, 0)
1186 }
1187 }
1188
1189 return output, nil
1190 },
1191 }
1192}
1193
1101// interpolationFuncKeys implements the "keys" function that yields a list of 1194// interpolationFuncKeys implements the "keys" function that yields a list of
1102// keys of map types within a Terraform configuration. 1195// keys of map types within a Terraform configuration.
1103func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function { 1196func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function {
@@ -1197,6 +1290,32 @@ func interpolationFuncBase64Decode() ast.Function {
1197 } 1290 }
1198} 1291}
1199 1292
1293// interpolationFuncBase64Gzip implements the "gzip" function that allows gzip
1294// compression encoding the result using base64
1295func interpolationFuncBase64Gzip() ast.Function {
1296 return ast.Function{
1297 ArgTypes: []ast.Type{ast.TypeString},
1298 ReturnType: ast.TypeString,
1299 Callback: func(args []interface{}) (interface{}, error) {
1300 s := args[0].(string)
1301
1302 var b bytes.Buffer
1303 gz := gzip.NewWriter(&b)
1304 if _, err := gz.Write([]byte(s)); err != nil {
1305 return "", fmt.Errorf("failed to write gzip raw data: '%s'", s)
1306 }
1307 if err := gz.Flush(); err != nil {
1308 return "", fmt.Errorf("failed to flush gzip writer: '%s'", s)
1309 }
1310 if err := gz.Close(); err != nil {
1311 return "", fmt.Errorf("failed to close gzip writer: '%s'", s)
1312 }
1313
1314 return base64.StdEncoding.EncodeToString(b.Bytes()), nil
1315 },
1316 }
1317}
1318
1200// interpolationFuncLower implements the "lower" function that does 1319// interpolationFuncLower implements the "lower" function that does
1201// string lower casing. 1320// string lower casing.
1202func interpolationFuncLower() ast.Function { 1321func interpolationFuncLower() ast.Function {
@@ -1396,6 +1515,29 @@ func interpolationFuncTimestamp() ast.Function {
1396 } 1515 }
1397} 1516}
1398 1517
1518func interpolationFuncTimeAdd() ast.Function {
1519 return ast.Function{
1520 ArgTypes: []ast.Type{
1521 ast.TypeString, // input timestamp string in RFC3339 format
1522 ast.TypeString, // duration to add to input timestamp that should be parsable by time.ParseDuration
1523 },
1524 ReturnType: ast.TypeString,
1525 Callback: func(args []interface{}) (interface{}, error) {
1526
1527 ts, err := time.Parse(time.RFC3339, args[0].(string))
1528 if err != nil {
1529 return nil, err
1530 }
1531 duration, err := time.ParseDuration(args[1].(string))
1532 if err != nil {
1533 return nil, err
1534 }
1535
1536 return ts.Add(duration).Format(time.RFC3339), nil
1537 },
1538 }
1539}
1540
1399// interpolationFuncTitle implements the "title" function that returns a copy of the 1541// interpolationFuncTitle implements the "title" function that returns a copy of the
1400// string in which first characters of all the words are capitalized. 1542// string in which first characters of all the words are capitalized.
1401func interpolationFuncTitle() ast.Function { 1543func interpolationFuncTitle() ast.Function {
@@ -1441,7 +1583,7 @@ func interpolationFuncSubstr() ast.Function {
1441 return nil, fmt.Errorf("length should be a non-negative integer") 1583 return nil, fmt.Errorf("length should be a non-negative integer")
1442 } 1584 }
1443 1585
1444 if offset > len(str) { 1586 if offset > len(str) || offset < 0 {
1445 return nil, fmt.Errorf("offset cannot be larger than the length of the string") 1587 return nil, fmt.Errorf("offset cannot be larger than the length of the string")
1446 } 1588 }
1447 1589
@@ -1453,3 +1595,160 @@ func interpolationFuncSubstr() ast.Function {
1453 }, 1595 },
1454 } 1596 }
1455} 1597}
1598
1599// Flatten until it's not ast.TypeList
1600func flattener(finalList []ast.Variable, flattenList []ast.Variable) []ast.Variable {
1601 for _, val := range flattenList {
1602 if val.Type == ast.TypeList {
1603 finalList = flattener(finalList, val.Value.([]ast.Variable))
1604 } else {
1605 finalList = append(finalList, val)
1606 }
1607 }
1608 return finalList
1609}
1610
1611// Flatten to single list
1612func interpolationFuncFlatten() ast.Function {
1613 return ast.Function{
1614 ArgTypes: []ast.Type{ast.TypeList},
1615 ReturnType: ast.TypeList,
1616 Variadic: false,
1617 Callback: func(args []interface{}) (interface{}, error) {
1618 inputList := args[0].([]ast.Variable)
1619
1620 var outputList []ast.Variable
1621 return flattener(outputList, inputList), nil
1622 },
1623 }
1624}
1625
1626func interpolationFuncURLEncode() ast.Function {
1627 return ast.Function{
1628 ArgTypes: []ast.Type{ast.TypeString},
1629 ReturnType: ast.TypeString,
1630 Callback: func(args []interface{}) (interface{}, error) {
1631 s := args[0].(string)
1632 return url.QueryEscape(s), nil
1633 },
1634 }
1635}
1636
1637// interpolationFuncTranspose implements the "transpose" function
1638// that converts a map (string,list) to a map (string,list) where
1639// the unique values of the original lists become the keys of the
1640// new map and the keys of the original map become values for the
1641// corresponding new keys.
1642func interpolationFuncTranspose() ast.Function {
1643 return ast.Function{
1644 ArgTypes: []ast.Type{ast.TypeMap},
1645 ReturnType: ast.TypeMap,
1646 Callback: func(args []interface{}) (interface{}, error) {
1647
1648 inputMap := args[0].(map[string]ast.Variable)
1649 outputMap := make(map[string]ast.Variable)
1650 tmpMap := make(map[string][]string)
1651
1652 for inKey, inVal := range inputMap {
1653 if inVal.Type != ast.TypeList {
1654 return nil, fmt.Errorf("transpose requires a map of lists of strings")
1655 }
1656 values := inVal.Value.([]ast.Variable)
1657 for _, listVal := range values {
1658 if listVal.Type != ast.TypeString {
1659 return nil, fmt.Errorf("transpose requires the given map values to be lists of strings")
1660 }
1661 outKey := listVal.Value.(string)
1662 if _, ok := tmpMap[outKey]; !ok {
1663 tmpMap[outKey] = make([]string, 0)
1664 }
1665 outVal := tmpMap[outKey]
1666 outVal = append(outVal, inKey)
1667 sort.Strings(outVal)
1668 tmpMap[outKey] = outVal
1669 }
1670 }
1671
1672 for outKey, outVal := range tmpMap {
1673 values := make([]ast.Variable, 0)
1674 for _, v := range outVal {
1675 values = append(values, ast.Variable{Type: ast.TypeString, Value: v})
1676 }
1677 outputMap[outKey] = ast.Variable{Type: ast.TypeList, Value: values}
1678 }
1679 return outputMap, nil
1680 },
1681 }
1682}
1683
1684// interpolationFuncAbs returns the absolute value of a given float.
1685func interpolationFuncAbs() ast.Function {
1686 return ast.Function{
1687 ArgTypes: []ast.Type{ast.TypeFloat},
1688 ReturnType: ast.TypeFloat,
1689 Callback: func(args []interface{}) (interface{}, error) {
1690 return math.Abs(args[0].(float64)), nil
1691 },
1692 }
1693}
1694
1695// interpolationFuncRsaDecrypt implements the "rsadecrypt" function that does
1696// RSA decryption.
1697func interpolationFuncRsaDecrypt() ast.Function {
1698 return ast.Function{
1699 ArgTypes: []ast.Type{ast.TypeString, ast.TypeString},
1700 ReturnType: ast.TypeString,
1701 Callback: func(args []interface{}) (interface{}, error) {
1702 s := args[0].(string)
1703 key := args[1].(string)
1704
1705 b, err := base64.StdEncoding.DecodeString(s)
1706 if err != nil {
1707 return "", fmt.Errorf("Failed to decode input %q: cipher text must be base64-encoded", s)
1708 }
1709
1710 block, _ := pem.Decode([]byte(key))
1711 if block == nil {
1712 return "", fmt.Errorf("Failed to read key %q: no key found", key)
1713 }
1714 if block.Headers["Proc-Type"] == "4,ENCRYPTED" {
1715 return "", fmt.Errorf(
1716 "Failed to read key %q: password protected keys are\n"+
1717 "not supported. Please decrypt the key prior to use.", key)
1718 }
1719
1720 x509Key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
1721 if err != nil {
1722 return "", err
1723 }
1724
1725 out, err := rsa.DecryptPKCS1v15(nil, x509Key, b)
1726 if err != nil {
1727 return "", err
1728 }
1729
1730 return string(out), nil
1731 },
1732 }
1733}
1734
1735// interpolationFuncMakeFileHash constructs a function that hashes the contents
1736// of a file by combining the implementations of the file(...) function and
1737// a given other function that is assumed to take a single string argument and
1738// return a hash value.
1739func interpolationFuncMakeFileHash(hashFunc ast.Function) ast.Function {
1740 fileFunc := interpolationFuncFile()
1741
1742 return ast.Function{
1743 ArgTypes: []ast.Type{ast.TypeString},
1744 ReturnType: ast.TypeString,
1745 Callback: func(args []interface{}) (interface{}, error) {
1746 filename := args[0].(string)
1747 contents, err := fileFunc.Callback([]interface{}{filename})
1748 if err != nil {
1749 return nil, err
1750 }
1751 return hashFunc.Callback([]interface{}{contents})
1752 },
1753 }
1754}
diff --git a/vendor/github.com/hashicorp/terraform/config/interpolate_walk.go b/vendor/github.com/hashicorp/terraform/config/interpolate_walk.go
index ead3d10..66a677d 100644
--- a/vendor/github.com/hashicorp/terraform/config/interpolate_walk.go
+++ b/vendor/github.com/hashicorp/terraform/config/interpolate_walk.go
@@ -271,9 +271,7 @@ func (w *interpolationWalker) splitSlice() {
271 result = append(result, val.Value) 271 result = append(result, val.Value)
272 } 272 }
273 case []interface{}: 273 case []interface{}:
274 for _, element := range val { 274 result = append(result, val...)
275 result = append(result, element)
276 }
277 default: 275 default:
278 result = append(result, v) 276 result = append(result, v)
279 } 277 }
diff --git a/vendor/github.com/hashicorp/terraform/config/loader.go b/vendor/github.com/hashicorp/terraform/config/loader.go
index 5dd7d46..6e34781 100644
--- a/vendor/github.com/hashicorp/terraform/config/loader.go
+++ b/vendor/github.com/hashicorp/terraform/config/loader.go
@@ -80,7 +80,7 @@ func LoadDir(root string) (*Config, error) {
80 if err != nil { 80 if err != nil {
81 return nil, err 81 return nil, err
82 } 82 }
83 if len(files) == 0 { 83 if len(files) == 0 && len(overrides) == 0 {
84 return nil, &ErrNoConfigsFound{Dir: root} 84 return nil, &ErrNoConfigsFound{Dir: root}
85 } 85 }
86 86
@@ -112,6 +112,9 @@ func LoadDir(root string) (*Config, error) {
112 result = c 112 result = c
113 } 113 }
114 } 114 }
115 if len(files) == 0 {
116 result = &Config{}
117 }
115 118
116 // Load all the overrides, and merge them into the config 119 // Load all the overrides, and merge them into the config
117 for _, f := range overrides { 120 for _, f := range overrides {
diff --git a/vendor/github.com/hashicorp/terraform/config/loader_hcl.go b/vendor/github.com/hashicorp/terraform/config/loader_hcl.go
index e85e493..68cffe2 100644
--- a/vendor/github.com/hashicorp/terraform/config/loader_hcl.go
+++ b/vendor/github.com/hashicorp/terraform/config/loader_hcl.go
@@ -17,10 +17,20 @@ type hclConfigurable struct {
17 Root *ast.File 17 Root *ast.File
18} 18}
19 19
20var ReservedDataSourceFields = []string{
21 "connection",
22 "count",
23 "depends_on",
24 "lifecycle",
25 "provider",
26 "provisioner",
27}
28
20var ReservedResourceFields = []string{ 29var ReservedResourceFields = []string{
21 "connection", 30 "connection",
22 "count", 31 "count",
23 "depends_on", 32 "depends_on",
33 "id",
24 "lifecycle", 34 "lifecycle",
25 "provider", 35 "provider",
26 "provisioner", 36 "provisioner",
@@ -35,6 +45,7 @@ func (t *hclConfigurable) Config() (*Config, error) {
35 validKeys := map[string]struct{}{ 45 validKeys := map[string]struct{}{
36 "atlas": struct{}{}, 46 "atlas": struct{}{},
37 "data": struct{}{}, 47 "data": struct{}{},
48 "locals": struct{}{},
38 "module": struct{}{}, 49 "module": struct{}{},
39 "output": struct{}{}, 50 "output": struct{}{},
40 "provider": struct{}{}, 51 "provider": struct{}{},
@@ -70,6 +81,15 @@ func (t *hclConfigurable) Config() (*Config, error) {
70 } 81 }
71 } 82 }
72 83
84 // Build local values
85 if locals := list.Filter("locals"); len(locals.Items) > 0 {
86 var err error
87 config.Locals, err = loadLocalsHcl(locals)
88 if err != nil {
89 return nil, err
90 }
91 }
92
73 // Get Atlas configuration 93 // Get Atlas configuration
74 if atlas := list.Filter("atlas"); len(atlas.Items) > 0 { 94 if atlas := list.Filter("atlas"); len(atlas.Items) > 0 {
75 var err error 95 var err error
@@ -373,9 +393,6 @@ func loadModulesHcl(list *ast.ObjectList) ([]*Module, error) {
373 err) 393 err)
374 } 394 }
375 395
376 // Remove the fields we handle specially
377 delete(config, "source")
378
379 rawConfig, err := NewRawConfig(config) 396 rawConfig, err := NewRawConfig(config)
380 if err != nil { 397 if err != nil {
381 return nil, fmt.Errorf( 398 return nil, fmt.Errorf(
@@ -384,7 +401,11 @@ func loadModulesHcl(list *ast.ObjectList) ([]*Module, error) {
384 err) 401 err)
385 } 402 }
386 403
387 // If we have a count, then figure it out 404 // Remove the fields we handle specially
405 delete(config, "source")
406 delete(config, "version")
407 delete(config, "providers")
408
388 var source string 409 var source string
389 if o := listVal.Filter("source"); len(o.Items) > 0 { 410 if o := listVal.Filter("source"); len(o.Items) > 0 {
390 err = hcl.DecodeObject(&source, o.Items[0].Val) 411 err = hcl.DecodeObject(&source, o.Items[0].Val)
@@ -396,9 +417,33 @@ func loadModulesHcl(list *ast.ObjectList) ([]*Module, error) {
396 } 417 }
397 } 418 }
398 419
420 var version string
421 if o := listVal.Filter("version"); len(o.Items) > 0 {
422 err = hcl.DecodeObject(&version, o.Items[0].Val)
423 if err != nil {
424 return nil, fmt.Errorf(
425 "Error parsing version for %s: %s",
426 k,
427 err)
428 }
429 }
430
431 var providers map[string]string
432 if o := listVal.Filter("providers"); len(o.Items) > 0 {
433 err = hcl.DecodeObject(&providers, o.Items[0].Val)
434 if err != nil {
435 return nil, fmt.Errorf(
436 "Error parsing providers for %s: %s",
437 k,
438 err)
439 }
440 }
441
399 result = append(result, &Module{ 442 result = append(result, &Module{
400 Name: k, 443 Name: k,
401 Source: source, 444 Source: source,
445 Version: version,
446 Providers: providers,
402 RawConfig: rawConfig, 447 RawConfig: rawConfig,
403 }) 448 })
404 } 449 }
@@ -406,6 +451,59 @@ func loadModulesHcl(list *ast.ObjectList) ([]*Module, error) {
406 return result, nil 451 return result, nil
407} 452}
408 453
454// loadLocalsHcl recurses into the given HCL object turns it into
455// a list of locals.
456func loadLocalsHcl(list *ast.ObjectList) ([]*Local, error) {
457
458 result := make([]*Local, 0, len(list.Items))
459
460 for _, block := range list.Items {
461 if len(block.Keys) > 0 {
462 return nil, fmt.Errorf(
463 "locals block at %s should not have label %q",
464 block.Pos(), block.Keys[0].Token.Value(),
465 )
466 }
467
468 blockObj, ok := block.Val.(*ast.ObjectType)
469 if !ok {
470 return nil, fmt.Errorf("locals value at %s should be a block", block.Val.Pos())
471 }
472
473 // blockObj now contains directly our local decls
474 for _, item := range blockObj.List.Items {
475 if len(item.Keys) != 1 {
476 return nil, fmt.Errorf("local declaration at %s may not be a block", item.Val.Pos())
477 }
478
479 // By the time we get here there can only be one item left, but
480 // we'll decode into a map anyway because it's a convenient way
481 // to extract both the key and the value robustly.
482 kv := map[string]interface{}{}
483 hcl.DecodeObject(&kv, item)
484 for k, v := range kv {
485 rawConfig, err := NewRawConfig(map[string]interface{}{
486 "value": v,
487 })
488
489 if err != nil {
490 return nil, fmt.Errorf(
491 "error parsing local value %q at %s: %s",
492 k, item.Val.Pos(), err,
493 )
494 }
495
496 result = append(result, &Local{
497 Name: k,
498 RawConfig: rawConfig,
499 })
500 }
501 }
502 }
503
504 return result, nil
505}
506
409// LoadOutputsHcl recurses into the given HCL object and turns 507// LoadOutputsHcl recurses into the given HCL object and turns
410// it into a mapping of outputs. 508// it into a mapping of outputs.
411func loadOutputsHcl(list *ast.ObjectList) ([]*Output, error) { 509func loadOutputsHcl(list *ast.ObjectList) ([]*Output, error) {
@@ -434,6 +532,7 @@ func loadOutputsHcl(list *ast.ObjectList) ([]*Output, error) {
434 532
435 // Delete special keys 533 // Delete special keys
436 delete(config, "depends_on") 534 delete(config, "depends_on")
535 delete(config, "description")
437 536
438 rawConfig, err := NewRawConfig(config) 537 rawConfig, err := NewRawConfig(config)
439 if err != nil { 538 if err != nil {
@@ -455,10 +554,23 @@ func loadOutputsHcl(list *ast.ObjectList) ([]*Output, error) {
455 } 554 }
456 } 555 }
457 556
557 // If we have a description field, then filter that
558 var description string
559 if o := listVal.Filter("description"); len(o.Items) > 0 {
560 err := hcl.DecodeObject(&description, o.Items[0].Val)
561 if err != nil {
562 return nil, fmt.Errorf(
563 "Error reading description for output %q: %s",
564 n,
565 err)
566 }
567 }
568
458 result = append(result, &Output{ 569 result = append(result, &Output{
459 Name: n, 570 Name: n,
460 RawConfig: rawConfig, 571 RawConfig: rawConfig,
461 DependsOn: dependsOn, 572 DependsOn: dependsOn,
573 Description: description,
462 }) 574 })
463 } 575 }
464 576
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 @@
1package config
2
3import (
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.
17type hcl2Configurable struct {
18 SourceFilename string
19 Body hcl2.Body
20}
21
22// hcl2Loader is a wrapper around a HCL parser that provides a fileLoaderFunc.
23type 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.
31var 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.
39func 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.
47func (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
68func (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}
diff --git a/vendor/github.com/hashicorp/terraform/config/merge.go b/vendor/github.com/hashicorp/terraform/config/merge.go
index db214be..55fc864 100644
--- a/vendor/github.com/hashicorp/terraform/config/merge.go
+++ b/vendor/github.com/hashicorp/terraform/config/merge.go
@@ -137,6 +137,17 @@ func Merge(c1, c2 *Config) (*Config, error) {
137 } 137 }
138 } 138 }
139 139
140 // Local Values
141 // These are simpler than the other config elements because they are just
142 // flat values and so no deep merging is required.
143 if localsCount := len(c1.Locals) + len(c2.Locals); localsCount != 0 {
144 // Explicit length check above because we want c.Locals to remain
145 // nil if the result would be empty.
146 c.Locals = make([]*Local, 0, len(c1.Locals)+len(c2.Locals))
147 c.Locals = append(c.Locals, c1.Locals...)
148 c.Locals = append(c.Locals, c2.Locals...)
149 }
150
140 return c, nil 151 return c, nil
141} 152}
142 153
diff --git a/vendor/github.com/hashicorp/terraform/config/module/get.go b/vendor/github.com/hashicorp/terraform/config/module/get.go
index 96b4a63..5073d0d 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/get.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/get.go
@@ -3,6 +3,7 @@ package module
3import ( 3import (
4 "io/ioutil" 4 "io/ioutil"
5 "os" 5 "os"
6 "path/filepath"
6 7
7 "github.com/hashicorp/go-getter" 8 "github.com/hashicorp/go-getter"
8) 9)
@@ -37,13 +38,10 @@ func GetCopy(dst, src string) error {
37 if err != nil { 38 if err != nil {
38 return err 39 return err
39 } 40 }
40 // FIXME: This isn't completely safe. Creating and removing our temp path
41 // exposes where to race to inject files.
42 if err := os.RemoveAll(tmpDir); err != nil {
43 return err
44 }
45 defer os.RemoveAll(tmpDir) 41 defer os.RemoveAll(tmpDir)
46 42
43 tmpDir = filepath.Join(tmpDir, "module")
44
47 // Get to that temporary dir 45 // Get to that temporary dir
48 if err := getter.Get(tmpDir, src); err != nil { 46 if err := getter.Get(tmpDir, src); err != nil {
49 return err 47 return err
@@ -57,15 +55,3 @@ func GetCopy(dst, src string) error {
57 // Copy to the final location 55 // Copy to the final location
58 return copyDir(dst, tmpDir) 56 return copyDir(dst, tmpDir)
59} 57}
60
61func getStorage(s getter.Storage, key string, src string, mode GetMode) (string, bool, error) {
62 // Get the module with the level specified if we were told to.
63 if mode > GetModeNone {
64 if err := s.Get(key, src, mode == GetModeUpdate); err != nil {
65 return "", false, err
66 }
67 }
68
69 // Get the directory where the module is.
70 return s.Dir(key)
71}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/inode.go b/vendor/github.com/hashicorp/terraform/config/module/inode.go
index 8603ee2..da520ab 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/inode.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/inode.go
@@ -1,4 +1,4 @@
1// +build linux darwin openbsd netbsd solaris 1// +build linux darwin openbsd netbsd solaris dragonfly
2 2
3package module 3package module
4 4
diff --git a/vendor/github.com/hashicorp/terraform/config/module/module.go b/vendor/github.com/hashicorp/terraform/config/module/module.go
index f8649f6..7dc8fcc 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/module.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/module.go
@@ -2,6 +2,8 @@ package module
2 2
3// Module represents the metadata for a single module. 3// Module represents the metadata for a single module.
4type Module struct { 4type Module struct {
5 Name string 5 Name string
6 Source string 6 Source string
7 Version string
8 Providers map[string]string
7} 9}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/storage.go b/vendor/github.com/hashicorp/terraform/config/module/storage.go
new file mode 100644
index 0000000..58e3a10
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/storage.go
@@ -0,0 +1,365 @@
1package module
2
3import (
4 "encoding/json"
5 "fmt"
6 "io/ioutil"
7 "log"
8 "os"
9 "path/filepath"
10 "strings"
11
12 getter "github.com/hashicorp/go-getter"
13 "github.com/hashicorp/terraform/registry"
14 "github.com/hashicorp/terraform/registry/regsrc"
15 "github.com/hashicorp/terraform/svchost/disco"
16 "github.com/mitchellh/cli"
17)
18
19const manifestName = "modules.json"
20
21// moduleManifest is the serialization structure used to record the stored
22// module's metadata.
23type moduleManifest struct {
24 Modules []moduleRecord
25}
26
27// moduleRecords represents the stored module's metadata.
28// This is compared for equality using '==', so all fields needs to remain
29// comparable.
30type moduleRecord struct {
31 // Source is the module source string from the config, minus any
32 // subdirectory.
33 Source string
34
35 // Key is the locally unique identifier for this module.
36 Key string
37
38 // Version is the exact version string for the stored module.
39 Version string
40
41 // Dir is the directory name returned by the FileStorage. This is what
42 // allows us to correlate a particular module version with the location on
43 // disk.
44 Dir string
45
46 // Root is the root directory containing the module. If the module is
47 // unpacked from an archive, and not located in the root directory, this is
48 // used to direct the loader to the correct subdirectory. This is
49 // independent from any subdirectory in the original source string, which
50 // may traverse further into the module tree.
51 Root string
52
53 // url is the location of the module source
54 url string
55
56 // Registry is true if this module is sourced from a registry
57 registry bool
58}
59
60// Storage implements methods to manage the storage of modules.
61// This is used by Tree.Load to query registries, authenticate requests, and
62// store modules locally.
63type Storage struct {
64 // StorageDir is the full path to the directory where all modules will be
65 // stored.
66 StorageDir string
67
68 // Ui is an optional cli.Ui for user output
69 Ui cli.Ui
70
71 // Mode is the GetMode that will be used for various operations.
72 Mode GetMode
73
74 registry *registry.Client
75}
76
77// NewStorage returns a new initialized Storage object.
78func NewStorage(dir string, services *disco.Disco) *Storage {
79 regClient := registry.NewClient(services, nil)
80
81 return &Storage{
82 StorageDir: dir,
83 registry: regClient,
84 }
85}
86
87// loadManifest returns the moduleManifest file from the parent directory.
88func (s Storage) loadManifest() (moduleManifest, error) {
89 manifest := moduleManifest{}
90
91 manifestPath := filepath.Join(s.StorageDir, manifestName)
92 data, err := ioutil.ReadFile(manifestPath)
93 if err != nil && !os.IsNotExist(err) {
94 return manifest, err
95 }
96
97 if len(data) == 0 {
98 return manifest, nil
99 }
100
101 if err := json.Unmarshal(data, &manifest); err != nil {
102 return manifest, err
103 }
104
105 for i, rec := range manifest.Modules {
106 // If the path was recorded before we changed to always using a
107 // slash as separator, we delete the record from the manifest so
108 // it can be discovered again and will be recorded using a slash.
109 if strings.Contains(rec.Dir, "\\") {
110 manifest.Modules[i] = manifest.Modules[len(manifest.Modules)-1]
111 manifest.Modules = manifest.Modules[:len(manifest.Modules)-1]
112 continue
113 }
114
115 // Make sure we use the correct path separator.
116 rec.Dir = filepath.FromSlash(rec.Dir)
117 }
118
119 return manifest, nil
120}
121
122// Store the location of the module, along with the version used and the module
123// root directory. The storage method loads the entire file and rewrites it
124// each time. This is only done a few times during init, so efficiency is
125// not a concern.
126func (s Storage) recordModule(rec moduleRecord) error {
127 manifest, err := s.loadManifest()
128 if err != nil {
129 // if there was a problem with the file, we will attempt to write a new
130 // one. Any non-data related error should surface there.
131 log.Printf("[WARN] error reading module manifest: %s", err)
132 }
133
134 // do nothing if we already have the exact module
135 for i, stored := range manifest.Modules {
136 if rec == stored {
137 return nil
138 }
139
140 // they are not equal, but if the storage path is the same we need to
141 // remove this rec to be replaced.
142 if rec.Dir == stored.Dir {
143 manifest.Modules[i] = manifest.Modules[len(manifest.Modules)-1]
144 manifest.Modules = manifest.Modules[:len(manifest.Modules)-1]
145 break
146 }
147 }
148
149 // Make sure we always use a slash separator.
150 rec.Dir = filepath.ToSlash(rec.Dir)
151
152 manifest.Modules = append(manifest.Modules, rec)
153
154 js, err := json.Marshal(manifest)
155 if err != nil {
156 panic(err)
157 }
158
159 manifestPath := filepath.Join(s.StorageDir, manifestName)
160 return ioutil.WriteFile(manifestPath, js, 0644)
161}
162
163// load the manifest from dir, and return all module versions matching the
164// provided source. Records with no version info will be skipped, as they need
165// to be uniquely identified by other means.
166func (s Storage) moduleVersions(source string) ([]moduleRecord, error) {
167 manifest, err := s.loadManifest()
168 if err != nil {
169 return manifest.Modules, err
170 }
171
172 var matching []moduleRecord
173
174 for _, m := range manifest.Modules {
175 if m.Source == source && m.Version != "" {
176 log.Printf("[DEBUG] found local version %q for module %s", m.Version, m.Source)
177 matching = append(matching, m)
178 }
179 }
180
181 return matching, nil
182}
183
184func (s Storage) moduleDir(key string) (string, error) {
185 manifest, err := s.loadManifest()
186 if err != nil {
187 return "", err
188 }
189
190 for _, m := range manifest.Modules {
191 if m.Key == key {
192 return m.Dir, nil
193 }
194 }
195
196 return "", nil
197}
198
199// return only the root directory of the module stored in dir.
200func (s Storage) getModuleRoot(dir string) (string, error) {
201 manifest, err := s.loadManifest()
202 if err != nil {
203 return "", err
204 }
205
206 for _, mod := range manifest.Modules {
207 if mod.Dir == dir {
208 return mod.Root, nil
209 }
210 }
211 return "", nil
212}
213
214// record only the Root directory for the module stored at dir.
215func (s Storage) recordModuleRoot(dir, root string) error {
216 rec := moduleRecord{
217 Dir: dir,
218 Root: root,
219 }
220
221 return s.recordModule(rec)
222}
223
224func (s Storage) output(msg string) {
225 if s.Ui == nil || s.Mode == GetModeNone {
226 return
227 }
228 s.Ui.Output(msg)
229}
230
231func (s Storage) getStorage(key string, src string) (string, bool, error) {
232 storage := &getter.FolderStorage{
233 StorageDir: s.StorageDir,
234 }
235
236 log.Printf("[DEBUG] fetching module from %s", src)
237
238 // Get the module with the level specified if we were told to.
239 if s.Mode > GetModeNone {
240 log.Printf("[DEBUG] fetching %q with key %q", src, key)
241 if err := storage.Get(key, src, s.Mode == GetModeUpdate); err != nil {
242 return "", false, err
243 }
244 }
245
246 // Get the directory where the module is.
247 dir, found, err := storage.Dir(key)
248 log.Printf("[DEBUG] found %q in %q: %t", src, dir, found)
249 return dir, found, err
250}
251
252// find a stored module that's not from a registry
253func (s Storage) findModule(key string) (string, error) {
254 if s.Mode == GetModeUpdate {
255 return "", nil
256 }
257
258 return s.moduleDir(key)
259}
260
261// GetModule fetches a module source into the specified directory. This is used
262// as a convenience function by the CLI to initialize a configuration.
263func (s Storage) GetModule(dst, src string) error {
264 // reset this in case the caller was going to re-use it
265 mode := s.Mode
266 s.Mode = GetModeUpdate
267 defer func() {
268 s.Mode = mode
269 }()
270
271 rec, err := s.findRegistryModule(src, anyVersion)
272 if err != nil {
273 return err
274 }
275
276 pwd, err := os.Getwd()
277 if err != nil {
278 return err
279 }
280
281 source := rec.url
282 if source == "" {
283 source, err = getter.Detect(src, pwd, getter.Detectors)
284 if err != nil {
285 return fmt.Errorf("module %s: %s", src, err)
286 }
287 }
288
289 if source == "" {
290 return fmt.Errorf("module %q not found", src)
291 }
292
293 return GetCopy(dst, source)
294}
295
296// find a registry module
297func (s Storage) findRegistryModule(mSource, constraint string) (moduleRecord, error) {
298 rec := moduleRecord{
299 Source: mSource,
300 }
301 // detect if we have a registry source
302 mod, err := regsrc.ParseModuleSource(mSource)
303 switch err {
304 case nil:
305 //ok
306 case regsrc.ErrInvalidModuleSource:
307 return rec, nil
308 default:
309 return rec, err
310 }
311 rec.registry = true
312
313 log.Printf("[TRACE] %q is a registry module", mod.Display())
314
315 versions, err := s.moduleVersions(mod.String())
316 if err != nil {
317 log.Printf("[ERROR] error looking up versions for %q: %s", mod.Display(), err)
318 return rec, err
319 }
320
321 match, err := newestRecord(versions, constraint)
322 if err != nil {
323 log.Printf("[INFO] no matching version for %q<%s>, %s", mod.Display(), constraint, err)
324 }
325 log.Printf("[DEBUG] matched %q version %s for %s", mod, match.Version, constraint)
326
327 rec.Dir = match.Dir
328 rec.Version = match.Version
329 found := rec.Dir != ""
330
331 // we need to lookup available versions
332 // Only on Get if it's not found, on unconditionally on Update
333 if (s.Mode == GetModeGet && !found) || (s.Mode == GetModeUpdate) {
334 resp, err := s.registry.Versions(mod)
335 if err != nil {
336 return rec, err
337 }
338
339 if len(resp.Modules) == 0 {
340 return rec, fmt.Errorf("module %q not found in registry", mod.Display())
341 }
342
343 match, err := newestVersion(resp.Modules[0].Versions, constraint)
344 if err != nil {
345 return rec, err
346 }
347
348 if match == nil {
349 return rec, fmt.Errorf("no versions for %q found matching %q", mod.Display(), constraint)
350 }
351
352 rec.Version = match.Version
353
354 rec.url, err = s.registry.Location(mod, rec.Version)
355 if err != nil {
356 return rec, err
357 }
358
359 // we've already validated this by now
360 host, _ := mod.SvcHost()
361 s.output(fmt.Sprintf(" Found version %s of %s on %s", rec.Version, mod.Module(), host.ForDisplay()))
362
363 }
364 return rec, nil
365}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/testing.go b/vendor/github.com/hashicorp/terraform/config/module/testing.go
index fc9e733..6f1ff05 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/testing.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/testing.go
@@ -4,8 +4,6 @@ import (
4 "io/ioutil" 4 "io/ioutil"
5 "os" 5 "os"
6 "testing" 6 "testing"
7
8 "github.com/hashicorp/go-getter"
9) 7)
10 8
11// TestTree loads a module at the given path and returns the tree as well 9// TestTree loads a module at the given path and returns the tree as well
@@ -26,8 +24,8 @@ func TestTree(t *testing.T, path string) (*Tree, func()) {
26 } 24 }
27 25
28 // Get the child modules 26 // Get the child modules
29 s := &getter.FolderStorage{StorageDir: dir} 27 s := &Storage{StorageDir: dir, Mode: GetModeGet}
30 if err := mod.Load(s, GetModeGet); err != nil { 28 if err := mod.Load(s); err != nil {
31 t.Fatalf("err: %s", err) 29 t.Fatalf("err: %s", err)
32 return nil, nil 30 return nil, nil
33 } 31 }
diff --git a/vendor/github.com/hashicorp/terraform/config/module/tree.go b/vendor/github.com/hashicorp/terraform/config/module/tree.go
index 4b0b153..f56d69b 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/tree.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/tree.go
@@ -4,11 +4,14 @@ import (
4 "bufio" 4 "bufio"
5 "bytes" 5 "bytes"
6 "fmt" 6 "fmt"
7 "log"
7 "path/filepath" 8 "path/filepath"
8 "strings" 9 "strings"
9 "sync" 10 "sync"
10 11
11 "github.com/hashicorp/go-getter" 12 "github.com/hashicorp/terraform/tfdiags"
13
14 getter "github.com/hashicorp/go-getter"
12 "github.com/hashicorp/terraform/config" 15 "github.com/hashicorp/terraform/config"
13) 16)
14 17
@@ -26,6 +29,17 @@ type Tree struct {
26 children map[string]*Tree 29 children map[string]*Tree
27 path []string 30 path []string
28 lock sync.RWMutex 31 lock sync.RWMutex
32
33 // version is the final version of the config loaded for the Tree's module
34 version string
35 // source is the "source" string used to load this module. It's possible
36 // for a module source to change, but the path remains the same, preventing
37 // it from being reloaded.
38 source string
39 // parent allows us to walk back up the tree and determine if there are any
40 // versioned ancestor modules which may effect the stored location of
41 // submodules
42 parent *Tree
29} 43}
30 44
31// NewTree returns a new Tree for the given config structure. 45// NewTree returns a new Tree for the given config structure.
@@ -40,7 +54,7 @@ func NewEmptyTree() *Tree {
40 // We do this dummy load so that the tree is marked as "loaded". It 54 // We do this dummy load so that the tree is marked as "loaded". It
41 // should never fail because this is just about a no-op. If it does fail 55 // should never fail because this is just about a no-op. If it does fail
42 // we panic so we can know its a bug. 56 // we panic so we can know its a bug.
43 if err := t.Load(nil, GetModeGet); err != nil { 57 if err := t.Load(&Storage{Mode: GetModeGet}); err != nil {
44 panic(err) 58 panic(err)
45 } 59 }
46 60
@@ -126,8 +140,10 @@ func (t *Tree) Modules() []*Module {
126 result := make([]*Module, len(t.config.Modules)) 140 result := make([]*Module, len(t.config.Modules))
127 for i, m := range t.config.Modules { 141 for i, m := range t.config.Modules {
128 result[i] = &Module{ 142 result[i] = &Module{
129 Name: m.Name, 143 Name: m.Name,
130 Source: m.Source, 144 Version: m.Version,
145 Source: m.Source,
146 Providers: m.Providers,
131 } 147 }
132 } 148 }
133 149
@@ -155,81 +171,178 @@ func (t *Tree) Name() string {
155// module trees inherently require the configuration to be in a reasonably 171// module trees inherently require the configuration to be in a reasonably
156// sane state: no circular dependencies, proper module sources, etc. A full 172// sane state: no circular dependencies, proper module sources, etc. A full
157// suite of validations can be done by running Validate (after loading). 173// suite of validations can be done by running Validate (after loading).
158func (t *Tree) Load(s getter.Storage, mode GetMode) error { 174func (t *Tree) Load(s *Storage) error {
159 t.lock.Lock() 175 t.lock.Lock()
160 defer t.lock.Unlock() 176 defer t.lock.Unlock()
161 177
162 // Reset the children if we have any 178 children, err := t.getChildren(s)
163 t.children = nil 179 if err != nil {
180 return err
181 }
182
183 // Go through all the children and load them.
184 for _, c := range children {
185 if err := c.Load(s); err != nil {
186 return err
187 }
188 }
189
190 // Set our tree up
191 t.children = children
164 192
165 modules := t.Modules() 193 return nil
194}
195
196func (t *Tree) getChildren(s *Storage) (map[string]*Tree, error) {
166 children := make(map[string]*Tree) 197 children := make(map[string]*Tree)
167 198
168 // Go through all the modules and get the directory for them. 199 // Go through all the modules and get the directory for them.
169 for _, m := range modules { 200 for _, m := range t.Modules() {
170 if _, ok := children[m.Name]; ok { 201 if _, ok := children[m.Name]; ok {
171 return fmt.Errorf( 202 return nil, fmt.Errorf(
172 "module %s: duplicated. module names must be unique", m.Name) 203 "module %s: duplicated. module names must be unique", m.Name)
173 } 204 }
174 205
175 // Determine the path to this child 206 // Determine the path to this child
176 path := make([]string, len(t.path), len(t.path)+1) 207 modPath := make([]string, len(t.path), len(t.path)+1)
177 copy(path, t.path) 208 copy(modPath, t.path)
178 path = append(path, m.Name) 209 modPath = append(modPath, m.Name)
179 210
180 // Split out the subdir if we have one 211 log.Printf("[TRACE] module source: %q", m.Source)
181 source, subDir := getter.SourceDirSubdir(m.Source)
182 212
183 source, err := getter.Detect(source, t.config.Dir, getter.Detectors) 213 // add the module path to help indicate where modules with relative
214 // paths are being loaded from
215 s.output(fmt.Sprintf("- module.%s", strings.Join(modPath, ".")))
216
217 // Lookup the local location of the module.
218 // dir is the local directory where the module is stored
219 mod, err := s.findRegistryModule(m.Source, m.Version)
184 if err != nil { 220 if err != nil {
185 return fmt.Errorf("module %s: %s", m.Name, err) 221 return nil, err
186 } 222 }
187 223
224 // The key is the string that will be used to uniquely id the Source in
225 // the local storage. The prefix digit can be incremented to
226 // invalidate the local module storage.
227 key := "1." + t.versionedPathKey(m)
228 if mod.Version != "" {
229 key += "." + mod.Version
230 }
231
232 // Check for the exact key if it's not a registry module
233 if !mod.registry {
234 mod.Dir, err = s.findModule(key)
235 if err != nil {
236 return nil, err
237 }
238 }
239
240 if mod.Dir != "" && s.Mode != GetModeUpdate {
241 // We found it locally, but in order to load the Tree we need to
242 // find out if there was another subDir stored from detection.
243 subDir, err := s.getModuleRoot(mod.Dir)
244 if err != nil {
245 // If there's a problem with the subdir record, we'll let the
246 // recordSubdir method fix it up. Any other filesystem errors
247 // will turn up again below.
248 log.Println("[WARN] error reading subdir record:", err)
249 }
250
251 fullDir := filepath.Join(mod.Dir, subDir)
252
253 child, err := NewTreeModule(m.Name, fullDir)
254 if err != nil {
255 return nil, fmt.Errorf("module %s: %s", m.Name, err)
256 }
257 child.path = modPath
258 child.parent = t
259 child.version = mod.Version
260 child.source = m.Source
261 children[m.Name] = child
262 continue
263 }
264
265 // Split out the subdir if we have one.
266 // Terraform keeps the entire requested tree, so that modules can
267 // reference sibling modules from the same archive or repo.
268 rawSource, subDir := getter.SourceDirSubdir(m.Source)
269
270 // we haven't found a source, so fallback to the go-getter detectors
271 source := mod.url
272 if source == "" {
273 source, err = getter.Detect(rawSource, t.config.Dir, getter.Detectors)
274 if err != nil {
275 return nil, fmt.Errorf("module %s: %s", m.Name, err)
276 }
277 }
278
279 log.Printf("[TRACE] detected module source %q", source)
280
188 // Check if the detector introduced something new. 281 // Check if the detector introduced something new.
189 source, subDir2 := getter.SourceDirSubdir(source) 282 // For example, the registry always adds a subdir of `//*`,
190 if subDir2 != "" { 283 // indicating that we need to strip off the first component from the
191 subDir = filepath.Join(subDir2, subDir) 284 // tar archive, though we may not yet know what it is called.
285 source, detectedSubDir := getter.SourceDirSubdir(source)
286 if detectedSubDir != "" {
287 subDir = filepath.Join(detectedSubDir, subDir)
288 }
289
290 output := ""
291 switch s.Mode {
292 case GetModeUpdate:
293 output = fmt.Sprintf(" Updating source %q", m.Source)
294 default:
295 output = fmt.Sprintf(" Getting source %q", m.Source)
192 } 296 }
297 s.output(output)
193 298
194 // Get the directory where this module is so we can load it 299 dir, ok, err := s.getStorage(key, source)
195 key := strings.Join(path, ".")
196 key = fmt.Sprintf("root.%s-%s", key, m.Source)
197 dir, ok, err := getStorage(s, key, source, mode)
198 if err != nil { 300 if err != nil {
199 return err 301 return nil, err
200 } 302 }
201 if !ok { 303 if !ok {
202 return fmt.Errorf( 304 return nil, fmt.Errorf("module %s: not found, may need to run 'terraform init'", m.Name)
203 "module %s: not found, may need to be downloaded using 'terraform get'", m.Name)
204 } 305 }
205 306
206 // If we have a subdirectory, then merge that in 307 log.Printf("[TRACE] %q stored in %q", source, dir)
308
309 // expand and record the subDir for later
310 fullDir := dir
207 if subDir != "" { 311 if subDir != "" {
208 dir = filepath.Join(dir, subDir) 312 fullDir, err = getter.SubdirGlob(dir, subDir)
209 } 313 if err != nil {
314 return nil, err
315 }
210 316
211 // Load the configurations.Dir(source) 317 // +1 to account for the pathsep
212 children[m.Name], err = NewTreeModule(m.Name, dir) 318 if len(dir)+1 > len(fullDir) {
213 if err != nil { 319 return nil, fmt.Errorf("invalid module storage path %q", fullDir)
214 return fmt.Errorf( 320 }
215 "module %s: %s", m.Name, err) 321 subDir = fullDir[len(dir)+1:]
216 } 322 }
217 323
218 // Set the path of this child 324 // add new info to the module record
219 children[m.Name].path = path 325 mod.Key = key
220 } 326 mod.Dir = dir
327 mod.Root = subDir
221 328
222 // Go through all the children and load them. 329 // record the module in our manifest
223 for _, c := range children { 330 if err := s.recordModule(mod); err != nil {
224 if err := c.Load(s, mode); err != nil { 331 return nil, err
225 return err
226 } 332 }
227 }
228 333
229 // Set our tree up 334 child, err := NewTreeModule(m.Name, fullDir)
230 t.children = children 335 if err != nil {
336 return nil, fmt.Errorf("module %s: %s", m.Name, err)
337 }
338 child.path = modPath
339 child.parent = t
340 child.version = mod.Version
341 child.source = m.Source
342 children[m.Name] = child
343 }
231 344
232 return nil 345 return children, nil
233} 346}
234 347
235// Path is the full path to this tree. 348// Path is the full path to this tree.
@@ -272,32 +385,35 @@ func (t *Tree) String() string {
272// as verifying things such as parameters/outputs between the various modules. 385// as verifying things such as parameters/outputs between the various modules.
273// 386//
274// Load must be called prior to calling Validate or an error will be returned. 387// Load must be called prior to calling Validate or an error will be returned.
275func (t *Tree) Validate() error { 388func (t *Tree) Validate() tfdiags.Diagnostics {
389 var diags tfdiags.Diagnostics
390
276 if !t.Loaded() { 391 if !t.Loaded() {
277 return fmt.Errorf("tree must be loaded before calling Validate") 392 diags = diags.Append(fmt.Errorf(
393 "tree must be loaded before calling Validate",
394 ))
395 return diags
278 } 396 }
279 397
280 // If something goes wrong, here is our error template
281 newErr := &treeError{Name: []string{t.Name()}}
282
283 // Terraform core does not handle root module children named "root". 398 // Terraform core does not handle root module children named "root".
284 // We plan to fix this in the future but this bug was brought up in 399 // We plan to fix this in the future but this bug was brought up in
285 // the middle of a release and we don't want to introduce wide-sweeping 400 // the middle of a release and we don't want to introduce wide-sweeping
286 // changes at that time. 401 // changes at that time.
287 if len(t.path) == 1 && t.name == "root" { 402 if len(t.path) == 1 && t.name == "root" {
288 return fmt.Errorf("root module cannot contain module named 'root'") 403 diags = diags.Append(fmt.Errorf(
404 "root module cannot contain module named 'root'",
405 ))
406 return diags
289 } 407 }
290 408
291 // Validate our configuration first. 409 // Validate our configuration first.
292 if err := t.config.Validate(); err != nil { 410 diags = diags.Append(t.config.Validate())
293 newErr.Add(err)
294 }
295 411
296 // If we're the root, we do extra validation. This validation usually 412 // If we're the root, we do extra validation. This validation usually
297 // requires the entire tree (since children don't have parent pointers). 413 // requires the entire tree (since children don't have parent pointers).
298 if len(t.path) == 0 { 414 if len(t.path) == 0 {
299 if err := t.validateProviderAlias(); err != nil { 415 if err := t.validateProviderAlias(); err != nil {
300 newErr.Add(err) 416 diags = diags.Append(err)
301 } 417 }
302 } 418 }
303 419
@@ -306,20 +422,11 @@ func (t *Tree) Validate() error {
306 422
307 // Validate all our children 423 // Validate all our children
308 for _, c := range children { 424 for _, c := range children {
309 err := c.Validate() 425 childDiags := c.Validate()
310 if err == nil { 426 diags = diags.Append(childDiags)
427 if diags.HasErrors() {
311 continue 428 continue
312 } 429 }
313
314 verr, ok := err.(*treeError)
315 if !ok {
316 // Unknown error, just return...
317 return err
318 }
319
320 // Append ourselves to the error and then return
321 verr.Name = append(verr.Name, t.Name())
322 newErr.AddChild(verr)
323 } 430 }
324 431
325 // Go over all the modules and verify that any parameters are valid 432 // Go over all the modules and verify that any parameters are valid
@@ -345,9 +452,10 @@ func (t *Tree) Validate() error {
345 // Compare to the keys in our raw config for the module 452 // Compare to the keys in our raw config for the module
346 for k, _ := range m.RawConfig.Raw { 453 for k, _ := range m.RawConfig.Raw {
347 if _, ok := varMap[k]; !ok { 454 if _, ok := varMap[k]; !ok {
348 newErr.Add(fmt.Errorf( 455 diags = diags.Append(fmt.Errorf(
349 "module %s: %s is not a valid parameter", 456 "module %q: %q is not a valid argument",
350 m.Name, k)) 457 m.Name, k,
458 ))
351 } 459 }
352 460
353 // Remove the required 461 // Remove the required
@@ -356,9 +464,10 @@ func (t *Tree) Validate() error {
356 464
357 // If we have any required left over, they aren't set. 465 // If we have any required left over, they aren't set.
358 for k, _ := range requiredMap { 466 for k, _ := range requiredMap {
359 newErr.Add(fmt.Errorf( 467 diags = diags.Append(fmt.Errorf(
360 "module %s: required variable %q not set", 468 "module %q: missing required argument %q",
361 m.Name, k)) 469 m.Name, k,
470 ))
362 } 471 }
363 } 472 }
364 473
@@ -373,9 +482,10 @@ func (t *Tree) Validate() error {
373 482
374 tree, ok := children[mv.Name] 483 tree, ok := children[mv.Name]
375 if !ok { 484 if !ok {
376 newErr.Add(fmt.Errorf( 485 diags = diags.Append(fmt.Errorf(
377 "%s: undefined module referenced %s", 486 "%s: reference to undefined module %q",
378 source, mv.Name)) 487 source, mv.Name,
488 ))
379 continue 489 continue
380 } 490 }
381 491
@@ -387,14 +497,56 @@ func (t *Tree) Validate() error {
387 } 497 }
388 } 498 }
389 if !found { 499 if !found {
390 newErr.Add(fmt.Errorf( 500 diags = diags.Append(fmt.Errorf(
391 "%s: %s is not a valid output for module %s", 501 "%s: %q is not a valid output for module %q",
392 source, mv.Field, mv.Name)) 502 source, mv.Field, mv.Name,
503 ))
393 } 504 }
394 } 505 }
395 } 506 }
396 507
397 return newErr.ErrOrNil() 508 return diags
509}
510
511// versionedPathKey returns a path string with every levels full name, version
512// and source encoded. This is to provide a unique key for our module storage,
513// since submodules need to know which versions of their ancestor modules they
514// are loaded from.
515// For example, if module A has a subdirectory B, if module A's source or
516// version is updated B's storage key must reflect this change in order for the
517// correct version of B's source to be loaded.
518func (t *Tree) versionedPathKey(m *Module) string {
519 path := make([]string, len(t.path)+1)
520 path[len(path)-1] = m.Name + ";" + m.Source
521 // We're going to load these in order for easier reading and debugging, but
522 // in practice they only need to be unique and consistent.
523
524 p := t
525 i := len(path) - 2
526 for ; i >= 0; i-- {
527 if p == nil {
528 break
529 }
530 // we may have been loaded under a blank Tree, so always check for a name
531 // too.
532 if p.name == "" {
533 break
534 }
535 seg := p.name
536 if p.version != "" {
537 seg += "#" + p.version
538 }
539
540 if p.source != "" {
541 seg += ";" + p.source
542 }
543
544 path[i] = seg
545 p = p.parent
546 }
547
548 key := strings.Join(path, "|")
549 return key
398} 550}
399 551
400// treeError is an error use by Tree.Validate to accumulates all 552// treeError is an error use by Tree.Validate to accumulates all
diff --git a/vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go b/vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go
index 090d4f7..f203556 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go
@@ -67,7 +67,7 @@ func (t *Tree) validateProviderAlias() error {
67 67
68 // We didn't find the alias, error! 68 // We didn't find the alias, error!
69 err = multierror.Append(err, fmt.Errorf( 69 err = multierror.Append(err, fmt.Errorf(
70 "module %s: provider alias must be defined by the module or a parent: %s", 70 "module %s: provider alias must be defined by the module: %s",
71 strings.Join(pv.Path, "."), k)) 71 strings.Join(pv.Path, "."), k))
72 } 72 }
73 } 73 }
diff --git a/vendor/github.com/hashicorp/terraform/config/module/versions.go b/vendor/github.com/hashicorp/terraform/config/module/versions.go
new file mode 100644
index 0000000..8348d4b
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/versions.go
@@ -0,0 +1,95 @@
1package module
2
3import (
4 "errors"
5 "fmt"
6 "sort"
7
8 version "github.com/hashicorp/go-version"
9 "github.com/hashicorp/terraform/registry/response"
10)
11
12const anyVersion = ">=0.0.0"
13
14// return the newest version that satisfies the provided constraint
15func newest(versions []string, constraint string) (string, error) {
16 if constraint == "" {
17 constraint = anyVersion
18 }
19 cs, err := version.NewConstraint(constraint)
20 if err != nil {
21 return "", err
22 }
23
24 switch len(versions) {
25 case 0:
26 return "", errors.New("no versions found")
27 case 1:
28 v, err := version.NewVersion(versions[0])
29 if err != nil {
30 return "", err
31 }
32
33 if !cs.Check(v) {
34 return "", fmt.Errorf("no version found matching constraint %q", constraint)
35 }
36 return versions[0], nil
37 }
38
39 sort.Slice(versions, func(i, j int) bool {
40 // versions should have already been validated
41 // sort invalid version strings to the end
42 iv, err := version.NewVersion(versions[i])
43 if err != nil {
44 return true
45 }
46 jv, err := version.NewVersion(versions[j])
47 if err != nil {
48 return true
49 }
50 return iv.GreaterThan(jv)
51 })
52
53 // versions are now in order, so just find the first which satisfies the
54 // constraint
55 for i := range versions {
56 v, err := version.NewVersion(versions[i])
57 if err != nil {
58 continue
59 }
60 if cs.Check(v) {
61 return versions[i], nil
62 }
63 }
64
65 return "", nil
66}
67
68// return the newest *moduleVersion that matches the given constraint
69// TODO: reconcile these two types and newest* functions
70func newestVersion(moduleVersions []*response.ModuleVersion, constraint string) (*response.ModuleVersion, error) {
71 var versions []string
72 modules := make(map[string]*response.ModuleVersion)
73
74 for _, m := range moduleVersions {
75 versions = append(versions, m.Version)
76 modules[m.Version] = m
77 }
78
79 match, err := newest(versions, constraint)
80 return modules[match], err
81}
82
83// return the newest moduleRecord that matches the given constraint
84func newestRecord(moduleVersions []moduleRecord, constraint string) (moduleRecord, error) {
85 var versions []string
86 modules := make(map[string]moduleRecord)
87
88 for _, m := range moduleVersions {
89 versions = append(versions, m.Version)
90 modules[m.Version] = m
91 }
92
93 match, err := newest(versions, constraint)
94 return modules[match], err
95}
diff --git a/vendor/github.com/hashicorp/terraform/config/raw_config.go b/vendor/github.com/hashicorp/terraform/config/raw_config.go
index f8498d8..1854a8b 100644
--- a/vendor/github.com/hashicorp/terraform/config/raw_config.go
+++ b/vendor/github.com/hashicorp/terraform/config/raw_config.go
@@ -3,8 +3,14 @@ package config
3import ( 3import (
4 "bytes" 4 "bytes"
5 "encoding/gob" 5 "encoding/gob"
6 "errors"
7 "strconv"
6 "sync" 8 "sync"
7 9
10 "github.com/zclconf/go-cty/cty"
11 "github.com/zclconf/go-cty/cty/convert"
12
13 hcl2 "github.com/hashicorp/hcl2/hcl"
8 "github.com/hashicorp/hil" 14 "github.com/hashicorp/hil"
9 "github.com/hashicorp/hil/ast" 15 "github.com/hashicorp/hil/ast"
10 "github.com/mitchellh/copystructure" 16 "github.com/mitchellh/copystructure"
@@ -27,8 +33,24 @@ const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
27// RawConfig supports a query-like interface to request 33// RawConfig supports a query-like interface to request
28// information from deep within the structure. 34// information from deep within the structure.
29type RawConfig struct { 35type RawConfig struct {
30 Key string 36 Key string
31 Raw map[string]interface{} 37
38 // Only _one_ of Raw and Body may be populated at a time.
39 //
40 // In the normal case, Raw is populated and Body is nil.
41 //
42 // When the experimental HCL2 parsing mode is enabled, "Body"
43 // is populated and RawConfig serves only to transport the hcl2.Body
44 // through the rest of Terraform core so we can ultimately decode it
45 // once its schema is known.
46 //
47 // Once we transition to HCL2 as the primary representation, RawConfig
48 // should be removed altogether and the hcl2.Body should be passed
49 // around directly.
50
51 Raw map[string]interface{}
52 Body hcl2.Body
53
32 Interpolations []ast.Node 54 Interpolations []ast.Node
33 Variables map[string]InterpolatedVariable 55 Variables map[string]InterpolatedVariable
34 56
@@ -48,6 +70,26 @@ func NewRawConfig(raw map[string]interface{}) (*RawConfig, error) {
48 return result, nil 70 return result, nil
49} 71}
50 72
73// NewRawConfigHCL2 creates a new RawConfig that is serving as a capsule
74// to transport a hcl2.Body. In this mode, the publicly-readable struct
75// fields are not populated since all operations should instead be diverted
76// to the HCL2 body.
77//
78// For a RawConfig object constructed with this function, the only valid use
79// is to later retrieve the Body value and call its own methods. Callers
80// may choose to set and then later handle the Key field, in a manner
81// consistent with how it is handled by the Value method, but the Value
82// method itself must not be used.
83//
84// This is an experimental codepath to be used only by the HCL2 config loader.
85// Non-experimental parsing should _always_ use NewRawConfig to produce a
86// fully-functional RawConfig object.
87func NewRawConfigHCL2(body hcl2.Body) *RawConfig {
88 return &RawConfig{
89 Body: body,
90 }
91}
92
51// RawMap returns a copy of the RawConfig.Raw map. 93// RawMap returns a copy of the RawConfig.Raw map.
52func (r *RawConfig) RawMap() map[string]interface{} { 94func (r *RawConfig) RawMap() map[string]interface{} {
53 r.lock.Lock() 95 r.lock.Lock()
@@ -69,6 +111,10 @@ func (r *RawConfig) Copy() *RawConfig {
69 r.lock.Lock() 111 r.lock.Lock()
70 defer r.lock.Unlock() 112 defer r.lock.Unlock()
71 113
114 if r.Body != nil {
115 return NewRawConfigHCL2(r.Body)
116 }
117
72 newRaw := make(map[string]interface{}) 118 newRaw := make(map[string]interface{})
73 for k, v := range r.Raw { 119 for k, v := range r.Raw {
74 newRaw[k] = v 120 newRaw[k] = v
@@ -223,6 +269,13 @@ func (r *RawConfig) init() error {
223} 269}
224 270
225func (r *RawConfig) interpolate(fn interpolationWalkerFunc) error { 271func (r *RawConfig) interpolate(fn interpolationWalkerFunc) error {
272 if r.Body != nil {
273 // For RawConfigs created for the HCL2 experiement, callers must
274 // use the HCL2 Body API directly rather than interpolating via
275 // the RawConfig.
276 return errors.New("this feature is not yet supported under the HCL2 experiment")
277 }
278
226 config, err := copystructure.Copy(r.Raw) 279 config, err := copystructure.Copy(r.Raw)
227 if err != nil { 280 if err != nil {
228 return err 281 return err
@@ -268,6 +321,74 @@ func (r *RawConfig) merge(r2 *RawConfig) *RawConfig {
268 return result 321 return result
269} 322}
270 323
324// couldBeInteger is a helper that determines if the represented value could
325// result in an integer.
326//
327// This function only works for RawConfigs that have "Key" set, meaning that
328// a single result can be produced. Calling this function will overwrite
329// the Config and Value results to be a test value.
330//
331// This function is conservative. If there is some doubt about whether the
332// result could be an integer -- for example, if it depends on a variable
333// whose type we don't know yet -- it will still return true.
334func (r *RawConfig) couldBeInteger() bool {
335 if r.Key == "" {
336 // un-keyed RawConfigs can never produce numbers
337 return false
338 }
339 if r.Body == nil {
340 // Normal path: using the interpolator in this package
341 // Interpolate with a fixed number to verify that its a number.
342 r.interpolate(func(root ast.Node) (interface{}, error) {
343 // Execute the node but transform the AST so that it returns
344 // a fixed value of "5" for all interpolations.
345 result, err := hil.Eval(
346 hil.FixedValueTransform(
347 root, &ast.LiteralNode{Value: "5", Typex: ast.TypeString}),
348 nil)
349 if err != nil {
350 return "", err
351 }
352
353 return result.Value, nil
354 })
355 _, err := strconv.ParseInt(r.Value().(string), 0, 0)
356 return err == nil
357 } else {
358 // HCL2 experiment path: using the HCL2 API via shims
359 //
360 // This path catches fewer situations because we have to assume all
361 // variables are entirely unknown in HCL2, rather than the assumption
362 // above that all variables can be numbers because names like "var.foo"
363 // are considered a single variable rather than an attribute access.
364 // This is fine in practice, because we get a definitive answer
365 // during the graph walk when we have real values to work with.
366 attrs, diags := r.Body.JustAttributes()
367 if diags.HasErrors() {
368 // This body is not just a single attribute with a value, so
369 // this can't be a number.
370 return false
371 }
372 attr, hasAttr := attrs[r.Key]
373 if !hasAttr {
374 return false
375 }
376 result, diags := hcl2EvalWithUnknownVars(attr.Expr)
377 if diags.HasErrors() {
378 // We'll conservatively assume that this error is a result of
379 // us not being ready to fully-populate the scope, and catch
380 // any further problems during the main graph walk.
381 return true
382 }
383
384 // If the result is convertable to number then we'll allow it.
385 // We do this because an unknown string is optimistically convertable
386 // to number (might be "5") but a _known_ string "hello" is not.
387 _, err := convert.Convert(result, cty.Number)
388 return err == nil
389 }
390}
391
271// UnknownKeys returns the keys of the configuration that are unknown 392// UnknownKeys returns the keys of the configuration that are unknown
272// because they had interpolated variables that must be computed. 393// because they had interpolated variables that must be computed.
273func (r *RawConfig) UnknownKeys() []string { 394func (r *RawConfig) UnknownKeys() []string {
diff --git a/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go b/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go
index ea68b4f..8a55e06 100644
--- a/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go
+++ b/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go
@@ -2,7 +2,7 @@
2 2
3package config 3package config
4 4
5import "fmt" 5import "strconv"
6 6
7const _ResourceMode_name = "ManagedResourceModeDataResourceMode" 7const _ResourceMode_name = "ManagedResourceModeDataResourceMode"
8 8
@@ -10,7 +10,7 @@ var _ResourceMode_index = [...]uint8{0, 19, 35}
10 10
11func (i ResourceMode) String() string { 11func (i ResourceMode) String() string {
12 if i < 0 || i >= ResourceMode(len(_ResourceMode_index)-1) { 12 if i < 0 || i >= ResourceMode(len(_ResourceMode_index)-1) {
13 return fmt.Sprintf("ResourceMode(%d)", i) 13 return "ResourceMode(" + strconv.FormatInt(int64(i), 10) + ")"
14 } 14 }
15 return _ResourceMode_name[_ResourceMode_index[i]:_ResourceMode_index[i+1]] 15 return _ResourceMode_name[_ResourceMode_index[i]:_ResourceMode_index[i+1]]
16} 16}
diff --git a/vendor/github.com/hashicorp/terraform/config/testing.go b/vendor/github.com/hashicorp/terraform/config/testing.go
index f7bfadd..831fc77 100644
--- a/vendor/github.com/hashicorp/terraform/config/testing.go
+++ b/vendor/github.com/hashicorp/terraform/config/testing.go
@@ -6,6 +6,8 @@ import (
6 6
7// TestRawConfig is used to create a RawConfig for testing. 7// TestRawConfig is used to create a RawConfig for testing.
8func TestRawConfig(t *testing.T, c map[string]interface{}) *RawConfig { 8func TestRawConfig(t *testing.T, c map[string]interface{}) *RawConfig {
9 t.Helper()
10
9 cfg, err := NewRawConfig(c) 11 cfg, err := NewRawConfig(c)
10 if err != nil { 12 if err != nil {
11 t.Fatalf("err: %s", err) 13 t.Fatalf("err: %s", err)