Add support for using ToscaTemplate with a parsed template string

* This patchset adds the ability for a ToscaTemplate object
   to be created with a parsed string instead of a file or URL.

Change-Id: I8e14d12f184bb4ebb5c22770f9c5017e946fb7ce
Closes-Bug: 1525377
This commit is contained in:
Bob.Haddleton 2015-12-11 15:36:53 -06:00
parent 1a6249ef62
commit b17656cb20
3 changed files with 138 additions and 32 deletions

View File

@ -31,10 +31,11 @@ class ImportsLoader(object):
('file', 'repository', 'namespace_uri',
'namespace_prefix')
def __init__(self, importslist, path, type_definition_list=None):
def __init__(self, importslist, path, type_definition_list=None,
tpl=None):
self.importslist = importslist
self.custom_defs = {}
if not path:
if not path and not tpl:
msg = _('Input tosca template is not provided.')
log.warning(msg)
ExceptionCollector.appendException(ValidationError(message=msg))
@ -136,6 +137,8 @@ class ImportsLoader(object):
+----------+--------+------------------------------+
| file | file | OK |
| file | URL | OK |
| preparsed| file | file must be a full path |
| preparsed| URL | OK |
| URL | file | file must be a relative path |
| URL | URL | OK |
+----------+--------+------------------------------+
@ -164,28 +167,42 @@ class ImportsLoader(object):
return YAML_LOADER(file_name, False)
elif not namespace_uri:
import_template = None
a_file = True
main_a_file = os.path.isfile(self.path)
if main_a_file:
if os.path.isfile(file_name):
if self.path:
if toscaparser.utils.urlutils.UrlUtils.validate_url(self.path):
if os.path.isabs(file_name):
msg = (_('Absolute file name "%(name)s" cannot be '
'used in a URL-based input template '
'"%(template)s".')
% {'name': file_name, 'template': self.path})
log.error(msg)
ExceptionCollector.appendException(ImportError(msg))
return
import_template = toscaparser.utils.urlutils.UrlUtils.\
join_url(self.path, file_name)
a_file = False
else:
a_file = True
main_a_file = os.path.isfile(self.path)
if main_a_file:
if os.path.isfile(file_name):
import_template = file_name
else:
full_path = os.path.join(
os.path.dirname(os.path.abspath(self.path)),
file_name)
if os.path.isfile(full_path):
import_template = full_path
else: # template is pre-parsed
if os.path.isabs(file_name):
import_template = file_name
else:
full_path = os.path.join(
os.path.dirname(os.path.abspath(self.path)),
file_name)
if os.path.isfile(full_path):
import_template = full_path
else: # main_a_url
if os.path.isabs(file_name):
msg = (_('Absolute file name "%(name)s" cannot be used '
'in a URL-based input template "%(template)s".')
% {'name': file_name, 'template': self.path})
msg = (_('Relative file name "%(name)s" cannot be used '
'in a pre-parsed input template.')
% {'name': file_name})
log.error(msg)
ExceptionCollector.appendException(ImportError(msg))
return
import_template = toscaparser.utils.urlutils.UrlUtils.\
join_url(self.path, file_name)
a_file = False
if not import_template:
log.error(_('Import "%(name)s" is not valid.') %
{'name': import_uri_def})

View File

@ -556,3 +556,62 @@ class ToscaTemplateTest(TestCase):
target.relationships
except TypeError as error:
self.fail(error)
def test_no_input(self):
self.assertRaises(exception.ValidationError, ToscaTemplate, None,
None, False, None)
err_msg = (('No path or yaml_dict_tpl was provided. '
'There is nothing to parse.'))
exception.ExceptionCollector.assertExceptionMessage(ValueError,
err_msg)
def test_path_and_yaml_dict_tpl_input(self):
test_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_helloworld.yaml")
yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
tosca = ToscaTemplate(test_tpl, yaml_dict_tpl=yaml_dict_tpl)
self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
def test_yaml_dict_tpl_input(self):
test_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_helloworld.yaml")
yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
tosca = ToscaTemplate(yaml_dict_tpl=yaml_dict_tpl)
self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
def test_yaml_dict_tpl_with_params_and_url_import(self):
test_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress_with_url_import.yaml")
yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
'db_root_pwd': 'mypasswd'}
tosca = ToscaTemplate(parsed_params=params,
yaml_dict_tpl=yaml_dict_tpl)
self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
def test_yaml_dict_tpl_with_rel_import(self):
test_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress.yaml")
yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
self.assertRaises(exception.ValidationError, ToscaTemplate, None,
None, False, yaml_dict_tpl)
err_msg = (_('Relative file name "custom_types/wordpress.yaml" '
'cannot be used in a pre-parsed input template.'))
exception.ExceptionCollector.assertExceptionMessage(ImportError,
err_msg)

View File

@ -51,13 +51,32 @@ class ToscaTemplate(object):
VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0']
'''Load the template data.'''
def __init__(self, path, parsed_params=None, a_file=True):
def __init__(self, path=None, parsed_params=None, a_file=True,
yaml_dict_tpl=None):
ExceptionCollector.start()
self.a_file = a_file
self.input_path = path
self.path = self._get_path(path)
if self.path:
self.tpl = YAML_LOADER(self.path, self.a_file)
self.input_path = None
self.path = None
self.tpl = None
if path:
self.input_path = path
self.path = self._get_path(path)
if self.path:
self.tpl = YAML_LOADER(self.path, self.a_file)
if yaml_dict_tpl:
msg = (_('Both path and yaml_dict_tpl arguments were '
'provided. Using path and ignoring yaml_dict_tpl.'))
log.info(msg)
print(msg)
else:
if yaml_dict_tpl:
self.tpl = yaml_dict_tpl
else:
ExceptionCollector.appendException(
ValueError(_('No path or yaml_dict_tpl was provided. '
'There is nothing to parse.')))
if self.tpl:
self.parsed_params = parsed_params
self._validate_field()
self.version = self._tpl_version()
@ -70,6 +89,7 @@ class ToscaTemplate(object):
self.nodetemplates = self._nodetemplates()
self.outputs = self._outputs()
self.graph = ToscaGraph(self.nodetemplates)
ExceptionCollector.stop()
self.verify_template()
@ -148,7 +168,7 @@ class ToscaTemplate(object):
if imports:
custom_defs = toscaparser.imports.\
ImportsLoader(imports, self.path,
type_defs).get_custom_defs()
type_defs, self.tpl).get_custom_defs()
if not custom_defs:
return
@ -199,13 +219,23 @@ class ToscaTemplate(object):
def verify_template(self):
if ExceptionCollector.exceptionsCaught():
raise ValidationError(
message=(_('\nThe input "%(path)s" failed validation with the '
'following error(s): \n\n\t')
% {'path': self.input_path}) +
'\n\t'.join(ExceptionCollector.getExceptionsReport()))
if self.input_path:
raise ValidationError(
message=(_('\nThe input "%(path)s" failed validation with '
'the following error(s): \n\n\t')
% {'path': self.input_path}) +
'\n\t'.join(ExceptionCollector.getExceptionsReport()))
else:
raise ValidationError(
message=_('\nThe pre-parsed input failed validation with '
'the following error(s): \n\n\t') +
'\n\t'.join(ExceptionCollector.getExceptionsReport()))
else:
msg = (_('The input "%(path)s" successfully passed validation.') %
{'path': self.input_path})
if self.input_path:
msg = (_('The input "%(path)s" successfully passed '
'validation.') % {'path': self.input_path})
else:
msg = _('The pre-parsed input successfully passed validation.')
log.info(msg)
print(msg)