diff --git a/terraform/context.go b/terraform/context.go index 13527ef42..922cc3627 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -463,11 +463,6 @@ func (c *walkContext) Walk() error { return err } - // If we're not applying, we're done. - if c.Operation != walkApply { - return nil - } - // We did an apply, so we need to calculate the outputs. If we have no // outputs, then we're done. m := c.Context.module @@ -475,6 +470,9 @@ func (c *walkContext) Walk() error { cs := m.Children() m = cs[n] } + if m == nil { + return nil + } config := m.Config() if len(config.Outputs) == 0 { return nil @@ -483,7 +481,10 @@ func (c *walkContext) Walk() error { // Likewise, if we have no resources in our state, we're done. This // guards against the case that we destroyed. mod := c.Context.state.ModuleByPath(c.Path) - mod.prune() + if c.Operation == walkApply { + // On Apply, we prune so that we don't do outputs if we destroyed + mod.prune() + } if len(mod.Resources) == 0 { return nil } @@ -493,7 +494,10 @@ func (c *walkContext) Walk() error { if err := c.computeVars(o.RawConfig); err != nil { return err } - outputs[o.Name] = o.RawConfig.Config()["value"].(string) + vraw := o.RawConfig.Config()["value"] + if vraw != nil { + outputs[o.Name] = vraw.(string) + } } // Assign the outputs to the root module @@ -1052,6 +1056,13 @@ func (c *walkContext) computeVars(raw *config.RawConfig) error { // Next, the actual computed variables for n, rawV := range raw.Variables { switch v := rawV.(type) { + case *config.ModuleVariable: + value, err := c.computeModuleVariable(v) + if err != nil { + return err + } + + vs[n] = value case *config.ResourceVariable: var attr string var err error @@ -1086,6 +1097,37 @@ func (c *walkContext) computeVars(raw *config.RawConfig) error { return raw.Interpolate(vs) } +func (c *walkContext) computeModuleVariable( + v *config.ModuleVariable) (string, error) { + // Build the path to our child + path := make([]string, len(c.Path), len(c.Path)+1) + copy(path, c.Path) + path = append(path, v.Name) + + // Grab some locks + c.Context.sl.RLock() + defer c.Context.sl.RUnlock() + + // Get that module from our state + mod := c.Context.state.ModuleByPath(path) + if mod == nil { + return "", fmt.Errorf( + "Module '%s' not found for variable '%s'", + strings.Join(path[1:], "."), + v.FullKey()) + } + + value, ok := mod.Outputs[v.Field] + if !ok { + return "", fmt.Errorf( + "Output field '%s' not found for variable '%s'", + v.Field, + v.FullKey()) + } + + return value, nil +} + func (c *walkContext) computeResourceVariable( v *config.ResourceVariable) (string, error) { id := v.ResourceId() @@ -1097,8 +1139,7 @@ func (c *walkContext) computeResourceVariable( defer c.Context.sl.RUnlock() // Get the relevant module - // TODO: Not use only root module - module := c.Context.state.RootModule() + module := c.Context.state.ModuleByPath(c.Path) r, ok := module.Resources[id] if !ok { diff --git a/terraform/context_test.go b/terraform/context_test.go index 9beb709ff..cb12b9cb3 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1491,7 +1491,6 @@ func TestContextPlan_moduleOrphans(t *testing.T) { } func TestContextPlan_moduleVar(t *testing.T) { - t.Skip() m := testModule(t, "plan-module-var") p := testProvider("aws") p.DiffFn = testDiffFn @@ -1508,7 +1507,7 @@ func TestContextPlan_moduleVar(t *testing.T) { } actual := strings.TrimSpace(plan.String()) - expected := strings.TrimSpace(testTerraformPlanModulesStr) + expected := strings.TrimSpace(testTerraformPlanModuleVarStr) if actual != expected { t.Fatalf("bad:\n%s", actual) } diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 13433d9b3..1215eb2f0 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -528,6 +528,23 @@ module.child: ID = baz ` +const testTerraformPlanModuleVarStr = ` +DIFF: + +CREATE: aws_instance.bar + foo: "" => "2" + type: "" => "aws_instance" + +module.child: + CREATE: aws_instance.foo + num: "" => "2" + type: "" => "aws_instance" + +STATE: + + +` + const testTerraformPlanOrphanStr = ` DIFF: