More specific exceptions when validating params

In addition to the example cited in the bug, this updates a few other
exception messages to indicate the name of the parameter that is failing
validation.

Change-Id: I1b7729305988444dc15abd6e5d958f443efc091d
Closes-Bug: #1294295
This commit is contained in:
Jay Dobies 2014-04-09 14:55:24 -04:00
parent 9628b71ef4
commit 4c582a2bc0
7 changed files with 60 additions and 36 deletions

View File

@ -44,7 +44,7 @@ class CfnTemplate(template.Template):
def param_schemata(self): def param_schemata(self):
params = self.t.get(self.PARAMETERS, {}).iteritems() params = self.t.get(self.PARAMETERS, {}).iteritems()
return dict((name, parameters.Schema.from_dict(schema)) return dict((name, parameters.Schema.from_dict(name, schema))
for name, schema in params) for name, schema in params)
def parameters(self, stack_identifier, user_params, validate_value=True, def parameters(self, stack_identifier, user_params, validate_value=True,

View File

@ -52,11 +52,15 @@ class HOTParamSchema(parameters.Schema):
PARAMETER_KEYS = KEYS PARAMETER_KEYS = KEYS
@classmethod @classmethod
def from_dict(cls, schema_dict): def from_dict(cls, param_name, schema_dict):
""" """
Return a Parameter Schema object from a legacy schema dictionary. Return a Parameter Schema object from a legacy schema dictionary.
:param param_name: name of the parameter owning the schema; used
for more verbose logging
:type param_name: str
""" """
cls._validate_dict(schema_dict) cls._validate_dict(param_name, schema_dict)
def constraints(): def constraints():
constraints = schema_dict.get(CONSTRAINTS) constraints = schema_dict.get(CONSTRAINTS)
@ -65,7 +69,8 @@ class HOTParamSchema(parameters.Schema):
if not isinstance(constraints, list): if not isinstance(constraints, list):
raise constr.InvalidSchemaError( raise constr.InvalidSchemaError(
_("Invalid parameter constraints, expected a list")) _("Invalid parameter constraints for parameter %s, "
"expected a list") % param_name)
valid_keys = (DESCRIPTION, LENGTH, RANGE, ALLOWED_VALUES, valid_keys = (DESCRIPTION, LENGTH, RANGE, ALLOWED_VALUES,
ALLOWED_PATTERN, CUSTOM_CONSTRAINT) ALLOWED_PATTERN, CUSTOM_CONSTRAINT)

View File

@ -134,7 +134,7 @@ class HOTemplate(template.Template):
def param_schemata(self): def param_schemata(self):
params = self.t.get(self.PARAMETERS, {}).iteritems() params = self.t.get(self.PARAMETERS, {}).iteritems()
return dict((name, parameters.HOTParamSchema.from_dict(schema)) return dict((name, parameters.HOTParamSchema.from_dict(name, schema))
for name, schema in params) for name, schema in params)
def parameters(self, stack_identifier, user_params, validate_value=True, def parameters(self, stack_identifier, user_params, validate_value=True,

View File

@ -108,18 +108,25 @@ class Schema(constr.Schema):
"key": key, "entity": entity}) "key": key, "entity": entity})
@classmethod @classmethod
def _validate_dict(cls, schema_dict): def _validate_dict(cls, param_name, schema_dict):
cls._check_dict(schema_dict, cls.PARAMETER_KEYS, "parameter") cls._check_dict(schema_dict,
cls.PARAMETER_KEYS,
"parameter (%s)" % param_name)
if cls.TYPE not in schema_dict: if cls.TYPE not in schema_dict:
raise constr.InvalidSchemaError(_("Missing parameter type")) raise constr.InvalidSchemaError(
_("Missing parameter type for parameter: %s") % param_name)
@classmethod @classmethod
def from_dict(cls, schema_dict): def from_dict(cls, param_name, schema_dict):
""" """
Return a Parameter Schema object from a legacy schema dictionary. Return a Parameter Schema object from a legacy schema dictionary.
:param param_name: name of the parameter owning the schema; used
for more verbose logging
:type param_name: str
""" """
cls._validate_dict(schema_dict) cls._validate_dict(param_name, schema_dict)
def constraints(): def constraints():
desc = schema_dict.get(CONSTRAINT_DESCRIPTION) desc = schema_dict.get(CONSTRAINT_DESCRIPTION)
@ -171,7 +178,7 @@ class Parameter(object):
# Check for fully-fledged Schema objects # Check for fully-fledged Schema objects
if not isinstance(schema, Schema): if not isinstance(schema, Schema):
schema = Schema.from_dict(schema) schema = Schema.from_dict(name, schema)
if schema.type == schema.STRING: if schema.type == schema.STRING:
ParamClass = StringParam ParamClass = StringParam

