terraform: module orphans are properly expanded and planned for destroy

This commit is contained in:
Mitchell Hashimoto 2015-02-11 17:47:30 -08:00
parent ce37165c06
commit e45308fa6d
7 changed files with 111 additions and 18 deletions

View File

@ -204,8 +204,7 @@ func TestContext2Plan_moduleMultiVar(t *testing.T) {
} }
} }
/* func TestContext2Plan_moduleOrphans(t *testing.T) {
func TestContextPlan_moduleOrphans(t *testing.T) {
m := testModule(t, "plan-modules-remove") m := testModule(t, "plan-modules-remove")
p := testProvider("aws") p := testProvider("aws")
p.DiffFn = testDiffFn p.DiffFn = testDiffFn
@ -224,7 +223,7 @@ func TestContextPlan_moduleOrphans(t *testing.T) {
}, },
}, },
} }
ctx := testContext(t, &ContextOpts{ ctx := testContext2(t, &ContextOpts{
Module: m, Module: m,
Providers: map[string]ResourceProviderFactory{ Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p), "aws": testProviderFuncFixed(p),
@ -244,6 +243,7 @@ func TestContextPlan_moduleOrphans(t *testing.T) {
} }
} }
/*
func TestContextPlan_moduleProviderInherit(t *testing.T) { func TestContextPlan_moduleProviderInherit(t *testing.T) {
var l sync.Mutex var l sync.Mutex
var calls []string var calls []string

View File

@ -96,6 +96,56 @@ func (n *EvalDiff) Type() EvalType {
return EvalTypeInstanceState return EvalTypeInstanceState
} }
// EvalDiffDestroy is an EvalNode implementation that returns a plain
// destroy diff.
type EvalDiffDestroy struct {
Info *InstanceInfo
State EvalNode
Output *InstanceDiff
}
func (n *EvalDiffDestroy) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.State}, []EvalType{EvalTypeInstanceState}
}
// TODO: test
func (n *EvalDiffDestroy) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
// Extract our arguments
var state *InstanceState
if args[0] != nil {
state = args[0].(*InstanceState)
}
// Call pre-diff hook
err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PreDiff(n.Info, state)
})
if err != nil {
return nil, err
}
// The diff
diff := &InstanceDiff{Destroy: true}
// Call post-diff hook
err = ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostDiff(n.Info, diff)
})
if err != nil {
return nil, err
}
// Update our output
*n.Output = *diff
return nil, nil
}
func (n *EvalDiffDestroy) Type() EvalType {
return EvalTypeNull
}
// EvalWriteDiff is an EvalNode implementation that writes the diff to // EvalWriteDiff is an EvalNode implementation that writes the diff to
// the full diff. // the full diff.
type EvalWriteDiff struct { type EvalWriteDiff struct {

View File

@ -105,9 +105,11 @@ func (s *State) ModuleByPath(path []string) *ModuleState {
// to return the actual state. // to return the actual state.
func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string {
childrenKeys := make(map[string]struct{}) childrenKeys := make(map[string]struct{})
if c != nil {
for _, m := range c.Modules { for _, m := range c.Modules {
childrenKeys[m.Name] = struct{}{} childrenKeys[m.Name] = struct{}{}
} }
}
// Go over the direct children and find any that aren't in our // Go over the direct children and find any that aren't in our
// keys. // keys.
@ -301,6 +303,7 @@ func (m *ModuleState) Orphans(c *config.Config) []string {
keys[k] = struct{}{} keys[k] = struct{}{}
} }
if c != nil {
for _, r := range c.Resources { for _, r := range c.Resources {
delete(keys, r.Id()) delete(keys, r.Id())
@ -310,6 +313,7 @@ func (m *ModuleState) Orphans(c *config.Config) []string {
} }
} }
} }
}
result := make([]string, 0, len(keys)) result := make([]string, 0, len(keys))
for k, _ := range keys { for k, _ := range keys {

View File

@ -85,6 +85,32 @@ func TestStateModuleOrphans(t *testing.T) {
} }
} }
func TestStateModuleOrphans_nilConfig(t *testing.T) {
state := &State{
Modules: []*ModuleState{
&ModuleState{
Path: RootModulePath,
},
&ModuleState{
Path: []string{RootModuleName, "foo"},
},
&ModuleState{
Path: []string{RootModuleName, "bar"},
},
},
}
actual := state.ModuleOrphans(RootModulePath, nil)
expected := [][]string{
[]string{RootModuleName, "foo"},
[]string{RootModuleName, "bar"},
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
}
func TestInstanceState_MergeDiff(t *testing.T) { func TestInstanceState_MergeDiff(t *testing.T) {
is := InstanceState{ is := InstanceState{
ID: "foo", ID: "foo",

View File

@ -29,8 +29,7 @@ func (t *ConfigTransformer) Transform(g *Graph) error {
// Get the module we care about // Get the module we care about
module := t.Module.Child(g.Path[1:]) module := t.Module.Child(g.Path[1:])
if module == nil { if module == nil {
return fmt.Errorf( return nil
"module not found for path: %#v", g.Path[1:])
} }
// Get the configuration for this module // Get the configuration for this module

View File

@ -1,6 +1,8 @@
package terraform package terraform
import ( import (
"log"
"github.com/hashicorp/terraform/dag" "github.com/hashicorp/terraform/dag"
) )
@ -41,5 +43,19 @@ func (t *ExpandTransform) Transform(v dag.Vertex) (dag.Vertex, error) {
} }
// Expand the subgraph! // Expand the subgraph!
log.Printf("[DEBUG] vertex %s: static expanding", dag.VertexName(ev))
return ev.Expand(t.Builder) return ev.Expand(t.Builder)
} }
type GraphNodeBasicSubgraph struct {
NameValue string
Graph *Graph
}
func (n *GraphNodeBasicSubgraph) Name() string {
return n.NameValue
}
func (n *GraphNodeBasicSubgraph) Subgraph() *Graph {
return n.Graph
}

View File

@ -3,6 +3,7 @@ package terraform
import ( import (
"fmt" "fmt"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/dag" "github.com/hashicorp/terraform/dag"
) )
@ -20,13 +21,10 @@ type OrphanTransformer struct {
} }
func (t *OrphanTransformer) Transform(g *Graph) error { func (t *OrphanTransformer) Transform(g *Graph) error {
module := t.Module.Child(g.Path[1:]) var config *config.Config
if module == nil { if module := t.Module.Child(g.Path[1:]); module != nil {
panic(fmt.Sprintf( config = module.Config()
"module not found for path: %#v",
g.Path[1:]))
} }
config := module.Config()
var resourceVertexes []dag.Vertex var resourceVertexes []dag.Vertex
if state := t.State.ModuleByPath(g.Path); state != nil { if state := t.State.ModuleByPath(g.Path); state != nil {