Merge "Improve StackValidationFailed response in properties"

This commit is contained in:
Jenkins 2015-04-20 03:54:08 +00:00 committed by Gerrit Code Review
commit bc60a1543b
26 changed files with 217 additions and 147 deletions

View File

@ -83,6 +83,9 @@ class CfnTemplate(template.Template):
return dict((name, parameters.Schema.from_dict(name, schema))
for name, schema in six.iteritems(params))
def get_section_name(self, section):
return section
def parameters(self, stack_identifier, user_params, param_defaults=None):
return parameters.Parameters(stack_identifier, self,
user_params=user_params,

View File

@ -56,6 +56,12 @@ class HOTemplate20130523(template.Template):
cfn_template.CfnTemplate.RESOURCES: RESOURCES,
cfn_template.CfnTemplate.OUTPUTS: OUTPUTS}
_RESOURCE_HOT_TO_CFN_ATTRS = {'type': 'Type',
'properties': 'Properties',
'metadata': 'Metadata',
'depends_on': 'DependsOn',
'deletion_policy': 'DeletionPolicy',
'update_policy': 'UpdatePolicy'}
functions = {
'Fn::GetAZs': cfn_funcs.GetAZs,
'get_param': hot_funcs.GetParam,
@ -157,15 +163,14 @@ class HOTemplate20130523(template.Template):
def _translate_resources(self, resources):
"""Get the resources of the template translated into CFN format."""
HOT_TO_CFN_ATTRS = {'type': 'Type',
'properties': 'Properties',
'metadata': 'Metadata',
'depends_on': 'DependsOn',
'deletion_policy': 'DeletionPolicy',
'update_policy': 'UpdatePolicy'}
return self._translate_section('resources', 'type', resources,
HOT_TO_CFN_ATTRS)
self._RESOURCE_HOT_TO_CFN_ATTRS)
def get_section_name(self, section):
cfn_to_hot_attrs = dict(zip(self._RESOURCE_HOT_TO_CFN_ATTRS.values(),
self._RESOURCE_HOT_TO_CFN_ATTRS.keys()))
return cfn_to_hot_attrs.get(section, section)
def _translate_outputs(self, outputs):
"""Get the outputs of the template translated into CFN format."""

View File

