Allow paths as lists in function.validate()

Previously when calling function.validate() we passed the path to the
function in the template (used for debugging purposes) as a string. This
change allows us to pass it as a list of path components, as we do
elsewhere, so that higher-level code that catches StackValidationFailed
can deal with its components separately.

Change-Id: I017aa6f7511b8478ef8273522ab8087684ae71c6
changes/29/520829/1
Zane Bitter 5 years ago
parent 38f1975cf7
commit cb80df4f4a
  1. 23
      heat/engine/function.py
  2. 8
      heat/tests/test_function.py
  3. 24
      heat/tests/test_hot.py

@ -267,29 +267,30 @@ def resolve(snippet):
return snippet
def validate(snippet, path=''):
def validate(snippet, path=None):
if path is None:
path = []
elif isinstance(path, six.string_types):
path = [path]
if isinstance(snippet, Function):
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))
path=path + [snippet.fn_name],
message=six.text_type(e))
elif isinstance(snippet, collections.Mapping):
def mkpath(key):
return '.'.join([path, key])
for k, v in six.iteritems(snippet):
validate(v, mkpath(k))
validate(v, path + [k])
elif (not isinstance(snippet, six.string_types) and
isinstance(snippet, collections.Iterable)):
def mkpath(indx):
return '.'.join([path, '[%d]' % indx])
basepath = list(path)
parent = basepath.pop() if basepath else ''
for i, v in enumerate(snippet):
validate(v, mkpath(i))
validate(v, basepath + ['%s[%d]' % (parent, i)])
def dependencies(snippet, path=''):

@ -180,7 +180,7 @@ class ValidateTest(common.HeatTestCase):
self.assertIsNone(function.validate(self.func))
self.func = TestFunction(None, 'foo', ['bar'])
self.assertRaisesRegex(exception.StackValidationFailed,
'.foo: Need more arguments',
'foo: Need more arguments',
function.validate, self.func)
def test_validate_dict(self):
@ -190,7 +190,7 @@ class ValidateTest(common.HeatTestCase):
self.func = TestFunction(None, 'foo', ['bar'])
snippet = {'foo': 'bar', 'blarg': self.func}
self.assertRaisesRegex(exception.StackValidationFailed,
'.blarg.foo: Need more arguments',
'blarg.foo: Need more arguments',
function.validate, snippet)
def test_validate_list(self):
@ -200,7 +200,7 @@ class ValidateTest(common.HeatTestCase):
self.func = TestFunction(None, 'foo', ['bar'])
snippet = {'foo': 'bar', 'blarg': self.func}
self.assertRaisesRegex(exception.StackValidationFailed,
'.blarg.foo: Need more arguments',
'blarg.foo: Need more arguments',
function.validate, snippet)
def test_validate_all(self):
@ -210,7 +210,7 @@ class ValidateTest(common.HeatTestCase):
self.func = TestFunction(None, 'foo', ['bar'])
snippet = {'foo': 'bar', 'blarg': self.func}
self.assertRaisesRegex(exception.StackValidationFailed,
'.blarg.foo: Need more arguments',
'blarg.foo: Need more arguments',
function.validate, snippet)

