Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions bundle/deploy/terraform/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"

"github.com/databricks/cli/bundle"
Expand Down Expand Up @@ -69,6 +70,44 @@ func (m *initialize) findExecPath(ctx context.Context, b *bundle.Bundle, tf *con
return tf.ExecPath, nil
}

// This function sets temp dir location for terraform to use. If user does not
// specify anything here, we fall back to a `tmp` directory in the bundle's cache
// directory
//
// This is necessary to avoid trying to create temporary files in directories
// the CLI and its dependencies do not have access to.
//
// see: os.TempDir for more context
func setTempDirEnvVars(env map[string]string, b *bundle.Bundle) error {
switch runtime.GOOS {
case "windows":
if v, ok := os.LookupEnv("TMP"); ok {
env["TMP"] = v
} else if v, ok := os.LookupEnv("TEMP"); ok {
env["TEMP"] = v
} else if v, ok := os.LookupEnv("USERPROFILE"); ok {
env["USERPROFILE"] = v
} else {
tmpDir, err := b.CacheDir("tmp")
if err != nil {
return err
}
env["TMP"] = tmpDir
}
default:
if v, ok := os.LookupEnv("TMPDIR"); ok {
env["TMPDIR"] = v
} else {
tmpDir, err := b.CacheDir("tmp")
if err != nil {
return err
}
env["TMPDIR"] = tmpDir
}
}
return nil
}

func (m *initialize) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Mutator, error) {
tfConfig := b.Config.Bundle.Terraform
if tfConfig == nil {
Expand Down Expand Up @@ -102,6 +141,12 @@ func (m *initialize) Apply(ctx context.Context, b *bundle.Bundle) ([]bundle.Muta
env["HOME"] = home
}

// Set the temporary directory environment variables
err = setTempDirEnvVars(env, b)
if err != nil {
return nil, err
}
Comment thread
pietern marked this conversation as resolved.

// Configure environment variables for auth for Terraform to use.
log.Debugf(ctx, "Environment variables for Terraform: %s", strings.Join(maps.Keys(env), ", "))
err = tf.SetEnv(env)
Expand Down
189 changes: 189 additions & 0 deletions bundle/deploy/terraform/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@ package terraform

import (
"context"
"os"
"os/exec"
"runtime"
"testing"

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func unsetEnv(t *testing.T, name string) {
t.Setenv(name, "")
err := os.Unsetenv(name)
require.NoError(t, err)
}

func TestInitEnvironmentVariables(t *testing.T) {
_, err := exec.LookPath("terraform")
if err != nil {
Expand Down Expand Up @@ -37,3 +46,183 @@ func TestInitEnvironmentVariables(t *testing.T) {
_, err = Initialize().Apply(context.Background(), bundle)
require.NoError(t, err)
}

func TestSetTempDirEnvVarsForUnixWithTmpDirSet(t *testing.T) {
if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
t.SkipNow()
}

b := &bundle.Bundle{
Config: config.Root{
Path: t.TempDir(),
Bundle: config.Bundle{
Environment: "whatever",
},
},
}

// Set TMPDIR environment variable
t.Setenv("TMPDIR", "/foo/bar")

// compute env
env := make(map[string]string, 0)
err := setTempDirEnvVars(env, b)
require.NoError(t, err)

// assert that we pass through env var value
assert.Equal(t, map[string]string{
"TMPDIR": "/foo/bar",
}, env)
}

func TestSetTempDirEnvVarsForUnixWithTmpDirNotSet(t *testing.T) {
if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
t.SkipNow()
}

b := &bundle.Bundle{
Config: config.Root{
Path: t.TempDir(),
Bundle: config.Bundle{
Environment: "whatever",
},
},
}

// Unset TMPDIR environment variable confirm it's not set
unsetEnv(t, "TMPDIR")

// compute env
env := make(map[string]string, 0)
err := setTempDirEnvVars(env, b)
require.NoError(t, err)

// assert tmp dir is set to b.CacheDir("tmp")
tmpDir, err := b.CacheDir("tmp")
require.NoError(t, err)
assert.Equal(t, map[string]string{
"TMPDIR": tmpDir,
}, env)
}

func TestSetTempDirEnvVarsForWindowWithAllTmpDirEnvVarsSet(t *testing.T) {
if runtime.GOOS != "windows" {
t.SkipNow()
}

b := &bundle.Bundle{
Config: config.Root{
Path: t.TempDir(),
Bundle: config.Bundle{
Environment: "whatever",
},
},
}

// Set environment variables
t.Setenv("TMP", "c:\\foo\\a")
t.Setenv("TEMP", "c:\\foo\\b")
t.Setenv("USERPROFILE", "c:\\foo\\c")

// compute env
env := make(map[string]string, 0)
err := setTempDirEnvVars(env, b)
require.NoError(t, err)

// assert that we pass through the highest priority env var value
assert.Equal(t, map[string]string{
"TMP": "c:\\foo\\a",
}, env)
}

func TestSetTempDirEnvVarsForWindowWithUserProfileAndTempSet(t *testing.T) {
if runtime.GOOS != "windows" {
t.SkipNow()
}

b := &bundle.Bundle{
Config: config.Root{
Path: t.TempDir(),
Bundle: config.Bundle{
Environment: "whatever",
},
},
}

// Set environment variables
unsetEnv(t, "TMP")
t.Setenv("TEMP", "c:\\foo\\b")
t.Setenv("USERPROFILE", "c:\\foo\\c")

// compute env
env := make(map[string]string, 0)
err := setTempDirEnvVars(env, b)
require.NoError(t, err)

// assert that we pass through the highest priority env var value
assert.Equal(t, map[string]string{
"TEMP": "c:\\foo\\b",
}, env)
}

func TestSetTempDirEnvVarsForWindowWithUserProfileSet(t *testing.T) {
if runtime.GOOS != "windows" {
t.SkipNow()
}

b := &bundle.Bundle{
Config: config.Root{
Path: t.TempDir(),
Bundle: config.Bundle{
Environment: "whatever",
},
},
}

// Set environment variables
unsetEnv(t, "TMP")
unsetEnv(t, "TEMP")
t.Setenv("USERPROFILE", "c:\\foo\\c")

// compute env
env := make(map[string]string, 0)
err := setTempDirEnvVars(env, b)
require.NoError(t, err)

// assert that we pass through the user profile
assert.Equal(t, map[string]string{
"USERPROFILE": "c:\\foo\\c",
}, env)
}

func TestSetTempDirEnvVarsForWindowsWithoutAnyTempDirEnvVarsSet(t *testing.T) {
if runtime.GOOS != "windows" {
t.SkipNow()
}

b := &bundle.Bundle{
Config: config.Root{
Path: t.TempDir(),
Bundle: config.Bundle{
Environment: "whatever",
},
},
}

// unset all env vars
unsetEnv(t, "TMP")
unsetEnv(t, "TEMP")
unsetEnv(t, "USERPROFILE")

// compute env
env := make(map[string]string, 0)
err := setTempDirEnvVars(env, b)
require.NoError(t, err)

// assert TMP is set to b.CacheDir("tmp")
tmpDir, err := b.CacheDir("tmp")
require.NoError(t, err)
assert.Equal(t, map[string]string{
"TMP": tmpDir,
}, env)
}