@ -267,7 +267,6 @@ class Property(object):
keys = list(self.schema.schema)
schemata = dict((k, self.schema.schema[k]) for k in keys)
properties = Properties(schemata, dict(child_values),
parent_name=self.name,
context=self.context)
if validate:
properties.validate()
@ -343,15 +342,16 @@ class Property(object):
class Properties(collections.Mapping):
def __init__(self, schema, data, resolver=lambda d: d, parent_name=None,
context=None):
context=None, section=None):
self.props = dict((k, Property(s, k, context))
for k, s in schema.items())
self.resolve = resolver
self.data = data
if parent_name is None:
self.error_prefix = ''
else:
self.error_prefix = '%s: ' % parent_name
self.error_prefix = []
if parent_name is not None:
self.error_prefix.append(parent_name)
if section is not None:
self.error_prefix.append(section)
self.context = context
@staticmethod
@ -369,38 +369,58 @@ class Properties(collections.Mapping):
return {}
def validate(self, with_value=True):
for (key, prop) in self.props.items():
# check that update_allowed and immutable
# do not contradict each other
if prop.update_allowed() and prop.immutable():
msg = _("Property %(prop)s: %(ua)s and %(im)s "
"cannot both be True") % {
'prop': key,
'ua': prop.schema.UPDATE_ALLOWED,
'im': prop.schema.IMMUTABLE}
raise exception.InvalidSchemaError(message=msg)
if with_value:
try:
self._get_property_value(key, validate=True)
except ValueError as e:
msg = _("Property error : %s") % e
try:
for key in self.data:
if key not in self.props:
msg = _("Unknown Property %s") % key
raise exception.StackValidationFailed(message=msg)
# are there unimplemented Properties
if not prop.implemented() and key in self.data:
msg = _("Property %s not implemented yet") % key
raise exception.StackValidationFailed(message=msg)
for (key, prop) in self.props.items():
# check that update_allowed and immutable
# do not contradict each other
if prop.update_allowed() and prop.immutable():
msg = _("Property %(prop)s: %(ua)s and %(im)s "
"cannot both be True") % {
'prop': key,
'ua': prop.schema.UPDATE_ALLOWED,
'im': prop.schema.IMMUTABLE}
raise exception.InvalidSchemaError(message=msg)
for key in self.data:
if key not in self.props:
msg = _("Unknown Property %s") % key
raise exception.StackValidationFailed(message=msg)
if with_value:
try:
self._get_property_value(key, validate=True)
except exception.StackValidationFailed as ex:
path = [key]
path.extend(ex.path)
raise exception.StackValidationFailed(
path=path, message=ex.error_message)
except ValueError as e:
if prop.required() and key not in self.data:
path = []
else:
path = [key]
raise exception.StackValidationFailed(
path=path, message=six.text_type(e))
# are there unimplemented Properties
if not prop.implemented() and key in self.data:
msg = _("Property %s not implemented yet") % key
raise exception.StackValidationFailed(message=msg)
except exception.StackValidationFailed as ex:
# NOTE(prazumovsky): should reraise exception for adding specific
# error name and error_prefix to path for correct error message
# building.
path = self.error_prefix
path.extend(ex.path)
raise exception.StackValidationFailed(
error=ex.error or 'Property error',
path=path,
message=ex.error_message
)
def _get_property_value(self, key, validate=False):
if key not in self:
raise KeyError(_('%(prefix)sInvalid Property %(key)s') %
{'prefix': self.error_prefix, 'key': key})
raise KeyError(_('Invalid Property %s') % key)
prop = self.props[key]
@ -414,16 +434,20 @@ class Properties(collections.Mapping):
value = self.resolve(unresolved_value)
return prop.get_value(value, validate)
# Children can raise StackValidationFailed with unique path which
# is necessary for further use in StackValidationFailed exception.
# So we need to handle this exception in this method.
except exception.StackValidationFailed as e:
raise exception.StackValidationFailed(path=e.path,
message=e.error_message)
# the resolver function could raise any number of exceptions,
# so handle this generically
except Exception as e:
raise ValueError('%s%s %s' % (self.error_prefix, key,
six.text_type(e)))
raise ValueError(six.text_type(e))
elif prop.has_default():
return prop.get_value(None, validate)
elif prop.required():
raise ValueError(_('%(prefix)sProperty %(key)s not assigned') %
{'prefix': self.error_prefix, 'key': key})
raise ValueError(_('Property %s not assigned') % key)
def __getitem__(self, key):
return self._get_property_value(key)

View File

@ -874,7 +874,18 @@ class Resource(object):
function.validate(self.t)
self.validate_deletion_policy(self.t.deletion_policy())
return self.properties.validate(with_value=self.stack.strict_validate)
try:
validate = self.properties.validate(
with_value=self.stack.strict_validate)
except exception.StackValidationFailed as ex:
path = [self.stack.t.RESOURCES, ex.path[0],
self.stack.t.get_section_name(ex.path[1])]
path.extend(ex.path[2:])
raise exception.StackValidationFailed(
error=ex.error,
path=path,
message=ex.error_message)
return validate
@classmethod
def validate_deletion_policy(cls, policy):

View File

@ -183,7 +183,8 @@ class ResourceDefinitionCore(object):
require a context to validate constraints.
"""
return properties.Properties(schema, self._properties or {},
function.resolve, self.name, context)
function.resolve, self.name, context,
section=PROPERTIES)
def deletion_policy(self):
"""
@ -201,7 +202,8 @@ class ResourceDefinitionCore(object):
require a context to validate constraints.
"""
return properties.Properties(schema, self._update_policy or {},
function.resolve, self.name, context)
function.resolve, self.name, context,
section=UPDATE_POLICY)
def metadata(self):
"""

View File

@ -816,7 +816,7 @@ class EngineService(service.Service):
env = environment.Environment(params)
for res in tmpl_resources.values():
for name, res in six.iteritems(tmpl_resources):
ResourceClass = env.get_class(res['Type'])
if ResourceClass == resources.template_resource.TemplateResource:
# we can't validate a TemplateResource unless we instantiate
@ -824,9 +824,12 @@ class EngineService(service.Service):
# parameters into properties_schema.
continue
props = properties.Properties(ResourceClass.properties_schema,
res.get('Properties', {}),
context=cnxt)
props = properties.Properties(
ResourceClass.properties_schema,
res.get('Properties', {}),
parent_name=six.text_type(name),
context=cnxt,
section='Properties')
deletion_policy = res.get('DeletionPolicy', 'Delete')
try:
ResourceClass.validate_deletion_policy(deletion_policy)

