Fixes template not using the JSON or YAML format

An internal unexpected exception is raised while validating a template
which only has string content. We should handle the case and raise the
correct error message such as "invalid format" and to tell the template is
not using the JSON or YAML format.

And modify incorrect version name and version date in this patch.
And change "template" from global variale to class varialbe in
test_api_cfn_v1.py. (missed in another patch which this patch
depends on: Change Idc2ba2b9 by misoperation)

Change-Id: I46ee8c48e3ddae71be061cfda0c029d86d132684
Closes-Bug: #1267379
This commit is contained in:
huangtianhua 2014-01-17 16:00:33 +08:00
parent 1b7fd3dc28
commit dbc66c1efd
4 changed files with 67 additions and 32 deletions

View File

@ -59,9 +59,9 @@ def parse(tmpl_str):
if len(tmpl_str) > cfg.CONF.max_template_size: if len(tmpl_str) > cfg.CONF.max_template_size:
msg = _('Template exceeds maximum allowed size.') msg = _('Template exceeds maximum allowed size.')
raise exception.RequestLimitExceeded(message=msg) raise exception.RequestLimitExceeded(message=msg)
if tmpl_str.startswith('{'): try:
tpl = json.loads(tmpl_str) tpl = json.loads(tmpl_str)
else: except ValueError:
try: try:
tpl = yaml.load(tmpl_str, Loader=yaml_loader) tpl = yaml.load(tmpl_str, Loader=yaml_loader)
except yaml.YAMLError as yea: except yaml.YAMLError as yea:
@ -69,6 +69,9 @@ def parse(tmpl_str):
else: else:
if tpl is None: if tpl is None:
tpl = {} tpl = {}
if not isinstance(tpl, dict):
raise ValueError(_('The template is not a JSON object '
'or YAML mapping.'))
# Looking for supported version keys in the loaded template # Looking for supported version keys in the loaded template
if not ('HeatTemplateFormatVersion' in tpl if not ('HeatTemplateFormatVersion' in tpl
or 'heat_template_version' in tpl or 'heat_template_version' in tpl

View File

@ -30,7 +30,6 @@ from heat.tests.common import HeatTestCase
from heat.tests import utils from heat.tests import utils
policy_path = os.path.dirname(os.path.realpath(__file__)) + "/policy/" policy_path = os.path.dirname(os.path.realpath(__file__)) + "/policy/"
template = {u'AWSTemplateFormatVersion': u'2010-09-09', u'Foo': u'bar'}
class CfnStackControllerTest(HeatTestCase): class CfnStackControllerTest(HeatTestCase):
@ -51,6 +50,8 @@ class CfnStackControllerTest(HeatTestCase):
cfg.CONF.set_default('host', 'host') cfg.CONF.set_default('host', 'host')
self.topic = rpc_api.ENGINE_TOPIC self.topic = rpc_api.ENGINE_TOPIC
self.api_version = '1.0' self.api_version = '1.0'
self.template = {u'AWSTemplateFormatVersion': u'2010-09-09',
u'Foo': u'bar'}
# Create WSGI controller instance # Create WSGI controller instance
class DummyConfig(): class DummyConfig():
@ -465,7 +466,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create(self): def test_create(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -488,7 +489,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -511,7 +512,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_rollback(self): def test_create_rollback(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -534,7 +535,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -557,7 +558,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_onfailure_true(self): def test_create_onfailure_true(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -580,7 +581,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -603,7 +604,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_onfailure_false_delete(self): def test_create_onfailure_false_delete(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -626,7 +627,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -649,7 +650,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_onfailure_false_rollback(self): def test_create_onfailure_false_rollback(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -672,7 +673,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -695,7 +696,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_onfailure_err(self): def test_create_onfailure_err(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -734,7 +735,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_err_rpcerr(self): def test_create_err_rpcerr(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -756,7 +757,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -769,7 +770,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -782,7 +783,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -803,7 +804,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_err_exists(self): def test_create_err_exists(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -822,7 +823,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -838,7 +839,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_create_err_engine(self): def test_create_err_engine(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'CreateStack', 'StackName': stack_name, params = {'Action': 'CreateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'TimeoutInMinutes': 30, 'TimeoutInMinutes': 30,
@ -856,7 +857,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'create_stack', 'method': 'create_stack',
'args': {'stack_name': stack_name, 'args': {'stack_name': stack_name,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -873,7 +874,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_update(self): def test_update(self):
# Format a dummy request # Format a dummy request
stack_name = "wordpress" stack_name = "wordpress"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'UpdateStack', 'StackName': stack_name, params = {'Action': 'UpdateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'Parameters.member.1.ParameterKey': 'InstanceType', 'Parameters.member.1.ParameterKey': 'InstanceType',
@ -897,7 +898,7 @@ class CfnStackControllerTest(HeatTestCase):
{'namespace': None, {'namespace': None,
'method': 'update_stack', 'method': 'update_stack',
'args': {'stack_identity': identity, 'args': {'stack_identity': identity,
'template': template, 'template': self.template,
'params': engine_parms, 'params': engine_parms,
'files': {}, 'files': {},
'args': engine_args}, 'args': engine_args},
@ -920,7 +921,7 @@ class CfnStackControllerTest(HeatTestCase):
def test_update_bad_name(self): def test_update_bad_name(self):
stack_name = "wibble" stack_name = "wibble"
json_template = json.dumps(template) json_template = json.dumps(self.template)
params = {'Action': 'UpdateStack', 'StackName': stack_name, params = {'Action': 'UpdateStack', 'StackName': stack_name,
'TemplateBody': '%s' % json_template, 'TemplateBody': '%s' % json_template,
'Parameters.member.1.ParameterKey': 'InstanceType', 'Parameters.member.1.ParameterKey': 'InstanceType',
@ -956,7 +957,7 @@ class CfnStackControllerTest(HeatTestCase):
self._stub_enforce(dummy_req, 'GetTemplate') self._stub_enforce(dummy_req, 'GetTemplate')
# Stub out the RPC call to the engine with a pre-canned response # Stub out the RPC call to the engine with a pre-canned response
engine_resp = template engine_resp = self.template
self.m.StubOutWithMock(rpc, 'call') self.m.StubOutWithMock(rpc, 'call')
rpc.call(dummy_req.context, self.topic, rpc.call(dummy_req.context, self.topic,
@ -976,7 +977,7 @@ class CfnStackControllerTest(HeatTestCase):
expected = {'GetTemplateResponse': expected = {'GetTemplateResponse':
{'GetTemplateResult': {'GetTemplateResult':
{'TemplateBody': template}}} {'TemplateBody': self.template}}}
self.assertEqual(response, expected) self.assertEqual(response, expected)

View File

@ -81,7 +81,7 @@ class InstantiationDataTest(HeatTestCase):
def test_format_parse_invalid_message(self): def test_format_parse_invalid_message(self):
# make sure the parser error gets through to the caller. # make sure the parser error gets through to the caller.
bad_temp = ''' bad_temp = '''
heat_template_version: '2012-12-12' heat_template_version: '2013-05-23'
parameters: parameters:
KeyName: KeyName:
type: string type: string
@ -110,7 +110,7 @@ parameters:
self.assertEqual(data.template(), template) self.assertEqual(data.template(), template)
def test_template_string_json(self): def test_template_string_json(self):
template = '{"heat_template_version": "2012-12-12",' \ template = '{"heat_template_version": "2013-05-23",' \
'"foo": "bar", "blarg": "wibble"}' '"foo": "bar", "blarg": "wibble"}'
body = {'template': template} body = {'template': template}
data = stacks.InstantiationData(body) data = stacks.InstantiationData(body)

View File

@ -79,8 +79,14 @@ class JsonToYamlTest(HeatTestCase):
class YamlMinimalTest(HeatTestCase): class YamlMinimalTest(HeatTestCase):
def _parse_template(self, tmpl_str, msg_str):
parse_ex = self.assertRaises(ValueError,
template_format.parse,
tmpl_str)
self.assertIn(msg_str, str(parse_ex))
def test_long_yaml(self): def test_long_yaml(self):
template = {'HeatTemplateVersion': '2012-12-12'} template = {'HeatTemplateFormatVersion': '2012-12-12'}
config.cfg.CONF.set_override('max_template_size', 1024) config.cfg.CONF.set_override('max_template_size', 1024)
template['Resources'] = ['a'] * (config.cfg.CONF.max_template_size / 3) template['Resources'] = ['a'] * (config.cfg.CONF.max_template_size / 3)
limit = config.cfg.CONF.max_template_size limit = config.cfg.CONF.max_template_size
@ -93,13 +99,38 @@ class YamlMinimalTest(HeatTestCase):
def test_parse_no_version_format(self): def test_parse_no_version_format(self):
yaml = '' yaml = ''
self.assertRaises(ValueError, template_format.parse, yaml) self._parse_template(yaml, 'Template format version not found')
yaml2 = '''Parameters: {} yaml2 = '''Parameters: {}
Mappings: {} Mappings: {}
Resources: {} Resources: {}
Outputs: {} Outputs: {}
''' '''
self.assertRaises(ValueError, template_format.parse, yaml2) self._parse_template(yaml2, 'Template format version not found')
def test_parse_string_template(self):
tmpl_str = 'just string'
msg = 'The template is not a JSON object or YAML mapping.'
self._parse_template(tmpl_str, msg)
def test_parse_invalid_yaml_and_json_template(self):
tmpl_str = '{test'
msg = 'line 1, column 1'
self._parse_template(tmpl_str, msg)
def test_parse_json_document(self):
tmpl_str = '["foo" , "bar"]'
msg = 'The template is not a JSON object or YAML mapping.'
self._parse_template(tmpl_str, msg)
def test_parse_empty_json_template(self):
tmpl_str = '{}'
msg = 'Template format version not found'
self._parse_template(tmpl_str, msg)
def test_parse_yaml_template(self):
tmpl_str = 'heat_template_version: 2013-05-23'
expected = {'heat_template_version': '2013-05-23'}
self.assertEqual(expected, template_format.parse(tmpl_str))
class YamlParseExceptions(HeatTestCase): class YamlParseExceptions(HeatTestCase):