diff --git a/backend/local/backend_refresh.go b/backend/local/backend_refresh.go index 5c09597e8..1de9902d1 100644 --- a/backend/local/backend_refresh.go +++ b/backend/local/backend_refresh.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/backend" clistate "github.com/hashicorp/terraform/command/state" + "github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/state" ) @@ -42,6 +43,12 @@ func (b *Local) opRefresh( } } + // If we have no config module given to use, create an empty tree to + // avoid crashes when Terraform.Context is initialized. + if op.Module == nil { + op.Module = module.NewEmptyTree() + } + // Get our context tfCtx, opState, err := b.context(op) if err != nil { diff --git a/backend/local/backend_refresh_test.go b/backend/local/backend_refresh_test.go index e52060f61..c6cc0bc0a 100644 --- a/backend/local/backend_refresh_test.go +++ b/backend/local/backend_refresh_test.go @@ -40,6 +40,63 @@ test_instance.foo: `) } +func TestLocal_refreshNilModule(t *testing.T) { + b := TestLocal(t) + p := TestLocalProvider(t, b, "test") + terraform.TestStateFile(t, b.StatePath, testRefreshState()) + + p.RefreshFn = nil + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} + + op := testOperationRefresh() + op.Module = nil + + run, err := b.Operation(context.Background(), op) + if err != nil { + t.Fatalf("bad: %s", err) + } + <-run.Done() + + if !p.RefreshCalled { + t.Fatal("refresh should be called") + } + + checkState(t, b.StateOutPath, ` +test_instance.foo: + ID = yes + `) +} + +// GH-12174 +func TestLocal_refreshNilModuleWithInput(t *testing.T) { + b := TestLocal(t) + p := TestLocalProvider(t, b, "test") + terraform.TestStateFile(t, b.StatePath, testRefreshState()) + + p.RefreshFn = nil + p.RefreshReturn = &terraform.InstanceState{ID: "yes"} + + b.OpInput = true + + op := testOperationRefresh() + op.Module = nil + + run, err := b.Operation(context.Background(), op) + if err != nil { + t.Fatalf("bad: %s", err) + } + <-run.Done() + + if !p.RefreshCalled { + t.Fatal("refresh should be called") + } + + checkState(t, b.StateOutPath, ` +test_instance.foo: + ID = yes + `) +} + func TestLocal_refreshInput(t *testing.T) { b := TestLocal(t) p := TestLocalProvider(t, b, "test")