View File

@ -158,6 +158,11 @@ class Template(collections.Mapping):
'''Return a dict of parameters.Schema objects for the parameters.'''
pass
@abc.abstractmethod
def get_section_name(self, section):
"""Return a correct section name."""
pass
@abc.abstractmethod
def parameters(self, stack_identifier, user_params, param_defaults=None):
'''Return a parameters.Parameters object for the stack.'''

View File

@ -133,8 +133,10 @@ class LaunchConfigurationTest(common.HeatTestCase):
self.patchobject(nova.NovaClientPlugin, 'get_server',
side_effect=exception.ServerNotFound(server='5678'))
msg = ("Property error : LaunchConfig: InstanceId Error validating "
"value '5678': The server (5678) could not be found.")
msg = ("Property error : "
"Resources.LaunchConfig.Properties.InstanceId: "
"Error validating value '5678': The server (5678) "
"could not be found.")
exc = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertIn(msg, six.text_type(exc))
@ -193,9 +195,10 @@ class LaunchConfigurationTest(common.HeatTestCase):
self.validate_launch_config, t,
stack, 'LaunchConfig')
excepted_error = ('Property error : LaunchConfig: BlockDeviceMappings '
'Property error : BlockDeviceMappings: 0 Property '
'error : 0: Property DeviceName not assigned')
excepted_error = (
'Property error : '
'Resources.LaunchConfig.Properties.BlockDeviceMappings[0]: '
'Property DeviceName not assigned')
self.assertIn(excepted_error, six.text_type(e))
self.m.VerifyAll()

View File

@ -220,8 +220,10 @@ class TestAutoScalingGroupValidation(common.HeatTestCase):
rsrc = stack['WebServerGroup']
self._stub_nova_server_get(not_found=True)
self.m.ReplayAll()
msg = ("Property error : WebServerGroup: InstanceId Error validating "
"value '5678': The server (5678) could not be found")
msg = ("Property error : "
"Resources.WebServerGroup.Properties.InstanceId: "
"Error validating value '5678': The server (5678) could "
"not be found.")
exc = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertIn(msg, six.text_type(exc))

View File

@ -203,7 +203,9 @@ class VolumeTest(vt_base.BaseVolumeTest):
ex = self.assertRaises(exception.StackValidationFailed,
self.create_volume, self.t, stack, 'DataVolume')
self.assertIn('Tags Property error', six.text_type(ex))
self.assertEqual("Property error : "
"Resources.DataVolume.Properties.Tags[0]: "
"Unknown Property Foo", six.text_type(ex))
self.m.VerifyAll()
@ -664,8 +666,8 @@ class VolumeTest(vt_base.BaseVolumeTest):
self.create_volume,
self.t, stack, 'DataVolume')
self.assertEqual(
"Property error : DataVolume: Size 0 is out of "
"range (min: 1, max: None)", six.text_type(error))
"Property error : Resources.DataVolume.Properties.Size: "
"0 is out of range (min: 1, max: None)", six.text_type(error))
def test_volume_attachment_updates_not_supported(self):
self.m.StubOutWithMock(nova.NovaClientPlugin, 'get_server')

View File

@ -103,8 +103,8 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
self.create_volume,
self.t, stack, 'volume')
self.assertEqual(
"Property error : volume: size 0 is out of "
"range (min: 1, max: None)", six.text_type(error))
"Property error : resources.volume.properties.size: "
"0 is out of range (min: 1, max: None)", six.text_type(error))
def test_cinder_create(self):
fv = vt_base.FakeVolume('creating')

View File

