From 51bd6ab7767d5679e1095f80019bd57c35da76de Mon Sep 17 00:00:00 2001 From: matbu Date: Thu, 12 Aug 2021 16:30:39 +0200 Subject: [PATCH] Expand validations_logs table with reason of failure This patch adds a new col in the result table with the reason of the failure. It avoid to dig into the logs for each failed validations. Example: https://paste.opendev.org/show/809351/ Change-Id: I4723b87b71390e1364480a8ca93e7dc7b3e654a5 --- validations_libs/tests/fakes.py | 19 +++++++++++++- .../tests/test_validation_logs.py | 25 +++++++++++++++++++ validations_libs/validation_logs.py | 21 ++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/validations_libs/tests/fakes.py b/validations_libs/tests/fakes.py index 20350196..01fc6f56 100644 --- a/validations_libs/tests/fakes.py +++ b/validations_libs/tests/fakes.py @@ -106,7 +106,24 @@ FAILED_VALIDATIONS_LOGS_CONTENTS_LIST = [{ 'unreachable': 0 } }, - 'validation_output': [] + 'validation_output': [ + { + "task": { + "hosts": { + "localhost": { + "_ansible_no_log": False, + "action": "fail", + "changed": False, + "failed": True, + "failed_when_result": True, + "msg": "Fake Failed" + } + }, + "name": "Verify Fake requirements", + "status": "FAILED" + } + } + ] }] VALIDATIONS_LOGS_CONTENTS_LIST = [{ diff --git a/validations_libs/tests/test_validation_logs.py b/validations_libs/tests/test_validation_logs.py index d9e467de..29ed3245 100644 --- a/validations_libs/tests/test_validation_logs.py +++ b/validations_libs/tests/test_validation_logs.py @@ -199,6 +199,7 @@ class TestValidationLogs(TestCase): self.assertEqual(content, [{ 'UUID': '123', 'Validations': 'foo', + 'Reasons': '', 'Status': 'PASSED', 'Status_by_Host': 'undercloud,PASSED', 'Host_Group': 'undercloud', @@ -206,6 +207,28 @@ class TestValidationLogs(TestCase): 'Duration': '0:00:03.753', 'Validations': 'foo'}]) + @mock.patch('validations_libs.validation_logs.ValidationLogs.' + 'get_logfile_by_uuid_validation_id') + @mock.patch('json.load', + return_value=fakes.FAILED_VALIDATIONS_LOGS_CONTENTS_LIST[0]) + @mock.patch('six.moves.builtins.open') + def test_get_failed_results(self, mock_open, mock_json, + mock_get_validation): + mock_get_validation.return_value = \ + ['/tmp/123_foo_2020-03-30T13:17:22.447857Z.json'] + vlogs = ValidationLogs('/tmp/foo') + content = vlogs.get_results(uuid='123', validation_id='foo') + self.assertEqual(content, [{ + 'UUID': '123', + 'Validations': 'foo', + 'Status': 'FAILED', + 'Status_by_Host': 'undercloud,FAILED', + 'Host_Group': 'undercloud', + 'Unreachable_Hosts': '', + 'Duration': '', + 'Validations': 'foo', + 'Reasons': "localhost: Fake Failed\n"}]) + def test_get_results_none(self): vlogs = ValidationLogs('/tmp/foo') self.assertRaises(RuntimeError, vlogs.get_results, uuid=None) @@ -224,6 +247,7 @@ class TestValidationLogs(TestCase): { 'UUID': '123', 'Validations': 'foo', + 'Reasons': '', 'Status': 'PASSED', 'Status_by_Host': 'undercloud,PASSED', 'Host_Group': 'undercloud', @@ -233,6 +257,7 @@ class TestValidationLogs(TestCase): { 'UUID': '123', 'Validations': 'foo', + 'Reasons': '', 'Status': 'PASSED', 'Status_by_Host': 'undercloud,PASSED', 'Host_Group': 'undercloud', diff --git a/validations_libs/validation_logs.py b/validations_libs/validation_logs.py index eeba03fe..df3a6d98 100644 --- a/validations_libs/validation_logs.py +++ b/validations_libs/validation_logs.py @@ -287,6 +287,26 @@ class ValidationLog(object): play in self.content['plays']] return ', '.join(filter(None, duration)) + @property + def get_reason(self): + """Return validation reason + + :return: hostname: reason of the failure + :rtype: ``string`` + """ + reason = [] + if self.get_status == 'FAILED': + for v_output in self.content['validation_output']: + for h in v_output['task']['hosts']: + msg = v_output['task']['hosts'][h].get('msg', + 'Unknown') + msg = msg[:50] + '\n' + msg[50:] + reason.append('{}: {}'.format(h, msg)) + if not self.content['validation_output']: + if self.get_unreachable_hosts: + reason.append('Unreachable') + return ',\n'.join(reason) + @property def get_start_time(self): """Return Ansible start time @@ -539,5 +559,6 @@ class ValidationLogs(object): data['Status_by_Host'] = vlog.get_hosts_status data['Unreachable_Hosts'] = vlog.get_unreachable_hosts data['Duration'] = vlog.get_duration + data['Reasons'] = vlog.get_reason res.append(data) return res