Nicer error when list/map assigned to string argument.

Previous this would return the following sort of error:
expected type 'string', got unconvertible type '[]interface {}'

This is the raw error returned by the underlying mapstructure library.
This is not a helpful error message for anyone who doesn't know Go's
type system, and it exposes Terraform's internals to the UI.

Instead we'll catch these cases before we try to use mapstructure and
return a more straightforward message.

By checking the type before the IsComputed exception this also avoids
a crash caused when the assigned value is a computed list. Otherwise
the list of interpolations is allowed through here and then crashes later
during Diff when the value is not a primitive as expected.
This commit is contained in:
Martin Atkins 2015-08-15 17:16:14 -07:00
parent 6a8ae92ea9
commit a67182543c
2 changed files with 48 additions and 1 deletions

View File

@ -1178,8 +1178,25 @@ func (m schemaMap) validatePrimitive(
raw interface{}, raw interface{},
schema *Schema, schema *Schema,
c *terraform.ResourceConfig) ([]string, []error) { c *terraform.ResourceConfig) ([]string, []error) {
// Catch if the user gave a complex type where a primitive was
// expected, so we can return a friendly error message that
// doesn't contain Go type system terminology.
switch reflect.ValueOf(raw).Type().Kind() {
case reflect.Slice:
return nil, []error{
fmt.Errorf("%s must be a single value, not a list", k),
}
case reflect.Map:
return nil, []error{
fmt.Errorf("%s must be a single value, not a map", k),
}
default: // ok
}
if c.IsComputed(k) { if c.IsComputed(k) {
// If the key is being computed, then it is not an error // If the key is being computed, then it is not an error as
// long as it's not a slice or map.
return nil, nil return nil, nil
} }

View File

@ -3409,6 +3409,36 @@ func TestSchemaMap_Validate(t *testing.T) {
Err: true, Err: true,
}, },
"Bad, should not allow lists to be assigned to string attributes": {
Schema: map[string]*Schema{
"availability_zone": &Schema{
Type: TypeString,
Required: true,
},
},
Config: map[string]interface{}{
"availability_zone": []interface{}{"foo", "bar", "baz"},
},
Err: true,
},
"Bad, should not allow maps to be assigned to string attributes": {
Schema: map[string]*Schema{
"availability_zone": &Schema{
Type: TypeString,
Required: true,
},
},
Config: map[string]interface{}{
"availability_zone": map[string]interface{}{"foo": "bar", "baz": "thing"},
},
Err: true,
},
"Deprecated attribute usage generates warning, but not error": { "Deprecated attribute usage generates warning, but not error": {
Schema: map[string]*Schema{ Schema: map[string]*Schema{
"old_news": &Schema{ "old_news": &Schema{