Skip to content

Commit

Permalink
Improved error message when 'bricks bundle run' is executed before 'b…
Browse files Browse the repository at this point in the history
…ricks 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

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 <pieter.noordhuis@databricks.com>
  • Loading branch information
andrewnester and pietern authored May 10, 2023
1 parent 1916bc9 commit 473d2bf
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 8 deletions.
8 changes: 0 additions & 8 deletions bundle/deploy/terraform/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
18 changes: 18 additions & 0 deletions bundle/deploy/terraform/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
Expand All @@ -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 {
Expand All @@ -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{}
}
41 changes: 41 additions & 0 deletions bundle/deploy/terraform/load_test.go
Original file line number Diff line number Diff line change
@@ -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'")
}

0 comments on commit 473d2bf

Please sign in to comment.