Merge "shell: refactor to use argparse"

This commit is contained in:
Jenkins 2016-06-29 15:05:03 +00:00 committed by Gerrit Code Review
commit 3b7fe1d7e4
2 changed files with 95 additions and 120 deletions

View File

@ -11,6 +11,7 @@
# under the License. # under the License.
import argparse
import ast import ast
import json import json
import logging import logging
@ -54,76 +55,72 @@ class TranslatorShell(object):
SUPPORTED_TYPES = ['tosca'] SUPPORTED_TYPES = ['tosca']
def _validate(self, args): def get_parser(self):
if len(args) < 2: parser = argparse.ArgumentParser(prog="heat-translator")
msg = _("The program requires minimum two arguments. "
"Please refer to the usage documentation.") parser.add_argument('--template-file',
log.error(msg) metavar='<filename>',
raise ValueError(msg) required=True,
if "--template-file=" not in args[0]: help=_('Template file to load.'))
msg = _("The program expects --template-file as first argument. "
"Please refer to the usage documentation.") parser.add_argument('--output-file',
log.error(msg) metavar='<filename>',
raise ValueError(msg) help=_('Where to store the output file. If not '
if "--template-type=" not in args[1]: 'passed, it will be printed to stdin.'))
msg = _("The program expects --template-type as second argument. "
"Please refer to the usage documentation.") parser.add_argument('--template-type',
log.error(msg) metavar='<input-template-type>',
raise ValueError(msg) choices=self.SUPPORTED_TYPES,
default='tosca',
help=(_('Template type to parse. Choose between '
'%s.') % self.SUPPORTED_TYPES))
parser.add_argument('--parameters',
metavar='<param1=val1;param2=val2;...>',
help=_('Optional input parameters.'))
parser.add_argument('--validate-only',
action='store_true',
default=False,
help=_('Only validate input template, do not '
'perform translation.'))
parser.add_argument('--deploy',
action='store_true',
default=False,
help=_('Whether to deploy the generated template '
'or not.'))
return parser
def main(self, argv):
parser = self.get_parser()
(args, args_list) = parser.parse_known_args(argv)
template_file = args.template_file
template_type = args.template_type
output_file = args.output_file
validate_only = args.validate_only
deploy = args.deploy
def main(self, args):
self.deploy = False
self._validate(args)
path = args[0].split('--template-file=')[1]
# e.g. --template_file=translator/tests/data/tosca_helloworld.yaml
template_type = args[1].split('--template-type=')[1]
# e.g. --template_type=tosca
if not template_type:
msg = _("Template type is needed. For example, 'tosca'")
log.error(msg)
raise ValueError(msg)
elif template_type not in self.SUPPORTED_TYPES:
msg = _("%(value)s is not a valid template type.") % {
'value': template_type}
log.error(msg)
raise ValueError(msg)
parsed_params = {} parsed_params = {}
validate_only = None if args.parameters:
output_file = None parsed_params = self._parse_parameters(args.parameters)
if len(args) > 2:
parameters = None a_file = os.path.isfile(template_file)
for arg in args: a_url = UrlUtils.validate_url(template_file) if not a_file else False
if "--validate-only=" in arg:
validate_only = arg
if "--parameters=" in arg:
parameters = arg
if "--output-file=" in arg:
output = arg
output_file = output.split('--output-file=')[1]
if "--deploy" in arg:
self.deploy = True
if parameters:
parsed_params = self._parse_parameters(parameters)
a_file = os.path.isfile(path)
a_url = UrlUtils.validate_url(path) if not a_file else False
if a_file or a_url: if a_file or a_url:
run_only_validation = False
if validate_only: if validate_only:
value = validate_only.split('-validate-only=')[1].lower() ToscaTemplate(template_file, parsed_params, a_file)
if template_type == 'tosca' and value == 'true': msg = (_('The input "%(template_file)s" successfully passed '
run_only_validation = True 'validation.') % {'template_file': template_file})
if run_only_validation:
ToscaTemplate(path, parsed_params, a_file)
msg = (_('The input "%(path)s" successfully passed '
'validation.') % {'path': path})
print(msg) print(msg)
else: else:
log.info( heat_tpl = self._translate(template_type, template_file,
_('Checked whether template path is a file or url path.')) parsed_params, a_file, deploy)
heat_tpl = self._translate(template_type, path, parsed_params,
a_file)
if heat_tpl: if heat_tpl:
if utils.check_for_env_variables() and self.deploy: if utils.check_for_env_variables() and deploy:
try: try:
heatclient(heat_tpl, parsed_params) heatclient(heat_tpl, parsed_params)
except Exception: except Exception:
@ -131,47 +128,42 @@ class TranslatorShell(object):
self._write_output(heat_tpl, output_file) self._write_output(heat_tpl, output_file)
else: else:
msg = _("The path %(path)s is not a valid file or URL.") % { msg = (_('The path %(template_file)s is not a valid '
'path': path} 'file or URL.') % {'template_file': template_file})
log.error(msg) log.error(msg)
raise ValueError(msg) raise ValueError(msg)
def _parse_parameters(self, parameter_list): def _parse_parameters(self, parameter_list):
parsed_inputs = {} parsed_inputs = {}
if parameter_list.startswith('--parameters'):
# Parameters are semi-colon separated # Parameters are semi-colon separated
inputs = parameter_list.split('--parameters=')[1].\ inputs = parameter_list.replace('"', '').split(';')
replace('"', '').split(';') # Each parameter should be an assignment
# Each parameter should be an assignment for param in inputs:
for param in inputs: keyvalue = param.split('=')
keyvalue = param.split('=') # Validate the parameter has both a name and value
# Validate the parameter has both a name and value msg = _("'%(param)s' is not a well-formed parameter.") % {
msg = _("'%(param)s' is not a well-formed parameter.") % { 'param': param}
'param': param} if keyvalue.__len__() is 2:
if keyvalue.__len__() is 2: # Assure parameter name is not zero-length or whitespace
# Assure parameter name is not zero-length or whitespace stripped_name = keyvalue[0].strip()
stripped_name = keyvalue[0].strip() if not stripped_name:
if not stripped_name:
log.error(msg)
raise ValueError(msg)
# Add the valid parameter to the dictionary
parsed_inputs[keyvalue[0]] = keyvalue[1]
else:
log.error(msg) log.error(msg)
raise ValueError(msg) raise ValueError(msg)
else: # Add the valid parameter to the dictionary
msg = _("'%(list)s' is not a valid parameter list.") % { parsed_inputs[keyvalue[0]] = keyvalue[1]
'list': parameter_list} else:
log.error(msg) log.error(msg)
raise ValueError(msg) raise ValueError(msg)
return parsed_inputs return parsed_inputs
def _translate(self, sourcetype, path, parsed_params, a_file): def _translate(self, sourcetype, path, parsed_params, a_file, deploy):
output = None output = None
if sourcetype == "tosca": if sourcetype == "tosca":
log.debug(_('Loading the tosca template.')) log.debug(_('Loading the tosca template.'))
tosca = ToscaTemplate(path, parsed_params, a_file) tosca = ToscaTemplate(path, parsed_params, a_file)
translator = TOSCATranslator(tosca, parsed_params, self.deploy) translator = TOSCATranslator(tosca, parsed_params, deploy)
log.debug(_('Translating the tosca template.')) log.debug(_('Translating the tosca template.'))
output = translator.translate() output = translator.translate()
return output return output

