From 99d0266585cc5b8d14637242fbc1ac72d3d2ad78 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 25 May 2021 17:06:25 -0400 Subject: [PATCH] return error for invalid resource import Most legacy provider resources do not implement any import functionality other than returning an empty object with the given ID, relying on core to later read that resource and obtain the complete state. Because of this, we need to check the response from ReadResource for a null value, and use that as an indication the import id was invalid. --- internal/terraform/transform_import_state.go | 19 +++++++ .../terraform/transform_import_state_test.go | 53 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/internal/terraform/transform_import_state.go b/internal/terraform/transform_import_state.go index c86870ed4..3aa53e22d 100644 --- a/internal/terraform/transform_import_state.go +++ b/internal/terraform/transform_import_state.go @@ -282,6 +282,25 @@ func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) (di return diags } + // Verify the existance of the imported resource + if state.Value.IsNull() { + var diags tfdiags.Diagnostics + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Cannot import non-existent remote object", + fmt.Sprintf( + "While attempting to import an existing object to %q, "+ + "the provider detected that no object exists with the given id. "+ + "Only pre-existing objects can be imported; check that the id "+ + "is correct and that it is associated with the provider's "+ + "configured region or endpoint, or use \"terraform apply\" to "+ + "create a new remote object for this resource.", + n.TargetAddr, + ), + )) + return diags + } + diags = diags.Append(riNode.writeResourceInstanceState(ctx, state, workingState)) return diags } diff --git a/internal/terraform/transform_import_state_test.go b/internal/terraform/transform_import_state_test.go index c58c243f9..8199dc226 100644 --- a/internal/terraform/transform_import_state_test.go +++ b/internal/terraform/transform_import_state_test.go @@ -1,6 +1,7 @@ package terraform import ( + "fmt" "strings" "testing" @@ -112,3 +113,55 @@ func TestGraphNodeImportStateSubExecute(t *testing.T) { t.Fatalf("bad state after import: \n%s", actual) } } + +func TestGraphNodeImportStateSubExecuteNull(t *testing.T) { + state := states.NewState() + provider := testProvider("aws") + provider.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { + // return null indicating that the requested resource does not exist + resp.NewState = cty.NullVal(cty.Object(map[string]cty.Type{ + "id": cty.String, + })) + return resp + } + + ctx := &MockEvalContext{ + StateState: state.SyncWrapper(), + ProviderProvider: provider, + ProviderSchemaSchema: &ProviderSchema{ + ResourceTypes: map[string]*configschema.Block{ + "aws_instance": { + Attributes: map[string]*configschema.Attribute{ + "id": { + Type: cty.String, + Computed: true, + }, + }, + }, + }, + }, + } + + importedResource := providers.ImportedResource{ + TypeName: "aws_instance", + State: cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}), + } + + node := graphNodeImportStateSub{ + TargetAddr: addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "aws_instance", + Name: "foo", + }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), + State: importedResource, + ResolvedProvider: addrs.AbsProviderConfig{ + Provider: addrs.NewDefaultProvider("aws"), + Module: addrs.RootModule, + }, + } + diags := node.Execute(ctx, walkImport) + if !diags.HasErrors() { + t.Fatal("expected error for non-existent resource") + } + fmt.Println(diags.ErrWithWarnings()) +}