diff --git a/terraform/state.go b/terraform/state.go index 89a404847..1818364b6 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -1089,7 +1089,7 @@ func (m *ModuleState) Orphans(c *config.Config) []string { defer m.Unlock() keys := make(map[string]struct{}) - for k, _ := range m.Resources { + for k := range m.Resources { keys[k] = struct{}{} } @@ -1097,7 +1097,7 @@ func (m *ModuleState) Orphans(c *config.Config) []string { for _, r := range c.Resources { delete(keys, r.Id()) - for k, _ := range keys { + for k := range keys { if strings.HasPrefix(k, r.Id()+".") { delete(keys, k) } @@ -1106,7 +1106,32 @@ func (m *ModuleState) Orphans(c *config.Config) []string { } result := make([]string, 0, len(keys)) - for k, _ := range keys { + for k := range keys { + result = append(result, k) + } + + return result +} + +// OrphanOutputs returns a list of outputs that are in the State but aren't +// present in the configuration itself. +func (m *ModuleState) OrphanOutputs(c *config.Config) []string { + m.Lock() + defer m.Unlock() + + keys := make(map[string]struct{}) + for k := range m.Outputs { + keys[k] = struct{}{} + } + + if c != nil { + for _, o := range c.Outputs { + delete(keys, o.Name) + } + } + + result := make([]string, 0, len(keys)) + for k := range keys { result = append(result, k) } diff --git a/terraform/transform_orphan_output.go b/terraform/transform_orphan_output.go index 49568d5bc..f27472dc2 100644 --- a/terraform/transform_orphan_output.go +++ b/terraform/transform_orphan_output.go @@ -21,43 +21,32 @@ func (t *OrphanOutputTransformer) Transform(g *Graph) error { return nil } - return t.transform(g, t.Module) -} - -func (t *OrphanOutputTransformer) transform(g *Graph, m *module.Tree) error { - // Get our configuration, and recurse into children - var c *config.Config - if m != nil { - c = m.Config() - for _, child := range m.Children() { - if err := t.transform(g, child); err != nil { - return err - } + for _, ms := range t.State.Modules { + if err := t.transform(g, ms); err != nil { + return err } } + return nil +} - // Get the state. If there is no state, then we have no orphans! - path := normalizeModulePath(m.Path()) - state := t.State.ModuleByPath(path) - if state == nil { +func (t *OrphanOutputTransformer) transform(g *Graph, ms *ModuleState) error { + if ms == nil { return nil } - // Make a map of the valid outputs - valid := make(map[string]struct{}) - for _, o := range c.Outputs { - valid[o.Name] = struct{}{} + path := normalizeModulePath(ms.Path) + + // Get the config for this path, which is nil if the entire module has been + // removed. + var c *config.Config + if m := t.Module.Child(path[1:]); m != nil { + c = m.Config() } - // Go through the outputs and find the ones that aren't in our config. - for n, _ := range state.Outputs { - // If it is in the valid map, then ignore - if _, ok := valid[n]; ok { - continue - } - - // Orphan! + // add all the orphaned outputs to the graph + for _, n := range ms.OrphanOutputs(c) { g.Add(&NodeOutputOrphan{OutputName: n, PathValue: path}) + } return nil