View File

@ -29,28 +29,9 @@ class ShellTest(TestCase):
"data/tosca_helloworld.yaml") "data/tosca_helloworld.yaml")
template_file = '--template-file=' + tosca_helloworld template_file = '--template-file=' + tosca_helloworld
template_type = '--template-type=tosca' template_type = '--template-type=tosca'
template_validation = "--validate-only=true" template_validation = "--validate-only"
failure_msg = _('The program raised an exception unexpectedly.') failure_msg = _('The program raised an exception unexpectedly.')
def test_missing_arg(self):
error = self.assertRaises(ValueError, shell.main, '')
err_msg = _('The program requires minimum two arguments. '
'Please refer to the usage documentation.')
self.assertEqual(err_msg, str(error))
def test_invalid_file_arg(self):
error = self.assertRaises(ValueError, shell.main, 'translate me')
err_msg = _('The program expects --template-file as first '
'argument. Please refer to the usage documentation.')
self.assertEqual(err_msg, str(error))
def test_invalid_type_arg(self):
error = self.assertRaises(ValueError,
shell.main, ('--template-file=', 'xyz'))
err_msg = _('The program expects --template-type as second argument. '
'Please refer to the usage documentation.')
self.assertEqual(err_msg, str(error))
def test_invalid_file_value(self): def test_invalid_file_value(self):
error = self.assertRaises(ValueError, error = self.assertRaises(ValueError,
shell.main, ('--template-file=template.txt', shell.main, ('--template-file=template.txt',
@ -59,17 +40,13 @@ class ShellTest(TestCase):
self.assertEqual(err_msg, str(error)) self.assertEqual(err_msg, str(error))
def test_invalid_type_value(self): def test_invalid_type_value(self):
error = self.assertRaises(ValueError, shell.main, self.assertRaises(SystemExit, shell.main,
(self.template_file, '--template-type=xyz')) (self.template_file, '--template-type=xyz'))
err_msg = _('xyz is not a valid template type.')
self.assertEqual(err_msg, str(error))
def test_invalid_parameters(self): def test_invalid_parameters(self):
error = self.assertRaises(ValueError, shell.main, self.assertRaises(ValueError, shell.main,
(self.template_file, self.template_type, (self.template_file, self.template_type,
'--parameters=key')) '--parameters=key'))
err_msg = _("'key' is not a well-formed parameter.")
self.assertEqual(err_msg, str(error))
def test_valid_template(self): def test_valid_template(self):
try: try:
@ -77,6 +54,12 @@ class ShellTest(TestCase):
except Exception: except Exception:
self.fail(self.failure_msg) self.fail(self.failure_msg)
def test_valid_template_without_type(self):
try:
shell.main([self.template_file])
except Exception:
self.fail(self.failure_msg)
def test_valid_template_with_parameters(self): def test_valid_template_with_parameters(self):
tosca_single_instance_wordpress = os.path.join( tosca_single_instance_wordpress = os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.path.dirname(os.path.abspath(__file__)),