Add validating of section 'conditions'
Validate section 'conditions' when stack validate. Change-Id: I0cf1abcc4656c573afbbd41e02b573ada63c1ae6 Blueprint: support-conditions-function
This commit is contained in:
parent
0803639788
commit
d072f6e7f1
|
@ -133,6 +133,11 @@ class InvalidConditionFunction(HeatException):
|
||||||
msg_fmt = _("The function is not supported in condition: %(func)s")
|
msg_fmt = _("The function is not supported in condition: %(func)s")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidConditionDefinition(HeatException):
|
||||||
|
msg_fmt = _("The definition of condition (%(cd)s) is "
|
||||||
|
"invalid: %(definition)s")
|
||||||
|
|
||||||
|
|
||||||
class ImmutableParameterModified(HeatException):
|
class ImmutableParameterModified(HeatException):
|
||||||
msg_fmt = _("The following parameters are immutable and may not be "
|
msg_fmt = _("The following parameters are immutable and may not be "
|
||||||
"updated: %(keys)s")
|
"updated: %(keys)s")
|
||||||
|
|
|
@ -176,6 +176,9 @@ class CfnTemplate(CfnTemplateBase):
|
||||||
(n, function.Invalid) for n in self.functions)
|
(n, function.Invalid) for n in self.functions)
|
||||||
self._parser_condition_functions.update(self.condition_functions)
|
self._parser_condition_functions.update(self.condition_functions)
|
||||||
|
|
||||||
|
def get_condition_definitions(self):
|
||||||
|
return self[self.CONDITIONS]
|
||||||
|
|
||||||
|
|
||||||
class HeatTemplate(CfnTemplateBase):
|
class HeatTemplate(CfnTemplateBase):
|
||||||
functions = {
|
functions = {
|
||||||
|
|
|
@ -511,3 +511,6 @@ class HOTemplate20161014(HOTemplate20160408):
|
||||||
else:
|
else:
|
||||||
self._parser_condition_functions[n] = f
|
self._parser_condition_functions[n] = f
|
||||||
self._parser_condition_functions.update(self.condition_functions)
|
self._parser_condition_functions.update(self.condition_functions)
|
||||||
|
|
||||||
|
def get_condition_definitions(self):
|
||||||
|
return self[self.CONDITIONS]
|
||||||
|
|
|
@ -779,6 +779,9 @@ class Stack(collections.Mapping):
|
||||||
parameter_groups = param_groups.ParameterGroups(self.t)
|
parameter_groups = param_groups.ParameterGroups(self.t)
|
||||||
parameter_groups.validate()
|
parameter_groups.validate()
|
||||||
|
|
||||||
|
# Validate condition definition of conditions section
|
||||||
|
self.t.validate_condition_definitions(self)
|
||||||
|
|
||||||
# Validate types of sections in ResourceDefinitions
|
# Validate types of sections in ResourceDefinitions
|
||||||
self.t.validate_resource_definitions(self)
|
self.t.validate_resource_definitions(self)
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,11 @@ class Template(collections.Mapping):
|
||||||
"""Check section's type of ResourceDefinitions."""
|
"""Check section's type of ResourceDefinitions."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def validate_condition_definitions(self, stack):
|
||||||
|
"""Check conditions section."""
|
||||||
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def resource_definitions(self, stack):
|
def resource_definitions(self, stack):
|
||||||
"""Return a dictionary of ResourceDefinition objects."""
|
"""Return a dictionary of ResourceDefinition objects."""
|
||||||
|
|
|
@ -74,3 +74,33 @@ class CommonTemplate(template.Template):
|
||||||
self.validate_resource_definition(name, data)
|
self.validate_resource_definition(name, data)
|
||||||
except (TypeError, ValueError, KeyError) as ex:
|
except (TypeError, ValueError, KeyError) as ex:
|
||||||
raise exception.StackValidationFailed(message=six.text_type(ex))
|
raise exception.StackValidationFailed(message=six.text_type(ex))
|
||||||
|
|
||||||
|
def validate_condition_definitions(self, stack):
|
||||||
|
"""Check conditions section."""
|
||||||
|
|
||||||
|
resolved_cds = self.resolve_conditions(stack)
|
||||||
|
if resolved_cds:
|
||||||
|
for cd_key, cd_value in six.iteritems(resolved_cds):
|
||||||
|
if not isinstance(cd_value, bool):
|
||||||
|
raise exception.InvalidConditionDefinition(
|
||||||
|
cd=cd_key,
|
||||||
|
definition=cd_value)
|
||||||
|
|
||||||
|
def resolve_conditions(self, stack):
|
||||||
|
cd_snippet = self.get_condition_definitions()
|
||||||
|
result = {}
|
||||||
|
if cd_snippet:
|
||||||
|
for cd_key, cd_value in six.iteritems(cd_snippet):
|
||||||
|
# hasn't been resolved yet
|
||||||
|
if not isinstance(cd_value, bool):
|
||||||
|
condition_func = self.parse_condition(
|
||||||
|
stack, cd_value)
|
||||||
|
resolved_cd_value = function.resolve(condition_func)
|
||||||
|
result[cd_key] = resolved_cd_value
|
||||||
|
else:
|
||||||
|
result[cd_key] = cd_value
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_condition_definitions(self):
|
||||||
|
return {}
|
||||||
|
|
|
@ -138,6 +138,9 @@ class TestTemplatePluginManager(common.HeatTestCase):
|
||||||
def validate_resource_definitions(self, stack):
|
def validate_resource_definitions(self, stack):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def validate_condition_definitions(self, stack):
|
||||||
|
pass
|
||||||
|
|
||||||
def resource_definitions(self, stack):
|
def resource_definitions(self, stack):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -274,6 +277,71 @@ class ParserTest(common.HeatTestCase):
|
||||||
self.assertIsNot(raw, parsed)
|
self.assertIsNot(raw, parsed)
|
||||||
|
|
||||||
|
|
||||||
|
class TestTemplateConditionParser(common.HeatTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestTemplateConditionParser, self).setUp()
|
||||||
|
self.ctx = utils.dummy_context()
|
||||||
|
|
||||||
|
def test_conditions_with_non_supported_functions(self):
|
||||||
|
t = {
|
||||||
|
'heat_template_version': '2016-10-14',
|
||||||
|
'parameters': {
|
||||||
|
'env_type': {
|
||||||
|
'type': 'string',
|
||||||
|
'default': 'test'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'conditions': {
|
||||||
|
'prod_env': {
|
||||||
|
'equals': [{'get_param': 'env_type'},
|
||||||
|
{'get_attr': [None, 'att']}]}}}
|
||||||
|
# test with get_attr in equals
|
||||||
|
tmpl = template.Template(t)
|
||||||
|
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
|
||||||
|
ex = self.assertRaises(exception.InvalidConditionFunction,
|
||||||
|
tmpl.resolve_conditions, stk)
|
||||||
|
self.assertIn('The function is not supported in condition: get_attr',
|
||||||
|
six.text_type(ex))
|
||||||
|
|
||||||
|
# test with get_resource in top level of a condition
|
||||||
|
tmpl.t['conditions']['prod_env'] = {'get_resource': 'R1'}
|
||||||
|
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
|
||||||
|
ex = self.assertRaises(exception.InvalidConditionFunction,
|
||||||
|
tmpl.resolve_conditions, stk)
|
||||||
|
self.assertIn('The function is not supported in condition: '
|
||||||
|
'get_resource', six.text_type(ex))
|
||||||
|
|
||||||
|
# test with get_attr in top level of a condition
|
||||||
|
tmpl.t['conditions']['prod_env'] = {'get_attr': [None, 'att']}
|
||||||
|
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
|
||||||
|
ex = self.assertRaises(exception.InvalidConditionFunction,
|
||||||
|
tmpl.resolve_conditions, stk)
|
||||||
|
self.assertIn('The function is not supported in condition: get_attr',
|
||||||
|
six.text_type(ex))
|
||||||
|
|
||||||
|
def test_condition_resolved_not_boolean(self):
|
||||||
|
t = {
|
||||||
|
'heat_template_version': '2016-10-14',
|
||||||
|
'parameters': {
|
||||||
|
'env_type': {
|
||||||
|
'type': 'string',
|
||||||
|
'default': 'test'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'conditions': {
|
||||||
|
'prod_env': {'get_param': 'env_type'}}}
|
||||||
|
|
||||||
|
# test with get_attr in equals
|
||||||
|
tmpl = template.Template(t)
|
||||||
|
stk = stack.Stack(self.ctx, 'test_condition_not_boolean', tmpl)
|
||||||
|
|
||||||
|
ex = self.assertRaises(exception.InvalidConditionDefinition,
|
||||||
|
tmpl.validate_condition_definitions, stk)
|
||||||
|
self.assertIn('The definition of condition (prod_env) is invalid',
|
||||||
|
six.text_type(ex))
|
||||||
|
|
||||||
|
|
||||||
class TestTemplateValidate(common.HeatTestCase):
|
class TestTemplateValidate(common.HeatTestCase):
|
||||||
|
|
||||||
def test_template_validate_cfn_check_t_digest(self):
|
def test_template_validate_cfn_check_t_digest(self):
|
||||||
|
|
Loading…
Reference in New Issue