Browse Source

Show history by play and add get status action

Show history filtered by plays to get a better view
if a log file contains a lot of playbooks.

Add get_status action in order to get debug information
of a given validation failure

Change-Id: I29ab90647d9ef9c86546065ca16a62c401be1969
tags/1.0.2^0
Mathieu Bultel 1 month ago
committed by mathieu bultel
parent
commit
21a722adac
5 changed files with 105 additions and 11 deletions
  1. +5
    -2
      validations_libs/tests/fakes.py
  2. +32
    -4
      validations_libs/tests/test_validation_actions.py
  3. +23
    -0
      validations_libs/tests/test_validation_log.py
  4. +35
    -5
      validations_libs/validation_actions.py
  5. +10
    -0
      validations_libs/validation_logs.py

+ 5
- 2
validations_libs/tests/fakes.py View File

@@ -159,7 +159,10 @@ VALIDATIONS_LOGS_CONTENTS_LIST = [{
'unreachable': 0
}
},
'validation_output': []
'validation_output': [{'task': {
'hosts': {u'foo': {}},
'name': u'Check if iscsi.service is enabled',
'status': u'FAILED'}}]
}]

VALIDATIONS_DATA = {'Description': 'My Validation One Description',
@@ -169,7 +172,7 @@ VALIDATIONS_DATA = {'Description': 'My Validation One Description',
'parameters': {}}

VALIDATIONS_STATS = {'Last execution date': '2019-11-25 13:40:14',
'Number of execution': 'Total: 1, Passed: 1, Failed: 0'}
'Number of execution': 'Total: 1, Passed: 0, Failed: 1'}

FAKE_PLAYBOOK = [{'hosts': 'undercloud',
'roles': ['advanced_format_512e_support'],


+ 32
- 4
validations_libs/tests/test_validation_actions.py View File

@@ -154,11 +154,20 @@ class TestValidationActions(TestCase):
'Description': 'foo', 'Groups': ['prep', 'pre-deployment'],
'ID': '512e'}
data.update({'Last execution date': '2019-11-25 13:40:14',
'Number of execution': 'Total: 1, Passed: 1, Failed: 0'})
'Number of execution': 'Total: 1, Passed: 0, Failed: 1'})
validations_show = ValidationActions()
out = validations_show.show_validations('512e')
self.assertEqual(out, data)

@mock.patch('os.path.exists', return_value=False)
def test_validation_show_not_found(self, mock_exists):
validations_show = ValidationActions()
self.assertRaises(
RuntimeError,
validations_show.show_validations,
'512e'
)

