Use Validations libs Client for main validation entry point
This patch implement validations-libs CLI in tripleo-validator
in order to converge and get only one entry point for the validations
in tripleo and Openstack.
Depends-On: https://review.opendev.org/c/openstack/validations-libs/+/782574
Depends-On: https://review.opendev.org/c/openstack/requirements/+/793797
Change-Id: I65fdbd0ffd42411196b0b3a25690670b76dda2c8
(cherry picked from commit 10a0873770
)
This commit is contained in:
parent
fea5819cc9
commit
0886ecd1bf
@ -16,5 +16,5 @@ osc-lib>=2.3.0 # Apache-2.0
|
|||||||
tripleo-common>=15.2.0 # Apache-2.0
|
tripleo-common>=15.2.0 # Apache-2.0
|
||||||
cryptography>=2.1 # BSD/Apache-2.0
|
cryptography>=2.1 # BSD/Apache-2.0
|
||||||
ansible-runner>=1.4.5 # Apache 2.0
|
ansible-runner>=1.4.5 # Apache 2.0
|
||||||
validations-libs>=1.0.0
|
validations-libs>=1.1.0 # Apache-2.0
|
||||||
openstacksdk>=0.48.0 # Apache-2.0
|
openstacksdk>=0.48.0 # Apache-2.0
|
||||||
|
@ -9,3 +9,4 @@ stestr>=2.0.0 # Apache-2.0
|
|||||||
testtools>=2.2.0 # MIT
|
testtools>=2.2.0 # MIT
|
||||||
requests-mock>=1.2.0 # Apache-2.0
|
requests-mock>=1.2.0 # Apache-2.0
|
||||||
testscenarios>=0.4 # Apache-2.0/BSD
|
testscenarios>=0.4 # Apache-2.0/BSD
|
||||||
|
validations-libs>=1.0.4 # Apache-2.0
|
@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
import mock
|
import mock
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -158,6 +159,7 @@ class FakeOptions(object):
|
|||||||
class FakeApp(object):
|
class FakeApp(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
_stdout = None
|
_stdout = None
|
||||||
|
self.LOG = logging.getLogger('FakeApp')
|
||||||
self.client_manager = None
|
self.client_manager = None
|
||||||
self.stdin = sys.stdin
|
self.stdin = sys.stdin
|
||||||
self.stdout = _stdout or sys.stdout
|
self.stdout = _stdout or sys.stdout
|
||||||
|
@ -13,18 +13,41 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from osc_lib.tests import utils
|
from tripleoclient.tests import base
|
||||||
|
|
||||||
from tripleoclient.v1 import tripleo_validator
|
from tripleoclient.v1 import tripleo_validator
|
||||||
from tripleoclient.tests import fakes
|
from tripleoclient.tests import fakes
|
||||||
|
|
||||||
|
|
||||||
class TestValidatorGroupInfo(utils.TestCommand):
|
class TestValidator(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.validator = tripleo_validator
|
||||||
|
super(TestValidator, self).setUp()
|
||||||
|
|
||||||
|
def test_module_init(self):
|
||||||
|
expected_names = set([
|
||||||
|
'LOG',
|
||||||
|
'TripleOValidatorList',
|
||||||
|
'TripleOValidatorShow',
|
||||||
|
'TripleOValidatorGroupInfo',
|
||||||
|
'TripleOValidatorShowParameter',
|
||||||
|
'TripleOValidatorRun',
|
||||||
|
'TripleOValidatorShowHistory',
|
||||||
|
'TripleOValidatorShowRun'
|
||||||
|
])
|
||||||
|
|
||||||
|
module_names = set(dir(self.validator))
|
||||||
|
|
||||||
|
self.assertTrue(expected_names.issubset(module_names))
|
||||||
|
|
||||||
|
|
||||||
|
class TestValidatorGroupInfo(base.TestCommand):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidatorGroupInfo, self).setUp()
|
super(TestValidatorGroupInfo, self).setUp()
|
||||||
@ -43,7 +66,7 @@ class TestValidatorGroupInfo(utils.TestCommand):
|
|||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestValidatorList(utils.TestCommand):
|
class TestValidatorList(base.TestCommand):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidatorList, self).setUp()
|
super(TestValidatorList, self).setUp()
|
||||||
@ -63,7 +86,7 @@ class TestValidatorList(utils.TestCommand):
|
|||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestValidatorShow(utils.TestCommand):
|
class TestValidatorShow(base.TestCommand):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidatorShow, self).setUp()
|
super(TestValidatorShow, self).setUp()
|
||||||
@ -76,14 +99,14 @@ class TestValidatorShow(utils.TestCommand):
|
|||||||
return_value=fakes.VALIDATIONS_LIST[0])
|
return_value=fakes.VALIDATIONS_LIST[0])
|
||||||
def test_validation_show(self, mock_validations):
|
def test_validation_show(self, mock_validations):
|
||||||
arglist = ['my_val1']
|
arglist = ['my_val1']
|
||||||
verifylist = [('validation_id', 'my_val1')]
|
verifylist = [('validation_name', 'my_val1')]
|
||||||
|
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestValidatorShowParameter(utils.TestCommand):
|
class TestValidatorShowParameter(base.TestCommand):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidatorShowParameter, self).setUp()
|
super(TestValidatorShowParameter, self).setUp()
|
||||||
@ -104,7 +127,7 @@ class TestValidatorShowParameter(utils.TestCommand):
|
|||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestValidatorShowRun(utils.TestCommand):
|
class TestValidatorShowRun(base.TestCommand):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidatorShowRun, self).setUp()
|
super(TestValidatorShowRun, self).setUp()
|
||||||
@ -125,7 +148,7 @@ class TestValidatorShowRun(utils.TestCommand):
|
|||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestValidatorShowHistory(utils.TestCommand):
|
class TestValidatorShowHistory(base.TestCommand):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidatorShowHistory, self).setUp()
|
super(TestValidatorShowHistory, self).setUp()
|
||||||
|
@ -12,525 +12,85 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import yaml
|
|
||||||
|
|
||||||
from openstack import exceptions as os_exceptions
|
from validations_libs.cli.history import GetHistory
|
||||||
from osc_lib.cli import parseractions
|
from validations_libs.cli.history import ListHistory
|
||||||
from osc_lib import exceptions
|
from validations_libs.cli.lister import ValidationList
|
||||||
from osc_lib.i18n import _
|
from validations_libs.cli.run import Run
|
||||||
from prettytable import PrettyTable
|
from validations_libs.cli.show import Show
|
||||||
|
from validations_libs.cli.show import ShowGroup
|
||||||
from osc_lib.command import command
|
from validations_libs.cli.show import ShowParameter
|
||||||
from tripleoclient import utils as oooutils
|
|
||||||
from tripleoclient.workflows import deployment
|
|
||||||
from tripleoclient import constants
|
|
||||||
|
|
||||||
from validations_libs import constants as v_consts
|
|
||||||
from validations_libs import utils as v_utils
|
|
||||||
from validations_libs.validation_actions import ValidationActions
|
|
||||||
from validations_libs.validation_logs import ValidationLogs
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__ + ".TripleoValidator")
|
|
||||||
|
|
||||||
RED = "\033[1;31m"
|
|
||||||
GREEN = "\033[0;32m"
|
|
||||||
CYAN = "\033[36m"
|
|
||||||
YELLOW = "\033[0;33m"
|
|
||||||
RESET = "\033[0;0m"
|
|
||||||
|
|
||||||
FAILED_VALIDATION = "{}FAILED{}".format(RED, RESET)
|
|
||||||
PASSED_VALIDATION = "{}PASSED{}".format(GREEN, RESET)
|
|
||||||
|
|
||||||
GROUP_FILE = constants.VALIDATION_GROUPS_INFO
|
|
||||||
|
|
||||||
NO_VALIDATION_STATE = ['DEPLOY_FAILED', 'DEPLOYING']
|
|
||||||
|
|
||||||
|
|
||||||
class _CommaListGroupAction(argparse.Action):
|
LOG = logging.getLogger(__name__)
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
|
||||||
opts = v_utils.get_validation_group_name_list(GROUP_FILE)
|
|
||||||
for value in values.split(','):
|
|
||||||
if value not in opts:
|
|
||||||
message = ("Invalid choice: {value} (choose from {choice})"
|
|
||||||
.format(value=value,
|
|
||||||
choice=opts))
|
|
||||||
raise argparse.ArgumentError(self, message)
|
|
||||||
setattr(namespace, self.dest, values.split(','))
|
|
||||||
|
|
||||||
|
|
||||||
class _CommaListAction(argparse.Action):
|
class TripleOValidatorList(ValidationList):
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
|
||||||
setattr(namespace, self.dest, values.split(','))
|
|
||||||
|
|
||||||
|
|
||||||
class TripleOValidatorGroupInfo(command.Lister):
|
|
||||||
"""Display Information about Validation Groups"""
|
|
||||||
|
|
||||||
auth_required = False
|
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
|
||||||
parser = super(TripleOValidatorGroupInfo, self).get_parser(prog_name)
|
|
||||||
return parser
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
actions = ValidationActions(constants.ANSIBLE_VALIDATION_DIR)
|
|
||||||
return actions.group_information(GROUP_FILE)
|
|
||||||
|
|
||||||
|
|
||||||
class TripleOValidatorShow(command.ShowOne):
|
|
||||||
"""Display detailed information about a Validation"""
|
|
||||||
|
|
||||||
auth_required = False
|
|
||||||
|
|
||||||
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):
|
|
||||||
LOG.debug(_('Show validation result'))
|
|
||||||
actions = ValidationActions(constants.ANSIBLE_VALIDATION_DIR)
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = actions.show_validations(parsed_args.validation_id)
|
|
||||||
except Exception as e:
|
|
||||||
raise exceptions.CommandError(e)
|
|
||||||
|
|
||||||
if data:
|
|
||||||
return data.keys(), data.values()
|
|
||||||
|
|
||||||
|
|
||||||
class TripleOValidatorShowParameter(command.Command):
|
|
||||||
"""Display Validations Parameters"""
|
|
||||||
|
|
||||||
auth_required = False
|
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description=self.get_description(),
|
|
||||||
prog=prog_name,
|
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
||||||
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(
|
|
||||||
'--download',
|
|
||||||
action='store',
|
|
||||||
default=None,
|
|
||||||
help=_("Create a json or a yaml file "
|
|
||||||
"containing all the variables "
|
|
||||||
"available for the validations: "
|
|
||||||
"/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
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
actions = ValidationActions(constants.ANSIBLE_VALIDATION_DIR)
|
|
||||||
params = actions.show_validations_parameters(
|
|
||||||
parsed_args.validation_name,
|
|
||||||
parsed_args.group,
|
|
||||||
parsed_args.format,
|
|
||||||
parsed_args.download)
|
|
||||||
if parsed_args.download:
|
|
||||||
print("The file {} has been created successfully".format(
|
|
||||||
parsed_args.download))
|
|
||||||
else:
|
|
||||||
print(params)
|
|
||||||
|
|
||||||
|
|
||||||
class TripleOValidatorList(command.Lister):
|
|
||||||
"""List the available validations"""
|
"""List the available validations"""
|
||||||
|
|
||||||
auth_required = False
|
auth_required = False
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, parser):
|
||||||
parser = super(TripleOValidatorList, self).get_parser(prog_name)
|
parser = super(TripleOValidatorList, self).get_parser(parser)
|
||||||
|
|
||||||
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
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
LOG.debug(_('Launch listing the validations'))
|
class TripleOValidatorShow(Show):
|
||||||
try:
|
"""Display detailed information about a Validation"""
|
||||||
v_consts.DEFAULT_VALIDATIONS_BASEDIR = constants.\
|
|
||||||
DEFAULT_VALIDATIONS_BASEDIR
|
auth_required = False
|
||||||
actions = ValidationActions(
|
|
||||||
validation_path=constants.ANSIBLE_VALIDATION_DIR
|
def get_parser(self, parser):
|
||||||
)
|
parser = super(TripleOValidatorShow, self).get_parser(parser)
|
||||||
return actions.list_validations(parsed_args.group)
|
return parser
|
||||||
except Exception as e:
|
|
||||||
raise RuntimeError(_("Validations listing finished with errors\n"
|
|
||||||
"Output: {}").format(e))
|
|
||||||
|
|
||||||
|
|
||||||
class TripleOValidatorRun(command.Command):
|
class TripleOValidatorGroupInfo(ShowGroup):
|
||||||
|
"""Display detailed information about a Group"""
|
||||||
|
|
||||||
|
auth_required = False
|
||||||
|
|
||||||
|
def get_parser(self, parser):
|
||||||
|
parser = super(TripleOValidatorGroupInfo, self).get_parser(parser)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
class TripleOValidatorShowParameter(ShowParameter):
|
||||||
|
"""Display Validations Parameters"""
|
||||||
|
|
||||||
|
auth_required = False
|
||||||
|
|
||||||
|
def get_parser(self, parser):
|
||||||
|
parser = super(TripleOValidatorShowParameter, self).get_parser(parser)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
class TripleOValidatorRun(Run):
|
||||||
"""Run the available validations"""
|
"""Run the available validations"""
|
||||||
|
|
||||||
auth_required = False
|
auth_required = False
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, parser):
|
||||||
parser = argparse.ArgumentParser(
|
parser = super(TripleOValidatorRun, self).get_parser(parser)
|
||||||
description=self.get_description(),
|
|
||||||
prog=prog_name,
|
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
||||||
add_help=False
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--plan', '--stack',
|
|
||||||
dest='plan',
|
|
||||||
default=None,
|
|
||||||
help=_("Execute the validations using a custom plan name")
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--ssh-user',
|
|
||||||
dest='ssh_user',
|
|
||||||
default='heat-admin',
|
|
||||||
help=_("Ssh User name for the Overcloud ssh connection.")
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--limit', action='store', required=False, help=_(
|
|
||||||
"A string that identifies a single node or comma-separated"
|
|
||||||
"list of nodes to be upgraded in parallel in this upgrade"
|
|
||||||
" run invocation. For example: --limit \"compute-0,"
|
|
||||||
" compute-1, compute-5\".")
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--static-inventory',
|
|
||||||
action='store',
|
|
||||||
default='',
|
|
||||||
help=_(
|
|
||||||
"Provide your own static inventory file. You can generate "
|
|
||||||
"such an inventory calling tripleo-ansible-inventory command. "
|
|
||||||
"Especially useful when heat service isn't available."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--python-interpreter',
|
|
||||||
action='store',
|
|
||||||
default="/usr/libexec/platform-python",
|
|
||||||
help=_("Python interpreter for Ansible execution. ")
|
|
||||||
)
|
|
||||||
|
|
||||||
extra_vars_group = parser.add_mutually_exclusive_group(required=False)
|
|
||||||
|
|
||||||
extra_vars_group.add_argument(
|
|
||||||
'--extra-vars',
|
|
||||||
metavar="key1=<val1>[,key2=val2 --extra-vars key3=<val3>]",
|
|
||||||
action=parseractions.MultiKeyValueAction,
|
|
||||||
help=_(
|
|
||||||
"Add Ansible extra variables to the validation(s) execution "
|
|
||||||
"as KEY=VALUE pair(s). Note that if you pass the same "
|
|
||||||
"KEY multiple times, the last given VALUE for that same KEY "
|
|
||||||
"will override the other(s)")
|
|
||||||
)
|
|
||||||
|
|
||||||
extra_vars_group.add_argument(
|
|
||||||
'--extra-vars-file',
|
|
||||||
action='store',
|
|
||||||
default='',
|
|
||||||
help=_(
|
|
||||||
"Add a JSON/YAML file containing extra variable "
|
|
||||||
"to a validation: "
|
|
||||||
"--extra-vars-file /home/stack/vars.[json|yaml] "
|
|
||||||
"If using Mistral, only a valid JSON file will be "
|
|
||||||
"supported."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
extra_vars_group.add_argument(
|
|
||||||
'--extra-env-vars',
|
|
||||||
metavar="key1=<val1>[,key2=val2 --extra-env-vars key3=<val3>]",
|
|
||||||
action=parseractions.MultiKeyValueAction,
|
|
||||||
help=_(
|
|
||||||
"Add extra environment variables you may need "
|
|
||||||
"to provide to your Ansible execution "
|
|
||||||
"as KEY=VALUE pairs. Note that if you pass the same "
|
|
||||||
"KEY multiple times, the last given VALUE for that same KEY "
|
|
||||||
"will override the other(s)")
|
|
||||||
)
|
|
||||||
|
|
||||||
ex_group = parser.add_mutually_exclusive_group(required=True)
|
|
||||||
|
|
||||||
ex_group.add_argument(
|
|
||||||
'--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 check-ftype,512e | "
|
|
||||||
"--validation 512e")
|
|
||||||
)
|
|
||||||
|
|
||||||
ex_group.add_argument(
|
|
||||||
'--group',
|
|
||||||
metavar='<group>[,<group>,...]',
|
|
||||||
action=_CommaListGroupAction,
|
|
||||||
default=[],
|
|
||||||
help=_("Run 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
|
return parser
|
||||||
|
|
||||||
def _run_validator_run(self, parsed_args):
|
|
||||||
LOG = logging.getLogger(__name__ + ".ValidationsRunAnsible")
|
|
||||||
|
|
||||||
plan = parsed_args.plan
|
class TripleOValidatorShowHistory(ListHistory):
|
||||||
# Try to perform OpenStack authentication, if no authentication
|
|
||||||
# and static inventory provided continue, else raise error.
|
|
||||||
try:
|
|
||||||
clients = self.app.client_manager
|
|
||||||
clients._auth_required = True
|
|
||||||
clients.setup_auth()
|
|
||||||
except os_exceptions.ConfigException:
|
|
||||||
msg = "Running Validations without authentication."
|
|
||||||
LOG.warning("{}{}{}".format(YELLOW, msg, RESET))
|
|
||||||
if not parsed_args.static_inventory:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
_("No static inventory provided, please provide a valid "
|
|
||||||
"inventory or use authentication."))
|
|
||||||
else:
|
|
||||||
if plan:
|
|
||||||
status = deployment.get_deployment_status(clients, plan)
|
|
||||||
if not status or status in NO_VALIDATION_STATE:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
_("The plan and the stack '{}' doesn't exist OR are "
|
|
||||||
"in 'failed' or 'deploying' state. "
|
|
||||||
"Please use a valid plan".format(plan)))
|
|
||||||
else:
|
|
||||||
msg = "Running Validations without Overcloud settings."
|
|
||||||
LOG.warning("{}{}{}".format(YELLOW, msg, RESET))
|
|
||||||
limit = parsed_args.limit
|
|
||||||
|
|
||||||
extra_vars = dict()
|
|
||||||
if parsed_args.extra_vars:
|
|
||||||
# if using multiple --extra-vars argument in the command-line
|
|
||||||
# we will get a list of multiple dictionaries.
|
|
||||||
for keypair in parsed_args.extra_vars:
|
|
||||||
extra_vars.update(keypair)
|
|
||||||
|
|
||||||
if parsed_args.extra_vars_file:
|
|
||||||
try:
|
|
||||||
with open(parsed_args.extra_vars_file, 'r') as env_file:
|
|
||||||
extra_vars.update(yaml.safe_load(env_file.read()))
|
|
||||||
except yaml.YAMLError as e:
|
|
||||||
error_msg = (
|
|
||||||
"The request body must be properly formatted YAML/JSON. "
|
|
||||||
"Details: %s." % e)
|
|
||||||
raise exceptions.CommandError(error_msg)
|
|
||||||
|
|
||||||
# Ansible execution should be quiet while using the validations_json
|
|
||||||
# default callback and be verbose while passing ANSIBLE_SDTOUT_CALLBACK
|
|
||||||
# environment variable to Ansible through the --extra-env-vars argument
|
|
||||||
quiet_mode = True
|
|
||||||
extra_env_vars = dict()
|
|
||||||
if parsed_args.extra_env_vars:
|
|
||||||
# if using multiple --extra-env-vars argument in the command-line
|
|
||||||
# we will get a list of multiple dictionaries.
|
|
||||||
for keypair in parsed_args.extra_env_vars:
|
|
||||||
if "ANSIBLE_STDOUT_CALLBACK" in keypair.keys():
|
|
||||||
quiet_mode = False
|
|
||||||
extra_env_vars.update(keypair)
|
|
||||||
|
|
||||||
# We don't check if the file exists in order to support
|
|
||||||
# passing a string such as "localhost,", like we can do with
|
|
||||||
# the "-i" option of ansible-playbook.
|
|
||||||
if parsed_args.static_inventory:
|
|
||||||
static_inventory = parsed_args.static_inventory
|
|
||||||
else:
|
|
||||||
static_inventory = oooutils.get_tripleo_ansible_inventory(
|
|
||||||
ssh_user=parsed_args.ssh_user,
|
|
||||||
stack=parsed_args.plan,
|
|
||||||
undercloud_connection='local',
|
|
||||||
return_inventory_file_path=True)
|
|
||||||
|
|
||||||
v_consts.DEFAULT_VALIDATIONS_BASEDIR = constants.\
|
|
||||||
DEFAULT_VALIDATIONS_BASEDIR
|
|
||||||
actions = ValidationActions()
|
|
||||||
try:
|
|
||||||
results = actions.run_validations(
|
|
||||||
inventory=static_inventory,
|
|
||||||
limit_hosts=limit,
|
|
||||||
group=parsed_args.group,
|
|
||||||
extra_vars=extra_vars,
|
|
||||||
validations_dir=constants.ANSIBLE_VALIDATION_DIR,
|
|
||||||
validation_name=parsed_args.validation_name,
|
|
||||||
extra_env_vars=extra_env_vars,
|
|
||||||
python_interpreter=parsed_args.python_interpreter,
|
|
||||||
quiet=quiet_mode,
|
|
||||||
ssh_user=parsed_args.ssh_user)
|
|
||||||
except RuntimeError as e:
|
|
||||||
raise exceptions.CommandError(e)
|
|
||||||
|
|
||||||
is_failed_validation = False
|
|
||||||
if results:
|
|
||||||
# Build output
|
|
||||||
t = PrettyTable(border=True, header=True, padding_width=1)
|
|
||||||
# Set Field name by getting the result dict keys
|
|
||||||
t.field_names = results[0].keys()
|
|
||||||
t.align = 'l'
|
|
||||||
for r in results:
|
|
||||||
if r.get('Status_by_Host'):
|
|
||||||
h = []
|
|
||||||
for host in r['Status_by_Host'].split(', '):
|
|
||||||
_name, _status = host.split(',')
|
|
||||||
color = (GREEN if _status == 'PASSED' else RED)
|
|
||||||
_name = '{}{}{}'.format(color, _name, RESET)
|
|
||||||
h.append(_name)
|
|
||||||
r['Status_by_Host'] = ', '.join(h)
|
|
||||||
if r.get('Status'):
|
|
||||||
status = r.get('Status')
|
|
||||||
if status == 'FAILED':
|
|
||||||
is_failed_validation = True
|
|
||||||
color = (CYAN if status in ['starting', 'running']
|
|
||||||
else GREEN if status == 'PASSED' else RED)
|
|
||||||
r['Status'] = '{}{}{}'.format(color, status, RESET)
|
|
||||||
t.add_row(r.values())
|
|
||||||
print(t)
|
|
||||||
else:
|
|
||||||
msg = "No Validation has been run, please check your parameters."
|
|
||||||
LOG.info(_(msg))
|
|
||||||
|
|
||||||
if not parsed_args.static_inventory:
|
|
||||||
LOG.debug(_('Removing static tripleo ansible inventory file'))
|
|
||||||
oooutils.cleanup_tripleo_ansible_inventory_file(
|
|
||||||
static_inventory)
|
|
||||||
|
|
||||||
if is_failed_validation:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
_("One or more validations have failed."))
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
self._run_validator_run(parsed_args)
|
|
||||||
|
|
||||||
|
|
||||||
class TripleOValidatorShowRun(command.Command):
|
|
||||||
"""Display details about a Validation execution"""
|
|
||||||
|
|
||||||
auth_required = False
|
|
||||||
|
|
||||||
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('uuid',
|
|
||||||
metavar="<uuid>",
|
|
||||||
type=str,
|
|
||||||
help='Validation UUID Run')
|
|
||||||
|
|
||||||
parser.add_argument('--full',
|
|
||||||
action='store_true',
|
|
||||||
help='Show Full Details for the run')
|
|
||||||
|
|
||||||
return parser
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
vlogs = ValidationLogs()
|
|
||||||
data = vlogs.get_logfile_content_by_uuid(parsed_args.uuid)
|
|
||||||
if data:
|
|
||||||
if parsed_args.full:
|
|
||||||
for d in data:
|
|
||||||
print(json.dumps(d, indent=4, sort_keys=True))
|
|
||||||
else:
|
|
||||||
for d in data:
|
|
||||||
for p in d.get('validation_output', []):
|
|
||||||
print(json.dumps(p['task'],
|
|
||||||
indent=4,
|
|
||||||
sort_keys=True))
|
|
||||||
else:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
"Could not find the log file linked to this UUID: %s" %
|
|
||||||
parsed_args.uuid)
|
|
||||||
|
|
||||||
|
|
||||||
class TripleOValidatorShowHistory(command.Lister):
|
|
||||||
"""Display Validations execution history"""
|
"""Display Validations execution history"""
|
||||||
|
|
||||||
auth_required = False
|
auth_required = False
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, parser):
|
||||||
parser = super(TripleOValidatorShowHistory, self).get_parser(prog_name)
|
parser = super(TripleOValidatorShowHistory, self).get_parser(parser)
|
||||||
|
|
||||||
parser.add_argument('--validation',
|
|
||||||
metavar="<validation>",
|
|
||||||
type=str,
|
|
||||||
help='Display execution history for a validation')
|
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
actions = ValidationActions(constants.ANSIBLE_VALIDATION_DIR)
|
class TripleOValidatorShowRun(GetHistory):
|
||||||
return actions.show_history(parsed_args.validation)
|
"""Display details about a Validation execution"""
|
||||||
|
|
||||||
|
auth_required = False
|
||||||
|
|
||||||
|
def get_parser(self, parser):
|
||||||
|
parser = super(TripleOValidatorShowRun, self).get_parser(parser)
|
||||||
|
return parser
|
||||||
|
Loading…
Reference in New Issue
Block a user