aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/config/config.go
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/config.go
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/config.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/config/config.go396
1 files changed, 261 insertions, 135 deletions
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