diff --git a/terraform/interpolate.go b/terraform/interpolate.go index 870fac762..b42ca8211 100644 --- a/terraform/interpolate.go +++ b/terraform/interpolate.go @@ -493,7 +493,8 @@ func (i *Interpolater) computeResourceMultiVariable( if module == nil || len(module.Resources) == 0 { return &unknownVariable, nil } - var values []string + + var values []interface{} for j := 0; j < count; j++ { id := fmt.Sprintf("%s.%d", v.ResourceId(), j) @@ -521,9 +522,10 @@ func (i *Interpolater) computeResourceMultiVariable( continue } - // computed list attribute - _, ok = r.Primary.Attributes[v.Field+".#"] - if !ok { + // computed list or map attribute + _, isList := r.Primary.Attributes[v.Field+".#"] + _, isMap := r.Primary.Attributes[v.Field+".%"] + if !(isList || isMap) { continue } multiAttr, err := i.interpolateComplexTypeAttribute(v.Field, r.Primary.Attributes) @@ -535,14 +537,7 @@ func (i *Interpolater) computeResourceMultiVariable( return &ast.Variable{Type: ast.TypeString, Value: ""}, nil } - for _, element := range multiAttr.Value.([]ast.Variable) { - strVal := element.Value.(string) - if strVal == config.UnknownVariableValue { - return &unknownVariable, nil - } - - values = append(values, strVal) - } + values = append(values, multiAttr) } if len(values) == 0 { @@ -595,7 +590,7 @@ func (i *Interpolater) interpolateComplexTypeAttribute( keys := make([]string, 0) listElementKey := regexp.MustCompile("^" + resourceID + "\\.[0-9]+$") - for id, _ := range attributes { + for id := range attributes { if listElementKey.MatchString(id) { keys = append(keys, id) } diff --git a/terraform/interpolate_test.go b/terraform/interpolate_test.go index 8012e16af..65d716c2e 100644 --- a/terraform/interpolate_test.go +++ b/terraform/interpolate_test.go @@ -449,11 +449,11 @@ func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) { // More than 1 element testInterpolate(t, i, scope, "aws_route53_zone.terra.0.name_servers", - interfaceToVariableSwallowError(name_servers[0:4])) + interfaceToVariableSwallowError(name_servers[:4])) // More than 1 element in both testInterpolate(t, i, scope, "aws_route53_zone.terra.*.name_servers", - interfaceToVariableSwallowError(name_servers)) + interfaceToVariableSwallowError([]interface{}{name_servers[:4], name_servers[4:]})) // Exactly 1 element testInterpolate(t, i, scope, "aws_route53_zone.terra.0.listeners", @@ -461,7 +461,7 @@ func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) { // Exactly 1 element in both testInterpolate(t, i, scope, "aws_route53_zone.terra.*.listeners", - interfaceToVariableSwallowError([]interface{}{"red", "blue"})) + interfaceToVariableSwallowError([]interface{}{[]interface{}{"red"}, []interface{}{"blue"}})) // Zero elements testInterpolate(t, i, scope, "aws_route53_zone.terra.0.nothing", @@ -469,7 +469,7 @@ func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) { // Zero + 1 element testInterpolate(t, i, scope, "aws_route53_zone.terra.*.special", - interfaceToVariableSwallowError([]interface{}{"extra"})) + interfaceToVariableSwallowError([]interface{}{[]interface{}{"extra"}})) // Maps still need to work testInterpolate(t, i, scope, "aws_route53_zone.terra.0.tags.Name", ast.Variable{ diff --git a/vendor/github.com/hashicorp/hil/convert.go b/vendor/github.com/hashicorp/hil/convert.go index 738e719ff..b7bff7544 100644 --- a/vendor/github.com/hashicorp/hil/convert.go +++ b/vendor/github.com/hashicorp/hil/convert.go @@ -42,6 +42,10 @@ func hilMapstructureWeakDecode(m interface{}, rawVal interface{}) error { } func InterfaceToVariable(input interface{}) (ast.Variable, error) { + if inputVariable, ok := input.(ast.Variable); ok { + return inputVariable, nil + } + var stringVal string if err := hilMapstructureWeakDecode(input, &stringVal); err == nil { return ast.Variable{ @@ -86,3 +90,59 @@ func InterfaceToVariable(input interface{}) (ast.Variable, error) { return ast.Variable{}, fmt.Errorf("value for conversion must be a string, interface{} or map[string]interface: got %T", input) } + +func VariableToInterface(input ast.Variable) (interface{}, error) { + if input.Type == ast.TypeString { + if inputStr, ok := input.Value.(string); ok { + return inputStr, nil + } else { + return nil, fmt.Errorf("ast.Variable with type string has value which is not a string") + } + } + + if input.Type == ast.TypeList { + inputList, ok := input.Value.([]ast.Variable) + if !ok { + return nil, fmt.Errorf("ast.Variable with type list has value which is not a []ast.Variable") + } + + result := make([]interface{}, 0) + if len(inputList) == 0 { + return result, nil + } + + for _, element := range inputList { + if convertedElement, err := VariableToInterface(element); err == nil { + result = append(result, convertedElement) + } else { + return nil, err + } + } + + return result, nil + } + + if input.Type == ast.TypeMap { + inputMap, ok := input.Value.(map[string]ast.Variable) + if !ok { + return nil, fmt.Errorf("ast.Variable with type map has value which is not a map[string]ast.Variable") + } + + result := make(map[string]interface{}, 0) + if len(inputMap) == 0 { + return result, nil + } + + for key, value := range inputMap { + if convertedValue, err := VariableToInterface(value); err == nil { + result[key] = convertedValue + } else { + return nil, err + } + } + + return result, nil + } + + return nil, fmt.Errorf("Find") +} diff --git a/vendor/github.com/hashicorp/hil/eval.go b/vendor/github.com/hashicorp/hil/eval.go index f5537312e..173c67f5a 100644 --- a/vendor/github.com/hashicorp/hil/eval.go +++ b/vendor/github.com/hashicorp/hil/eval.go @@ -63,15 +63,23 @@ func Eval(root ast.Node, config *EvalConfig) (EvaluationResult, error) { switch outputType { case ast.TypeList: + val, err := VariableToInterface(ast.Variable{ + Type: ast.TypeList, + Value: output, + }) return EvaluationResult{ Type: TypeList, - Value: hilListToGoSlice(output.([]ast.Variable)), - }, nil + Value: val, + }, err case ast.TypeMap: + val, err := VariableToInterface(ast.Variable{ + Type: ast.TypeMap, + Value: output, + }) return EvaluationResult{ - Type: TypeMap, - Value: hilMapToGoMap(output.(map[string]ast.Variable)), - }, nil + Type: TypeMap, + Value: val, + }, err case ast.TypeString: return EvaluationResult{ Type: TypeString, @@ -337,32 +345,6 @@ func (v *evalIndex) evalMapIndex(variableName string, target interface{}, key in return value.Value, value.Type, nil } -// hilListToGoSlice converts an ast.Variable into a []interface{}. We assume that -// the type checking is already done since this is internal and only used in output -// evaluation. -func hilListToGoSlice(variable []ast.Variable) []interface{} { - output := make([]interface{}, len(variable)) - - for index, element := range variable { - output[index] = element.Value - } - - return output -} - -// hilMapToGoMap converts an ast.Variable into a map[string]interface{}. We assume -// that the type checking is already done since this is internal and only used in -// output evaluation. -func hilMapToGoMap(variable map[string]ast.Variable) map[string]interface{} { - output := make(map[string]interface{}) - - for key, element := range variable { - output[key] = element.Value - } - - return output -} - type evalOutput struct{ *ast.Output } func (v *evalOutput) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { diff --git a/vendor/vendor.json b/vendor/vendor.json index 25225b8be..023364c2c 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -892,10 +892,10 @@ "revisionTime": "2016-07-08T14:13:38Z" }, { - "checksumSHA1": "vWW3HXm7OTOMISuZPcCSJODRYkU=", + "checksumSHA1": "o5JhQCQpoSRFcMwD8LxqP8iJ04o=", "path": "github.com/hashicorp/hil", - "revision": "7130f7330953adacbfb4ca0ad4b14b806bce3762", - "revisionTime": "2016-06-12T11:49:46Z" + "revision": "79fc9230647576201673b35c724c58ec034bd21d", + "revisionTime": "2016-07-11T16:29:56Z" }, { "checksumSHA1": "UICubs001+Q4MsUf9zl2vcMzWQQ=",