From 96a04c16f6a182804af7f709dc367538464e88b5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 19 Jul 2015 13:41:57 -0700 Subject: [PATCH] terraform: state ModuleOrphans should return grandchild orphans --- terraform/state.go | 33 ++++++++++++++++++++++++++++++--- terraform/state_test.go | 22 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index d3b19c9de..520988668 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -111,17 +111,44 @@ func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { } } - // Go over the direct children and find any that aren't in our - // keys. + // Go over the direct children and find any that aren't in our keys. var orphans [][]string + direct := make(map[string]struct{}, len(childrenKeys)) for _, m := range s.Children(path) { - if _, ok := childrenKeys[m.Path[len(m.Path)-1]]; ok { + key := m.Path[len(m.Path)-1] + if _, ok := childrenKeys[key]; ok { continue } + // Record that we found this key as a direct child. We use this + // later to find orphan nested modules. + direct[key] = struct{}{} + orphans = append(orphans, m.Path) } + // Find the orphans that are nested... + for _, m := range s.Modules { + // We only want modules that are at least grandchildren + if len(m.Path) < len(path)+2 { + continue + } + + // If it isn't part of our tree, continue + if !reflect.DeepEqual(path, m.Path[:len(path)]) { + continue + } + + // If we have the direct child, then just skip it. + key := m.Path[len(m.Path)-1] + if _, ok := direct[key]; ok { + continue + } + + // Add this orphan + orphans = append(orphans, m.Path[:len(path)+1]) + } + return orphans } diff --git a/terraform/state_test.go b/terraform/state_test.go index 7f3dbb567..eeb974d0b 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -85,6 +85,28 @@ func TestStateModuleOrphans(t *testing.T) { } } +func TestStateModuleOrphans_nested(t *testing.T) { + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: RootModulePath, + }, + &ModuleState{ + Path: []string{RootModuleName, "foo", "bar"}, + }, + }, + } + + actual := state.ModuleOrphans(RootModulePath, nil) + expected := [][]string{ + []string{RootModuleName, "foo"}, + } + + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: %#v", actual) + } +} + func TestStateModuleOrphans_nilConfig(t *testing.T) { state := &State{ Modules: []*ModuleState{