View File

@ -1014,7 +1014,8 @@ class HOTParamValidatorTest(HeatTestCase):
schema = param['db_name'] schema = param['db_name']
def v(value): def v(value):
hot_param.HOTParamSchema.from_dict(schema).validate(name, value) hot_param.HOTParamSchema.from_dict(name, schema).validate(name,
value)
return True return True
value = 'wp' value = 'wp'
@ -1107,7 +1108,8 @@ class HOTParamValidatorTest(HeatTestCase):
schema = param['db_port'] schema = param['db_port']
def v(value): def v(value):
hot_param.HOTParamSchema.from_dict(schema).validate(name, value) hot_param.HOTParamSchema.from_dict(name, schema).validate(name,
value)
return True return True
value = 29999 value = 29999
@ -1148,7 +1150,8 @@ class HOTParamValidatorTest(HeatTestCase):
schema = param['param1'] schema = param['param1']
def v(value): def v(value):
hot_param.HOTParamSchema.from_dict(schema).validate(name, value) hot_param.HOTParamSchema.from_dict(name, schema).validate(name,
value)
return True return True
value = "1" value = "1"
@ -1176,7 +1179,9 @@ class HOTParamValidatorTest(HeatTestCase):
schema = param['db_port'] schema = param['db_port']
err = self.assertRaises(constraints.InvalidSchemaError, err = self.assertRaises(constraints.InvalidSchemaError,
hot_param.HOTParamSchema.from_dict, schema) hot_param.HOTParamSchema.from_dict,
'name',
schema)
self.assertIn(range_desc, str(err)) self.assertIn(range_desc, str(err))
def test_validate_schema_wrong_key(self): def test_validate_schema_wrong_key(self):
@ -1189,7 +1194,8 @@ class HOTParamValidatorTest(HeatTestCase):
error = self.assertRaises( error = self.assertRaises(
constraints.InvalidSchemaError, parameters.Parameters, constraints.InvalidSchemaError, parameters.Parameters,
"stack_testit", parser.Template(hot_tpl)) "stack_testit", parser.Template(hot_tpl))
self.assertEqual("Invalid key 'foo' for parameter", str(error)) self.assertEqual("Invalid key 'foo' for parameter (param1)",
str(error))
def test_validate_schema_no_type(self): def test_validate_schema_no_type(self):
hot_tpl = template_format.parse(''' hot_tpl = template_format.parse('''
@ -1201,7 +1207,8 @@ class HOTParamValidatorTest(HeatTestCase):
error = self.assertRaises( error = self.assertRaises(
constraints.InvalidSchemaError, parameters.Parameters, constraints.InvalidSchemaError, parameters.Parameters,
"stack_testit", parser.Template(hot_tpl)) "stack_testit", parser.Template(hot_tpl))
self.assertEqual("Missing parameter type", str(error)) self.assertEqual("Missing parameter type for parameter: param1",
str(error))
def test_validate_schema_unknown_type(self): def test_validate_schema_unknown_type(self):
hot_tpl = template_format.parse(''' hot_tpl = template_format.parse('''
@ -1246,7 +1253,8 @@ class HOTParamValidatorTest(HeatTestCase):
constraints.InvalidSchemaError, parameters.Parameters, constraints.InvalidSchemaError, parameters.Parameters,
"stack_testit", parser.Template(hot_tpl)) "stack_testit", parser.Template(hot_tpl))
self.assertEqual( self.assertEqual(
"Invalid parameter constraints, expected a list", str(error)) "Invalid parameter constraints for parameter param1, "
"expected a list", str(error))
def test_validate_schema_constraints_not_mapping(self): def test_validate_schema_constraints_not_mapping(self):
hot_tpl = template_format.parse(''' hot_tpl = template_format.parse('''

View File

@ -419,11 +419,15 @@ class ParameterSchemaTest(testtools.TestCase):
def test_validate_schema_wrong_key(self): def test_validate_schema_wrong_key(self):
error = self.assertRaises(constr.InvalidSchemaError, error = self.assertRaises(constr.InvalidSchemaError,
parameters.Schema.from_dict, {"foo": "bar"}) parameters.Schema.from_dict, 'param_name',
self.assertEqual("Invalid key 'foo' for parameter", str(error)) {"foo": "bar"})
self.assertEqual("Invalid key 'foo' for parameter (param_name)",
str(error))
def test_validate_schema_no_type(self): def test_validate_schema_no_type(self):
error = self.assertRaises(constr.InvalidSchemaError, error = self.assertRaises(constr.InvalidSchemaError,
parameters.Schema.from_dict, parameters.Schema.from_dict,
'broken',
{"Description": "Hi!"}) {"Description": "Hi!"})
self.assertEqual("Missing parameter type", str(error)) self.assertEqual("Missing parameter type for parameter: broken",
str(error))

View File

@ -320,7 +320,7 @@ class PropertySchemaTest(testtools.TestCase):
"m2.xlarge", "m2.2xlarge", "m2.4xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge",
"c1.medium", "c1.xlarge", "cc1.4xlarge"] "c1.medium", "c1.xlarge", "cc1.4xlarge"]
constraint_desc = "Must be a valid EC2 instance type." constraint_desc = "Must be a valid EC2 instance type."
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "String", "Type": "String",
"Description": description, "Description": description,
"Default": "m1.large", "Default": "m1.large",
@ -345,7 +345,7 @@ class PropertySchemaTest(testtools.TestCase):
description = "WebServer EC2 instance type" description = "WebServer EC2 instance type"
allowed_pattern = "[A-Za-z0-9.]*" allowed_pattern = "[A-Za-z0-9.]*"
constraint_desc = "Must contain only alphanumeric characters." constraint_desc = "Must contain only alphanumeric characters."
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "String", "Type": "String",
"Description": description, "Description": description,
"Default": "m1.large", "Default": "m1.large",
@ -370,7 +370,7 @@ class PropertySchemaTest(testtools.TestCase):
description = "WebServer EC2 instance type" description = "WebServer EC2 instance type"
allowed_pattern = "[A-Za-z0-9.]*" allowed_pattern = "[A-Za-z0-9.]*"
constraint_desc = "Must contain only alphanumeric characters." constraint_desc = "Must contain only alphanumeric characters."
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "String", "Type": "String",
"Description": description, "Description": description,
"Default": "m1.large", "Default": "m1.large",
@ -396,7 +396,7 @@ class PropertySchemaTest(testtools.TestCase):
self.assertEqual(constraint_desc, allowed_constraint.description) self.assertEqual(constraint_desc, allowed_constraint.description)
def test_from_param_string_min_len(self): def test_from_param_string_min_len(self):
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Description": "WebServer EC2 instance type", "Description": "WebServer EC2 instance type",
"Type": "String", "Type": "String",
"Default": "m1.large", "Default": "m1.large",
@ -413,7 +413,7 @@ class PropertySchemaTest(testtools.TestCase):
self.assertIsNone(len_constraint.max) self.assertIsNone(len_constraint.max)
def test_from_param_string_max_len(self): def test_from_param_string_max_len(self):
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Description": "WebServer EC2 instance type", "Description": "WebServer EC2 instance type",
"Type": "String", "Type": "String",
"Default": "m1.large", "Default": "m1.large",
@ -430,7 +430,7 @@ class PropertySchemaTest(testtools.TestCase):
self.assertEqual(11, len_constraint.max) self.assertEqual(11, len_constraint.max)
def test_from_param_string_min_max_len(self): def test_from_param_string_min_max_len(self):
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Description": "WebServer EC2 instance type", "Description": "WebServer EC2 instance type",
"Type": "String", "Type": "String",
"Default": "m1.large", "Default": "m1.large",
@ -448,7 +448,7 @@ class PropertySchemaTest(testtools.TestCase):
self.assertEqual(11, len_constraint.max) self.assertEqual(11, len_constraint.max)
def test_from_param_no_default(self): def test_from_param_no_default(self):
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Description": "WebServer EC2 instance type", "Description": "WebServer EC2 instance type",
"Type": "String", "Type": "String",
}) })
@ -460,7 +460,7 @@ class PropertySchemaTest(testtools.TestCase):
def test_from_number_param_min(self): def test_from_number_param_min(self):
default = "42" default = "42"
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "Number", "Type": "Number",
"Default": default, "Default": default,
"MinValue": "10", "MinValue": "10",
@ -480,7 +480,7 @@ class PropertySchemaTest(testtools.TestCase):
def test_from_number_param_max(self): def test_from_number_param_max(self):
default = "42" default = "42"
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "Number", "Type": "Number",
"Default": default, "Default": default,
"MaxValue": "100", "MaxValue": "100",
@ -500,7 +500,7 @@ class PropertySchemaTest(testtools.TestCase):
def test_from_number_param_min_max(self): def test_from_number_param_min_max(self):
default = "42" default = "42"
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "Number", "Type": "Number",
"Default": default, "Default": default,
"MinValue": "10", "MinValue": "10",
@ -522,7 +522,7 @@ class PropertySchemaTest(testtools.TestCase):
def test_from_number_param_allowed_vals(self): def test_from_number_param_allowed_vals(self):
default = "42" default = "42"
constraint_desc = "The quick brown fox jumps over the lazy dog." constraint_desc = "The quick brown fox jumps over the lazy dog."
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "Number", "Type": "Number",
"Default": default, "Default": default,
"AllowedValues": ["10", "42", "100"], "AllowedValues": ["10", "42", "100"],
@ -542,7 +542,7 @@ class PropertySchemaTest(testtools.TestCase):
self.assertEqual(constraint_desc, allowed_constraint.description) self.assertEqual(constraint_desc, allowed_constraint.description)
def test_from_list_param(self): def test_from_list_param(self):
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "CommaDelimitedList", "Type": "CommaDelimitedList",
"Default": "foo,bar,baz" "Default": "foo,bar,baz"
}) })
@ -554,7 +554,7 @@ class PropertySchemaTest(testtools.TestCase):
self.assertFalse(schema.required) self.assertFalse(schema.required)
def test_from_json_param(self): def test_from_json_param(self):
param = parameters.Schema.from_dict({ param = parameters.Schema.from_dict('name', {
"Type": "Json", "Type": "Json",
"Default": {"foo": "bar", "blarg": "wibble"} "Default": {"foo": "bar", "blarg": "wibble"}
}) })
@ -1206,7 +1206,7 @@ class PropertiesTest(testtools.TestCase):
] ]
}, },
} }
params = dict((n, parameters.Schema.from_dict(s)) for n, s params = dict((n, parameters.Schema.from_dict(n, s)) for n, s
in params_snippet.items()) in params_snippet.items())
props_schemata = properties.Properties.schema_from_params(params) props_schemata = properties.Properties.schema_from_params(params)
@ -1379,7 +1379,7 @@ class PropertiesTest(testtools.TestCase):
] ]
} }
} }
params = dict((n, hot_param.HOTParamSchema.from_dict(s)) for n, s params = dict((n, hot_param.HOTParamSchema.from_dict(n, s)) for n, s
in params_snippet.items()) in params_snippet.items())
props_schemata = properties.Properties.schema_from_params(params) props_schemata = properties.Properties.schema_from_params(params)