@ -864,7 +864,7 @@ class HOTemplateTest(common.HeatTestCase):
ex = self.assertRaises(exception.StackValidationFailed,
self.resolve, snippet, tmpl)
self.assertIn('.str_replace: "str_replace" parameters must be a'
self.assertIn('str_replace: "str_replace" parameters must be a'
' mapping', six.text_type(ex))
def test_str_replace_invalid_param_type_init(self):
@ -1027,13 +1027,13 @@ class HOTemplateTest(common.HeatTestCase):
l_tmpl = template.Template(hot_liberty_tpl_empty)
exc = self.assertRaises(exception.StackValidationFailed,
self.resolve, snippet, l_tmpl)
self.assertIn('.list_join: Incorrect arguments to "list_join"',
self.assertIn('list_join: Incorrect arguments to "list_join"',
six.text_type(exc))
k_tmpl = template.Template(hot_kilo_tpl_empty)
exc1 = self.assertRaises(exception.StackValidationFailed,
self.resolve, snippet, k_tmpl)
self.assertIn('.list_join: Incorrect arguments to "list_join"',
self.assertIn('list_join: Incorrect arguments to "list_join"',
six.text_type(exc1))
def test_join_int_invalid(self):
@ -1041,25 +1041,25 @@ class HOTemplateTest(common.HeatTestCase):
l_tmpl = template.Template(hot_liberty_tpl_empty)
exc = self.assertRaises(exception.StackValidationFailed,
self.resolve, snippet, l_tmpl)
self.assertIn('.list_join: Incorrect arguments', six.text_type(exc))
self.assertIn('list_join: Incorrect arguments', six.text_type(exc))
k_tmpl = template.Template(hot_kilo_tpl_empty)
exc1 = self.assertRaises(exception.StackValidationFailed,
self.resolve, snippet, k_tmpl)
self.assertIn('.list_join: Incorrect arguments', six.text_type(exc1))
self.assertIn('list_join: Incorrect arguments', six.text_type(exc1))
def test_join_invalid_value(self):
snippet = {'list_join': [',']}
l_tmpl = template.Template(hot_liberty_tpl_empty)
exc = self.assertRaises(exception.StackValidationFailed,
self.resolve, snippet, l_tmpl)
self.assertIn('.list_join: Incorrect arguments to "list_join"',
self.assertIn('list_join: Incorrect arguments to "list_join"',
six.text_type(exc))
k_tmpl = template.Template(hot_kilo_tpl_empty)
exc1 = self.assertRaises(exception.StackValidationFailed,
self.resolve, snippet, k_tmpl)
self.assertIn('.list_join: Incorrect arguments to "list_join"',
self.assertIn('list_join: Incorrect arguments to "list_join"',
six.text_type(exc1))
def test_join_invalid_multiple(self):
@ -1269,7 +1269,7 @@ class HOTemplateTest(common.HeatTestCase):
def test_yaql_non_map_args(self):
snippet = {'yaql': 'invalid'}
tmpl = template.Template(hot_newton_tpl_empty)
msg = '.yaql: Arguments to "yaql" must be a map.'
msg = 'yaql: Arguments to "yaql" must be a map.'
self.assertRaisesRegex(exception.StackValidationFailed,
msg, self.resolve, snippet, tmpl)
@ -1278,7 +1278,7 @@ class HOTemplateTest(common.HeatTestCase):
'data': {'var1': [1, 2, 3, 4]}}}
tmpl = template.Template(hot_newton_tpl_empty)
yaql = tmpl.parse(None, snippet)
regxp = ('.yaql: Bad expression Parse error: unexpected end '
regxp = ('yaql: Bad expression Parse error: unexpected end '
'of statement.')
self.assertRaisesRegex(exception.StackValidationFailed, regxp,
function.validate, yaql)
@ -1363,7 +1363,7 @@ class HOTemplateTest(common.HeatTestCase):
exc = self.assertRaises(exception.StackValidationFailed,
self.resolve_condition, snippet, tmpl)
error_msg = ('.equals: Arguments to "equals" must be '
error_msg = ('equals: Arguments to "equals" must be '
'of the form: [value_1, value_2]')
self.assertIn(error_msg, six.text_type(exc))
@ -1715,7 +1715,7 @@ resources:
snippet = {'repeat': {'template': 'this is %var%',
'for_each': '%var%'}}
repeat = tmpl.parse(None, snippet)
regxp = ('.repeat: The "for_each" argument to "repeat" '
regxp = ('repeat: The "for_each" argument to "repeat" '
'must contain a map')
self.assertRaisesRegex(exception.StackValidationFailed, regxp,
function.validate, repeat)
@ -1968,7 +1968,7 @@ resources:
snippet = {'Fn::GetAZs': ''}
stack = parser.Stack(utils.dummy_context(), 'test_stack',
template.Template(hot_juno_tpl_empty))
regxp = '.Fn::GetAZs: The template version is invalid'
regxp = 'Fn::GetAZs: The template version is invalid'
self.assertRaisesRegex(exception.StackValidationFailed,
regxp,
function.validate,

Loading…
Cancel
Save