Merge "TripleO Validator CLI Refactor" into stable/stein
This commit is contained in:
commit
d09212f5ed
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
Features:
|
||||
- |
|
||||
The TripleO Validator CLI has been revamped and new subcommands have been
|
||||
created. Moreover, the latter has been fully integrated with native
|
||||
openstack client library.
|
||||
|
||||
To list all the available validations:
|
||||
- openstack tripleo validator list
|
||||
To show detailed information about a validation:
|
||||
- openstack tripleo validator show
|
||||
To display validations parameters:
|
||||
- openstack tripleo validator show parameter
|
||||
To display information about the validations groups:
|
||||
- openstack tripleo validator group info
|
||||
To run the validations, by name or by group(s):
|
||||
- openstack tripleo validator run
|
|
@ -109,8 +109,11 @@ openstack.tripleoclient.v1 =
|
|||
undercloud_install = tripleoclient.v1.undercloud:InstallUndercloud
|
||||
undercloud_upgrade = tripleoclient.v1.undercloud:UpgradeUndercloud
|
||||
undercloud_backup = tripleoclient.v1.undercloud_backup:BackupUndercloud
|
||||
tripleo_validator_group_info = tripleoclient.v1.tripleo_validator:TripleOValidatorGroupInfo
|
||||
tripleo_validator_list = tripleoclient.v1.tripleo_validator:TripleOValidatorList
|
||||
tripleo_validator_run = tripleoclient.v1.tripleo_validator:TripleOValidatorRun
|
||||
tripleo_validator_show = tripleoclient.v1.tripleo_validator:TripleOValidatorShow
|
||||
tripleo_validator_show_parameter = tripleoclient.v1.tripleo_validator:TripleOValidatorShowParameter
|
||||
oslo.config.opts =
|
||||
undercloud_config = tripleoclient.config.undercloud:list_opts
|
||||
standalone_config = tripleoclient.config.standalone:list_opts
|
||||
|
|
|
@ -41,6 +41,10 @@ class Lister(Command, command.Lister):
|
|||
pass
|
||||
|
||||
|
||||
class ShowOne(Command, command.ShowOne):
|
||||
pass
|
||||
|
||||
|
||||
class DeprecatedActionStore(_StoreAction):
|
||||
"""To deprecated an option an store the value"""
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
|
@ -80,7 +80,10 @@ DEFAULT_VALIDATIONS_BASEDIR = '/usr/share/openstack-tripleo-validations'
|
|||
ANSIBLE_VALIDATION_DIR = \
|
||||
'/usr/share/openstack-tripleo-validations/playbooks'
|
||||
|
||||
VALIDATION_GROUPS = ['openshift-on-openstack',
|
||||
VALIDATION_GROUPS_INFO = '%s/groups.yaml' % DEFAULT_VALIDATIONS_BASEDIR
|
||||
|
||||
VALIDATION_GROUPS = ['no-op',
|
||||
'openshift-on-openstack',
|
||||
'prep',
|
||||
'pre-introspection',
|
||||
'pre-deployment',
|
||||
|
|
|
@ -30,9 +30,34 @@ VALIDATIONS_LIST = [{
|
|||
'groups': ['prep', 'pre-introspection'],
|
||||
'id': 'my_val2',
|
||||
'name': 'My Validition Two Name',
|
||||
'parameters': {}
|
||||
'parameters': {'min_value': 8}
|
||||
}]
|
||||
|
||||
GROUPS_LIST = [
|
||||
('group1', 'Group1 description'),
|
||||
('group2', 'Group2 description'),
|
||||
('group3', 'Group3 description'),
|
||||
]
|
||||
|
||||
|
||||
class TestValidatorGroupInfo(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestValidatorGroupInfo, self).setUp()
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = tripleo_validator.TripleOValidatorGroupInfo(self.app, None)
|
||||
|
||||
@mock.patch('tripleoclient.utils.parse_all_validation_groups_on_disk',
|
||||
return_value=GROUPS_LIST)
|
||||
def test_show_group_info(self, mock_validations):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
|
||||
class TestValidatorList(utils.TestCommand):
|
||||
|
||||
|
@ -53,6 +78,45 @@ class TestValidatorList(utils.TestCommand):
|
|||
self.cmd.take_action(parsed_args)
|
||||
|
||||
|
||||
class TestValidatorShow(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestValidatorShow, self).setUp()
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = tripleo_validator.TripleOValidatorShow(self.app, None)
|
||||
|
||||
@mock.patch('tripleoclient.utils.parse_all_validations_on_disk',
|
||||
return_value=VALIDATIONS_LIST)
|
||||
def test_validation_show(self, mock_validations):
|
||||
arglist = ['my_val1']
|
||||
verifylist = [('validation_id', 'my_val1')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
|
||||
class TestValidatorShowParameter(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestValidatorShowParameter, self).setUp()
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = tripleo_validator.TripleOValidatorShowParameter(self.app,
|
||||
None)
|
||||
|
||||
@mock.patch('tripleoclient.utils.parse_all_validations_on_disk',
|
||||
return_value=VALIDATIONS_LIST)
|
||||
def test_validation_show_parameter(self, mock_validations):
|
||||
arglist = ['--validation', 'my_val2']
|
||||
verifylist = [('validation_name', ['my_val2'])]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
|
||||
class TestValidatorRun(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -81,10 +145,10 @@ class TestValidatorRun(utils.TestCommand):
|
|||
|
||||
playbooks_dir = '/usr/share/openstack-tripleo-validations/playbooks'
|
||||
arglist = [
|
||||
'--validation-name',
|
||||
'--validation',
|
||||
'check-ftype'
|
||||
]
|
||||
verifylist = []
|
||||
verifylist = [('validation_name', ['check-ftype'])]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
|
|
@ -40,7 +40,6 @@ import socket
|
|||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import textwrap
|
||||
import time
|
||||
import yaml
|
||||
|
||||
|
@ -61,8 +60,6 @@ from tripleo_common.utils import config
|
|||
from tripleoclient import constants
|
||||
from tripleoclient import exceptions
|
||||
|
||||
from prettytable import PrettyTable
|
||||
|
||||
LOG = logging.getLogger(__name__ + ".utils")
|
||||
|
||||
|
||||
|
@ -1906,6 +1903,24 @@ def get_validation_parameters(validation):
|
|||
return dict()
|
||||
|
||||
|
||||
def parse_all_validation_groups_on_disk(groups_file_path=None):
|
||||
results = []
|
||||
|
||||
if not groups_file_path:
|
||||
groups_file_path = constants.VALIDATION_GROUPS_INFO
|
||||
|
||||
if not os.path.exists(groups_file_path):
|
||||
return results
|
||||
|
||||
with open(groups_file_path, 'r') as grps:
|
||||
contents = yaml.safe_load(grps)
|
||||
|
||||
for grp_name, grp_desc in sorted(contents.items()):
|
||||
results.append((grp_name, grp_desc[0].get('description')))
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def parse_all_validations_on_disk(path, groups=None):
|
||||
results = []
|
||||
validations_abspath = glob.glob("{path}/*.yaml".format(path=path))
|
||||
|
@ -1976,34 +1991,6 @@ def get_validations_parameters(validations_data,
|
|||
return params
|
||||
|
||||
|
||||
def get_validations_table(validations_data):
|
||||
"""Return the validations information as a pretty printed table """
|
||||
param_field_name = get_param_field_name(validations_data)
|
||||
|
||||
t = PrettyTable(border=True, header=True, padding_width=1)
|
||||
t.title = "TripleO validations"
|
||||
t.field_names = [
|
||||
"ID", "Name",
|
||||
"Description", "Groups",
|
||||
param_field_name.capitalize()
|
||||
]
|
||||
|
||||
for validation in validations_data['validations']:
|
||||
t.add_row([validation['id'],
|
||||
validation['name'],
|
||||
"\n".join(textwrap.wrap(validation['description'])),
|
||||
"\n".join(textwrap.wrap(' '.join(validation['groups']))),
|
||||
validation[param_field_name]])
|
||||
|
||||
t.sortby = "ID"
|
||||
t.align["ID"] = "l"
|
||||
t.align["Name"] = "l"
|
||||
t.align["Description"] = "l"
|
||||
t.align["Groups"] = "l"
|
||||
t.align[param_field_name.capitalize()] = "l"
|
||||
return t
|
||||
|
||||
|
||||
def get_validations_json(validations_data):
|
||||
"""Return the validations information as a pretty printed json """
|
||||
return json.dumps(validations_data, indent=4, sort_keys=True)
|
||||
|
|
|
@ -20,11 +20,13 @@ import os
|
|||
import pwd
|
||||
import six
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib.i18n import _
|
||||
|
||||
from tripleoclient import command
|
||||
from tripleoclient import constants
|
||||
from tripleoclient import utils as oooutils
|
||||
|
||||
|
@ -48,35 +50,116 @@ class _CommaListAction(argparse.Action):
|
|||
setattr(namespace, self.dest, values.split(','))
|
||||
|
||||
|
||||
class TripleOValidatorList(command.Command):
|
||||
"""List the available validations"""
|
||||
class TripleOValidatorGroupInfo(command.Lister):
|
||||
"""Display Information about Validation Groups"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(TripleOValidatorGroupInfo, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
group_file = constants.VALIDATION_GROUPS_INFO
|
||||
group = oooutils.parse_all_validation_groups_on_disk(group_file)
|
||||
|
||||
if not group:
|
||||
raise exceptions.CommandError(
|
||||
"Could not find groups information file %s" % group_file)
|
||||
|
||||
column_name = ("Groups", "Description")
|
||||
return (column_name, group)
|
||||
|
||||
|
||||
class TripleOValidatorShow(command.ShowOne):
|
||||
"""Display detailed information about a Validation"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(TripleOValidatorShow, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('validation_id',
|
||||
metavar="<validation>",
|
||||
type=str,
|
||||
help='Validation ID')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
validation = self.get_validations_details(parsed_args.validation_id)
|
||||
if not validation:
|
||||
raise exceptions.CommandError(
|
||||
"Could not find validation %s" % parsed_args.validation_id)
|
||||
|
||||
return self.format_validation(validation)
|
||||
|
||||
def get_validations_details(self, validation):
|
||||
results = oooutils.parse_all_validations_on_disk(
|
||||
constants.ANSIBLE_VALIDATION_DIR)
|
||||
|
||||
for r in results:
|
||||
if r['id'] == validation:
|
||||
return r
|
||||
return []
|
||||
|
||||
def format_validation(self, validation):
|
||||
column_names = ["ID"]
|
||||
data = [validation.pop('id')]
|
||||
|
||||
if 'name' in validation:
|
||||
column_names.append("Name")
|
||||
data.append(validation.pop('name'))
|
||||
|
||||
if 'description' in validation:
|
||||
column_names.append("Description")
|
||||
data.append(textwrap.fill(validation.pop('description')))
|
||||
|
||||
other_fields = list(validation.keys())
|
||||
other_fields.sort()
|
||||
for field in other_fields:
|
||||
column_names.append(field.capitalize())
|
||||
data.append(validation[field])
|
||||
|
||||
return column_names, data
|
||||
|
||||
|
||||
class TripleOValidatorShowParameter(command.Command):
|
||||
"""Display Validations Parameters"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = argparse.ArgumentParser(
|
||||
description=self.get_description(),
|
||||
prog=prog_name,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
add_help=False
|
||||
add_help=True
|
||||
)
|
||||
|
||||
ex_group = parser.add_mutually_exclusive_group(required=False)
|
||||
|
||||
ex_group.add_argument(
|
||||
'--validation',
|
||||
metavar='<validation_id>[,<validation_id>,...]',
|
||||
dest='validation_name',
|
||||
action=_CommaListAction,
|
||||
default=[],
|
||||
help=_("List specific validations, "
|
||||
"if more than one validation is required "
|
||||
"separate the names with commas: "
|
||||
"--validation check-ftype,512e | "
|
||||
"--validation 512e")
|
||||
)
|
||||
|
||||
ex_group.add_argument(
|
||||
'--group',
|
||||
metavar='<group_id>[,<group_id>,...]',
|
||||
action=_CommaListGroupAction,
|
||||
default=[],
|
||||
help=_("List specific group validations, "
|
||||
"if more than one group is required "
|
||||
"separate the group names with commas: "
|
||||
"pre-upgrade,prep | "
|
||||
"openshift-on-openstack")
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--output',
|
||||
action='store',
|
||||
default='table',
|
||||
choices=['table', 'json', 'yaml'],
|
||||
help=_("Change the default output: "
|
||||
"--output json|yaml")
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--parameters',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("List available validations parameters")
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--create-vars-file',
|
||||
'--download',
|
||||
metavar=('[json|yaml]', '/tmp/myvars'),
|
||||
action='store',
|
||||
default=[],
|
||||
|
@ -87,30 +170,14 @@ class TripleOValidatorList(command.Command):
|
|||
"[yaml|json] /tmp/myvars")
|
||||
)
|
||||
|
||||
ex_group = parser.add_mutually_exclusive_group(required=False)
|
||||
|
||||
ex_group.add_argument(
|
||||
'--validation-name',
|
||||
metavar='<validation_id>[,<validation_id>,...]',
|
||||
action=_CommaListAction,
|
||||
default=[],
|
||||
help=_("List specific validations, "
|
||||
"if more than one validation is required "
|
||||
"separate the names with commas: "
|
||||
"--validation-name check-ftype,512e | "
|
||||
"--validation-name 512e")
|
||||
)
|
||||
|
||||
ex_group.add_argument(
|
||||
'--group',
|
||||
metavar='<group>[,<group>,...]',
|
||||
action=_CommaListGroupAction,
|
||||
default=[],
|
||||
help=_("List specific group validations, "
|
||||
"if more than one group is required "
|
||||
"separate the group names with commas: "
|
||||
"--group pre-upgrade,prep | "
|
||||
"--group openshift-on-openstack")
|
||||
parser.add_argument(
|
||||
'-f', '--format',
|
||||
action='store',
|
||||
metavar='<format>',
|
||||
default='json',
|
||||
choices=['json', 'yaml'],
|
||||
help=_("Print representation of the validation. "
|
||||
"The choices of the output format is json,yaml. ")
|
||||
)
|
||||
|
||||
return parser
|
||||
|
@ -147,42 +214,72 @@ class TripleOValidatorList(command.Command):
|
|||
print(_("Creating variables file finished with errors"))
|
||||
print('Output: {}'.format(e))
|
||||
|
||||
def _run_validator_list(self, parsed_args):
|
||||
def _run_validator_show_parameter(self, parsed_args):
|
||||
LOG.debug(_('Launch showing parameters for the validations'))
|
||||
try:
|
||||
validations = oooutils.parse_all_validations_on_disk(
|
||||
constants.ANSIBLE_VALIDATION_DIR)
|
||||
|
||||
out = oooutils.get_validations_parameters(
|
||||
{'validations': validations},
|
||||
parsed_args.validation_name,
|
||||
parsed_args.group
|
||||
)
|
||||
|
||||
if parsed_args.download:
|
||||
self._create_variables_file(out,
|
||||
parsed_args.download)
|
||||
else:
|
||||
if parsed_args.format == 'yaml':
|
||||
print(oooutils.get_validations_yaml(out))
|
||||
else:
|
||||
print(oooutils.get_validations_json(out))
|
||||
except Exception as e:
|
||||
raise RuntimeError(_("Validations Show Parameters "
|
||||
"finished with errors\n"
|
||||
"Output: {}").format(e))
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self._run_validator_show_parameter(parsed_args)
|
||||
|
||||
|
||||
class TripleOValidatorList(command.Lister):
|
||||
"""List the available validations"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(TripleOValidatorList, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--group',
|
||||
metavar='<group>[,<group>,...]',
|
||||
action=_CommaListGroupAction,
|
||||
default=[],
|
||||
help=_("List specific group validations, "
|
||||
"if more than one group is required "
|
||||
"separate the group names with commas: "
|
||||
"--group pre-upgrade,prep | "
|
||||
"--group openshift-on-openstack")
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
LOG.debug(_('Launch listing the validations'))
|
||||
try:
|
||||
validations = oooutils.parse_all_validations_on_disk(
|
||||
constants.ANSIBLE_VALIDATION_DIR, parsed_args.group)
|
||||
|
||||
if parsed_args.parameters:
|
||||
out = oooutils.get_validations_parameters(
|
||||
{'validations': validations},
|
||||
parsed_args.validation_name,
|
||||
parsed_args.group
|
||||
)
|
||||
return_values = []
|
||||
column_name = ('ID', 'Name', 'Groups')
|
||||
|
||||
if parsed_args.create_vars_file:
|
||||
self._create_variables_file(out,
|
||||
parsed_args.create_vars_file)
|
||||
else:
|
||||
print(oooutils.get_validations_json(out))
|
||||
else:
|
||||
if parsed_args.output == 'json':
|
||||
out = oooutils.get_validations_json(
|
||||
{'validations': validations})
|
||||
elif parsed_args.output == 'yaml':
|
||||
out = oooutils.get_validations_yaml(
|
||||
{'validations': validations})
|
||||
else:
|
||||
out = oooutils.get_validations_table(
|
||||
{'validations': validations})
|
||||
print(out)
|
||||
for val in validations:
|
||||
return_values.append((val.get('id'), val.get('name'),
|
||||
val.get('groups')))
|
||||
return (column_name, return_values)
|
||||
except Exception as e:
|
||||
raise RuntimeError(_("Validations listing finished with errors\n"
|
||||
"Output: {}").format(e))
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self._run_validator_list(parsed_args)
|
||||
|
||||
|
||||
class TripleOValidatorRun(command.Command):
|
||||
"""Run the available validations"""
|
||||
|
@ -240,15 +337,16 @@ class TripleOValidatorRun(command.Command):
|
|||
ex_group = parser.add_mutually_exclusive_group(required=True)
|
||||
|
||||
ex_group.add_argument(
|
||||
'--validation-name',
|
||||
'--validation',
|
||||
metavar='<validation_id>[,<validation_id>,...]',
|
||||
dest="validation_name",
|
||||
action=_CommaListAction,
|
||||
default=[],
|
||||
help=_("Run specific validations, "
|
||||
"if more than one validation is required "
|
||||
"separate the names with commas: "
|
||||
"--validation-name check-ftype,512e | "
|
||||
"--validation-name 512e")
|
||||
"--validation check-ftype,512e | "
|
||||
"--validation 512e")
|
||||
)
|
||||
|
||||
ex_group.add_argument(
|
||||
|
|
Loading…
Reference in New Issue