core: Fix interpolation of complex structures

This commit makes two changes: map interpolation can now read flatmapped
structures, such as those present in remote state outputs, and lists are
sorted by the index instead of the value.
pull/7127/head
James Nugent 10 years ago
parent dbf725bd68
commit f51c9d5efd

@ -13,6 +13,7 @@ import (
"github.com/hashicorp/hil/ast"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/flatmap"
)
const (
@ -213,6 +214,7 @@ func (i *Interpolater) valueResourceVar(
result map[string]ast.Variable) error {
// If we're computing all dynamic fields, then module vars count
// and we mark it as computed.
if i.Operation == walkValidate {
result[n] = ast.Variable{
Value: config.UnknownVariableValue,
@ -343,6 +345,7 @@ func (i *Interpolater) valueUserVar(
func (i *Interpolater) computeResourceVariable(
scope *InterpolationScope,
v *config.ResourceVariable) (*ast.Variable, error) {
id := v.ResourceId()
if v.Multi {
id = fmt.Sprintf("%s.%d", id, v.Index)
@ -589,21 +592,19 @@ func (i *Interpolater) interpolateComplexTypeAttribute(
return unknownVariable(), nil
}
var keys []string
keys := make([]string, 0)
listElementKey := regexp.MustCompile("^" + resourceID + "\\.[0-9]+$")
for id, _ := range attributes {
if listElementKey.MatchString(id) {
keys = append(keys, id)
}
}
sort.Strings(keys)
var members []string
for _, key := range keys {
members = append(members, attributes[key])
}
// This behaviour still seems very broken to me... it retains BC but is
// probably going to cause problems in future
sort.Strings(members)
return hil.InterfaceToVariable(members)
}
@ -620,19 +621,16 @@ func (i *Interpolater) interpolateComplexTypeAttribute(
return unknownVariable(), nil
}
var keys []string
resourceFlatMap := make(map[string]string)
mapElementKey := regexp.MustCompile("^" + resourceID + "\\.([^%]+)$")
for id, _ := range attributes {
if submatches := mapElementKey.FindAllStringSubmatch(id, -1); len(submatches) > 0 {
keys = append(keys, submatches[0][1])
for id, val := range attributes {
if mapElementKey.MatchString(id) {
resourceFlatMap[id] = val
}
}
members := make(map[string]interface{})
for _, key := range keys {
members[key] = attributes[resourceID+"."+key]
}
return hil.InterfaceToVariable(members)
expanded := flatmap.Expand(resourceFlatMap, resourceID)
return hil.InterfaceToVariable(expanded)
}
return ast.Variable{}, fmt.Errorf("No complex type %s found", resourceID)

@ -141,6 +141,95 @@ func TestInterpolater_pathRoot(t *testing.T) {
})
}
func TestInterpolater_resourceVariableMap(t *testing.T) {
lock := new(sync.RWMutex)
state := &State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.web": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "bar",
Attributes: map[string]string{
"amap.%": "3",
"amap.key1": "value1",
"amap.key2": "value2",
"amap.key3": "value3",
},
},
},
},
},
},
}
i := &Interpolater{
Module: testModule(t, "interpolate-resource-variable"),
State: state,
StateLock: lock,
}
scope := &InterpolationScope{
Path: rootModulePath,
}
expected := map[string]interface{}{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
testInterpolate(t, i, scope, "aws_instance.web.amap",
interfaceToVariableSwallowError(expected))
}
func TestInterpolater_resourceVariableComplexMap(t *testing.T) {
lock := new(sync.RWMutex)
state := &State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.web": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "bar",
Attributes: map[string]string{
"amap.%": "2",
"amap.key1.#": "2",
"amap.key1.0": "hello",
"amap.key1.1": "world",
"amap.key2.#": "1",
"amap.key2.0": "foo",
},
},
},
},
},
},
}
i := &Interpolater{
Module: testModule(t, "interpolate-resource-variable"),
State: state,
StateLock: lock,
}
scope := &InterpolationScope{
Path: rootModulePath,
}
expected := map[string]interface{}{
"key1": []interface{}{"hello", "world"},
"key2": []interface{}{"foo"},
}
testInterpolate(t, i, scope, "aws_instance.web.amap",
interfaceToVariableSwallowError(expected))
}
func TestInterpolater_resourceVariable(t *testing.T) {
lock := new(sync.RWMutex)
state := &State{
@ -278,10 +367,10 @@ func TestInterpolator_resourceMultiAttributes(t *testing.T) {
lock := new(sync.RWMutex)
state := &State{
Modules: []*ModuleState{
&ModuleState{
{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_route53_zone.yada": &ResourceState{
"aws_route53_zone.yada": {
Type: "aws_route53_zone",
Dependencies: []string{},
Primary: &InstanceState{
@ -354,8 +443,8 @@ func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) {
"ns-601.awsdns-11.net",
"ns-000.awsdns-38.org",
"ns-444.awsdns-18.co.uk",
"ns-666.awsdns-11.net",
"ns-999.awsdns-62.com",
"ns-666.awsdns-11.net",
}
// More than 1 element

Loading…
Cancel
Save