Merge pull request #7591 from hashicorp/b-7143
Fix interpolation of lists and maps from resources
This commit is contained in:
commit
6aa92437c4
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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=",
|
||||
|
|
Loading…
Reference in New Issue