@mock.patch('validations_libs.utils.parse_all_validations_on_disk',
return_value=fakes.VALIDATIONS_LIST)
@mock.patch('yaml.safe_load', return_value=fakes.GROUP)
@@ -193,11 +202,12 @@ class TestValidationActions(TestCase):
@mock.patch('six.moves.builtins.open')
def test_show_history(self, mock_open, mock_load, mock_get_log):
v_actions = ValidationActions()
col, values = v_actions.show_history('foo')
col, values = v_actions.show_history('512e')
self.assertEqual(col, ('UUID', 'Validations',
'Status', 'Execution at',
'Duration'))
self.assertEqual(values, [('123', 'foo', 'PASSED',
self.assertEqual(values, [('008886df-d297-1eaa-2a74-000000000008',
'512e', 'PASSED',
'2019-11-25T13:40:14.404623Z',
'0:00:03.753')])

@@ -213,6 +223,24 @@ class TestValidationActions(TestCase):
self.assertEqual(col, ('UUID', 'Validations',
'Status', 'Execution at',
'Duration'))
self.assertEqual(values, [('123', 'foo', 'PASSED',
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.'
'get_logfile_by_validation',
return_value=['/tmp/123_foo_2020-03-30T13:17:22.447857Z.json'])
@mock.patch('json.load',
return_value=fakes.VALIDATIONS_LOGS_CONTENTS_LIST[0])
@mock.patch('six.moves.builtins.open')
def test_get_status(self, mock_open, mock_load, mock_get_log):
v_actions = ValidationActions()
col, values = v_actions.get_status('foo')
self.assertEqual(col, ['name', 'host', 'status', 'task_data'])
self.assertEqual(values, [('Check if iscsi.service is enabled', 'foo',
'FAILED', {})])

def test_get_status_no_param(self):
v_actions = ValidationActions()
self.assertRaises(RuntimeError, v_actions.get_status)

+ 23
- 0
validations_libs/tests/test_validation_log.py View File

@@ -224,3 +224,26 @@ class TestValidationLog(TestCase):
val = ValidationLog(
logfile='/tmp/123_foo_2020-03-30T13:17:22.447857Z.json')
self.assertTrue(val.is_valid_format())

@mock.patch('json.load',
return_value=fakes.VALIDATIONS_LOGS_CONTENTS_LIST[0])
@mock.patch('six.moves.builtins.open')
def test_get_plays(self, mock_open, mock_json):
val = ValidationLog(
logfile='/tmp/123_foo_2020-03-30T13:17:22.447857Z.json')
plays = val.get_plays
self.assertEquals(
plays,
[fakes.VALIDATIONS_LOGS_CONTENTS_LIST[0]['plays'][0]['play']])

@mock.patch('json.load',
return_value=fakes.VALIDATIONS_LOGS_CONTENTS_LIST[0])
@mock.patch('six.moves.builtins.open')
def test_get_tasks_data(self, mock_open, mock_json):
val = ValidationLog(
logfile='/tmp/123_foo_2020-03-30T13:17:22.447857Z.json')
tasks_data = val.get_tasks_data
self.assertEquals(
tasks_data,
[fakes.VALIDATIONS_LOGS_CONTENTS_LIST[0]
['validation_output'][0]['task']])

+ 35
- 5
validations_libs/validation_actions.py View File

@@ -53,6 +53,11 @@ class ValidationActions(object):
# Get validation data:
vlog = ValidationLogs(log_path)
data = v_utils.get_validations_data(validation, self.validation_path)
if not data:
msg = "Validation {} not found in the path: {}".format(
validation,
self.validation_path)
raise RuntimeError(msg)
logfiles = vlog.get_all_logfiles_content()
format = vlog.get_validations_stats(logfiles)
data.update(format)
@@ -148,9 +153,10 @@ class ValidationActions(object):
f.write(params)
return params

def show_history(self, validation_id=None, extension='json'):
def show_history(self, validation_id=None, extension='json',
log_path=constants.VALIDATIONS_LOG_BASEDIR):
"""Return validations history"""
vlogs = ValidationLogs(self.validation_path)
vlogs = ValidationLogs(log_path)
logs = (vlogs.get_logfile_by_validation(validation_id)
if validation_id else vlogs.get_all_logfiles(extension))

@@ -158,11 +164,35 @@ class ValidationActions(object):
column_name = ('UUID', 'Validations',
'Status', 'Execution at',
'Duration')
for log in logs:
vlog = ValidationLog(logfile=log)
if vlog.is_valid_format():
for play in vlog.get_plays:
values.append((play['id'], play['validation_id'],
vlog.get_status,
play['duration'].get('start'),
play['duration'].get('time_elapsed')))
return (column_name, values)

def get_status(self, validation_id=None, uuid=None, status='FAILED',
log_path=constants.VALIDATIONS_LOG_BASEDIR):
"""Return validations execution details by status"""
vlogs = ValidationLogs(log_path)
if validation_id:
logs = vlogs.get_logfile_by_validation(validation_id)
elif uuid:
logs = vlogs.get_logfile_by_uuid(uuid)
else:
raise RuntimeError("You need to provide a validation_id or a uuid")

values = []
column_name = ['name', 'host', 'status', 'task_data']
for log in logs:
vlog = ValidationLog(logfile=log)
if vlog.is_valid_format():
values.append((vlog.get_uuid, vlog.validation_id,
vlog.get_status, vlog.get_start_time,
vlog.get_duration))
for task in vlog.get_tasks_data:
if task['status'] == status:
for host in task['hosts']:
values.append((task['name'], host, task['status'],
task['hosts'][host]))
return (column_name, values)

+ 10
- 0
validations_libs/validation_logs.py View File

@@ -150,6 +150,16 @@ class ValidationLog(object):
play in self.content['plays']]
return ', '.join(filter(None, start_time))

@property
def get_plays(self):
"""Return a list of Playbook data"""
return [play['play'] for play in self.content['plays']]

@property
def get_tasks_data(self):
"""Return a list of task from validation output"""
return [output['task'] for output in self.content['validation_output']]


class ValidationLogs(object):



Loading…
Cancel
Save