Retrieve n latest validation results

New optional parameter for the CLI limiting
number of validation results returned by history subcommand.

Resolves: rhbz#1944872

Signed-off-by: Jiri Podivin <jpodivin@redhat.com>
Change-Id: Ie79062e85351ed545c33001866773bf38fdf8517
This commit is contained in:
Jiri Podivin 2021-04-30 10:27:08 +02:00
parent 36c9b8cbcb
commit 6bfdb04137
3 changed files with 95 additions and 3 deletions

View File

@ -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
@ -36,6 +37,15 @@ class ListHistory(Lister):
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,
default=15,
help=(
'Display <n> most recent '
'runs of the selected <validation>. '
'<n> must be > 0\n'
'The default display limit is set to 15.\n'))
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 +53,24 @@ class ListHistory(Lister):
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
if parsed_args.history_limit < 1:
raise ValueError(
(
"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))
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):

View File

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

View File

@ -203,6 +203,22 @@ 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.
"""
history_limit = min(history_limit, len(logs))
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 +516,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 +526,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 +579,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',