terraform: error if import with collision

This commit is contained in:
Mitchell Hashimoto 2016-04-30 17:53:48 -05:00
parent c814d36333
commit 33bbf09ff6
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
3 changed files with 81 additions and 3 deletions

View File

@ -48,12 +48,12 @@ func (c *Context) Import(opts *ImportOpts) (*State, error) {
// Build the graph! // Build the graph!
graph, err := builder.Build(RootModulePath) graph, err := builder.Build(RootModulePath)
if err != nil { if err != nil {
return nil, err return c.state, err
} }
// Walk it // Walk it
if _, err := c.walk(graph, walkImport); err != nil { if _, err := c.walk(graph, walkImport); err != nil {
return nil, err return c.state, err
} }
// Clean the state // Clean the state

View File

@ -39,6 +39,56 @@ func TestContextImport_basic(t *testing.T) {
} }
} }
func TestContextImport_collision(t *testing.T) {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
State: &State{
Modules: []*ModuleState{
&ModuleState{
Path: []string{"root"},
Resources: map[string]*ResourceState{
"aws_instance.foo": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "bar",
},
},
},
},
},
},
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
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(testImportCollisionStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_missingType(t *testing.T) { func TestContextImport_missingType(t *testing.T) {
p := testProvider("aws") p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{ ctx := testContext2(t, &ContextOpts{
@ -66,7 +116,7 @@ func TestContextImport_missingType(t *testing.T) {
} }
actual := strings.TrimSpace(state.String()) actual := strings.TrimSpace(state.String())
expected := "<nil>" expected := "<no state>"
if actual != expected { if actual != expected {
t.Fatalf("bad: \n%s", actual) t.Fatalf("bad: \n%s", actual)
} }
@ -367,6 +417,11 @@ aws_instance.foo:
provider = aws provider = aws
` `
const testImportCollisionStr = `
aws_instance.foo:
ID = bar
`
const testImportModuleStr = ` const testImportModuleStr = `
<no state> <no state>
module.foo: module.foo:

View File

@ -117,6 +117,29 @@ func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
addrs[i] = &addr addrs[i] = &addr
} }
// Verify that all the addresses are clear
state, lock := ctx.State()
lock.RLock()
defer lock.RUnlock()
filter := &StateFilter{State: state}
for _, addr := range addrs {
result, err := filter.Filter(addr.String())
if err != nil {
return nil, fmt.Errorf("Error verifying address %s: %s", addr, err)
}
// Go through the filter results and it is an error if we find
// a matching InstanceState, meaning that we would have a collision.
for _, r := range result {
if _, ok := r.Value.(*InstanceState); ok {
return nil, fmt.Errorf(
"Can't import %s, would collide with an existing resource.\n\n"+
"Please remove or rename this resource before continuing.",
addr)
}
}
}
// For each of the states, we add a node to handle the refresh/add to state. // 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 // "n.states" is populated by our own EvalTree with the result of
// ImportState. Since DynamicExpand is always called after EvalTree, this // ImportState. Since DynamicExpand is always called after EvalTree, this