diff --git a/terraform/context.go b/terraform/context.go index 519146d72..8ae8b7e68 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -32,7 +32,6 @@ type Context struct { providers map[string]ResourceProviderFactory provisioners map[string]ResourceProvisionerFactory variables map[string]string - defaultVars map[string]string l sync.Mutex // Lock acquired during any task parCh chan struct{} // Semaphore used to limit parallelism @@ -80,16 +79,6 @@ func NewContext(opts *ContextOpts) *Context { config = opts.Module.Config() } - // Calculate all the default variables - defaultVars := make(map[string]string) - if config != nil { - for _, v := range config.Variables { - for k, val := range v.DefaultsMap() { - defaultVars[k] = val - } - } - } - return &Context{ config: config, diff: opts.Diff, @@ -99,7 +88,6 @@ func NewContext(opts *ContextOpts) *Context { providers: opts.Providers, provisioners: opts.Provisioners, variables: opts.Variables, - defaultVars: defaultVars, parCh: parCh, sh: sh, @@ -394,10 +382,34 @@ func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc } func (c *Context) walkContext(op walkOperation, path []string) *walkContext { + // Get the config structure + m := c.module + for _, n := range path[1:] { + cs := m.Children() + m = cs[n] + } + var conf *config.Config + if m != nil { + conf = m.Config() + } + + // Calculate the default variable values + defaultVars := make(map[string]string) + if conf != nil { + for _, v := range conf.Variables { + for k, val := range v.DefaultsMap() { + defaultVars[k] = val + } + } + } + return &walkContext{ Context: c, Operation: op, Path: path, + Variables: c.variables, + + defaultVariables: defaultVars, } } @@ -408,6 +420,9 @@ type walkContext struct { Meta interface{} Operation walkOperation Path []string + Variables map[string]string + + defaultVariables map[string]string // This is only set manually by subsequent context creations // in genericWalkFunc. @@ -865,6 +880,17 @@ func (c *walkContext) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc { // Preserve the meta wc.Meta = c.Meta + // Set the variables + if m.Config != nil { + wc.Variables = make(map[string]string) + + rc := NewResourceConfig(m.Config.RawConfig) + rc.interpolate(c) + for k, v := range rc.Config { + wc.Variables[k] = v.(string) + } + } + return wc.Walk() case *GraphNodeResource: // Continue, we care about this the most @@ -1054,9 +1080,9 @@ func (c *walkContext) computeVars(raw *config.RawConfig) error { return nil } - // Start building up the variables. First, defaults + // Copy the default variables vs := make(map[string]string) - for k, v := range c.Context.defaultVars { + for k, v := range c.defaultVariables { vs[k] = v } @@ -1084,7 +1110,7 @@ func (c *walkContext) computeVars(raw *config.RawConfig) error { vs[n] = attr case *config.UserVariable: - val, ok := c.Context.variables[v.Name] + val, ok := c.Variables[v.Name] if ok { vs[n] = val continue @@ -1092,7 +1118,7 @@ func (c *walkContext) computeVars(raw *config.RawConfig) error { // Look up if we have any variables with this prefix because // those are map overrides. Include those. - for k, val := range c.Context.variables { + for k, val := range c.Variables { if strings.HasPrefix(k, v.Name+".") { vs["var."+k] = val } diff --git a/terraform/context_test.go b/terraform/context_test.go index 023a0e62d..c5c70d114 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1451,6 +1451,29 @@ func TestContextPlan_modules(t *testing.T) { } } +func TestContextPlan_moduleInput(t *testing.T) { + m := testModule(t, "plan-module-input") + p := testProvider("aws") + p.DiffFn = testDiffFn + ctx := testContext(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + plan, err := ctx.Plan(nil) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(plan.String()) + expected := strings.TrimSpace(testTerraformPlanModuleInputStr) + if actual != expected { + t.Fatalf("bad:\n%s", actual) + } +} + func TestContextPlan_moduleOrphans(t *testing.T) { m := testModule(t, "plan-modules-remove") p := testProvider("aws") diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 46a4e9f33..c37700569 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -511,6 +511,23 @@ STATE: ` +const testTerraformPlanModuleInputStr = ` +DIFF: + +CREATE: aws_instance.bar + foo: "" => "2" + type: "" => "aws_instance" + +module.child: + CREATE: aws_instance.foo + foo: "" => "42" + type: "" => "aws_instance" + +STATE: + + +` + const testTerraformPlanModuleOrphansStr = ` DIFF: diff --git a/terraform/test-fixtures/plan-module-input/child/main.tf b/terraform/test-fixtures/plan-module-input/child/main.tf new file mode 100644 index 000000000..c1a00c5a3 --- /dev/null +++ b/terraform/test-fixtures/plan-module-input/child/main.tf @@ -0,0 +1,5 @@ +variable "input" {} + +resource "aws_instance" "foo" { + foo = "${var.input}" +} diff --git a/terraform/test-fixtures/plan-module-input/main.tf b/terraform/test-fixtures/plan-module-input/main.tf new file mode 100644 index 000000000..2ad8ec0ca --- /dev/null +++ b/terraform/test-fixtures/plan-module-input/main.tf @@ -0,0 +1,8 @@ +module "child" { + input = "42" + source = "./child" +} + +resource "aws_instance" "bar" { + foo = "2" +}