Merge "Return error with path in function validate"
This commit is contained in:
commit
bc6fa5dedf
|
@ -18,6 +18,7 @@ import weakref
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from heat.common import exception
|
||||||
from heat.common.i18n import _
|
from heat.common.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
@ -198,16 +199,29 @@ def resolve(snippet):
|
||||||
return snippet
|
return snippet
|
||||||
|
|
||||||
|
|
||||||
def validate(snippet):
|
def validate(snippet, path=''):
|
||||||
if isinstance(snippet, Function):
|
if isinstance(snippet, Function):
|
||||||
snippet.validate()
|
try:
|
||||||
|
snippet.validate()
|
||||||
|
except AssertionError:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
path = '.'.join([path, snippet.fn_name])
|
||||||
|
raise exception.StackValidationFailed(
|
||||||
|
path=path, message=six.text_type(e))
|
||||||
elif isinstance(snippet, collections.Mapping):
|
elif isinstance(snippet, collections.Mapping):
|
||||||
for v in six.itervalues(snippet):
|
def mkpath(key):
|
||||||
validate(v)
|
return '.'.join([path, key])
|
||||||
|
|
||||||
|
for k, v in six.iteritems(snippet):
|
||||||
|
validate(v, mkpath(k))
|
||||||
elif (not isinstance(snippet, six.string_types) and
|
elif (not isinstance(snippet, six.string_types) and
|
||||||
isinstance(snippet, collections.Iterable)):
|
isinstance(snippet, collections.Iterable)):
|
||||||
for v in snippet:
|
def mkpath(indx):
|
||||||
validate(v)
|
return '.'.join([path, '[%d]' % indx])
|
||||||
|
|
||||||
|
for i, v in enumerate(snippet):
|
||||||
|
validate(v, mkpath(i))
|
||||||
|
|
||||||
|
|
||||||
def dependencies(snippet, path=''):
|
def dependencies(snippet, path=''):
|
||||||
|
|
|
@ -25,9 +25,9 @@ class OutputDefinition(object):
|
||||||
self._resolved_value = None
|
self._resolved_value = None
|
||||||
self._description = description
|
self._description = description
|
||||||
|
|
||||||
def validate(self):
|
def validate(self, path=''):
|
||||||
"""Validate the output value without resolving it."""
|
"""Validate the output value without resolving it."""
|
||||||
function.validate(self._value)
|
function.validate(self._value, path)
|
||||||
|
|
||||||
def dep_attrs(self, resource_name):
|
def dep_attrs(self, resource_name):
|
||||||
"""Iterate over attributes of a given resource that this references.
|
"""Iterate over attributes of a given resource that this references.
|
||||||
|
|
|
@ -1501,8 +1501,8 @@ class Resource(object):
|
||||||
self.stack.context,
|
self.stack.context,
|
||||||
self.t.resource_type
|
self.t.resource_type
|
||||||
)
|
)
|
||||||
|
path = '.'.join([self.stack.t.RESOURCES, self.name])
|
||||||
function.validate(self.t)
|
function.validate(self.t, path)
|
||||||
self.validate_deletion_policy(self.t.deletion_policy())
|
self.validate_deletion_policy(self.t.deletion_policy())
|
||||||
self.t.update_policy(self.update_policy_schema,
|
self.t.update_policy(self.update_policy_schema,
|
||||||
self.context).validate()
|
self.context).validate()
|
||||||
|
|
|
@ -838,15 +838,13 @@ class Stack(collections.Mapping):
|
||||||
|
|
||||||
for op_name, output in six.iteritems(self.outputs):
|
for op_name, output in six.iteritems(self.outputs):
|
||||||
try:
|
try:
|
||||||
output.validate()
|
path = '.'.join([self.t.OUTPUTS, op_name,
|
||||||
except exception.StackValidationFailed as ex:
|
self.t.OUTPUT_VALUE])
|
||||||
|
output.validate(path)
|
||||||
|
except exception.StackValidationFailed:
|
||||||
raise
|
raise
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
raise
|
raise
|
||||||
except Exception as ex:
|
|
||||||
raise exception.StackValidationFailed(
|
|
||||||
error='Validation error in output "%s"' % op_name,
|
|
||||||
message=six.text_type(ex))
|
|
||||||
|
|
||||||
def requires_deferred_auth(self):
|
def requires_deferred_auth(self):
|
||||||
"""Determine whether to perform API requests with deferred auth.
|
"""Determine whether to perform API requests with deferred auth.
|
||||||
|
|
|
@ -178,8 +178,9 @@ class ValidateTest(common.HeatTestCase):
|
||||||
def test_validate_func(self):
|
def test_validate_func(self):
|
||||||
self.assertIsNone(function.validate(self.func))
|
self.assertIsNone(function.validate(self.func))
|
||||||
self.func = TestFunction(None, 'foo', ['bar'])
|
self.func = TestFunction(None, 'foo', ['bar'])
|
||||||
ex = self.assertRaises(TypeError, function.validate, self.func)
|
self.assertRaisesRegexp(exception.StackValidationFailed,
|
||||||
self.assertEqual('Need more arguments', six.text_type(ex))
|
'.foo: Need more arguments',
|
||||||
|
function.validate, self.func)
|
||||||
|
|
||||||
def test_validate_dict(self):
|
def test_validate_dict(self):
|
||||||
snippet = {'foo': 'bar', 'blarg': self.func}
|
snippet = {'foo': 'bar', 'blarg': self.func}
|
||||||
|
@ -187,8 +188,9 @@ class ValidateTest(common.HeatTestCase):
|
||||||
|
|
||||||
self.func = TestFunction(None, 'foo', ['bar'])
|
self.func = TestFunction(None, 'foo', ['bar'])
|
||||||
snippet = {'foo': 'bar', 'blarg': self.func}
|
snippet = {'foo': 'bar', 'blarg': self.func}
|
||||||
ex = self.assertRaises(TypeError, function.validate, snippet)
|
self.assertRaisesRegexp(exception.StackValidationFailed,
|
||||||
self.assertEqual('Need more arguments', six.text_type(ex))
|
'.blarg.foo: Need more arguments',
|
||||||
|
function.validate, snippet)
|
||||||
|
|
||||||
def test_validate_list(self):
|
def test_validate_list(self):
|
||||||
snippet = ['foo', 'bar', 'baz', 'blarg', self.func]
|
snippet = ['foo', 'bar', 'baz', 'blarg', self.func]
|
||||||
|
@ -196,8 +198,9 @@ class ValidateTest(common.HeatTestCase):
|
||||||
|
|
||||||
self.func = TestFunction(None, 'foo', ['bar'])
|
self.func = TestFunction(None, 'foo', ['bar'])
|
||||||
snippet = {'foo': 'bar', 'blarg': self.func}
|
snippet = {'foo': 'bar', 'blarg': self.func}
|
||||||
ex = self.assertRaises(TypeError, function.validate, snippet)
|
self.assertRaisesRegexp(exception.StackValidationFailed,
|
||||||
self.assertEqual('Need more arguments', six.text_type(ex))
|
'.blarg.foo: Need more arguments',
|
||||||
|
function.validate, snippet)
|
||||||
|
|
||||||
def test_validate_all(self):
|
def test_validate_all(self):
|
||||||
snippet = ['foo', {'bar': ['baz', {'blarg': self.func}]}]
|
snippet = ['foo', {'bar': ['baz', {'blarg': self.func}]}]
|
||||||
|
@ -205,8 +208,9 @@ class ValidateTest(common.HeatTestCase):
|
||||||
|
|
||||||
self.func = TestFunction(None, 'foo', ['bar'])
|
self.func = TestFunction(None, 'foo', ['bar'])
|
||||||
snippet = {'foo': 'bar', 'blarg': self.func}
|
snippet = {'foo': 'bar', 'blarg': self.func}
|
||||||
ex = self.assertRaises(TypeError, function.validate, snippet)
|
self.assertRaisesRegexp(exception.StackValidationFailed,
|
||||||
self.assertEqual('Need more arguments', six.text_type(ex))
|
'.blarg.foo: Need more arguments',
|
||||||
|
function.validate, snippet)
|
||||||
|
|
||||||
|
|
||||||
class DependenciesTest(common.HeatTestCase):
|
class DependenciesTest(common.HeatTestCase):
|
||||||
|
|
|
@ -1120,7 +1120,10 @@ class HOTemplateTest(common.HeatTestCase):
|
||||||
'data': {'var1': [1, 2, 3, 4]}}}
|
'data': {'var1': [1, 2, 3, 4]}}}
|
||||||
tmpl = template.Template(hot_newton_tpl_empty)
|
tmpl = template.Template(hot_newton_tpl_empty)
|
||||||
yaql = tmpl.parse(None, snippet)
|
yaql = tmpl.parse(None, snippet)
|
||||||
self.assertRaises(ValueError, function.validate, yaql)
|
regxp = ('.yaql: Bad expression Parse error: unexpected end '
|
||||||
|
'of statement.')
|
||||||
|
self.assertRaisesRegexp(exception.StackValidationFailed, regxp,
|
||||||
|
function.validate, yaql)
|
||||||
|
|
||||||
def test_yaql_data_as_function(self):
|
def test_yaql_data_as_function(self):
|
||||||
snippet = {'yaql': {'expression': '$.data.var1.len()',
|
snippet = {'yaql': {'expression': '$.data.var1.len()',
|
||||||
|
@ -1383,7 +1386,10 @@ conditions:
|
||||||
snippet = {'repeat': {'template': 'this is %var%',
|
snippet = {'repeat': {'template': 'this is %var%',
|
||||||
'for_each': '%var%'}}
|
'for_each': '%var%'}}
|
||||||
repeat = tmpl.parse(None, snippet)
|
repeat = tmpl.parse(None, snippet)
|
||||||
self.assertRaises(TypeError, function.validate, repeat)
|
regxp = ('.repeat: The "for_each" argument to "repeat" '
|
||||||
|
'must contain a map')
|
||||||
|
self.assertRaisesRegexp(exception.StackValidationFailed, regxp,
|
||||||
|
function.validate, repeat)
|
||||||
|
|
||||||
def test_digest(self):
|
def test_digest(self):
|
||||||
snippet = {'digest': ['md5', 'foobar']}
|
snippet = {'digest': ['md5', 'foobar']}
|
||||||
|
@ -1626,10 +1632,11 @@ conditions:
|
||||||
snippet = {'Fn::GetAZs': ''}
|
snippet = {'Fn::GetAZs': ''}
|
||||||
stack = parser.Stack(utils.dummy_context(), 'test_stack',
|
stack = parser.Stack(utils.dummy_context(), 'test_stack',
|
||||||
template.Template(hot_juno_tpl_empty))
|
template.Template(hot_juno_tpl_empty))
|
||||||
error = self.assertRaises(exception.InvalidTemplateVersion,
|
regxp = '.Fn::GetAZs: The template version is invalid'
|
||||||
function.validate,
|
self.assertRaisesRegexp(exception.StackValidationFailed,
|
||||||
stack.t.parse(stack, snippet))
|
regxp,
|
||||||
self.assertIn(next(iter(snippet)), six.text_type(error))
|
function.validate,
|
||||||
|
stack.t.parse(stack, snippet))
|
||||||
|
|
||||||
def test_add_resource(self):
|
def test_add_resource(self):
|
||||||
hot_tpl = template_format.parse('''
|
hot_tpl = template_format.parse('''
|
||||||
|
|
|
@ -1846,13 +1846,11 @@ class StackTest(common.HeatTestCase):
|
||||||
self.stack = stack.Stack(self.ctx, 'stack_with_correct_outputs',
|
self.stack = stack.Stack(self.ctx, 'stack_with_correct_outputs',
|
||||||
template.Template(tmpl))
|
template.Template(tmpl))
|
||||||
|
|
||||||
ex = self.assertRaises(exception.StackValidationFailed,
|
self.assertRaisesRegexp(
|
||||||
self.stack.validate)
|
exception.StackValidationFailed,
|
||||||
|
('Outputs.Resource_attr.Value.Fn::GetAtt: The Referenced '
|
||||||
self.assertEqual('Validation error in output "Resource_attr": '
|
'Attribute \(AResource Bar\) is incorrect.'),
|
||||||
'The Referenced Attribute '
|
self.stack.validate)
|
||||||
'(AResource Bar) is incorrect.',
|
|
||||||
six.text_type(ex))
|
|
||||||
|
|
||||||
def test_incorrect_outputs_cfn_incorrect_reference(self):
|
def test_incorrect_outputs_cfn_incorrect_reference(self):
|
||||||
tmpl = template_format.parse("""
|
tmpl = template_format.parse("""
|
||||||
|
@ -2212,13 +2210,11 @@ class StackTest(common.HeatTestCase):
|
||||||
self.stack = stack.Stack(self.ctx, 'stack_with_correct_outputs',
|
self.stack = stack.Stack(self.ctx, 'stack_with_correct_outputs',
|
||||||
template.Template(tmpl))
|
template.Template(tmpl))
|
||||||
|
|
||||||
ex = self.assertRaises(exception.StackValidationFailed,
|
self.assertRaisesRegexp(
|
||||||
self.stack.validate)
|
exception.StackValidationFailed,
|
||||||
|
('outputs.resource_attr.value.get_attr: The Referenced Attribute '
|
||||||
self.assertEqual('Validation error in output "resource_attr": '
|
'\(AResource Bar\) is incorrect.'),
|
||||||
'The Referenced Attribute '
|
self.stack.validate)
|
||||||
'(AResource Bar) is incorrect.',
|
|
||||||
six.text_type(ex))
|
|
||||||
|
|
||||||
def test_snapshot_save_called_first(self):
|
def test_snapshot_save_called_first(self):
|
||||||
def snapshotting_called_first(stack, action, status, reason):
|
def snapshotting_called_first(stack, action, status, reason):
|
||||||
|
|
Loading…
Reference in New Issue