Browse Source

Merge "TripleO Validator CLI Refactor" into stable/stein

changes/35/705035/1
Zuul 1 month ago
parent
commit
d09212f5ed
7 changed files with 277 additions and 101 deletions
  1. +17
    -0
      releasenotes/notes/tripleo_validator_cli_refactor-64c298348d405347.yaml
  2. +3
    -0
      setup.cfg
  3. +4
    -0
      tripleoclient/command.py
  4. +4
    -1
      tripleoclient/constants.py
  5. +67
    -3
      tripleoclient/tests/v1/tripleo/test_tripleo_validator.py
  6. +18
    -31
      tripleoclient/utils.py
  7. +164
    -66
      tripleoclient/v1/tripleo_validator.py

+ 17
- 0
releasenotes/notes/tripleo_validator_cli_refactor-64c298348d405347.yaml View File

@@ -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

+ 3
- 0
setup.cfg View File

@@ -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

+ 4
- 0
tripleoclient/command.py View File

@@ -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__)

+ 4
- 1
tripleoclient/constants.py View File

@@ -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',

+ 67
- 3
tripleoclient/tests/v1/tripleo/test_tripleo_validator.py View File

@@ -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)

+ 18
- 31
tripleoclient/utils.py View File

@@ -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)

+ 164
- 66
tripleoclient/v1/tripleo_validator.py View File

@@ -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,69 +50,134 @@ 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
)

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',
metavar=('[json|yaml]', '/tmp/myvars'),
action='store',
default=[],
nargs=2,
help=_("Create a json or a yaml file "
"containing all the variables "
"available for the validations: "
"[yaml|json] /tmp/myvars")
add_help=True
)

ex_group = parser.add_mutually_exclusive_group(required=False)

ex_group.add_argument(
'--validation-name',
'--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-name check-ftype,512e | "
"--validation-name 512e")
"--validation check-ftype,512e | "
"--validation 512e")
)

ex_group.add_argument(
'--group',
metavar='<group>[,<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: "
"--group pre-upgrade,prep | "
"--group openshift-on-openstack")
"pre-upgrade,prep | "
"openshift-on-openstack")
)

parser.add_argument(
'--download',
metavar=('[json|yaml]', '/tmp/myvars'),
action='store',
default=[],
nargs=2,
help=_("Create a json or a yaml file "
"containing all the variables "
"available for the validations: "
"[yaml|json] /tmp/myvars")
)

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,41 +214,71 @@ class TripleOValidatorList(command.Command):
print(_("Creating variables file finished with errors"))
print('Output: {}'.format(e))

def _run_validator_list(self, parsed_args):
LOG.debug(_('Launch listing the validations'))
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, parsed_args.group)
constants.ANSIBLE_VALIDATION_DIR)

if parsed_args.parameters:
out = oooutils.get_validations_parameters(
{'validations': validations},
parsed_args.validation_name,
parsed_args.group
)
out = oooutils.get_validations_parameters(
{'validations': validations},
parsed_args.validation_name,
parsed_args.group
)

if parsed_args.create_vars_file:
self._create_variables_file(out,
parsed_args.create_vars_file)
else:
print(oooutils.get_validations_json(out))
if parsed_args.download:
self._create_variables_file(out,
parsed_args.download)
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})
if parsed_args.format == 'yaml':
print(oooutils.get_validations_yaml(out))
else:
out = oooutils.get_validations_table(
{'validations': validations})
print(out)
print(oooutils.get_validations_json(out))
except Exception as e:
raise RuntimeError(_("Validations listing finished with errors\n"
raise RuntimeError(_("Validations Show Parameters "
"finished with errors\n"
"Output: {}").format(e))

def take_action(self, parsed_args):
self._run_validator_list(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)

return_values = []
column_name = ('ID', 'Name', 'Groups')

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))


class TripleOValidatorRun(command.Command):
@@ -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…
Cancel
Save