core: EvalVariableBlock to decode maps and slices more carefully

Previously this function was depending on the mapstructure behavior of
failing with an error when trying to decode a map into a list or
vice-versa, but mapstructure's WeakDecode behavior changed so that it
will go to greater lengths to coerce the given value to fit into the
target type, causing us to mis-handle certain ambigous cases.

Here we exert a bit more control over what's going on by using 'reflect'
to first check whether we have a slice or map value and only then try
to decode into one with mapstructure. This allows us to still rely on
mapstructure's ability to decode nested structures but ensure that lists
and maps never get implicitly converted to each other.
This commit is contained in:
Martin Atkins 2017-04-07 15:30:53 -07:00
parent 46994483e1
commit e4a5d36127
1 changed files with 20 additions and 15 deletions

View File

@ -123,22 +123,27 @@ func (n *EvalVariableBlock) Eval(ctx EvalContext) (interface{}, error) {
// Get our configuration
rc := *n.Config
for k, v := range rc.Config {
var vString string
if err := hilmapstructure.WeakDecode(v, &vString); err == nil {
n.VariableValues[k] = vString
continue
}
vKind := reflect.ValueOf(v).Type().Kind()
var vMap map[string]interface{}
if err := hilmapstructure.WeakDecode(v, &vMap); err == nil {
n.VariableValues[k] = vMap
continue
}
var vSlice []interface{}
if err := hilmapstructure.WeakDecode(v, &vSlice); err == nil {
n.VariableValues[k] = vSlice
continue
switch vKind {
case reflect.Slice:
var vSlice []interface{}
if err := hilmapstructure.WeakDecode(v, &vSlice); err == nil {
n.VariableValues[k] = vSlice
continue
}
case reflect.Map:
var vMap map[string]interface{}
if err := hilmapstructure.WeakDecode(v, &vMap); err == nil {
n.VariableValues[k] = vMap
continue
}
default:
var vString string
if err := hilmapstructure.WeakDecode(v, &vString); err == nil {
n.VariableValues[k] = vString
continue
}
}
return nil, fmt.Errorf("Variable value for %s is not a string, list or map type", k)