return tfdiags.Diagnostics from validation methods
Validation is the best time to return detailed diagnostics to the user since we're much more likely to have source location information, etc than we are in later operations. This change doesn't actually add any detail to the messages yet, but it changes the interface so that we can gradually introduce more detailed diagnostics over time. While here there are some minor adjustments to some of the messages to improve their consistency with terminology we use elsewhere.
This commit is contained in:
parent
9f1a773655
commit
ba0514106a
|
@ -2,12 +2,13 @@ package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
|
||||||
|
"github.com/hashicorp/terraform/command/format"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
|
|
||||||
"github.com/hashicorp/errwrap"
|
"github.com/hashicorp/errwrap"
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/hashicorp/terraform/backend"
|
"github.com/hashicorp/terraform/backend"
|
||||||
"github.com/hashicorp/terraform/state"
|
"github.com/hashicorp/terraform/state"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
@ -91,29 +92,33 @@ func (b *Local) context(op *backend.Operation) (*terraform.Context, state.State,
|
||||||
|
|
||||||
// If validation is enabled, validate
|
// If validation is enabled, validate
|
||||||
if b.OpValidation {
|
if b.OpValidation {
|
||||||
// We ignore warnings here on purpose. We expect users to be listening
|
diags := tfCtx.Validate()
|
||||||
// to the terraform.Hook called after a validation.
|
if len(diags) > 0 {
|
||||||
ws, es := tfCtx.Validate()
|
if diags.HasErrors() {
|
||||||
if len(ws) > 0 {
|
// If there are warnings _and_ errors then we'll take this
|
||||||
// Log just in case the CLI isn't enabled
|
// path and return them all together in this error.
|
||||||
log.Printf("[WARN] backend/local: %d warnings: %v", len(ws), ws)
|
return nil, nil, diags.Err()
|
||||||
|
}
|
||||||
|
|
||||||
// If we have a CLI, output the warnings
|
// For now we can't propagate warnings any further without
|
||||||
|
// printing them directly to the UI, so we'll need to
|
||||||
|
// format them here ourselves.
|
||||||
|
for _, diag := range diags {
|
||||||
|
if diag.Severity() != tfdiags.Warning {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if b.CLI != nil {
|
if b.CLI != nil {
|
||||||
b.CLI.Warn(strings.TrimSpace(validateWarnHeader) + "\n")
|
b.CLI.Warn(format.Diagnostic(diag, b.Colorize(), 72))
|
||||||
for _, w := range ws {
|
} else {
|
||||||
b.CLI.Warn(fmt.Sprintf(" * %s", w))
|
desc := diag.Description()
|
||||||
|
log.Printf("[WARN] backend/local: %s", desc.Summary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a newline before continuing
|
// Make a newline before continuing
|
||||||
b.CLI.Output("")
|
b.CLI.Output("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(es) > 0 {
|
|
||||||
return nil, nil, multierror.Append(nil, es...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tfCtx, s, nil
|
return tfCtx, s, nil
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/mitchellh/cli"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set to true when we're testing
|
// Set to true when we're testing
|
||||||
|
@ -82,39 +81,18 @@ func ModulePath(args []string) (string, error) {
|
||||||
return args[0], nil
|
return args[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateContext(ctx *terraform.Context, ui cli.Ui) bool {
|
func (m *Meta) validateContext(ctx *terraform.Context) bool {
|
||||||
log.Println("[INFO] Validating the context...")
|
log.Println("[INFO] Validating the context...")
|
||||||
ws, es := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
log.Printf("[INFO] Validation result: %d warnings, %d errors", len(ws), len(es))
|
log.Printf("[INFO] Validation result: %d diagnostics", len(diags))
|
||||||
|
|
||||||
if len(ws) > 0 || len(es) > 0 {
|
if len(diags) > 0 {
|
||||||
ui.Output(
|
m.Ui.Output(
|
||||||
"There are warnings and/or errors related to your configuration. Please\n" +
|
"There are warnings and/or errors related to your configuration. Please\n" +
|
||||||
"fix these before continuing.\n")
|
"fix these before continuing.\n")
|
||||||
|
|
||||||
if len(ws) > 0 {
|
m.showDiagnostics(diags)
|
||||||
ui.Warn("Warnings:\n")
|
|
||||||
for _, w := range ws {
|
|
||||||
ui.Warn(fmt.Sprintf(" * %s", w))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(es) > 0 {
|
return !diags.HasErrors()
|
||||||
ui.Output("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(es) > 0 {
|
|
||||||
ui.Error("Errors:\n")
|
|
||||||
for _, e := range es {
|
|
||||||
ui.Error(fmt.Sprintf(" * %s", e))
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
ui.Warn(fmt.Sprintf("\n"+
|
|
||||||
"No errors found. Continuing with %d warning(s).\n", len(ws)))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,7 +280,8 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mod.Validate(); err != nil {
|
if diags := mod.Validate(); diags.HasErrors() {
|
||||||
|
err := diags.Err()
|
||||||
c.Ui.Error(fmt.Sprintf("Error getting plugins: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error getting plugins: %s", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,11 +53,12 @@ func (c *ProvidersCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the config (to ensure the version constraints are valid)
|
// Validate the config (to ensure the version constraints are valid)
|
||||||
err = root.Validate()
|
if diags := root.Validate(); len(diags) != 0 {
|
||||||
if err != nil {
|
c.showDiagnostics(diags)
|
||||||
c.Ui.Error(err.Error())
|
if diags.HasErrors() {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load the backend
|
// Load the backend
|
||||||
b, err := c.Backend(&BackendOpts{
|
b, err := c.Backend(&BackendOpts{
|
||||||
|
|
|
@ -100,11 +100,12 @@ func (c *ValidateCommand) validate(dir string, checkVars bool) int {
|
||||||
c.showDiagnostics(err)
|
c.showDiagnostics(err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
err = cfg.Validate()
|
if diags := cfg.Validate(); len(diags) != 0 {
|
||||||
if err != nil {
|
c.showDiagnostics(diags)
|
||||||
c.showDiagnostics(err)
|
if diags.HasErrors() {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if checkVars {
|
if checkVars {
|
||||||
mod, err := c.Module(dir)
|
mod, err := c.Module(dir)
|
||||||
|
@ -122,7 +123,7 @@ func (c *ValidateCommand) validate(dir string, checkVars bool) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validateContext(tfCtx, c.Ui) {
|
if !c.validateContext(tfCtx) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ func TestValidateFailingCommandMissingVariable(t *testing.T) {
|
||||||
if code != 1 {
|
if code != 1 {
|
||||||
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "config: unknown variable referenced: 'description'. define it with 'variable' blocks") {
|
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "config: unknown variable referenced: 'description'; define it with a 'variable' block") {
|
||||||
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func TestSameProviderMutipleTimesShouldFail(t *testing.T) {
|
||||||
if code != 1 {
|
if code != 1 {
|
||||||
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "provider.aws: declared multiple times, you can only declare a provider once") {
|
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "provider.aws: multiple configurations present; only one configuration is allowed per provider") {
|
||||||
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ func TestSameModuleMultipleTimesShouldFail(t *testing.T) {
|
||||||
if code != 1 {
|
if code != 1 {
|
||||||
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "multi_module: module repeated multiple times") {
|
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "module \"multi_module\": module repeated multiple times") {
|
||||||
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func TestOutputWithoutValueShouldFail(t *testing.T) {
|
||||||
if code != 1 {
|
if code != 1 {
|
||||||
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "output is missing required 'value' key") {
|
if !strings.HasSuffix(strings.TrimSpace(ui.ErrorWriter.String()), "output \"myvalue\": missing required 'value' argument") {
|
||||||
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ func TestModuleWithIncorrectNameShouldFail(t *testing.T) {
|
||||||
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(ui.ErrorWriter.String(), "module name can only contain letters, numbers, dashes, and underscores") {
|
if !strings.Contains(ui.ErrorWriter.String(), "module name must be a letter or underscore followed by only letters, numbers, dashes, and underscores") {
|
||||||
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
if !strings.Contains(ui.ErrorWriter.String(), "module source cannot contain interpolations") {
|
if !strings.Contains(ui.ErrorWriter.String(), "module source cannot contain interpolations") {
|
||||||
|
@ -142,7 +142,7 @@ func TestWronglyUsedInterpolationShouldFail(t *testing.T) {
|
||||||
if !strings.Contains(ui.ErrorWriter.String(), "depends on value cannot contain interpolations") {
|
if !strings.Contains(ui.ErrorWriter.String(), "depends on value cannot contain interpolations") {
|
||||||
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
if !strings.Contains(ui.ErrorWriter.String(), "Variable 'vairable_with_interpolation': cannot contain interpolations") {
|
if !strings.Contains(ui.ErrorWriter.String(), "variable \"vairable_with_interpolation\": default may not contain interpolations") {
|
||||||
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
t.Fatalf("Should have failed: %d\n\n'%s'", code, ui.ErrorWriter.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
270
config/config.go
270
config/config.go
|
@ -8,10 +8,10 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/hashicorp/hil/ast"
|
"github.com/hashicorp/hil/ast"
|
||||||
"github.com/hashicorp/terraform/helper/hilmapstructure"
|
"github.com/hashicorp/terraform/helper/hilmapstructure"
|
||||||
"github.com/hashicorp/terraform/plugin/discovery"
|
"github.com/hashicorp/terraform/plugin/discovery"
|
||||||
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
"github.com/mitchellh/reflectwalk"
|
"github.com/mitchellh/reflectwalk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -278,30 +278,35 @@ func ResourceProviderFullName(resourceType, explicitProvider string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate does some basic semantic checking of the configuration.
|
// Validate does some basic semantic checking of the configuration.
|
||||||
func (c *Config) Validate() error {
|
func (c *Config) Validate() tfdiags.Diagnostics {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []error
|
var diags tfdiags.Diagnostics
|
||||||
|
|
||||||
for _, k := range c.unknownKeys {
|
for _, k := range c.unknownKeys {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(
|
||||||
"Unknown root level key: %s", k))
|
fmt.Errorf("Unknown root level key: %s", k),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the Terraform config
|
// Validate the Terraform config
|
||||||
if tf := c.Terraform; tf != nil {
|
if tf := c.Terraform; tf != nil {
|
||||||
errs = append(errs, c.Terraform.Validate()...)
|
errs := c.Terraform.Validate()
|
||||||
|
for _, err := range errs {
|
||||||
|
diags = diags.Append(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vars := c.InterpolatedVariables()
|
vars := c.InterpolatedVariables()
|
||||||
varMap := make(map[string]*Variable)
|
varMap := make(map[string]*Variable)
|
||||||
for _, v := range c.Variables {
|
for _, v := range c.Variables {
|
||||||
if _, ok := varMap[v.Name]; ok {
|
if _, ok := varMap[v.Name]; ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"Variable '%s': duplicate found. Variable names must be unique.",
|
"Variable '%s': duplicate found. Variable names must be unique.",
|
||||||
v.Name))
|
v.Name,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
varMap[v.Name] = v
|
varMap[v.Name] = v
|
||||||
|
@ -309,17 +314,19 @@ func (c *Config) Validate() error {
|
||||||
|
|
||||||
for k, _ := range varMap {
|
for k, _ := range varMap {
|
||||||
if !NameRegexp.MatchString(k) {
|
if !NameRegexp.MatchString(k) {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"variable %q: variable name must match regular expresion %s",
|
"variable %q: variable name must match regular expression %s",
|
||||||
k, NameRegexp))
|
k, NameRegexp,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range c.Variables {
|
for _, v := range c.Variables {
|
||||||
if v.Type() == VariableTypeUnknown {
|
if v.Type() == VariableTypeUnknown {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"Variable '%s': must be a string or a map",
|
"Variable '%s': must be a string or a map",
|
||||||
v.Name))
|
v.Name,
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,9 +347,10 @@ func (c *Config) Validate() error {
|
||||||
if v.Default != nil {
|
if v.Default != nil {
|
||||||
if err := reflectwalk.Walk(v.Default, w); err == nil {
|
if err := reflectwalk.Walk(v.Default, w); err == nil {
|
||||||
if interp {
|
if interp {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"Variable '%s': cannot contain interpolations",
|
"variable %q: default may not contain interpolations",
|
||||||
v.Name))
|
v.Name,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,10 +366,11 @@ func (c *Config) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := varMap[uv.Name]; !ok {
|
if _, ok := varMap[uv.Name]; !ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: unknown variable referenced: '%s'. define it with 'variable' blocks",
|
"%s: unknown variable referenced: '%s'; define it with a 'variable' block",
|
||||||
source,
|
source,
|
||||||
uv.Name))
|
uv.Name,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -372,17 +381,19 @@ func (c *Config) Validate() error {
|
||||||
switch v := rawV.(type) {
|
switch v := rawV.(type) {
|
||||||
case *CountVariable:
|
case *CountVariable:
|
||||||
if v.Type == CountValueInvalid {
|
if v.Type == CountValueInvalid {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: invalid count variable: %s",
|
"%s: invalid count variable: %s",
|
||||||
source,
|
source,
|
||||||
v.FullKey()))
|
v.FullKey(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
case *PathVariable:
|
case *PathVariable:
|
||||||
if v.Type == PathValueInvalid {
|
if v.Type == PathValueInvalid {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: invalid path variable: %s",
|
"%s: invalid path variable: %s",
|
||||||
source,
|
source,
|
||||||
v.FullKey()))
|
v.FullKey(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,16 +405,17 @@ func (c *Config) Validate() error {
|
||||||
for _, p := range c.ProviderConfigs {
|
for _, p := range c.ProviderConfigs {
|
||||||
name := p.FullName()
|
name := p.FullName()
|
||||||
if _, ok := providerSet[name]; ok {
|
if _, ok := providerSet[name]; ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"provider.%s: declared multiple times, you can only declare a provider once",
|
"provider.%s: multiple configurations present; only one configuration is allowed per provider",
|
||||||
name))
|
name,
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Version != "" {
|
if p.Version != "" {
|
||||||
_, err := discovery.ConstraintStr(p.Version).Parse()
|
_, err := discovery.ConstraintStr(p.Version).Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"provider.%s: invalid version constraint %q: %s",
|
"provider.%s: invalid version constraint %q: %s",
|
||||||
name, p.Version, err,
|
name, p.Version, err,
|
||||||
))
|
))
|
||||||
|
@ -422,9 +434,10 @@ func (c *Config) Validate() error {
|
||||||
if _, ok := dupped[m.Id()]; !ok {
|
if _, ok := dupped[m.Id()]; !ok {
|
||||||
dupped[m.Id()] = struct{}{}
|
dupped[m.Id()] = struct{}{}
|
||||||
|
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: module repeated multiple times",
|
"module %q: module repeated multiple times",
|
||||||
m.Id()))
|
m.Id(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already seen this module, just skip it
|
// Already seen this module, just skip it
|
||||||
|
@ -438,21 +451,23 @@ func (c *Config) Validate() error {
|
||||||
"root": m.Source,
|
"root": m.Source,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: module source error: %s",
|
"module %q: module source error: %s",
|
||||||
m.Id(), err))
|
m.Id(), err,
|
||||||
|
))
|
||||||
} else if len(rc.Interpolations) > 0 {
|
} else if len(rc.Interpolations) > 0 {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: module source cannot contain interpolations",
|
"module %q: module source cannot contain interpolations",
|
||||||
m.Id()))
|
m.Id(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the name matches our regexp
|
// Check that the name matches our regexp
|
||||||
if !NameRegexp.Match([]byte(m.Name)) {
|
if !NameRegexp.Match([]byte(m.Name)) {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: module name can only contain letters, numbers, "+
|
"module %q: module name must be a letter or underscore followed by only letters, numbers, dashes, and underscores",
|
||||||
"dashes, and underscores",
|
m.Id(),
|
||||||
m.Id()))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the configuration can all be strings, lists or maps
|
// Check that the configuration can all be strings, lists or maps
|
||||||
|
@ -476,36 +491,44 @@ func (c *Config) Validate() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: variable %s must be a string, list or map value",
|
"module %q: argument %s must have a string, list, or map value",
|
||||||
m.Id(), k))
|
m.Id(), k,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for invalid count variables
|
// Check for invalid count variables
|
||||||
for _, v := range m.RawConfig.Variables {
|
for _, v := range m.RawConfig.Variables {
|
||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
case *CountVariable:
|
case *CountVariable:
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: count variables are only valid within resources", m.Name))
|
"module %q: count variables are only valid within resources",
|
||||||
|
m.Name,
|
||||||
|
))
|
||||||
case *SelfVariable:
|
case *SelfVariable:
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: self variables are only valid within resources", m.Name))
|
"module %q: self variables are only valid within resources",
|
||||||
|
m.Name,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the raw configuration to only contain the string values
|
// Update the raw configuration to only contain the string values
|
||||||
m.RawConfig, err = NewRawConfig(raw)
|
m.RawConfig, err = NewRawConfig(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: can't initialize configuration: %s",
|
"%s: can't initialize configuration: %s",
|
||||||
m.Id(), err))
|
m.Id(), err,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that all named providers actually exist
|
// check that all named providers actually exist
|
||||||
for _, p := range m.Providers {
|
for _, p := range m.Providers {
|
||||||
if !providerSet[p] {
|
if !providerSet[p] {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"provider %q named in module %q does not exist", p, m.Name))
|
"module %q: cannot pass non-existent provider %q",
|
||||||
|
m.Name, p,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,10 +545,10 @@ func (c *Config) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := modules[mv.Name]; !ok {
|
if _, ok := modules[mv.Name]; !ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: unknown module referenced: %s",
|
"%s: unknown module referenced: %s",
|
||||||
source,
|
source, mv.Name,
|
||||||
mv.Name))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,9 +561,10 @@ func (c *Config) Validate() error {
|
||||||
if _, ok := dupped[r.Id()]; !ok {
|
if _, ok := dupped[r.Id()]; !ok {
|
||||||
dupped[r.Id()] = struct{}{}
|
dupped[r.Id()] = struct{}{}
|
||||||
|
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: resource repeated multiple times",
|
"%s: resource repeated multiple times",
|
||||||
r.Id()))
|
r.Id(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,15 +578,15 @@ func (c *Config) Validate() error {
|
||||||
for _, v := range r.RawCount.Variables {
|
for _, v := range r.RawCount.Variables {
|
||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
case *CountVariable:
|
case *CountVariable:
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: resource count can't reference count variable: %s",
|
"%s: resource count can't reference count variable: %s",
|
||||||
n,
|
n, v.FullKey(),
|
||||||
v.FullKey()))
|
))
|
||||||
case *SimpleVariable:
|
case *SimpleVariable:
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: resource count can't reference variable: %s",
|
"%s: resource count can't reference variable: %s",
|
||||||
n,
|
n, v.FullKey(),
|
||||||
v.FullKey()))
|
))
|
||||||
|
|
||||||
// Good
|
// Good
|
||||||
case *ModuleVariable:
|
case *ModuleVariable:
|
||||||
|
@ -572,21 +596,24 @@ func (c *Config) Validate() error {
|
||||||
case *LocalVariable:
|
case *LocalVariable:
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"Internal error. Unknown type in count var in %s: %T",
|
"Internal error. Unknown type in count var in %s: %T",
|
||||||
n, v))
|
n, v,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !r.RawCount.couldBeInteger() {
|
if !r.RawCount.couldBeInteger() {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: resource count must be an integer",
|
"%s: resource count must be an integer", n,
|
||||||
n))
|
))
|
||||||
}
|
}
|
||||||
r.RawCount.init()
|
r.RawCount.init()
|
||||||
|
|
||||||
// Validate DependsOn
|
// Validate DependsOn
|
||||||
errs = append(errs, c.validateDependsOn(n, r.DependsOn, resources, modules)...)
|
for _, err := range c.validateDependsOn(n, r.DependsOn, resources, modules) {
|
||||||
|
diags = diags.Append(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Verify provisioners
|
// Verify provisioners
|
||||||
for _, p := range r.Provisioners {
|
for _, p := range r.Provisioners {
|
||||||
|
@ -600,9 +627,10 @@ func (c *Config) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
|
if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: connection info cannot contain splat variable "+
|
"%s: connection info cannot contain splat variable referencing itself",
|
||||||
"referencing itself", n))
|
n,
|
||||||
|
))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -614,9 +642,10 @@ func (c *Config) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
|
if rv.Multi && rv.Index == -1 && rv.Type == r.Type && rv.Name == r.Name {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: connection info cannot contain splat variable "+
|
"%s: connection info cannot contain splat variable referencing itself",
|
||||||
"referencing itself", n))
|
n,
|
||||||
|
))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -624,21 +653,24 @@ func (c *Config) Validate() error {
|
||||||
// Check for invalid when/onFailure values, though this should be
|
// Check for invalid when/onFailure values, though this should be
|
||||||
// picked up by the loader we check here just in case.
|
// picked up by the loader we check here just in case.
|
||||||
if p.When == ProvisionerWhenInvalid {
|
if p.When == ProvisionerWhenInvalid {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: provisioner 'when' value is invalid", n))
|
"%s: provisioner 'when' value is invalid", n,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
if p.OnFailure == ProvisionerOnFailureInvalid {
|
if p.OnFailure == ProvisionerOnFailureInvalid {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: provisioner 'on_failure' value is invalid", n))
|
"%s: provisioner 'on_failure' value is invalid", n,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify ignore_changes contains valid entries
|
// Verify ignore_changes contains valid entries
|
||||||
for _, v := range r.Lifecycle.IgnoreChanges {
|
for _, v := range r.Lifecycle.IgnoreChanges {
|
||||||
if strings.Contains(v, "*") && v != "*" {
|
if strings.Contains(v, "*") && v != "*" {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: ignore_changes does not support using a partial string "+
|
"%s: ignore_changes does not support using a partial string together with a wildcard: %s",
|
||||||
"together with a wildcard: %s", n, v))
|
n, v,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,21 +679,24 @@ func (c *Config) Validate() error {
|
||||||
"root": r.Lifecycle.IgnoreChanges,
|
"root": r.Lifecycle.IgnoreChanges,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: lifecycle ignore_changes error: %s",
|
"%s: lifecycle ignore_changes error: %s",
|
||||||
n, err))
|
n, err,
|
||||||
|
))
|
||||||
} else if len(rc.Interpolations) > 0 {
|
} else if len(rc.Interpolations) > 0 {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: lifecycle ignore_changes cannot contain interpolations",
|
"%s: lifecycle ignore_changes cannot contain interpolations",
|
||||||
n))
|
n,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is a data source then it can't have provisioners
|
// If it is a data source then it can't have provisioners
|
||||||
if r.Mode == DataResourceMode {
|
if r.Mode == DataResourceMode {
|
||||||
if _, ok := r.RawConfig.Raw["provisioner"]; ok {
|
if _, ok := r.RawConfig.Raw["provisioner"]; ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: data sources cannot have provisioners",
|
"%s: data sources cannot have provisioners",
|
||||||
n))
|
n,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -675,11 +710,12 @@ func (c *Config) Validate() error {
|
||||||
|
|
||||||
id := rv.ResourceId()
|
id := rv.ResourceId()
|
||||||
if _, ok := resources[id]; !ok {
|
if _, ok := resources[id]; !ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: unknown resource '%s' referenced in variable %s",
|
"%s: unknown resource '%s' referenced in variable %s",
|
||||||
source,
|
source,
|
||||||
id,
|
id,
|
||||||
rv.FullKey()))
|
rv.FullKey(),
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -690,7 +726,7 @@ func (c *Config) Validate() error {
|
||||||
found := make(map[string]struct{})
|
found := make(map[string]struct{})
|
||||||
for _, l := range c.Locals {
|
for _, l := range c.Locals {
|
||||||
if _, ok := found[l.Name]; ok {
|
if _, ok := found[l.Name]; ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: duplicate local. local value names must be unique",
|
"%s: duplicate local. local value names must be unique",
|
||||||
l.Name,
|
l.Name,
|
||||||
))
|
))
|
||||||
|
@ -700,7 +736,7 @@ func (c *Config) Validate() error {
|
||||||
|
|
||||||
for _, v := range l.RawConfig.Variables {
|
for _, v := range l.RawConfig.Variables {
|
||||||
if _, ok := v.(*CountVariable); ok {
|
if _, ok := v.(*CountVariable); ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"local %s: count variables are only valid within resources", l.Name,
|
"local %s: count variables are only valid within resources", l.Name,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -714,9 +750,10 @@ func (c *Config) Validate() error {
|
||||||
for _, o := range c.Outputs {
|
for _, o := range c.Outputs {
|
||||||
// Verify the output is new
|
// Verify the output is new
|
||||||
if _, ok := found[o.Name]; ok {
|
if _, ok := found[o.Name]; ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: duplicate output. output names must be unique.",
|
"output %q: an output of this name was already defined",
|
||||||
o.Name))
|
o.Name,
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
found[o.Name] = struct{}{}
|
found[o.Name] = struct{}{}
|
||||||
|
@ -736,9 +773,10 @@ func (c *Config) Validate() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: value for 'sensitive' must be boolean",
|
"output %q: value for 'sensitive' must be boolean",
|
||||||
o.Name))
|
o.Name,
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if k == "description" {
|
if k == "description" {
|
||||||
|
@ -747,29 +785,35 @@ func (c *Config) Validate() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: value for 'description' must be string",
|
"output %q: value for 'description' must be string",
|
||||||
o.Name))
|
o.Name,
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
invalidKeys = append(invalidKeys, k)
|
invalidKeys = append(invalidKeys, k)
|
||||||
}
|
}
|
||||||
if len(invalidKeys) > 0 {
|
if len(invalidKeys) > 0 {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: output has invalid keys: %s",
|
"output %q: invalid keys: %s",
|
||||||
o.Name, strings.Join(invalidKeys, ", ")))
|
o.Name, strings.Join(invalidKeys, ", "),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
if !valueKeyFound {
|
if !valueKeyFound {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: output is missing required 'value' key", o.Name))
|
"output %q: missing required 'value' argument", o.Name,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range o.RawConfig.Variables {
|
for _, v := range o.RawConfig.Variables {
|
||||||
if _, ok := v.(*CountVariable); ok {
|
if _, ok := v.(*CountVariable); ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: count variables are only valid within resources", o.Name))
|
"output %q: count variables are only valid within resources",
|
||||||
|
o.Name,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,17 +827,15 @@ func (c *Config) Validate() error {
|
||||||
|
|
||||||
for _, v := range rc.Variables {
|
for _, v := range rc.Variables {
|
||||||
if _, ok := v.(*SelfVariable); ok {
|
if _, ok := v.(*SelfVariable); ok {
|
||||||
errs = append(errs, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: cannot contain self-reference %s", source, v.FullKey()))
|
"%s: cannot contain self-reference %s",
|
||||||
|
source, v.FullKey(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
return diags
|
||||||
return &multierror.Error{Errors: errs}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterpolatedVariables is a helper that returns a mapping of all the interpolated
|
// InterpolatedVariables is a helper that returns a mapping of all the interpolated
|
||||||
|
|
|
@ -223,20 +223,21 @@ func TestConfigValidate_table(t *testing.T) {
|
||||||
"invalid provider name in module block",
|
"invalid provider name in module block",
|
||||||
"validate-missing-provider",
|
"validate-missing-provider",
|
||||||
true,
|
true,
|
||||||
"does not exist",
|
"cannot pass non-existent provider",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
|
||||||
c := testConfig(t, tc.Fixture)
|
c := testConfig(t, tc.Fixture)
|
||||||
err := c.Validate()
|
diags := c.Validate()
|
||||||
if (err != nil) != tc.Err {
|
if diags.HasErrors() != tc.Err {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", diags.Err().Error())
|
||||||
}
|
}
|
||||||
if err != nil {
|
if diags.HasErrors() {
|
||||||
if tc.ErrString != "" && !strings.Contains(err.Error(), tc.ErrString) {
|
gotErr := diags.Err().Error()
|
||||||
t.Fatalf("expected err to contain: %s\n\ngot: %s", tc.ErrString, err)
|
if tc.ErrString != "" && !strings.Contains(gotErr, tc.ErrString) {
|
||||||
|
t.Fatalf("expected err to contain: %s\n\ngot: %s", tc.ErrString, gotErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -291,15 +292,16 @@ func TestConfigValidate_countInt_HCL2(t *testing.T) {
|
||||||
func TestConfigValidate_countBadContext(t *testing.T) {
|
func TestConfigValidate_countBadContext(t *testing.T) {
|
||||||
c := testConfig(t, "validate-count-bad-context")
|
c := testConfig(t, "validate-count-bad-context")
|
||||||
|
|
||||||
err := c.Validate()
|
diags := c.Validate()
|
||||||
|
|
||||||
expected := []string{
|
expected := []string{
|
||||||
"no_count_in_output: count variables are only valid within resources",
|
"output \"no_count_in_output\": count variables are only valid within resources",
|
||||||
"no_count_in_module: count variables are only valid within resources",
|
"module \"no_count_in_module\": count variables are only valid within resources",
|
||||||
}
|
}
|
||||||
for _, exp := range expected {
|
for _, exp := range expected {
|
||||||
if !strings.Contains(err.Error(), exp) {
|
errStr := diags.Err().Error()
|
||||||
t.Fatalf("expected: %q,\nto contain: %q", err, exp)
|
if !strings.Contains(errStr, exp) {
|
||||||
|
t.Errorf("expected: %q,\nto contain: %q", errStr, exp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
|
|
||||||
getter "github.com/hashicorp/go-getter"
|
getter "github.com/hashicorp/go-getter"
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
)
|
)
|
||||||
|
@ -383,32 +385,35 @@ func (t *Tree) String() string {
|
||||||
// as verifying things such as parameters/outputs between the various modules.
|
// as verifying things such as parameters/outputs between the various modules.
|
||||||
//
|
//
|
||||||
// Load must be called prior to calling Validate or an error will be returned.
|
// Load must be called prior to calling Validate or an error will be returned.
|
||||||
func (t *Tree) Validate() error {
|
func (t *Tree) Validate() tfdiags.Diagnostics {
|
||||||
if !t.Loaded() {
|
var diags tfdiags.Diagnostics
|
||||||
return fmt.Errorf("tree must be loaded before calling Validate")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If something goes wrong, here is our error template
|
if !t.Loaded() {
|
||||||
newErr := &treeError{Name: []string{t.Name()}}
|
diags = diags.Append(fmt.Errorf(
|
||||||
|
"tree must be loaded before calling Validate",
|
||||||
|
))
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
// Terraform core does not handle root module children named "root".
|
// Terraform core does not handle root module children named "root".
|
||||||
// We plan to fix this in the future but this bug was brought up in
|
// We plan to fix this in the future but this bug was brought up in
|
||||||
// the middle of a release and we don't want to introduce wide-sweeping
|
// the middle of a release and we don't want to introduce wide-sweeping
|
||||||
// changes at that time.
|
// changes at that time.
|
||||||
if len(t.path) == 1 && t.name == "root" {
|
if len(t.path) == 1 && t.name == "root" {
|
||||||
return fmt.Errorf("root module cannot contain module named 'root'")
|
diags = diags.Append(fmt.Errorf(
|
||||||
|
"root module cannot contain module named 'root'",
|
||||||
|
))
|
||||||
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate our configuration first.
|
// Validate our configuration first.
|
||||||
if err := t.config.Validate(); err != nil {
|
diags = diags.Append(t.config.Validate())
|
||||||
newErr.Add(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're the root, we do extra validation. This validation usually
|
// If we're the root, we do extra validation. This validation usually
|
||||||
// requires the entire tree (since children don't have parent pointers).
|
// requires the entire tree (since children don't have parent pointers).
|
||||||
if len(t.path) == 0 {
|
if len(t.path) == 0 {
|
||||||
if err := t.validateProviderAlias(); err != nil {
|
if err := t.validateProviderAlias(); err != nil {
|
||||||
newErr.Add(err)
|
diags = diags.Append(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,20 +422,11 @@ func (t *Tree) Validate() error {
|
||||||
|
|
||||||
// Validate all our children
|
// Validate all our children
|
||||||
for _, c := range children {
|
for _, c := range children {
|
||||||
err := c.Validate()
|
childDiags := c.Validate()
|
||||||
if err == nil {
|
diags = diags.Append(childDiags)
|
||||||
|
if diags.HasErrors() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
verr, ok := err.(*treeError)
|
|
||||||
if !ok {
|
|
||||||
// Unknown error, just return...
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append ourselves to the error and then return
|
|
||||||
verr.Name = append(verr.Name, t.Name())
|
|
||||||
newErr.AddChild(verr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go over all the modules and verify that any parameters are valid
|
// Go over all the modules and verify that any parameters are valid
|
||||||
|
@ -456,9 +452,10 @@ func (t *Tree) Validate() error {
|
||||||
// Compare to the keys in our raw config for the module
|
// Compare to the keys in our raw config for the module
|
||||||
for k, _ := range m.RawConfig.Raw {
|
for k, _ := range m.RawConfig.Raw {
|
||||||
if _, ok := varMap[k]; !ok {
|
if _, ok := varMap[k]; !ok {
|
||||||
newErr.Add(fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"module %s: %s is not a valid parameter",
|
"module %q: %q is not a valid argument",
|
||||||
m.Name, k))
|
m.Name, k,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the required
|
// Remove the required
|
||||||
|
@ -467,9 +464,10 @@ func (t *Tree) Validate() error {
|
||||||
|
|
||||||
// If we have any required left over, they aren't set.
|
// If we have any required left over, they aren't set.
|
||||||
for k, _ := range requiredMap {
|
for k, _ := range requiredMap {
|
||||||
newErr.Add(fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"module %s: required variable %q not set",
|
"module %q: missing required argument %q",
|
||||||
m.Name, k))
|
m.Name, k,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,9 +482,10 @@ func (t *Tree) Validate() error {
|
||||||
|
|
||||||
tree, ok := children[mv.Name]
|
tree, ok := children[mv.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
newErr.Add(fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: undefined module referenced %s",
|
"%s: reference to undefined module %q",
|
||||||
source, mv.Name))
|
source, mv.Name,
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,14 +497,15 @@ func (t *Tree) Validate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
newErr.Add(fmt.Errorf(
|
diags = diags.Append(fmt.Errorf(
|
||||||
"%s: %s is not a valid output for module %s",
|
"%s: %q is not a valid output for module %q",
|
||||||
source, mv.Field, mv.Name))
|
source, mv.Field, mv.Name,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newErr.ErrOrNil()
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// versionedPathKey returns a path string with every levels full name, version
|
// versionedPathKey returns a path string with every levels full name, version
|
||||||
|
|
|
@ -404,15 +404,15 @@ func TestTreeValidate_table(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := tree.Validate()
|
diags := tree.Validate()
|
||||||
if (err != nil) != (tc.Err != "") {
|
if (diags.HasErrors()) != (tc.Err != "") {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", diags.Err())
|
||||||
}
|
}
|
||||||
if err == nil {
|
if len(diags) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !strings.Contains(err.Error(), tc.Err) {
|
if !strings.Contains(diags.Err().Error(), tc.Err) {
|
||||||
t.Fatalf("err should contain %q: %s", tc.Err, err)
|
t.Fatalf("err should contain %q: %s", tc.Err, diags.Err().Error())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -519,13 +519,13 @@ func TestTreeValidate_requiredChildVar(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := tree.Validate()
|
diags := tree.Validate()
|
||||||
if err == nil {
|
if !diags.HasErrors() {
|
||||||
t.Fatal("should error")
|
t.Fatal("should error")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure both variables are mentioned in the output
|
// ensure both variables are mentioned in the output
|
||||||
errMsg := err.Error()
|
errMsg := diags.Err().Error()
|
||||||
for _, v := range []string{"feature", "memory"} {
|
for _, v := range []string{"feature", "memory"} {
|
||||||
if !strings.Contains(errMsg, v) {
|
if !strings.Contains(errMsg, v) {
|
||||||
t.Fatalf("no mention of missing variable %q", v)
|
t.Fatalf("no mention of missing variable %q", v)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/hashicorp/errwrap"
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/hashicorp/logutils"
|
"github.com/hashicorp/logutils"
|
||||||
"github.com/hashicorp/terraform/config/module"
|
"github.com/hashicorp/terraform/config/module"
|
||||||
|
@ -662,18 +663,12 @@ func testIDOnlyRefresh(c TestCase, opts terraform.ContextOpts, step TestStep, r
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 {
|
if diags := ctx.Validate(); len(diags) > 0 {
|
||||||
if len(es) > 0 {
|
if diags.HasErrors() {
|
||||||
estrs := make([]string, len(es))
|
return errwrap.Wrapf("config is invalid: {{err}}", diags.Err())
|
||||||
for i, e := range es {
|
|
||||||
estrs[i] = e.Error()
|
|
||||||
}
|
|
||||||
return fmt.Errorf(
|
|
||||||
"Configuration is invalid.\n\nWarnings: %#v\n\nErrors: %#v",
|
|
||||||
ws, estrs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[WARN] Config warnings: %#v", ws)
|
log.Printf("[WARN] Config warnings:\n%s", diags.Err().Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh!
|
// Refresh!
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/errwrap"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,17 +34,12 @@ func testStep(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state, fmt.Errorf("Error initializing context: %s", err)
|
return state, fmt.Errorf("Error initializing context: %s", err)
|
||||||
}
|
}
|
||||||
if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 {
|
if diags := ctx.Validate(); len(diags) > 0 {
|
||||||
if len(es) > 0 {
|
if diags.HasErrors() {
|
||||||
estrs := make([]string, len(es))
|
return nil, errwrap.Wrapf("config is invalid: {{err}}", diags.Err())
|
||||||
for i, e := range es {
|
|
||||||
estrs[i] = e.Error()
|
|
||||||
}
|
}
|
||||||
return state, fmt.Errorf(
|
|
||||||
"Configuration is invalid.\n\nWarnings: %#v\n\nErrors: %#v",
|
log.Printf("[WARN] Config warnings:\n%s", diags)
|
||||||
ws, estrs)
|
|
||||||
}
|
|
||||||
log.Printf("[WARN] Config warnings: %#v", ws)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh!
|
// Refresh!
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/hashicorp/hcl"
|
"github.com/hashicorp/hcl"
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
|
@ -671,29 +673,27 @@ func (c *Context) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the configuration and returns any warnings or errors.
|
// Validate validates the configuration and returns any warnings or errors.
|
||||||
func (c *Context) Validate() ([]string, []error) {
|
func (c *Context) Validate() tfdiags.Diagnostics {
|
||||||
defer c.acquireRun("validate")()
|
defer c.acquireRun("validate")()
|
||||||
|
|
||||||
var errs error
|
var diags tfdiags.Diagnostics
|
||||||
|
|
||||||
// Validate the configuration itself
|
// Validate the configuration itself
|
||||||
if err := c.module.Validate(); err != nil {
|
diags = diags.Append(c.module.Validate())
|
||||||
errs = multierror.Append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This only needs to be done for the root module, since inter-module
|
// This only needs to be done for the root module, since inter-module
|
||||||
// variables are validated in the module tree.
|
// variables are validated in the module tree.
|
||||||
if config := c.module.Config(); config != nil {
|
if config := c.module.Config(); config != nil {
|
||||||
// Validate the user variables
|
// Validate the user variables
|
||||||
if err := smcUserVariables(config, c.variables); len(err) > 0 {
|
for _, err := range smcUserVariables(config, c.variables) {
|
||||||
errs = multierror.Append(errs, err...)
|
diags = diags.Append(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have errors at this point, the graphing has no chance,
|
// If we have errors at this point, the graphing has no chance,
|
||||||
// so just bail early.
|
// so just bail early.
|
||||||
if errs != nil {
|
if diags.HasErrors() {
|
||||||
return nil, []error{errs}
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the graph so we can walk it and run Validate on nodes.
|
// Build the graph so we can walk it and run Validate on nodes.
|
||||||
|
@ -702,24 +702,29 @@ func (c *Context) Validate() ([]string, []error) {
|
||||||
// graph again later after Planning.
|
// graph again later after Planning.
|
||||||
graph, err := c.Graph(GraphTypeValidate, nil)
|
graph, err := c.Graph(GraphTypeValidate, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{err}
|
diags = diags.Append(err)
|
||||||
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk
|
// Walk
|
||||||
walker, err := c.walk(graph, walkValidate)
|
walker, err := c.walk(graph, walkValidate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, multierror.Append(errs, err).Errors
|
diags = diags.Append(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the result
|
|
||||||
rerrs := multierror.Append(errs, walker.ValidationErrors...)
|
|
||||||
|
|
||||||
sort.Strings(walker.ValidationWarnings)
|
sort.Strings(walker.ValidationWarnings)
|
||||||
sort.Slice(rerrs.Errors, func(i, j int) bool {
|
sort.Slice(walker.ValidationErrors, func(i, j int) bool {
|
||||||
return rerrs.Errors[i].Error() < rerrs.Errors[j].Error()
|
return walker.ValidationErrors[i].Error() < walker.ValidationErrors[j].Error()
|
||||||
})
|
})
|
||||||
|
|
||||||
return walker.ValidationWarnings, rerrs.Errors
|
for _, warn := range walker.ValidationWarnings {
|
||||||
|
diags = diags.Append(tfdiags.SimpleWarning(warn))
|
||||||
|
}
|
||||||
|
for _, err := range walker.ValidationErrors {
|
||||||
|
diags = diags.Append(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module returns the module tree associated with this context.
|
// Module returns the module tree associated with this context.
|
||||||
|
|
|
@ -7966,12 +7966,9 @@ func TestContext2Apply_vars(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if len(w) > 0 {
|
if len(diags) != 0 {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := ctx.Plan(); err != nil {
|
if _, err := ctx.Plan(); err != nil {
|
||||||
|
@ -8009,12 +8006,9 @@ func TestContext2Apply_varsEnv(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if len(w) > 0 {
|
if len(diags) != 0 {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := ctx.Plan(); err != nil {
|
if _, err := ctx.Plan(); err != nil {
|
||||||
|
|
|
@ -3499,12 +3499,9 @@ func TestContext2Plan_resourceNestedCount(t *testing.T) {
|
||||||
State: s,
|
State: s,
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if len(w) > 0 {
|
if len(diags) != 0 {
|
||||||
t.Fatalf("warnings generated on validate: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("errors generated on validate: %#v", e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ctx.Refresh()
|
_, err := ctx.Refresh()
|
||||||
|
@ -3582,12 +3579,9 @@ output "out" {
|
||||||
})
|
})
|
||||||
|
|
||||||
// if this ever fails to pass validate, add a resource to reference in the config
|
// if this ever fails to pass validate, add a resource to reference in the config
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if len(w) > 0 {
|
if len(diags) != 0 {
|
||||||
t.Fatalf("warnings generated on validate: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("errors generated on validate: %v", e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ctx.Refresh()
|
_, err := ctx.Refresh()
|
||||||
|
@ -3630,12 +3624,9 @@ resource "aws_instance" "foo" {
|
||||||
})
|
})
|
||||||
|
|
||||||
// if this ever fails to pass validate, add a resource to reference in the config
|
// if this ever fails to pass validate, add a resource to reference in the config
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if len(w) > 0 {
|
if len(diags) != 0 {
|
||||||
t.Fatalf("warnings generated on validate: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("errors generated on validate: %v", e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ctx.Refresh()
|
_, err := ctx.Refresh()
|
||||||
|
|
|
@ -1042,12 +1042,9 @@ func TestContext2Validate(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if len(diags) != 0 {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,9 @@ func TestContext2Validate_badCount(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +36,9 @@ func TestContext2Validate_badVar(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,12 +57,9 @@ func TestContext2Validate_varMapOverrideOld(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,12 +69,9 @@ func TestContext2Validate_varNoDefaultExplicitType(t *testing.T) {
|
||||||
Module: m,
|
Module: m,
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,14 +100,9 @@ func TestContext2Validate_computedVar(t *testing.T) {
|
||||||
return fmt.Errorf("Configure should not be called for provider")
|
return fmt.Errorf("Configure should not be called for provider")
|
||||||
}
|
}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
for _, err := range e {
|
|
||||||
t.Errorf("bad: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,12 +121,9 @@ func TestContext2Validate_countComputed(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,12 +139,9 @@ func TestContext2Validate_countNegative(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,12 +157,9 @@ func TestContext2Validate_countVariable(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,12 +175,9 @@ func TestContext2Validate_countVariableNoDefault(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) != 1 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,12 +195,9 @@ func TestContext2Validate_cycle(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("expected no warns, got: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) != 1 {
|
|
||||||
t.Fatalf("expected 1 err, got: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -246,12 +214,9 @@ func TestContext2Validate_moduleBadOutput(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,12 +232,9 @@ func TestContext2Validate_moduleGood(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,12 +252,9 @@ func TestContext2Validate_moduleBadResource(t *testing.T) {
|
||||||
|
|
||||||
p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")}
|
p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,13 +270,9 @@ func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
|
if diags.HasErrors() {
|
||||||
if len(w) > 0 {
|
t.Fatalf("bad: %#v", diags)
|
||||||
t.Fatalf("expected no warnings, got: %s", w)
|
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("expected no errors, got: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,12 +315,9 @@ func TestContext2Validate_moduleProviderInheritOrphan(t *testing.T) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,12 +340,9 @@ func TestContext2Validate_moduleProviderVar(t *testing.T) {
|
||||||
return nil, c.CheckSet([]string{"foo"})
|
return nil, c.CheckSet([]string{"foo"})
|
||||||
}
|
}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,12 +362,9 @@ func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) {
|
||||||
return nil, c.CheckSet([]string{"foo"})
|
return nil, c.CheckSet([]string{"foo"})
|
||||||
}
|
}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,12 +401,9 @@ func TestContext2Validate_orphans(t *testing.T) {
|
||||||
return nil, c.CheckSet([]string{"foo"})
|
return nil, c.CheckSet([]string{"foo"})
|
||||||
}
|
}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,15 +421,12 @@ func TestContext2Validate_providerConfig_bad(t *testing.T) {
|
||||||
|
|
||||||
p.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
p.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if len(diags) != 1 {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("wrong number of diagnostics %d; want %d", len(diags), 1)
|
||||||
}
|
}
|
||||||
if len(e) == 0 {
|
if !strings.Contains(diags.Err().Error(), "bad") {
|
||||||
t.Fatalf("bad: %s", e)
|
t.Fatalf("bad: %s", diags.Err().Error())
|
||||||
}
|
|
||||||
if !strings.Contains(fmt.Sprintf("%s", e), "bad") {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,12 +444,9 @@ func TestContext2Validate_providerConfig_badEmpty(t *testing.T) {
|
||||||
|
|
||||||
p.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
p.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,12 +462,9 @@ func TestContext2Validate_providerConfig_good(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,12 +486,9 @@ func TestContext2Validate_provisionerConfig_bad(t *testing.T) {
|
||||||
|
|
||||||
pr.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
pr.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,12 +514,9 @@ func TestContext2Validate_provisionerConfig_good(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,12 +532,9 @@ func TestContext2Validate_requiredVar(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,12 +552,9 @@ func TestContext2Validate_resourceConfig_bad(t *testing.T) {
|
||||||
|
|
||||||
p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")}
|
p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,12 +570,9 @@ func TestContext2Validate_resourceConfig_good(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,12 +588,9 @@ func TestContext2Validate_resourceNameSymbol(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,12 +606,9 @@ func TestContext2Validate_selfRef(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,12 +624,9 @@ func TestContext2Validate_selfRefMulti(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,12 +642,9 @@ func TestContext2Validate_selfRefMultiAll(t *testing.T) {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if !diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,12 +682,9 @@ func TestContext2Validate_tainted(t *testing.T) {
|
||||||
return nil, c.CheckSet([]string{"foo"})
|
return nil, c.CheckSet([]string{"foo"})
|
||||||
}
|
}
|
||||||
|
|
||||||
w, e := c.Validate()
|
diags := c.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
t.Fatalf("bad: %#v", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,16 +719,9 @@ func TestContext2Validate_targetedDestroy(t *testing.T) {
|
||||||
Destroy: true,
|
Destroy: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if len(w) > 0 {
|
if diags.HasErrors() {
|
||||||
warnStr := ""
|
t.Fatalf("bad: %#v", diags)
|
||||||
for _, v := range w {
|
|
||||||
warnStr = warnStr + " " + v
|
|
||||||
}
|
|
||||||
t.Fatalf("bad: %s", warnStr)
|
|
||||||
}
|
|
||||||
if len(e) > 0 {
|
|
||||||
t.Fatalf("bad: %s", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,12 +772,9 @@ func TestContext2Validate_interpolateVar(t *testing.T) {
|
||||||
UIInput: input,
|
UIInput: input,
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if w != nil {
|
if diags.HasErrors() {
|
||||||
t.Log("warnings:", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if e != nil {
|
|
||||||
t.Fatal("err:", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,12 +798,9 @@ func TestContext2Validate_interpolateComputedModuleVarDef(t *testing.T) {
|
||||||
UIInput: input,
|
UIInput: input,
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if w != nil {
|
if diags.HasErrors() {
|
||||||
t.Log("warnings:", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if e != nil {
|
|
||||||
t.Fatal("err:", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -932,12 +823,9 @@ func TestContext2Validate_interpolateMap(t *testing.T) {
|
||||||
UIInput: input,
|
UIInput: input,
|
||||||
})
|
})
|
||||||
|
|
||||||
w, e := ctx.Validate()
|
diags := ctx.Validate()
|
||||||
if w != nil {
|
if diags.HasErrors() {
|
||||||
t.Log("warnings:", w)
|
t.Fatalf("bad: %#v", diags)
|
||||||
}
|
|
||||||
if e != nil {
|
|
||||||
t.Fatal("err:", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue