diff --git a/terraform/context_import_test.go b/terraform/context_import_test.go index c5611272a..5649ba64b 100644 --- a/terraform/context_import_test.go +++ b/terraform/context_import_test.go @@ -319,6 +319,48 @@ func TestContextImport_multiState(t *testing.T) { } } +func TestContextImport_multiStateSame(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"}, + }, + &InstanceState{ + ID: "bar", + Ephemeral: EphemeralState{Type: "aws_instance_thing"}, + }, + &InstanceState{ + ID: "qux", + Ephemeral: EphemeralState{Type: "aws_instance_thing"}, + }, + } + + state, err := ctx.Import(&ImportOpts{ + Targets: []*ImportTarget{ + &ImportTarget{ + Addr: "aws_instance.foo", + ID: "bar", + }, + }, + }) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(testImportMultiSameStr) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + const testImportStr = ` aws_instance.foo: ID = foo @@ -369,6 +411,18 @@ aws_instance_thing.foo: provider = aws ` +const testImportMultiSameStr = ` +aws_instance.foo: + ID = foo + provider = aws +aws_instance_thing.foo: + ID = bar + provider = aws +aws_instance_thing.foo-1: + ID = qux + provider = aws +` + const testImportRefreshStr = ` aws_instance.foo: ID = foo diff --git a/terraform/transform_import_state.go b/terraform/transform_import_state.go index f99af7c64..37eee274d 100644 --- a/terraform/transform_import_state.go +++ b/terraform/transform_import_state.go @@ -91,13 +91,39 @@ func (n *graphNodeImportState) EvalTree() EvalNode { func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) { g := &Graph{Path: ctx.Path()} + // nameCounter is used to de-dup names in the state. + nameCounter := make(map[string]int) + + // Compile the list of addresses that we'll be inserting into the state. + // We do this ahead of time so we can verify that we aren't importing + // something that already exists. + addrs := make([]*ResourceAddress, len(n.states)) + for i, state := range n.states { + addr := *n.Addr + if t := state.Ephemeral.Type; t != "" { + addr.Type = t + } + + // Determine if we need to suffix the name to de-dup + key := addr.String() + count, ok := nameCounter[key] + if ok { + count++ + addr.Name += fmt.Sprintf("-%d", count) + } + nameCounter[key] = count + + // Add it to our list + addrs[i] = &addr + } + // For each of the states, we add a node to handle the refresh/add to state. // "n.states" is populated by our own EvalTree with the result of // ImportState. Since DynamicExpand is always called after EvalTree, this // is safe. - for _, state := range n.states { + for i, state := range n.states { g.Add(&graphNodeImportStateSub{ - Target: n.Addr, + Target: addrs[i], Path_: n.Path(), State: state, })