Merge "shell: refactor to use argparse"
This commit is contained in:
commit
3b7fe1d7e4
@ -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
|
||||||
|
@ -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__)),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user