From 609219fc65c1e0f7720b94e468b9456a973cd2ce Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 3 Sep 2016 15:26:49 -0700 Subject: [PATCH] command/meta: validate config immediately * config: test for validating multi-vars (passes) * command/plan: test invalid run * command/meta: validate module on load --- command/command.go | 7 +++- command/meta.go | 5 +++ command/plan_test.go | 34 +++++++++++++++++++ command/push_test.go | 3 +- command/test-fixtures/plan-invalid/main.tf | 7 ++++ command/test-fixtures/push-tfvars/main.tf | 1 - config/config_test.go | 7 ++++ .../validate-count-resource-var-multi/main.tf | 5 +++ 8 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 command/test-fixtures/plan-invalid/main.tf create mode 100644 config/test-fixtures/validate-count-resource-var-multi/main.tf diff --git a/command/command.go b/command/command.go index d9ad0cf30..a4ca00532 100644 --- a/command/command.go +++ b/command/command.go @@ -2,6 +2,7 @@ package command import ( "fmt" + "log" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" @@ -27,7 +28,11 @@ const DefaultBackupExtension = ".backup" const DefaultParallelism = 10 func validateContext(ctx *terraform.Context, ui cli.Ui) bool { - if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 { + log.Println("[INFO] Validating the context...") + ws, es := ctx.Validate() + log.Printf("[INFO] Validation result: %d warnings, %d errors", len(ws), len(es)) + + if len(ws) > 0 || len(es) > 0 { ui.Output( "There are warnings and/or errors related to your configuration. Please\n" + "fix these before continuing.\n") diff --git a/command/meta.go b/command/meta.go index 5adf1b667..f18b910d4 100644 --- a/command/meta.go +++ b/command/meta.go @@ -165,6 +165,11 @@ func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) { return nil, false, fmt.Errorf("Error downloading modules: %s", err) } + // Validate the module right away + if err := mod.Validate(); err != nil { + return nil, false, err + } + opts.Module = mod opts.Parallelism = copts.Parallelism opts.State = state.State() diff --git a/command/plan_test.go b/command/plan_test.go index 710d993a9..c4af9c141 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -395,6 +395,40 @@ func TestPlan_statePast(t *testing.T) { } } +func TestPlan_validate(t *testing.T) { + // This is triggered by not asking for input so we have to set this to false + test = false + defer func() { test = true }() + + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("err: %s", err) + } + if err := os.Chdir(testFixturePath("plan-invalid")); err != nil { + t.Fatalf("err: %s", err) + } + defer os.Chdir(cwd) + + p := testProvider() + ui := new(cli.MockUi) + c := &PlanCommand{ + Meta: Meta{ + ContextOpts: testCtxConfig(p), + Ui: ui, + }, + } + + args := []string{} + if code := c.Run(args); code != 1 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + actual := ui.ErrorWriter.String() + if !strings.Contains(actual, "can't reference") { + t.Fatalf("bad: %s", actual) + } +} + func TestPlan_vars(t *testing.T) { p := testProvider() ui := new(cli.MockUi) diff --git a/command/push_test.go b/command/push_test.go index b48add166..b441edced 100644 --- a/command/push_test.go +++ b/command/push_test.go @@ -765,8 +765,7 @@ func pushTFVars() []atlas.TFVar { return []atlas.TFVar{ {"bar", "foo", false}, {"baz", `{ - A = "a" - interp = "${file("t.txt")}" + A = "a" }`, true}, {"fob", `["a", "quotes \"in\" quotes"]`, true}, {"foo", "bar", false}, diff --git a/command/test-fixtures/plan-invalid/main.tf b/command/test-fixtures/plan-invalid/main.tf new file mode 100644 index 000000000..fd8142032 --- /dev/null +++ b/command/test-fixtures/plan-invalid/main.tf @@ -0,0 +1,7 @@ +resource "test_instance" "foo" { + count = 5 +} + +resource "test_instance" "bar" { + count = "${length(test_instance.foo.*.id)}" +} diff --git a/command/test-fixtures/push-tfvars/main.tf b/command/test-fixtures/push-tfvars/main.tf index 2110bea73..2699d50ee 100644 --- a/command/test-fixtures/push-tfvars/main.tf +++ b/command/test-fixtures/push-tfvars/main.tf @@ -7,7 +7,6 @@ variable "baz" { default = { "A" = "a" - interp = "${file("t.txt")}" } } diff --git a/config/config_test.go b/config/config_test.go index 084a301ee..201a62893 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -195,6 +195,13 @@ func TestConfigValidate_countResourceVar(t *testing.T) { } } +func TestConfigValidate_countResourceVarMulti(t *testing.T) { + c := testConfig(t, "validate-count-resource-var-multi") + if err := c.Validate(); err == nil { + t.Fatal("should not be valid") + } +} + func TestConfigValidate_countUserVar(t *testing.T) { c := testConfig(t, "validate-count-user-var") if err := c.Validate(); err != nil { diff --git a/config/test-fixtures/validate-count-resource-var-multi/main.tf b/config/test-fixtures/validate-count-resource-var-multi/main.tf new file mode 100644 index 000000000..fca11701d --- /dev/null +++ b/config/test-fixtures/validate-count-resource-var-multi/main.tf @@ -0,0 +1,5 @@ +resource "aws_instance" "foo" {} + +resource "aws_instance" "web" { + count = "${length(aws_instance.foo.*.bar)}" +}