terraform: provider input should be scoped by path

The provider input before wasn't scoped by path, which caused
non-descendant parts of the graph to grab the configuration of another
sub-tree. The result is that you'd often get copied provider
configurations across the module barriers.

See GH-2024
This commit is contained in:
Mitchell Hashimoto 2015-06-24 09:34:21 -07:00
parent cddd54c3de
commit d0519f226d
2 changed files with 64 additions and 4 deletions

View File

@ -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 {

View File

@ -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{}
}