Merge "Create dedicated CLI for the Validation Framework"
This commit is contained in:
commit
8b44eeb231
@ -7,3 +7,4 @@ six>=1.11.0 # MIT
|
||||
PyYAML>=3.13 # MIT
|
||||
ansible>=2.8,!=2.8.9,!=2.9.12,<2.10.0
|
||||
ansible-runner>=1.4.0 # Apache-2.0
|
||||
cliff>=3.2.0 # Apache-2.0
|
||||
|
11
setup.cfg
11
setup.cfg
@ -36,3 +36,14 @@ mapping_file = babel.cfg
|
||||
output_file = validations-libs/locale/validations-libs.pot
|
||||
|
||||
[entry_points]
|
||||
console_scripts:
|
||||
validation = validations_libs.cli.app:main
|
||||
|
||||
validation.cli:
|
||||
list = validations_libs.cli.lister:ValidationList
|
||||
show = validations_libs.cli.show:Show
|
||||
show_group = validations_libs.cli.show:ShowGroup
|
||||
show_parameter = validations_libs.cli.show:ShowParameter
|
||||
run = validations_libs.cli.run:Run
|
||||
history_list = validations_libs.cli.history:ListHistory
|
||||
history_get = validations_libs.cli.history:GetHistory
|
||||
|
15
validations_libs/cli/__init__.py
Normal file
15
validations_libs/cli/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
58
validations_libs/cli/app.py
Normal file
58
validations_libs/cli/app.py
Normal file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import sys
|
||||
|
||||
from cliff.app import App
|
||||
from cliff.commandmanager import CommandManager
|
||||
|
||||
|
||||
class ValidationCliApp(App):
|
||||
"""Cliff application for the `ValidationCli` tool.
|
||||
:param description: one-liner explaining the program purpose
|
||||
:param version: application version number
|
||||
:param command_manager: plugin loader
|
||||
:param deferred_help: Allow subcommands to accept `–help` with allowing
|
||||
to defer help print after initialize_app
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(ValidationCliApp, self).__init__(
|
||||
description="Validations Framework Command Line Interface (CLI)",
|
||||
version='1.0',
|
||||
command_manager=CommandManager('validation.cli'),
|
||||
deferred_help=True,
|
||||
)
|
||||
|
||||
def initialize_app(self, argv):
|
||||
self.LOG.debug('Initialize Validation App.')
|
||||
|
||||
def prepare_to_run_command(self, cmd):
|
||||
self.LOG.debug('prepare_to_run_command %s', cmd.__class__.__name__)
|
||||
|
||||
def clean_up(self, cmd, result, err):
|
||||
self.LOG.debug('clean_up %s', cmd.__class__.__name__)
|
||||
if err:
|
||||
self.LOG.debug('got an error: %s', err)
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
v_cli = ValidationCliApp()
|
||||
return v_cli.run(argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
70
validations_libs/cli/common.py
Normal file
70
validations_libs/cli/common.py
Normal file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
from prettytable import PrettyTable
|
||||
|
||||
from validations_libs import constants
|
||||
from validations_libs import utils as v_utils
|
||||
|
||||
GROUP_FILE = constants.VALIDATION_GROUPS_INFO
|
||||
|
||||
# PrettyTable Colors:
|
||||
RED = "\033[1;31m"
|
||||
GREEN = "\033[0;32m"
|
||||
CYAN = "\033[36m"
|
||||
RESET = "\033[0;0m"
|
||||
YELLOW = "\033[0;33m"
|
||||
|
||||
|
||||
def print_dict(data):
|
||||
"""Print table from python dict with PrettyTable"""
|
||||
table = PrettyTable(border=True, header=True, padding_width=1)
|
||||
# Set Field name by getting the result dict keys
|
||||
try:
|
||||
table.field_names = data[0].keys()
|
||||
table.align = 'l'
|
||||
except IndexError:
|
||||
raise IndexError()
|
||||
for row in data:
|
||||
if row.get('Status_by_Host'):
|
||||
hosts = []
|
||||
for host in row['Status_by_Host'].split(', '):
|
||||
try:
|
||||
_name, _status = host.split(',')
|
||||
except ValueError:
|
||||
# if ValueError, then host is in unknown state:
|
||||
_name = host
|
||||
_status = 'UNKNOWN'
|
||||
color = (GREEN if _status == 'PASSED' else
|
||||
(YELLOW if _status == 'UNREACHABLE' else RED))
|
||||
_name = '{}{}{}'.format(color, _name, RESET)
|
||||
hosts.append(_name)
|
||||
row['Status_by_Host'] = ', '.join(hosts)
|
||||
if row.get('Status'):
|
||||
status = row.get('Status')
|
||||
color = (CYAN if status in ['starting', 'running']
|
||||
else GREEN if status == 'PASSED' else RED)
|
||||
row['Status'] = '{}{}{}'.format(color, status, RESET)
|
||||
table.add_row(row.values())
|
||||
print(table)
|
||||
|
||||
|
||||
def write_output(output_log, results):
|
||||
"""Write output log file as Json format"""
|
||||
with open(output_log, 'w') as output:
|
||||
output.write(json.dumps({'results': results}, indent=4,
|
||||
sort_keys=True))
|
86
validations_libs/cli/history.py
Normal file
86
validations_libs/cli/history.py
Normal file
@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from cliff.command import Command
|
||||
from cliff.lister import Lister
|
||||
|
||||
from validations_libs import constants
|
||||
from validations_libs.validation_actions import ValidationActions
|
||||
from validations_libs.validation_logs import ValidationLogs
|
||||
|
||||
|
||||
class ListHistory(Lister):
|
||||
"""Display Validations execution history"""
|
||||
|
||||
def get_parser(self, parser):
|
||||
parser = super(ListHistory, self).get_parser(parser)
|
||||
|
||||
parser.add_argument('--validation',
|
||||
metavar="<validation>",
|
||||
type=str,
|
||||
help='Display execution history for a validation')
|
||||
parser.add_argument('--validation-log-dir', dest='validation_log_dir',
|
||||
default=constants.VALIDATIONS_LOG_BASEDIR,
|
||||
help=("Path where the validation log files "
|
||||
"is located."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
actions = ValidationActions(parsed_args.validation_log_dir)
|
||||
return actions.show_history(parsed_args.validation)
|
||||
|
||||
|
||||
class GetHistory(Command):
|
||||
"""Display details about a Validation execution"""
|
||||
|
||||
def get_parser(self, parser):
|
||||
parser = super(GetHistory, self).get_parser(parser)
|
||||
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')
|
||||
|
||||
parser.add_argument('--validation-log-dir', dest='validation_log_dir',
|
||||
default=constants.VALIDATIONS_LOG_BASEDIR,
|
||||
help=("Path where the validation log files "
|
||||
"is located."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
vlogs = ValidationLogs(logs_path=parsed_args.validation_log_dir)
|
||||
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 RuntimeError(
|
||||
"Could not find the log file linked to this UUID: %s" %
|
||||
parsed_args.uuid)
|
55
validations_libs/cli/lister.py
Normal file
55
validations_libs/cli/lister.py
Normal file
@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
||||
from cliff.lister import Lister
|
||||
|
||||
from validations_libs.validation_actions import ValidationActions
|
||||
from validations_libs import constants
|
||||
from validations_libs.cli.parseractions import CommaListAction
|
||||
|
||||
|
||||
class ValidationList(Lister):
|
||||
"""Validation List client implementation class"""
|
||||
|
||||
def get_parser(self, parser):
|
||||
"""Argument parser for validation run"""
|
||||
parser = super(ValidationList, self).get_parser(parser)
|
||||
parser.add_argument('--group', '-g',
|
||||
metavar='<group>[,<group>,...]',
|
||||
action=CommaListAction,
|
||||
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"))
|
||||
parser.add_argument('--validation-dir', dest='validation_dir',
|
||||
default=constants.ANSIBLE_VALIDATION_DIR,
|
||||
help=("Path where the validation playbooks "
|
||||
"is located."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Take validation action"""
|
||||
# Get parameters:
|
||||
group = parsed_args.group
|
||||
validation_dir = parsed_args.validation_dir
|
||||
|
||||
v_actions = ValidationActions(validation_path=validation_dir)
|
||||
return (v_actions.list_validations(group))
|
45
validations_libs/cli/parseractions.py
Normal file
45
validations_libs/cli/parseractions.py
Normal file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
class CommaListAction(argparse.Action):
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
setattr(namespace, self.dest, values.split(','))
|
||||
|
||||
|
||||
class KeyValueAction(argparse.Action):
|
||||
"""A custom action to parse arguments as key=value pairs
|
||||
Ensures that ``dest`` is a dict and values are strings.
|
||||
"""
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
# Make sure we have an empty dict rather than None
|
||||
if getattr(namespace, self.dest, None) is None:
|
||||
setattr(namespace, self.dest, {})
|
||||
|
||||
# Add value if an assignment else remove it
|
||||
if '=' in values and values.count('=') == 1:
|
||||
values_list = values.split('=', 1)
|
||||
if '' == values_list[0]:
|
||||
msg = ("Property key must be specified: %s")
|
||||
raise argparse.ArgumentTypeError(msg % str(values))
|
||||
else:
|
||||
getattr(namespace, self.dest, {}).update([values_list])
|
||||
else:
|
||||
msg = ("Expected 'key=value' type, but got: %s")
|
||||
raise argparse.ArgumentTypeError(msg % str(values))
|
174
validations_libs/cli/run.py
Normal file
174
validations_libs/cli/run.py
Normal file
@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import getpass
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
from cliff.command import Command
|
||||
|
||||
from validations_libs import constants
|
||||
from validations_libs.validation_actions import ValidationActions
|
||||
from validations_libs.cli import common
|
||||
from validations_libs.cli.parseractions import CommaListAction, KeyValueAction
|
||||
|
||||
|
||||
class Run(Command):
|
||||
"""Validation Run client implementation class"""
|
||||
|
||||
def get_parser(self, parser):
|
||||
"""Argument parser for validation run"""
|
||||
parser = super(Run, self).get_parser(parser)
|
||||
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(
|
||||
'--ssh-user',
|
||||
dest='ssh_user',
|
||||
default=getpass.getuser(),
|
||||
help=("Ssh User name for the Ansible ssh connection.")
|
||||
)
|
||||
parser.add_argument('--validation-dir', dest='validation_dir',
|
||||
default=constants.ANSIBLE_VALIDATION_DIR,
|
||||
help=("Path where the validation playbooks "
|
||||
"is located."))
|
||||
|
||||
parser.add_argument('--ansible-base-dir', dest='ansible_base_dir',
|
||||
default=constants.DEFAULT_VALIDATIONS_BASEDIR,
|
||||
help=("Path where the ansible roles, library "
|
||||
"and plugins are located."))
|
||||
|
||||
parser.add_argument('--inventory', '-i', type=str,
|
||||
default="localhost",
|
||||
help="Path of the Ansible inventory.")
|
||||
|
||||
parser.add_argument('--output-log', dest='output_log',
|
||||
default=None,
|
||||
help=("Path where the run result will be stored."))
|
||||
|
||||
parser.add_argument(
|
||||
'--extra-env-vars',
|
||||
action=KeyValueAction,
|
||||
default=None,
|
||||
metavar="key1=<val1> [--extra-vars key3=<val3>]",
|
||||
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)")
|
||||
)
|
||||
|
||||
extra_vars_group = parser.add_mutually_exclusive_group(required=False)
|
||||
extra_vars_group.add_argument(
|
||||
'--extra-vars',
|
||||
default=None,
|
||||
metavar="key1=<val1> [--extra-vars key3=<val3>]",
|
||||
action=KeyValueAction,
|
||||
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=None,
|
||||
help=(
|
||||
"Add a JSON/YAML file containing extra variable "
|
||||
"to a validation: "
|
||||
"--extra-vars-file /home/stack/vars.[json|yaml]."
|
||||
)
|
||||
)
|
||||
|
||||
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', '-g',
|
||||
metavar='<group>[,<group>,...]',
|
||||
action=CommaListAction,
|
||||
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
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Take validation action"""
|
||||
v_actions = ValidationActions(
|
||||
validation_path=parsed_args.validation_dir)
|
||||
|
||||
extra_vars = parsed_args.extra_vars
|
||||
if parsed_args.extra_vars_file:
|
||||
try:
|
||||
with open(parsed_args.extra_vars_file, 'r') as env_file:
|
||||
extra_vars = yaml.safe_load(env_file.read())
|
||||
except yaml.YAMLError as e:
|
||||
error_msg = (
|
||||
"The extra_vars file must be properly formatted YAML/JSON."
|
||||
"Details: %s." % e)
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
try:
|
||||
results = v_actions.run_validations(
|
||||
inventory=parsed_args.inventory,
|
||||
limit_hosts=parsed_args.limit,
|
||||
group=parsed_args.group,
|
||||
extra_vars=extra_vars,
|
||||
validations_dir=parsed_args.validation_dir,
|
||||
base_dir=parsed_args.ansible_base_dir,
|
||||
validation_name=parsed_args.validation_name,
|
||||
extra_env_vars=parsed_args.extra_env_vars,
|
||||
quiet=True,
|
||||
ssh_user=parsed_args.ssh_user)
|
||||
except RuntimeError as e:
|
||||
raise RuntimeError(e)
|
||||
|
||||
_rc = None
|
||||
if results:
|
||||
_rc = any([1 for r in results if r['Status'] == 'FAILED'])
|
||||
|
||||
if parsed_args.output_log:
|
||||
common.write_output(parsed_args.output_log, results)
|
||||
common.print_dict(results)
|
||||
|
||||
if _rc:
|
||||
raise RuntimeError("One or more validations have failed.")
|
151
validations_libs/cli/show.py
Normal file
151
validations_libs/cli/show.py
Normal file
@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from validations_libs.validation_actions import ValidationActions
|
||||
from validations_libs import constants
|
||||
from validations_libs.cli.parseractions import CommaListAction
|
||||
|
||||
|
||||
class Show(ShowOne):
|
||||
"""Validation Show client implementation class"""
|
||||
|
||||
def get_parser(self, parser):
|
||||
"""Argument parser for validation show"""
|
||||
parser = super(Show, self).get_parser(parser)
|
||||
parser.add_argument('--validation-dir', dest='validation_dir',
|
||||
default=constants.ANSIBLE_VALIDATION_DIR,
|
||||
help=("Path where the validation playbooks "
|
||||
"is located."))
|
||||
parser.add_argument('validation_name',
|
||||
metavar="<validation>",
|
||||
type=str,
|
||||
help="Show a specific validation.")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Take validation action"""
|
||||
# Get parameters:
|
||||
validation_dir = parsed_args.validation_dir
|
||||
validation_name = parsed_args.validation_name
|
||||
|
||||
v_actions = ValidationActions(validation_path=validation_dir)
|
||||
data = v_actions.show_validations(validation_name)
|
||||
|
||||
if data:
|
||||
return data.keys(), data.values()
|
||||
|
||||
|
||||
class ShowGroup(ShowOne):
|
||||
"""Validation Show group client implementation class"""
|
||||
|
||||
def get_parser(self, parser):
|
||||
"""Argument parser for validation show group"""
|
||||
parser = super(ShowGroup, self).get_parser(parser)
|
||||
parser.add_argument('--validation-dir', dest='validation_dir',
|
||||
default=constants.ANSIBLE_VALIDATION_DIR,
|
||||
help=("Path where the validation playbooks "
|
||||
"is located."))
|
||||
parser.add_argument('--group', '-g',
|
||||
metavar='<group_name>',
|
||||
dest="group",
|
||||
help=("Show a specific group."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Take validation action"""
|
||||
# Get parameters:
|
||||
validation_dir = parsed_args.validation_dir
|
||||
group = parsed_args.group
|
||||
|
||||
v_actions = ValidationActions(validation_path=validation_dir)
|
||||
return v_actions.group_information(group)
|
||||
|
||||
|
||||
class ShowParameter(ShowOne):
|
||||
"""Display Validations Parameters"""
|
||||
|
||||
def get_parser(self, parser):
|
||||
parser = super(ShowParameter, self).get_parser(parser)
|
||||
|
||||
parser.add_argument('--validation-dir', dest='validation_dir',
|
||||
default=constants.ANSIBLE_VALIDATION_DIR,
|
||||
help=("Path where the validation playbooks "
|
||||
"is located."))
|
||||
|
||||
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', '-g',
|
||||
metavar='<group_id>[,<group_id>,...]',
|
||||
action=CommaListAction,
|
||||
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(
|
||||
'--format-output',
|
||||
action='store',
|
||||
metavar='<format_output>',
|
||||
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):
|
||||
v_actions = ValidationActions(parsed_args.validation_dir)
|
||||
params = v_actions.show_validations_parameters(
|
||||
parsed_args.validation_name,
|
||||
parsed_args.group,
|
||||
parsed_args.format_output,
|
||||
parsed_args.download)
|
||||
if parsed_args.download:
|
||||
print("The file {} has been created successfully".format(
|
||||
parsed_args.download))
|
||||
return params.keys(), params.values()
|
14
validations_libs/tests/cli/__init__.py
Normal file
14
validations_libs/tests/cli/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
42
validations_libs/tests/cli/fakes.py
Normal file
42
validations_libs/tests/cli/fakes.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import mock
|
||||
from unittest import TestCase
|
||||
|
||||
from validations_libs.cli import app
|
||||
|
||||
|
||||
class BaseCommand(TestCase):
|
||||
|
||||
def check_parser(self, cmd, args, verify_args):
|
||||
cmd_parser = cmd.get_parser('check_parser')
|
||||
try:
|
||||
parsed_args = cmd_parser.parse_args(args)
|
||||
except SystemExit:
|
||||
raise Exception("Argument parse failed")
|
||||
for av in verify_args:
|
||||
attr, value = av
|
||||
if attr:
|
||||
self.assertIn(attr, parsed_args)
|
||||
self.assertEqual(value, getattr(parsed_args, attr))
|
||||
return parsed_args
|
||||
|
||||
def setUp(self):
|
||||
super(BaseCommand, self).setUp()
|
||||
self.app = app.ValidationCliApp()
|
83
validations_libs/tests/cli/test_history.py
Normal file
83
validations_libs/tests/cli/test_history.py
Normal file
@ -0,0 +1,83 @@
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import mock
|
||||
from unittest import TestCase
|
||||
|
||||
from validations_libs.cli import history
|
||||
from validations_libs.tests import fakes
|
||||
from validations_libs.tests.cli.fakes import BaseCommand
|
||||
|
||||
|
||||
class TestListHistory(BaseCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestListHistory, self).setUp()
|
||||
self.cmd = history.ListHistory(self.app, None)
|
||||
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'show_history')
|
||||
def test_list_history(self, mock_history):
|
||||
arglist = ['--validation-log-dir', '/foo/log/dir']
|
||||
verifylist = [('validation_log_dir', '/foo/log/dir')]
|
||||
|
||||
col = ('UUID', 'Validations', 'Status', 'Execution at', 'Duration')
|
||||
values = [('008886df-d297-1eaa-2a74-000000000008',
|
||||
'512e', 'PASSED',
|
||||
'2019-11-25T13:40:14.404623Z',
|
||||
'0:00:03.753')]
|
||||
mock_history.return_value = (col, values)
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(result, (col, values))
|
||||
|
||||
|
||||
class TestGetHistory(BaseCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestGetHistory, self).setUp()
|
||||
self.cmd = history.GetHistory(self.app, None)
|
||||
|
||||
@mock.patch('validations_libs.validation_logs.ValidationLogs.'
|
||||
'get_logfile_content_by_uuid',
|
||||
return_value=fakes.VALIDATIONS_LOGS_CONTENTS_LIST)
|
||||
def test_get_history(self, mock_logs):
|
||||
arglist = ['123']
|
||||
verifylist = [('uuid', '123')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
@mock.patch('validations_libs.validation_logs.ValidationLogs.'
|
||||
'get_logfile_content_by_uuid',
|
||||
return_value=fakes.VALIDATIONS_LOGS_CONTENTS_LIST)
|
||||
def test_get_history_from_log_dir(self, mock_logs):
|
||||
arglist = ['123', '--validation-log-dir', '/foo/log/dir']
|
||||
verifylist = [('uuid', '123'), ('validation_log_dir', '/foo/log/dir')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
@mock.patch('validations_libs.validation_logs.ValidationLogs.'
|
||||
'get_logfile_content_by_uuid',
|
||||
return_value=fakes.VALIDATIONS_LOGS_CONTENTS_LIST)
|
||||
def test_get_history_full_arg(self, mock_logs):
|
||||
arglist = ['123', '--full']
|
||||
verifylist = [('uuid', '123'), ('full', True)]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
78
validations_libs/tests/cli/test_list.py
Normal file
78
validations_libs/tests/cli/test_list.py
Normal file
@ -0,0 +1,78 @@
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import mock
|
||||
from unittest import TestCase
|
||||
|
||||
from validations_libs.cli import lister
|
||||
from validations_libs.tests import fakes
|
||||
from validations_libs.tests.cli.fakes import BaseCommand
|
||||
|
||||
|
||||
class TestList(BaseCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestList, self).setUp()
|
||||
self.cmd = lister.ValidationList(self.app, None)
|
||||
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'list_validations',
|
||||
return_value=fakes.VALIDATIONS_LIST)
|
||||
def test_list_validations(self, mock_list):
|
||||
arglist = ['--validation-dir', 'foo']
|
||||
verifylist = [('validation_dir', 'foo')]
|
||||
|
||||
list = [{'description': 'My Validation One Description',
|
||||
'groups': ['prep', 'pre-deployment'],
|
||||
'id': 'my_val1',
|
||||
'name': 'My Validation One Name',
|
||||
'parameters': {}
|
||||
}, {
|
||||
'description': 'My Validation Two Description',
|
||||
'groups': ['prep', 'pre-introspection'],
|
||||
'id': 'my_val2',
|
||||
'name': 'My Validation Two Name',
|
||||
'parameters': {'min_value': 8}
|
||||
}]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(result, list)
|
||||
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'list_validations',
|
||||
return_value=[])
|
||||
def test_list_validations_empty(self, mock_list):
|
||||
arglist = ['--validation-dir', 'foo']
|
||||
verifylist = [('validation_dir', 'foo')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(result, [])
|
||||
|
||||
@mock.patch('validations_libs.utils.parse_all_validations_on_disk',
|
||||
return_value=fakes.VALIDATIONS_LIST_GROUP)
|
||||
def test_list_validations_group(self, mock_list):
|
||||
arglist = ['--validation-dir', 'foo', '--group', 'prep']
|
||||
verifylist = [('validation_dir', 'foo'),
|
||||
('group', ['prep'])]
|
||||
|
||||
list = fakes.VALIDATION_LIST_RESULT
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(result, list)
|
274
validations_libs/tests/cli/test_run.py
Normal file
274
validations_libs/tests/cli/test_run.py
Normal file
@ -0,0 +1,274 @@
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import mock
|
||||
from unittest import TestCase
|
||||
|
||||
from validations_libs.cli import run
|
||||
from validations_libs.tests import fakes
|
||||
from validations_libs.tests.cli.fakes import BaseCommand
|
||||
|
||||
|
||||
class TestRun(BaseCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestRun, self).setUp()
|
||||
self.cmd = run.Run(self.app, None)
|
||||
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=None)
|
||||
def test_run_command_return_none(self, mock_run):
|
||||
arglist = ['--validation', 'foo']
|
||||
verifylist = [('validation_name', ['foo'])]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(result, None)
|
||||
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_SUCCESS_RUN)
|
||||
def test_run_command_success(self, mock_run):
|
||||
arglist = ['--validation', 'foo']
|
||||
verifylist = [('validation_name', ['foo'])]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
def test_run_command_exclusive_group(self):
|
||||
arglist = ['--validation', 'foo', '--group', 'bar']
|
||||
verifylist = [('validation_name', ['foo'], 'group', 'bar')]
|
||||
|
||||
self.assertRaises(Exception, self.check_parser, self.cmd,
|
||||
arglist, verifylist)
|
||||
|
||||
@mock.patch('validations_libs.cli.common.print_dict')
|
||||
@mock.patch('getpass.getuser',
|
||||
return_value='doe')
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_SUCCESS_RUN)
|
||||
def test_run_command_extra_vars(self, mock_run, mock_user, mock_print):
|
||||
run_called_args = {
|
||||
'inventory': 'localhost',
|
||||
'limit_hosts': None,
|
||||
'group': [],
|
||||
'extra_vars': {'key': 'value'},
|
||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||
'base_dir': '/usr/share/ansible/',
|
||||
'validation_name': ['foo'],
|
||||
'extra_env_vars': None,
|
||||
'quiet': True,
|
||||
'ssh_user': 'doe'}
|
||||
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-vars', 'key=value']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_vars', {'key': 'value'})]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_run.assert_called_with(**run_called_args)
|
||||
|
||||
@mock.patch('validations_libs.cli.common.print_dict')
|
||||
@mock.patch('getpass.getuser',
|
||||
return_value='doe')
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_SUCCESS_RUN)
|
||||
def test_run_command_extra_vars_twice(self, mock_run, mock_user,
|
||||
mock_print):
|
||||
run_called_args = {
|
||||
'inventory': 'localhost',
|
||||
'limit_hosts': None,
|
||||
'group': [],
|
||||
'extra_vars': {'key': 'value2'},
|
||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||
'base_dir': '/usr/share/ansible/',
|
||||
'validation_name': ['foo'],
|
||||
'extra_env_vars': None,
|
||||
'quiet': True,
|
||||
'ssh_user': 'doe'}
|
||||
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-vars', 'key=value1',
|
||||
'--extra-vars', 'key=value2']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_vars', {'key': 'value2'})]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_run.assert_called_with(**run_called_args)
|
||||
|
||||
def test_run_command_exclusive_vars(self):
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-vars', 'key=value1',
|
||||
'--extra-vars-file', '/foo/vars.yaml']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_vars', {'key': 'value2'})]
|
||||
|
||||
self.assertRaises(Exception, self.check_parser, self.cmd,
|
||||
arglist, verifylist)
|
||||
|
||||
@mock.patch('yaml.safe_load', return_value={'key': 'value'})
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
@mock.patch('getpass.getuser',
|
||||
return_value='doe')
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_SUCCESS_RUN)
|
||||
def test_run_command_extra_vars_file(self, mock_run, mock_user, mock_open,
|
||||
mock_yaml):
|
||||
run_called_args = {
|
||||
'inventory': 'localhost',
|
||||
'limit_hosts': None,
|
||||
'group': [],
|
||||
'extra_vars': {'key': 'value'},
|
||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||
'base_dir': '/usr/share/ansible/',
|
||||
'validation_name': ['foo'],
|
||||
'extra_env_vars': None,
|
||||
'quiet': True,
|
||||
'ssh_user': 'doe'}
|
||||
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-vars-file', '/foo/vars.yaml']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_vars_file', '/foo/vars.yaml')]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_run.assert_called_with(**run_called_args)
|
||||
|
||||
@mock.patch('getpass.getuser',
|
||||
return_value='doe')
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_SUCCESS_RUN)
|
||||
def test_run_command_extra_env_vars(self, mock_run, mock_user):
|
||||
run_called_args = {
|
||||
'inventory': 'localhost',
|
||||
'limit_hosts': None,
|
||||
'group': [],
|
||||
'extra_vars': None,
|
||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||
'base_dir': '/usr/share/ansible/',
|
||||
'validation_name': ['foo'],
|
||||
'extra_env_vars': {'key': 'value'},
|
||||
'quiet': True,
|
||||
'ssh_user': 'doe'}
|
||||
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-env-vars', 'key=value']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_env_vars', {'key': 'value'})]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_run.assert_called_with(**run_called_args)
|
||||
|
||||
@mock.patch('getpass.getuser',
|
||||
return_value='doe')
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_SUCCESS_RUN)
|
||||
def test_run_command_extra_env_vars_twice(self, mock_run, mock_user):
|
||||
run_called_args = {
|
||||
'inventory': 'localhost',
|
||||
'limit_hosts': None,
|
||||
'group': [],
|
||||
'extra_vars': None,
|
||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||
'base_dir': '/usr/share/ansible/',
|
||||
'validation_name': ['foo'],
|
||||
'extra_env_vars': {'key': 'value2'},
|
||||
'quiet': True,
|
||||
'ssh_user': 'doe'}
|
||||
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-env-vars', 'key=value1',
|
||||
'--extra-env-vars', 'key=value2']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_env_vars', {'key': 'value2'})]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_run.assert_called_with(**run_called_args)
|
||||
|
||||
@mock.patch('getpass.getuser',
|
||||
return_value='doe')
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_SUCCESS_RUN)
|
||||
def test_run_command_extra_env_vars_and_extra_vars(self, mock_run,
|
||||
mock_user):
|
||||
run_called_args = {
|
||||
'inventory': 'localhost',
|
||||
'limit_hosts': None,
|
||||
'group': [],
|
||||
'extra_vars': {'key': 'value'},
|
||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||
'base_dir': '/usr/share/ansible/',
|
||||
'validation_name': ['foo'],
|
||||
'extra_env_vars': {'key2': 'value2'},
|
||||
'quiet': True,
|
||||
'ssh_user': 'doe'}
|
||||
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-vars', 'key=value',
|
||||
'--extra-env-vars', 'key2=value2']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_vars', {'key': 'value'}),
|
||||
('extra_env_vars', {'key2': 'value2'})]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_run.assert_called_with(**run_called_args)
|
||||
|
||||
def test_run_command_exclusive_wrong_extra_vars(self):
|
||||
arglist = ['--validation', 'foo',
|
||||
'--extra-vars', 'key=value1,key=value2']
|
||||
verifylist = [('validation_name', ['foo']),
|
||||
('extra_vars', {'key': 'value2'})]
|
||||
|
||||
self.assertRaises(Exception, self.check_parser, self.cmd,
|
||||
arglist, verifylist)
|
||||
|
||||
@mock.patch('getpass.getuser',
|
||||
return_value='doe')
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'run_validations',
|
||||
return_value=fakes.FAKE_FAILED_RUN)
|
||||
def test_run_command_failed_validation(self, mock_run, mock_user):
|
||||
run_called_args = {
|
||||
'inventory': 'localhost',
|
||||
'limit_hosts': None,
|
||||
'group': [],
|
||||
'extra_vars': {'key': 'value'},
|
||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||
'base_dir': '/usr/share/ansible/',
|
||||
'validation_name': ['foo'],
|
||||
'extra_env_vars': {'key2': 'value2'},
|
||||
'quiet': True,
|
||||
'ssh_user': 'doe'}
|
||||
|
||||
arglist = ['--validation', 'foo']
|
||||
verifylist = [('validation_name', ['foo'])]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(RuntimeError, self.cmd.take_action, parsed_args)
|
79
validations_libs/tests/cli/test_show.py
Normal file
79
validations_libs/tests/cli/test_show.py
Normal file
@ -0,0 +1,79 @@
|
||||
# Copyright 2021 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import mock
|
||||
from unittest import TestCase
|
||||
|
||||
from validations_libs.cli import show
|
||||
from validations_libs.tests import fakes
|
||||
from validations_libs.tests.cli.fakes import BaseCommand
|
||||
|
||||
|
||||
class TestShow(BaseCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShow, self).setUp()
|
||||
self.cmd = show.Show(self.app, None)
|
||||
|
||||
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||
'show_validations')
|
||||
def test_show_validations(self, mock_show):
|
||||
arglist = ['foo']
|
||||
verifylist = [('validation_name', 'foo')]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
|
||||
class TestShowGroup(BaseCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShowGroup, self).setUp()
|
||||
self.cmd = show.ShowGroup(self.app, None)
|
||||
|
||||
@mock.patch('yaml.safe_load', return_value=fakes.GROUP)
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
def test_show_validations_group_info(self, mock_open, mock_yaml):
|
||||
arglist = ['--group', 'group.yaml']
|
||||
verifylist = [('group', 'group.yaml')]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
|
||||
class TestShowParameter(BaseCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShowParameter, self).setUp()
|
||||
self.cmd = show.ShowParameter(self.app, None)
|
||||
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
def test_show_validations_parameters_by_group(self, mock_open):
|
||||
arglist = ['--group', 'prep']
|
||||
verifylist = [('group', ['prep'])]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
def test_show_parameter_exclusive_group(self):
|
||||
arglist = ['--validation', 'foo', '--group', 'bar']
|
||||
verifylist = [('validation_name', ['foo'], 'group', ['bar'])]
|
||||
|
||||
self.assertRaises(Exception, self.check_parser, self.cmd,
|
||||
arglist, verifylist)
|
||||
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
def test_show_validations_parameters_by_validations(self, mock_open):
|
||||
arglist = ['--group', 'prep']
|
||||
verifylist = [('group', ['prep'])]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
@ -27,6 +27,19 @@ VALIDATIONS_LIST = [{
|
||||
'parameters': {'min_value': 8}
|
||||
}]
|
||||
|
||||
VALIDATIONS_LIST_GROUP = [{
|
||||
'description': 'My Validation Two Description',
|
||||
'groups': ['prep', 'pre-introspection'],
|
||||
'id': 'my_val2',
|
||||
'name': 'My Validation Two Name',
|
||||
'parameters': {'min_value': 8}
|
||||
}]
|
||||
|
||||
|
||||
VALIDATION_LIST_RESULT = (('ID', 'Name', 'Groups'),
|
||||
[('my_val2', 'My Validation Two Name',
|
||||
['prep', 'pre-introspection'])])
|
||||
|
||||
GROUPS_LIST = [
|
||||
('group1', 'Group1 description'),
|
||||
('group2', 'Group2 description'),
|
||||
@ -252,6 +265,36 @@ GROUP = {'no-op': [{'description': 'noop-foo'}],
|
||||
'pre': [{'description': 'pre-foo'}],
|
||||
'post': [{'description': 'post-foo'}]}
|
||||
|
||||
FAKE_SUCCESS_RUN = [{'Duration': '0:00:01.761',
|
||||
'Host_Group': 'overcloud',
|
||||
'Status': 'PASSED',
|
||||
'Status_by_Host': 'subnode-1,PASSED, subnode-2,PASSED',
|
||||
'UUID': '123',
|
||||
'Unreachable_Hosts': '',
|
||||
'Validations': 'foo'}]
|
||||
|
||||
FAKE_FAILED_RUN = [{'Duration': '0:00:01.761',
|
||||
'Host_Group': 'overcloud',
|
||||
'Status': 'FAILED',
|
||||
'Status_by_Host': 'subnode-1,FAILED, subnode-2,PASSED',
|
||||
'UUID': '123',
|
||||
'Unreachable_Hosts': '',
|
||||
'Validations': 'foo'},
|
||||
{'Duration': '0:00:01.761',
|
||||
'Host_Group': 'overcloud',
|
||||
'Status': 'FAILED',
|
||||
'Status_by_Host': 'subnode-1,FAILED, subnode-2,PASSED',
|
||||
'UUID': '123',
|
||||
'Unreachable_Hosts': '',
|
||||
'Validations': 'foo'},
|
||||
{'Duration': '0:00:01.761',
|
||||
'Host_Group': 'overcloud',
|
||||
'Status': 'PASSED',
|
||||
'Status_by_Host': 'subnode-1,PASSED, subnode-2,PASSED',
|
||||
'UUID': '123',
|
||||
'Unreachable_Hosts': '',
|
||||
'Validations': 'foo'}]
|
||||
|
||||
|
||||
def fake_ansible_runner_run_return(status='successful', rc=0):
|
||||
return status, rc
|
||||
|
@ -308,8 +308,7 @@ class TestValidationActions(TestCase):
|
||||
{'parameters': fakes.FAKE_METADATA}}
|
||||
v_actions = ValidationActions()
|
||||
result = v_actions.show_validations_parameters('foo')
|
||||
self.assertEqual(result, json.dumps(mock_get_param.return_value,
|
||||
indent=4, sort_keys=True))
|
||||
self.assertEqual(result, mock_get_param.return_value)
|
||||
|
||||
@mock.patch('six.moves.builtins.open')
|
||||
def test_show_validations_parameters_non_supported_format(self, mock_open):
|
||||
|
@ -44,9 +44,8 @@ class ValidationActions(object):
|
||||
self.log = logging.getLogger(__name__ + ".ValidationActions")
|
||||
self.validation_path = (validation_path if validation_path
|
||||
else constants.ANSIBLE_VALIDATION_DIR)
|
||||
self.group = group
|
||||
|
||||
def list_validations(self):
|
||||
def list_validations(self, group=None):
|
||||
"""Get a list of the available validations
|
||||
|
||||
This is used to print table from python ``Tuple`` with ``PrettyTable``.
|
||||
@ -76,7 +75,7 @@ class ValidationActions(object):
|
||||
"""
|
||||
self.log = logging.getLogger(__name__ + ".list_validations")
|
||||
validations = v_utils.parse_all_validations_on_disk(
|
||||
self.validation_path, self.group)
|
||||
self.validation_path, group)
|
||||
|
||||
return_values = []
|
||||
column_name = ('ID', 'Name', 'Groups')
|
||||
@ -498,15 +497,7 @@ class ValidationActions(object):
|
||||
allow_unicode=True,
|
||||
default_flow_style=False,
|
||||
indent=2))
|
||||
if output_format == 'json':
|
||||
return json.dumps(params,
|
||||
indent=4,
|
||||
sort_keys=True)
|
||||
else:
|
||||
return yaml.safe_dump(params,
|
||||
allow_unicode=True,
|
||||
default_flow_style=False,
|
||||
indent=2)
|
||||
return params
|
||||
|
||||
def show_history(self, validation_ids=None, extension='json',
|
||||
log_path=constants.VALIDATIONS_LOG_BASEDIR):
|
||||
|
Loading…
x
Reference in New Issue
Block a user