@ -377,8 +377,8 @@ class CeilometerAlarmTest(common.HeatTestCase):
error = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertEqual(
"Property error : MEMAlarmHigh: %s Value '60a' is not an "
"integer" % p, six.text_type(error))
"Property error : Resources.MEMAlarmHigh.Properties.%s: "
"Value '60a' is not an integer" % p, six.text_type(error))
def test_mem_alarm_high_not_integer_parameters(self):
snippet = template_format.parse(not_string_alarm_template)
@ -392,8 +392,9 @@ class CeilometerAlarmTest(common.HeatTestCase):
error = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertEqual(
"Property error : MEMAlarmHigh: %s int() argument must be "
"a string or a number, not 'list'" % p, six.text_type(error))
"Property error : Resources.MEMAlarmHigh.Properties.%s: "
"int() argument must be a string or a number, not "
"'list'" % p, six.text_type(error))
def test_mem_alarm_high_check_not_required_parameters(self):
snippet = template_format.parse(not_string_alarm_template)
@ -406,7 +407,8 @@ class CeilometerAlarmTest(common.HeatTestCase):
error = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertEqual(
"Property error : MEMAlarmHigh: Property meter_name not assigned",
"Property error : Resources.MEMAlarmHigh.Properties: "
"Property meter_name not assigned",
six.text_type(error))
for p in ('period', 'evaluation_periods', 'statistic',
@ -521,8 +523,9 @@ class CombinationAlarmTest(common.HeatTestCase):
error = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertEqual(
"Property error : CombinAlarm: alarm_ids length (0) is out of "
"range (min: 1, max: None)", six.text_type(error))
"Property error : Resources.CombinAlarm.Properties.alarm_ids: "
"length (0) is out of range (min: 1, max: None)",
six.text_type(error))
def test_update(self):
rsrc = self.create_alarm()

View File

@ -99,7 +99,8 @@ class GlanceImageTest(common.HeatTestCase):
)
image = stack['image']
image.t['Properties']['min_disk'] = -1
error_msg = 'min_disk -1 is out of range (min: 0, max: None)'
error_msg = ('Property error : resources.image.properties.min_disk: '
'-1 is out of range (min: 0, max: None)')
self._test_validate(image, error_msg)
def test_invalid_min_ram(self):
@ -111,7 +112,8 @@ class GlanceImageTest(common.HeatTestCase):
)
image = stack['image']
image.t['Properties']['min_ram'] = -1
error_msg = 'min_ram -1 is out of range (min: 0, max: None)'
error_msg = ('Property error : resources.image.properties.min_ram: '
'-1 is out of range (min: 0, max: None)')
self._test_validate(image, error_msg)
def test_miss_disk_format(self):
@ -135,7 +137,9 @@ class GlanceImageTest(common.HeatTestCase):
)
image = stack['image']
image.t['Properties']['disk_format'] = 'incorrect_format'
error_msg = ('disk_format "incorrect_format" is not an allowed value '
error_msg = ('Property error : '
'resources.image.properties.disk_format: '
'"incorrect_format" is not an allowed value '
'[ami, ari, aki, vhd, vmdk, raw, qcow2, vdi, iso]')
self._test_validate(image, error_msg)
@ -160,8 +164,10 @@ class GlanceImageTest(common.HeatTestCase):
)
image = stack['image']
image.t['Properties']['container_format'] = 'incorrect_format'
error_msg = ('container_format "incorrect_format" is not an '
'allowed value [ami, ari, aki, bare, ova, ovf]')
error_msg = ('Property error : '
'resources.image.properties.container_format: '
'"incorrect_format" is not an allowed value '
'[ami, ari, aki, bare, ova, ovf]')
self._test_validate(image, error_msg)
def test_miss_location(self):

View File

