diff --git a/terraform/eval_context_builtin.go b/terraform/eval_context_builtin.go index f7cdf27cc..a25c1c6a1 100644 --- a/terraform/eval_context_builtin.go +++ b/terraform/eval_context_builtin.go @@ -168,14 +168,32 @@ func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} { ctx.ProviderLock.Lock() defer ctx.ProviderLock.Unlock() - return ctx.ProviderInputConfig[n] + // Make a copy of the path so we can safely edit it + path := ctx.Path() + pathCopy := make([]string, len(path)+1) + copy(pathCopy, path) + + // Go up the tree. + for i := len(path) - 1; i >= 0; i-- { + pathCopy[i+1] = n + k := PathCacheKey(pathCopy[:i+2]) + if v, ok := ctx.ProviderInputConfig[k]; ok { + return v + } + } + + return nil } func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) { - ctx.ProviderLock.Lock() - defer ctx.ProviderLock.Unlock() + providerPath := make([]string, len(ctx.Path())+1) + copy(providerPath, ctx.Path()) + providerPath[len(providerPath)-1] = n - ctx.ProviderInputConfig[n] = c + // Save the configuration + ctx.ProviderLock.Lock() + ctx.ProviderInputConfig[PathCacheKey(providerPath)] = c + ctx.ProviderLock.Unlock() } func (ctx *BuiltinEvalContext) ParentProviderConfig(n string) *ResourceConfig { diff --git a/terraform/eval_context_builtin_test.go b/terraform/eval_context_builtin_test.go new file mode 100644 index 000000000..4d07e75e0 --- /dev/null +++ b/terraform/eval_context_builtin_test.go @@ -0,0 +1,42 @@ +package terraform + +import ( + "reflect" + "sync" + "testing" +) + +func TestBuiltinEvalContextProviderInput(t *testing.T) { + var lock sync.Mutex + cache := make(map[string]map[string]interface{}) + + ctx1 := testBuiltinEvalContext(t) + ctx1.PathValue = []string{"root"} + ctx1.ProviderInputConfig = cache + ctx1.ProviderLock = &lock + + ctx2 := testBuiltinEvalContext(t) + ctx2.PathValue = []string{"root", "child"} + ctx2.ProviderInputConfig = cache + ctx2.ProviderLock = &lock + + expected1 := map[string]interface{}{"value": "foo"} + ctx1.SetProviderInput("foo", expected1) + + expected2 := map[string]interface{}{"value": "bar"} + ctx2.SetProviderInput("foo", expected2) + + actual1 := ctx1.ProviderInput("foo") + actual2 := ctx2.ProviderInput("foo") + + if !reflect.DeepEqual(actual1, expected1) { + t.Fatalf("bad: %#v %#v", actual1, expected1) + } + if !reflect.DeepEqual(actual2, expected2) { + t.Fatalf("bad: %#v %#v", actual2, expected2) + } +} + +func testBuiltinEvalContext(t *testing.T) *BuiltinEvalContext { + return &BuiltinEvalContext{} +}