diff --git a/terraform/context.go b/terraform/context.go index d0777142aa..598c63eb14 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -381,8 +381,11 @@ func (c *Context) computeResourceVariable( v.FullKey()) } - attr, ok := r.Primary.Attributes[v.Field] - if ok { + if r.Primary == nil { + goto MISSING + } + + if attr, ok := r.Primary.Attributes[v.Field]; ok { return attr, nil } @@ -390,8 +393,7 @@ func (c *Context) computeResourceVariable( // and see if anything along the way is a computed set. i.e. if // we have "foo.0.bar" as the field, check to see if "foo" is // a computed list. If so, then the whole thing is computed. - parts := strings.Split(v.Field, ".") - if len(parts) > 1 { + if parts := strings.Split(v.Field, "."); len(parts) > 1 { for i := 1; i < len(parts); i++ { key := fmt.Sprintf("%s.#", strings.Join(parts[:i], ".")) if attr, ok := r.Primary.Attributes[key]; ok { @@ -400,6 +402,7 @@ func (c *Context) computeResourceVariable( } } +MISSING: return "", fmt.Errorf( "Resource '%s' does not have attribute '%s' "+ "for variable '%s'", @@ -448,6 +451,10 @@ func (c *Context) computeResourceMultiVariable( continue } + if r.Primary == nil { + continue + } + attr, ok := r.Primary.Attributes[v.Field] if !ok { continue @@ -854,7 +861,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { } r := rn.Resource - if r.State.Primary.ID != "" { + if r.State.Primary != nil && r.State.Primary.ID != "" { log.Printf("[DEBUG] %s: Making for destroy", r.Id) l.Lock() @@ -870,7 +877,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc { func (c *Context) refreshWalkFn() depgraph.WalkFunc { cb := func(r *Resource) error { - if r.State.Primary.ID == "" { + if r.State.Primary == nil || r.State.Primary.ID == "" { log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) return nil } @@ -899,7 +906,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc { // TODO: Handle other moduels mod := c.state.RootModule() - if rs.Primary.ID == "" { + if len(rs.Tainted) == 0 && (rs.Primary == nil || rs.Primary.ID == "") { delete(mod.Resources, r.Id) } else { mod.Resources[r.Id] = rs diff --git a/terraform/context_test.go b/terraform/context_test.go index 1dbbc7d9bd..9c1021711c 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1543,6 +1543,7 @@ func TestContextPlan_countDecreaseToOne(t *testing.T) { s := &State{ Modules: []*ModuleState{ &ModuleState{ + Path: rootModulePath, Resources: map[string]*ResourceState{ "aws_instance.foo.0": &ResourceState{ Type: "aws_instance", diff --git a/terraform/graph.go b/terraform/graph.go index ef09fc707d..f5e7babd94 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -189,13 +189,12 @@ func graphAddConfigResources( } tainted := false - var mod *ModuleState var state *ResourceState - if s != nil { - // TODO: Handle non-root modules - mod = s.RootModule() + // TODO: Handle non-root modules + mod := s.ModuleByPath(rootModulePath) + if s != nil && mod != nil { // Lookup the resource state state = mod.Resources[name] if state == nil { @@ -511,7 +510,10 @@ func graphAddMissingResourceProviders( // graphAddOrphans adds the orphans to the graph. func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { // TODO: Handle other modules - mod := s.RootModule() + mod := s.ModuleByPath(rootModulePath) + if mod == nil { + return + } for _, k := range mod.Orphans(c) { rs := mod.Resources[k] noun := &depgraph.Noun{ diff --git a/terraform/state.go b/terraform/state.go index 2a201a5a7f..0ea366610f 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -42,6 +42,9 @@ func (s *State) ModuleByPath(path []string) *ModuleState { return nil } for _, mod := range s.Modules { + if mod.Path == nil { + panic("missing module path") + } if reflect.DeepEqual(mod.Path, path) { return mod }