From 473d2bf503e73514f2eb5b86bb555baf545a9d01 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Wed, 10 May 2023 11:02:25 +0200 Subject: [PATCH] Improved error message when 'bricks bundle run' is executed before 'bricks bundle deploy' (#378) ## Changes Improved error message when 'bricks bundle run' is executed before 'bricks bundle deploy' The error happens when we attempt to load terraform state when it does not exist. The best way to check if terraform state actually exists is to call `terraform show -json` and that's what already happens here https://github.com/databricks/bricks/compare/main...error-before-deploy#diff-8c50f8c04e568397bc865b7e02d1f4ec5b18379d8d32daddfeb041035d804f5fL28 Absence of `state.Values` indicates that there is no state and likely bundle was just never deployed. ## Tests Ran `bricks bundle run test_job` on a new non-deployed bundle. **Output:** `Error: terraform show: No state. Did you forget to run 'bricks bundle deploy'?` Running `bricks bundle deploy && bricks bundle run test_job` succeeds. --------- Co-authored-by: Pieter Noordhuis --- bundle/deploy/terraform/convert.go | 8 ------ bundle/deploy/terraform/load.go | 18 ++++++++++++ bundle/deploy/terraform/load_test.go | 41 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 bundle/deploy/terraform/load_test.go diff --git a/bundle/deploy/terraform/convert.go b/bundle/deploy/terraform/convert.go index 38c7b247..f2d2605a 100644 --- a/bundle/deploy/terraform/convert.go +++ b/bundle/deploy/terraform/convert.go @@ -154,14 +154,6 @@ func BundleToTerraform(config *config.Root) *schema.Root { } func TerraformToBundle(state *tfjson.State, config *config.Root) error { - if state.Values == nil { - return fmt.Errorf("state.Values not set") - } - - if state.Values.RootModule == nil { - return fmt.Errorf("state.Values.RootModule not set") - } - for _, resource := range state.Values.RootModule.Resources { // Limit to resources. if resource.Mode != tfjson.ManagedResourceMode { diff --git a/bundle/deploy/terraform/load.go b/bundle/deploy/terraform/load.go index 7f350abf..f312811e 100644 --- a/bundle/deploy/terraform/load.go +++ b/bundle/deploy/terraform/load.go @@ -6,6 +6,7 @@ import ( "github.com/databricks/bricks/bundle" "github.com/hashicorp/terraform-exec/tfexec" + tfjson "github.com/hashicorp/terraform-json" ) type load struct{} @@ -30,6 +31,11 @@ func (l *load) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, e return nil, err } + err = ValidateState(state) + if err != nil { + return nil, err + } + // Merge state into configuration. err = TerraformToBundle(state, &b.Config) if err != nil { @@ -39,6 +45,18 @@ func (l *load) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, e return nil, nil } +func ValidateState(state *tfjson.State) error { + if state.Values == nil { + return fmt.Errorf("no deployment state. Did you forget to run 'bricks bundle deploy'?") + } + + if state.Values.RootModule == nil { + return fmt.Errorf("malformed terraform state: RootModule not set") + } + + return nil +} + func Load() bundle.Mutator { return &load{} } diff --git a/bundle/deploy/terraform/load_test.go b/bundle/deploy/terraform/load_test.go new file mode 100644 index 00000000..5ed1c261 --- /dev/null +++ b/bundle/deploy/terraform/load_test.go @@ -0,0 +1,41 @@ +package terraform + +import ( + "context" + "os/exec" + "testing" + + "github.com/databricks/bricks/bundle" + "github.com/databricks/bricks/bundle/config" + "github.com/stretchr/testify/require" +) + +func TestLoadWithNoState(t *testing.T) { + _, err := exec.LookPath("terraform") + if err != nil { + t.Skipf("cannot find terraform binary: %s", err) + } + + b := &bundle.Bundle{ + Config: config.Root{ + Path: t.TempDir(), + Bundle: config.Bundle{ + Environment: "whatever", + Terraform: &config.Terraform{ + ExecPath: "terraform", + }, + }, + }, + } + + t.Setenv("DATABRICKS_HOST", "https://x") + t.Setenv("DATABRICKS_TOKEN", "foobar") + b.WorkspaceClient() + + err = bundle.Apply(context.Background(), b, []bundle.Mutator{ + Initialize(), + Load(), + }) + + require.ErrorContains(t, err, "Did you forget to run 'bricks bundle deploy'") +}