From 0d1debc0ae78e1512b377856960afd1b97196c55 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 9 May 2016 13:39:34 -0700 Subject: [PATCH] terraform: import verifies the refresh results in non-nil state /cc @jen20 --- terraform/context_import_test.go | 38 +++++++++++++++++++++++++++++ terraform/eval_import_state.go | 23 +++++++++++++++++ terraform/transform_import_state.go | 7 +++++- 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/terraform/context_import_test.go b/terraform/context_import_test.go index 6b1512a61..b9810c9c0 100644 --- a/terraform/context_import_test.go +++ b/terraform/context_import_test.go @@ -163,6 +163,44 @@ func TestContextImport_refresh(t *testing.T) { } } +func TestContextImport_refreshNil(t *testing.T) { + p := testProvider("aws") + ctx := testContext2(t, &ContextOpts{ + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + p.ImportStateReturn = []*InstanceState{ + &InstanceState{ + ID: "foo", + Ephemeral: EphemeralState{Type: "aws_instance"}, + }, + } + + p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { + return nil, nil + } + + state, err := ctx.Import(&ImportOpts{ + Targets: []*ImportTarget{ + &ImportTarget{ + Addr: "aws_instance.foo", + ID: "bar", + }, + }, + }) + if err == nil { + t.Fatal("should error") + } + + actual := strings.TrimSpace(state.String()) + expected := "" + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + func TestContextImport_module(t *testing.T) { p := testProvider("aws") ctx := testContext2(t, &ContextOpts{ diff --git a/terraform/eval_import_state.go b/terraform/eval_import_state.go index e2cc41dde..62cc581fa 100644 --- a/terraform/eval_import_state.go +++ b/terraform/eval_import_state.go @@ -51,3 +51,26 @@ func (n *EvalImportState) Eval(ctx EvalContext) (interface{}, error) { return nil, nil } + +// EvalImportStateVerify verifies the state after ImportState and +// after the refresh to make sure it is non-nil and valid. +type EvalImportStateVerify struct { + Info *InstanceInfo + Id string + State **InstanceState +} + +// TODO: test +func (n *EvalImportStateVerify) Eval(ctx EvalContext) (interface{}, error) { + state := *n.State + if state.Empty() { + return nil, fmt.Errorf( + "import %s (id: %s): Terraform detected a resource with this ID doesn't\n"+ + "exist. Please verify the ID is correct. You cannot import non-existent\n"+ + "resources using Terraform import.", + n.Info.HumanId(), + n.Id) + } + + return nil, nil +} diff --git a/terraform/transform_import_state.go b/terraform/transform_import_state.go index 4fd9363cd..2324aea0f 100644 --- a/terraform/transform_import_state.go +++ b/terraform/transform_import_state.go @@ -195,7 +195,7 @@ func (n *graphNodeImportStateSub) EvalTree() EvalNode { // Build the resource info info := &InstanceInfo{ - Id: n.State.ID, + Id: fmt.Sprintf("%s.%s", n.Target.Type, n.Target.Name), ModulePath: n.Path_, Type: n.State.Ephemeral.Type, } @@ -221,6 +221,11 @@ func (n *graphNodeImportStateSub) EvalTree() EvalNode { Info: info, Output: &state, }, + &EvalImportStateVerify{ + Info: info, + Id: n.State.ID, + State: &state, + }, &EvalWriteState{ Name: key.String(), ResourceType: info.Type,