Retrieve n latest validation results
New optional parameter for the CLI limiting number of validation results returned by history subcommand. Number of validations shown will be limited to 15 if the `--limit` arg is passed to the command. Behavior without the `--limit` remains the same. Resolves: rhbz#1944872 Signed-off-by: Jiri Podivin <jpodivin@redhat.com> Change-Id: Ie79062e85351ed545c33001866773bf38fdf8517
This commit is contained in:
parent
36c9b8cbcb
commit
01f4e7806f
|
@ -17,6 +17,7 @@
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from argparse import ArgumentError
|
||||||
|
|
||||||
from cliff.command import Command
|
from cliff.command import Command
|
||||||
from cliff.lister import Lister
|
from cliff.lister import Lister
|
||||||
|
@ -30,12 +31,35 @@ class ListHistory(Lister):
|
||||||
"""Display Validations execution history"""
|
"""Display Validations execution history"""
|
||||||
|
|
||||||
def get_parser(self, parser):
|
def get_parser(self, parser):
|
||||||
|
"""Get parser for the history subcommand.
|
||||||
|
The output can be narrowed down by the `--validation`
|
||||||
|
and the `--limit` args.
|
||||||
|
If the `--limit` isn't specified, information about
|
||||||
|
all validation runs is send to the stdout.
|
||||||
|
Default behavior of the arg is controlled by the values
|
||||||
|
of the`constant` and the `default` parameter of the
|
||||||
|
add_argument method.
|
||||||
|
"""
|
||||||
parser = super(ListHistory, self).get_parser(parser)
|
parser = super(ListHistory, self).get_parser(parser)
|
||||||
|
|
||||||
parser.add_argument('--validation',
|
parser.add_argument('--validation',
|
||||||
metavar="<validation>",
|
metavar="<validation>",
|
||||||
type=str,
|
type=str,
|
||||||
help='Display execution history for a validation')
|
help='Display execution history for a validation')
|
||||||
|
parser.add_argument('--limit',
|
||||||
|
dest='history_limit',
|
||||||
|
type=int,
|
||||||
|
nargs='?',
|
||||||
|
const=15,
|
||||||
|
default=None,
|
||||||
|
help=(
|
||||||
|
'Display <n> most recent '
|
||||||
|
'runs of the selected <validation>. '
|
||||||
|
'<n> must be > 0\n'
|
||||||
|
'In the absence of specified number '
|
||||||
|
'the display limit is set to 15.\n'
|
||||||
|
'Without the argument all validations '
|
||||||
|
'are displayed by default.'))
|
||||||
parser.add_argument('--validation-log-dir', dest='validation_log_dir',
|
parser.add_argument('--validation-log-dir', dest='validation_log_dir',
|
||||||
default=constants.VALIDATIONS_LOG_BASEDIR,
|
default=constants.VALIDATIONS_LOG_BASEDIR,
|
||||||
help=("Path where the validation log files "
|
help=("Path where the validation log files "
|
||||||
|
@ -43,8 +67,26 @@ class ListHistory(Lister):
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
|
if parsed_args.history_limit:
|
||||||
|
if parsed_args.history_limit < 1:
|
||||||
|
raise ArgumentError(
|
||||||
|
(
|
||||||
|
"Number <n> of the most recent runs must be > 0. "
|
||||||
|
"You have provided {}").format(
|
||||||
|
parsed_args.history_limit))
|
||||||
|
self.app.LOG.info(
|
||||||
|
(
|
||||||
|
"Limiting output to the maximum of "
|
||||||
|
"{} last validations.").format(
|
||||||
|
parsed_args.history_limit))
|
||||||
|
else:
|
||||||
|
self.app.LOG.warning(
|
||||||
|
"Showing results of all validations since the beginning of time!"
|
||||||
|
)
|
||||||
actions = ValidationActions(parsed_args.validation_log_dir)
|
actions = ValidationActions(parsed_args.validation_log_dir)
|
||||||
return actions.show_history(parsed_args.validation)
|
return actions.show_history(
|
||||||
|
validation_ids=parsed_args.validation,
|
||||||
|
history_limit=parsed_args.history_limit)
|
||||||
|
|
||||||
|
|
||||||
class GetHistory(Command):
|
class GetHistory(Command):
|
||||||
|
|
|
@ -368,6 +368,47 @@ class TestValidationActions(TestCase):
|
||||||
'2019-11-25T13:40:14.404623Z',
|
'2019-11-25T13:40:14.404623Z',
|
||||||
'0:00:03.753')])
|
'0:00:03.753')])
|
||||||
|
|
||||||
|
@mock.patch('os.stat')
|
||||||
|
@mock.patch('validations_libs.validation_logs.ValidationLogs.'
|
||||||
|
'get_all_logfiles',
|
||||||
|
return_value=[
|
||||||
|
'/tmp/123_foo_2020-03-30T13:17:22.447857Z.json',
|
||||||
|
'/tmp/123_bar_2020-03-05T13:17:22.447857Z.json'])
|
||||||
|
@mock.patch('json.load',
|
||||||
|
return_value=fakes.VALIDATIONS_LOGS_CONTENTS_LIST[0])
|
||||||
|
@mock.patch('six.moves.builtins.open')
|
||||||
|
def test_show_history_most_recent(self, mock_open, mock_load,
|
||||||
|
mock_get_log, mock_stat):
|
||||||
|
|
||||||
|
first_validation = mock.MagicMock()
|
||||||
|
second_validation = mock.MagicMock()
|
||||||
|
|
||||||
|
first_validation.st_mtime = 5
|
||||||
|
second_validation.st_mtime = 7
|
||||||
|
|
||||||
|
validations = {
|
||||||
|
'/tmp/123_foo_2020-03-30T13:17:22.447857Z.json': first_validation,
|
||||||
|
'/tmp/123_bar_2020-03-05T13:17:22.447857Z.json': second_validation
|
||||||
|
}
|
||||||
|
|
||||||
|
def _generator(x=None):
|
||||||
|
if x:
|
||||||
|
return validations[x]
|
||||||
|
return first_validation
|
||||||
|
|
||||||
|
mock_stat.side_effect = _generator
|
||||||
|
|
||||||
|
v_actions = ValidationActions()
|
||||||
|
col, values = v_actions.show_history(history_limit=1)
|
||||||
|
|
||||||
|
self.assertEqual(col, ('UUID', 'Validations',
|
||||||
|
'Status', 'Execution at',
|
||||||
|
'Duration'))
|
||||||
|
self.assertEqual(values, [('008886df-d297-1eaa-2a74-000000000008',
|
||||||
|
'512e', 'PASSED',
|
||||||
|
'2019-11-25T13:40:14.404623Z',
|
||||||
|
'0:00:03.753')])
|
||||||
|
|
||||||
@mock.patch('validations_libs.validation_logs.ValidationLogs.'
|
@mock.patch('validations_libs.validation_logs.ValidationLogs.'
|
||||||
'get_logfile_by_validation',
|
'get_logfile_by_validation',
|
||||||
return_value=['/tmp/123_foo_2020-03-30T13:17:22.447857Z.json'])
|
return_value=['/tmp/123_foo_2020-03-30T13:17:22.447857Z.json'])
|
||||||
|
|
|
@ -203,6 +203,19 @@ class ValidationActions(object):
|
||||||
return None, _hosts
|
return None, _hosts
|
||||||
return playbook, limit_hosts
|
return playbook, limit_hosts
|
||||||
|
|
||||||
|
def _retrieve_latest_results(self, logs, history_limit):
|
||||||
|
"""Retrieve the most recent validation results.
|
||||||
|
Previously retrieved logs are sorted in ascending order,
|
||||||
|
with the last time the file was modified serving as a key.
|
||||||
|
Finally we take the last `n` logs, where `n` == `history_limit`
|
||||||
|
and return them while discarding the time information.
|
||||||
|
"""
|
||||||
|
logs = sorted(
|
||||||
|
[(os.stat(path).st_mtime, path) for path in logs],
|
||||||
|
key=lambda path: path[0])
|
||||||
|
|
||||||
|
return [path[1] for path in logs[-history_limit:]]
|
||||||
|
|
||||||
def run_validations(self, validation_name=None, inventory='localhost',
|
def run_validations(self, validation_name=None, inventory='localhost',
|
||||||
group=None, extra_vars=None, validations_dir=None,
|
group=None, extra_vars=None, validations_dir=None,
|
||||||
extra_env_vars=None, ansible_cfg=None, quiet=True,
|
extra_env_vars=None, ansible_cfg=None, quiet=True,
|
||||||
|
@ -500,7 +513,8 @@ class ValidationActions(object):
|
||||||
return params
|
return params
|
||||||
|
|
||||||
def show_history(self, validation_ids=None, extension='json',
|
def show_history(self, validation_ids=None, extension='json',
|
||||||
log_path=constants.VALIDATIONS_LOG_BASEDIR):
|
log_path=constants.VALIDATIONS_LOG_BASEDIR,
|
||||||
|
history_limit=None):
|
||||||
"""Return validation executions history
|
"""Return validation executions history
|
||||||
|
|
||||||
:param validation_ids: The validation ids
|
:param validation_ids: The validation ids
|
||||||
|
@ -509,6 +523,9 @@ class ValidationActions(object):
|
||||||
:type extension: ``string``
|
:type extension: ``string``
|
||||||
:param log_path: The absolute path of the validations logs directory
|
:param log_path: The absolute path of the validations logs directory
|
||||||
:type log_path: ``string``
|
:type log_path: ``string``
|
||||||
|
:param history_limit: The number of most recent history logs
|
||||||
|
to be displayed.
|
||||||
|
:type history_limit: ``int``
|
||||||
|
|
||||||
:return: Returns the information about the validation executions
|
:return: Returns the information about the validation executions
|
||||||
history
|
history
|
||||||
|
@ -559,10 +576,15 @@ class ValidationActions(object):
|
||||||
validation_ids = [validation_ids]
|
validation_ids = [validation_ids]
|
||||||
logs = []
|
logs = []
|
||||||
for validation_id in validation_ids:
|
for validation_id in validation_ids:
|
||||||
logs.extend(vlogs.get_logfile_by_validation(validation_id))
|
logs.extend(
|
||||||
|
vlogs.get_logfile_by_validation(
|
||||||
|
validation_id))
|
||||||
else:
|
else:
|
||||||
logs = vlogs.get_all_logfiles(extension)
|
logs = vlogs.get_all_logfiles(extension)
|
||||||
|
|
||||||
|
if history_limit and history_limit < len(logs):
|
||||||
|
logs = self._retrieve_latest_results(logs, history_limit)
|
||||||
|
|
||||||
values = []
|
values = []
|
||||||
column_name = ('UUID', 'Validations',
|
column_name = ('UUID', 'Validations',
|
||||||
'Status', 'Execution at',
|
'Status', 'Execution at',
|
||||||
|
|
Loading…
Reference in New Issue