@ -227,8 +227,9 @@ class InstancesTest(common.HeatTestCase):
exc = self.assertRaises(exception.StackValidationFailed,
instance.validate)
self.assertIn("VolumeId Error validating value '1234': "
"The Volume (1234) could not be found.",
self.assertIn("WebServer.Properties.Volumes[0].VolumeId: "
"Error validating value '1234': The Volume "
"(1234) could not be found.",
six.text_type(exc))
self.m.VerifyAll()
@ -322,9 +323,10 @@ class InstancesTest(common.HeatTestCase):
exc = self.assertRaises(exception.StackValidationFailed,
instance.validate)
excepted_error = ('Property error : WebServer: BlockDeviceMappings '
'Property error : BlockDeviceMappings: 0 Property '
'error : 0: Property DeviceName not assigned')
excepted_error = (
'Property error : '
'Resources.WebServer.Properties.BlockDeviceMappings[0]: '
'Property DeviceName not assigned')
self.assertIn(excepted_error, six.text_type(exc))
self.m.VerifyAll()
@ -382,9 +384,9 @@ class InstancesTest(common.HeatTestCase):
create = scheduler.TaskRunner(instance.create)
error = self.assertRaises(exception.ResourceFailure, create)
self.assertEqual(
"StackValidationFailed: Property error : WebServer: "
"ImageId Error validating value 'Slackware': "
"The Image (Slackware) could not be found.",
"StackValidationFailed: Property error : "
"WebServer.Properties.ImageId: Error validating value "
"'Slackware': The Image (Slackware) could not be found.",
six.text_type(error))
self.m.VerifyAll()
@ -409,9 +411,9 @@ class InstancesTest(common.HeatTestCase):
create = scheduler.TaskRunner(instance.create)
error = self.assertRaises(exception.ResourceFailure, create)
self.assertEqual(
'StackValidationFailed: Property error : WebServer: '
'ImageId Multiple physical resources were '
'found with name (CentOS 5.2).',
'StackValidationFailed: Property error : '
'WebServer.Properties.ImageId: Multiple physical '
'resources were found with name (CentOS 5.2).',
six.text_type(error))
self.m.VerifyAll()
@ -433,8 +435,8 @@ class InstancesTest(common.HeatTestCase):
create = scheduler.TaskRunner(instance.create)
error = self.assertRaises(exception.ResourceFailure, create)
self.assertEqual(
'StackValidationFailed: Property error : WebServer: '
'ImageId 404 (HTTP 404)',
'StackValidationFailed: Property error : '
'WebServer.Properties.ImageId: 404 (HTTP 404)',
six.text_type(error))
self.m.VerifyAll()

View File

@ -103,11 +103,11 @@ class NovaKeyPairTest(common.HeatTestCase):
definition = stack.t.resource_definitions(stack)['kp']
kp_res = nova_keypair.KeyPair('kp', definition, stack)
self.m.ReplayAll()
create = scheduler.TaskRunner(kp_res.create)
error = self.assertRaises(exception.ResourceFailure, create)
error = self.assertRaises(exception.StackValidationFailed,
kp_res.validate)
self.assertIn("Property error", six.text_type(error))
self.assertIn("name length (0) is out of range (min: 1, max: 255)",
six.text_type(error))
self.assertIn("kp.properties.name: length (0) is out of "
"range (min: 1, max: 255)", six.text_type(error))
self.m.VerifyAll()
def test_create_key_excess_name_length(self):
@ -119,11 +119,11 @@ class NovaKeyPairTest(common.HeatTestCase):
definition = stack.t.resource_definitions(stack)['kp']
kp_res = nova_keypair.KeyPair('kp', definition, stack)
self.m.ReplayAll()
create = scheduler.TaskRunner(kp_res.create)
error = self.assertRaises(exception.ResourceFailure, create)
error = self.assertRaises(exception.StackValidationFailed,
kp_res.validate)
self.assertIn("Property error", six.text_type(error))
self.assertIn("name length (256) is out of range (min: 1, max: 255)",
six.text_type(error))
self.assertIn("kp.properties.name: length (256) is out of "
"range (min: 1, max: 255)", six.text_type(error))
self.m.VerifyAll()
def test_delete_key(self):

View File

@ -882,8 +882,8 @@ class PropertyTest(common.HeatTestCase):
p = properties.Property({'Type': 'Map', 'Schema': map_schema})
ex = self.assertRaises(exception.StackValidationFailed,
p.get_value, {'valid': 'fish'}, True)
self.assertEqual('Property error : valid "fish" is not '
'a valid boolean', six.text_type(ex))
self.assertEqual('Property error : valid: "fish" is not a '
'valid boolean', six.text_type(ex))
def test_map_schema_missing_data(self):
map_schema = {'valid': {'Type': 'Boolean'}}
@ -914,8 +914,8 @@ class PropertyTest(common.HeatTestCase):
ex = self.assertRaises(exception.StackValidationFailed,
p.get_value,
[{'valid': 'True'}, {'valid': 'fish'}], True)
self.assertEqual('Property error : 1 Property error : 1: valid '
'"fish" is not a valid boolean', six.text_type(ex))
self.assertEqual('Property error : [1].valid: "fish" is not '
'a valid boolean', six.text_type(ex))
def test_list_schema_int_good(self):
list_schema = {'Type': 'Integer'}
@ -927,7 +927,7 @@ class PropertyTest(common.HeatTestCase):
p = properties.Property({'Type': 'List', 'Schema': list_schema})
ex = self.assertRaises(exception.StackValidationFailed,
p.get_value, [42, 'fish'], True)
self.assertEqual("Property error : 1 Value 'fish' is not "
self.assertEqual("Property error : [1]: Value 'fish' is not "
"an integer", six.text_type(ex))
@ -1056,16 +1056,6 @@ class PropertiesTest(common.HeatTestCase):
props = properties.Properties(schema, {'foo': None})
self.assertEqual(['one', 'two'], props['foo'])
def test_bad_resolver(self):
schema = {'foo': {'Type': 'String', 'Default': 'bar'}}
def bad_resolver(prop):
raise Exception('resolution failed!')
props = properties.Properties(schema, {'foo': 'baz'}, bad_resolver)
err = self.assertRaises(ValueError, props.get, 'foo')
self.assertEqual('foo resolution failed!', six.text_type(err))
def test_resolve_returns_none(self):
schema = {'foo': {'Type': 'String', "MinLength": "5"}}
@ -1543,14 +1533,14 @@ class PropertiesValidationTest(common.HeatTestCase):
schema = {'foo': {'Type': 'String'}}
props = properties.Properties(schema, {'foo': ['foo', 'bar']})
ex = self.assertRaises(exception.StackValidationFailed, props.validate)
self.assertEqual('Property error : foo Value must be a string',
self.assertEqual('Property error : foo: Value must be a string',
six.text_type(ex))
def test_dict_instead_string(self):
schema = {'foo': {'Type': 'String'}}
props = properties.Properties(schema, {'foo': {'foo': 'bar'}})
ex = self.assertRaises(exception.StackValidationFailed, props.validate)
self.assertEqual('Property error : foo Value must be a string',
self.assertEqual('Property error : foo: Value must be a string',
six.text_type(ex))
def test_none_string(self):
@ -1717,8 +1707,8 @@ class PropertiesValidationTest(common.HeatTestCase):
props = properties.Properties(schema, invalid_data)
ex = self.assertRaises(exception.StackValidationFailed,
props.validate)
self.assertEqual('Property error : foo Property error : foo: 0 '
'Unknown Property bar', six.text_type(ex))
self.assertEqual('Property error : foo[0]: Unknown Property bar',
six.text_type(ex))
def test_nested_properties_schema_invalid_property_in_map(self):
child_schema = {'Key': {'Type': 'String',
@ -1736,8 +1726,8 @@ class PropertiesValidationTest(common.HeatTestCase):
props = properties.Properties(schema, invalid_data)
ex = self.assertRaises(exception.StackValidationFailed,
props.validate)
self.assertEqual('Property error : foo Property error : foo: boo '
'Unknown Property bar', six.text_type(ex))
self.assertEqual('Property error : foo.boo: Unknown Property bar',
six.text_type(ex))
def test_more_nested_properties_schema_invalid_property_in_list(self):
nested_child_schema = {'Key': {'Type': 'String',
@ -1754,8 +1744,7 @@ class PropertiesValidationTest(common.HeatTestCase):
props = properties.Properties(schema, invalid_data)
ex = self.assertRaises(exception.StackValidationFailed,
props.validate)
self.assertEqual('Property error : foo Property error : foo: 0 '
'Property error : 0: doo Unknown Property bar',
self.assertEqual('Property error : foo[0].doo: Unknown Property bar',
six.text_type(ex))
def test_more_nested_properties_schema_invalid_property_in_map(self):
@ -1773,8 +1762,7 @@ class PropertiesValidationTest(common.HeatTestCase):
props = properties.Properties(schema, invalid_data)
ex = self.assertRaises(exception.StackValidationFailed,
props.validate)
self.assertEqual('Property error : foo Property error : foo: boo '
'Property error : boo: doo Unknown Property bar',
self.assertEqual('Property error : foo.boo.doo: Unknown Property bar',
six.text_type(ex))
def test_schema_to_template_empty_schema(self):

View File

@ -223,7 +223,7 @@ Resources:
'''
exc = self.assertRaises(exception.StackValidationFailed,
self.create_stack, template_random_string)
self.assertIn('length 513 is out of range (min: 1, max: 512)',
self.assertIn('513 is out of range (min: 1, max: 512)',
six.text_type(exc))

View File

@ -547,7 +547,8 @@ class ResourceTest(common.HeatTestCase):
tmpl = rsrc_defn.ResourceDefinition(rname, 'Foo', {})
res = generic_rsrc.ResourceWithRequiredProps(rname, tmpl, self.stack)
estr = 'Property error : test_resource: Property Foo not assigned'
estr = ('Property error : test_resource.Properties: '
'Property Foo not assigned')
create = scheduler.TaskRunner(res.create)
err = self.assertRaises(exception.ResourceFailure, create)
self.assertIn(estr, six.text_type(err))
@ -559,7 +560,8 @@ class ResourceTest(common.HeatTestCase):
{'Food': 'abc'})
res = generic_rsrc.ResourceWithProps(rname, tmpl, self.stack)
estr = 'StackValidationFailed: Unknown Property Food'
estr = ('StackValidationFailed: Property error : '
'test_resource.Properties: Unknown Property Food')
create = scheduler.TaskRunner(res.create)
err = self.assertRaises(exception.ResourceFailure, create)
self.assertIn(estr, six.text_type(err))
@ -1506,8 +1508,9 @@ class ResourceDependenciesTest(common.HeatTestCase):
stack = parser.Stack(utils.dummy_context(), 'test', tmpl)
ex = self.assertRaises(exception.StackValidationFailed,
stack.validate)
expected = "FooInt Value 'notanint' is not an integer"
self.assertIn(expected, six.text_type(ex))
self.assertIn("Property error : resources.bar.properties.FooInt: "
"Value 'notanint' is not an integer",
six.text_type(ex))
# You can turn off value validation via strict_validate
stack_novalidate = parser.Stack(utils.dummy_context(), 'test', tmpl,

View File

@ -328,7 +328,7 @@ class ResourceGroupTest(common.HeatTestCase):
resg = resource_group.ResourceGroup('test', snip, stack)
exc = self.assertRaises(exception.StackValidationFailed,
resg.validate)
errstr = "removal_policies \"'notallowed'\" is not a list"
errstr = "removal_policies: \"'notallowed'\" is not a list"
self.assertIn(errstr, six.text_type(exc))
def test_invalid_removal_policies_nomap(self):

View File

@ -188,8 +188,10 @@ class SaharaNodeGroupTemplateTest(common.HeatTestCase):
self.patchobject(ngt, 'is_using_neutron').return_value = False
ex = self.assertRaises(exception.StackValidationFailed, ngt.validate)
self.assertEqual(u"Property error : node-group: flavor Error "
u"validating value u'm1.large'", six.text_type(ex))
self.assertEqual(u"Property error : "
u"resources.node-group.properties.flavor: "
u"Error validating value u'm1.large'",
six.text_type(ex))
class SaharaClusterTemplateTest(common.HeatTestCase):

View File

@ -425,8 +425,8 @@ class ServersTest(common.HeatTestCase):
create = scheduler.TaskRunner(server.create)
error = self.assertRaises(exception.ResourceFailure, create)
self.assertEqual(
"StackValidationFailed: Property error : WebServer: "
"image Error validating value 'Slackware': "
"StackValidationFailed: Property error : "
"WebServer.Properties.image: Error validating value 'Slackware': "
"The Image (Slackware) could not be found.",
six.text_type(error))
@ -450,9 +450,9 @@ class ServersTest(common.HeatTestCase):
create = scheduler.TaskRunner(server.create)
error = self.assertRaises(exception.ResourceFailure, create)
self.assertEqual(
'StackValidationFailed: Property error : WebServer: '
'image Multiple physical resources were '
'found with name (CentOS 5.2).',
'StackValidationFailed: Property error : '
'WebServer.Properties.image: Multiple physical '
'resources were found with name (CentOS 5.2).',
six.text_type(error))
self.m.VerifyAll()
@ -474,8 +474,8 @@ class ServersTest(common.HeatTestCase):
create = scheduler.TaskRunner(server.create)
error = self.assertRaises(exception.ResourceFailure, create)
self.assertEqual(
"StackValidationFailed: Property error : WebServer: "
"image Error validating value '1': "
"StackValidationFailed: Property error : "
"WebServer.Properties.image: Error validating value '1': "
"The Image (1) could not be found.",
six.text_type(error))
@ -1049,9 +1049,9 @@ class ServersTest(common.HeatTestCase):
error = self.assertRaises(exception.StackValidationFailed,
server.validate)
self.assertEqual(
"Property error : WebServer: key_name Error validating "
"value 'test2': The Key (test2) could not be found.",
six.text_type(error))
"Property error : Resources.WebServer.Properties.key_name: "
"Error validating value 'test2': The Key (test2) could not "
"be found.", six.text_type(error))
self.m.VerifyAll()
def test_server_validate_with_networks(self):
@ -3020,8 +3020,9 @@ class ServersTest(common.HeatTestCase):
# update
updater = scheduler.TaskRunner(server.update, update_template)
err = self.assertRaises(exception.ResourceFailure, updater)
self.assertEqual('StackValidationFailed: Property error : WebServer: '
'image The Image (Update Image) could not be found.',
self.assertEqual('StackValidationFailed: Property error : '
'WebServer.Properties.image: The Image '
'(Update Image) could not be found.',
six.text_type(err))
self.m.VerifyAll()

View File

@ -217,8 +217,8 @@ class SoftwareComponentValidationTest(common.HeatTestCase):
tool: script
''',
err=exc.StackValidationFailed,
err_msg='actions length (0) is out of range '
'(min: 1, max: None)')
err_msg='component.properties.configs[0].actions: '
'length (0) is out of range (min: 1, max: None)')
),
(
'multiple_configs_per_action_single',

View File

@ -124,6 +124,9 @@ class TestTemplatePluginManager(common.HeatTestCase):
def param_schemata(self):
pass
def get_section_name(self, section):
pass
def parameters(self, stack_identifier, user_params):
pass

View File

@ -160,8 +160,8 @@ class TroveClusterTest(common.HeatTestCase):
self.rsrc_defn['Properties']['instances'][0]['flavor'] = 'm1.small'
tc = trove_cluster.TroveCluster('cluster', self.rsrc_defn, self.stack)
ex = self.assertRaises(exception.StackValidationFailed, tc.validate)
error_msg = ("Property error : cluster: instances Property error : "
"instances: 0 Property error : 0: flavor "
error_msg = ("Property error : "
"resources.cluster.properties.instances[0].flavor: "
"Error validating value 'm1.small': "
"The Flavor ID (m1.small) could not be found.")
self.assertEqual(error_msg, six.text_type(ex))

View File

@ -1035,7 +1035,8 @@ class validateTest(common.HeatTestCase):
t = template_format.parse(test_template_invalid_property)
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t, {}))
self.assertEqual({'Error': 'Unknown Property UnknownProperty'}, res)
self.assertEqual({'Error': 'Property error : WikiDatabase.Properties: '
'Unknown Property UnknownProperty'}, res)
def test_invalid_resources(self):
t = template_format.parse(test_template_invalid_resources)
@ -1084,7 +1085,8 @@ class validateTest(common.HeatTestCase):
engine = service.EngineService('a', 't')
res = dict(engine.validate_template(None, t, {}))
self.assertEqual(
{'Error': 'Property SourceDestCheck not implemented yet'},
{'Error': 'Property error : WikiDatabase.Properties: '
'Property SourceDestCheck not implemented yet'},
res)
def test_invalid_deletion_policy(self):

View File

@ -98,7 +98,7 @@ resources:
# Prove validation works for non-zero create/update
template_two_nested = self.template.replace("count: 0", "count: 2")
expected_err = "length Value 'BAD' is not an integer"
expected_err = "Value 'BAD' is not an integer"
ex = self.assertRaises(exc.HTTPBadRequest, self.update_stack,
stack_identifier, template_two_nested,
environment=env, files=files)