From 8d9e1b5dfd43be5cb41b67b6071c1a35a00cbaa1 Mon Sep 17 00:00:00 2001 From: matbu Date: Tue, 12 Sep 2023 16:37:50 +0200 Subject: [PATCH] Move No hosts matched status to skipped instead of failed When no hosts matched the callback and the cli return the validation as failed state. This patch move this status as 'skipped' and ignored instead of 'failed'. Resolves: rhbz#2237500 Change-Id: I82bba29f802ef98e327c5421ef9a5079a3586d70 --- .../callback_plugins/vf_validation_json.py | 6 +-- .../test_vf_validation_json.py | 6 +-- validations_libs/tests/fakes.py | 38 +++++++++++++++++++ validations_libs/tests/test_validation_log.py | 18 +++++++++ validations_libs/validation_logs.py | 8 +++- 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/validations_libs/callback_plugins/vf_validation_json.py b/validations_libs/callback_plugins/vf_validation_json.py index 549351c1..0b16cbf6 100644 --- a/validations_libs/callback_plugins/vf_validation_json.py +++ b/validations_libs/callback_plugins/vf_validation_json.py @@ -189,7 +189,7 @@ class CallbackModule(CallbackBase): def v2_playbook_on_no_hosts_matched(self): no_match_result = self._val_task('No tasks run') - no_match_result['task']['status'] = "FAILED" + no_match_result['task']['status'] = "SKIPPED" no_match_result['task']['info'] = ( "None of the hosts specified" " were matched in the inventory file") @@ -199,11 +199,11 @@ class CallbackModule(CallbackBase): 'stats': { 'No host matched': { 'changed': 0, - 'failures': 1, + 'failures': 0, 'ignored': 0, 'ok': 0, 'rescued': 0, - 'skipped': 0, + 'skipped': 1, 'unreachable': 0}}, 'validation_output': self.simple_results + [no_match_result] } diff --git a/validations_libs/tests/callback_plugins/test_vf_validation_json.py b/validations_libs/tests/callback_plugins/test_vf_validation_json.py index e91ffa9e..7777237b 100644 --- a/validations_libs/tests/callback_plugins/test_vf_validation_json.py +++ b/validations_libs/tests/callback_plugins/test_vf_validation_json.py @@ -382,7 +382,7 @@ class TestValidationJson(base.BaseTestCase): dummy_stats.processed['foohost'] = 5 no_match_result = validation_task - no_match_result['task']['status'] = "FAILED" + no_match_result['task']['status'] = "SKIPPED" no_match_result['task']['info'] = ( "None of the hosts specified" " were matched in the inventory file") @@ -392,11 +392,11 @@ class TestValidationJson(base.BaseTestCase): 'stats': { 'No host matched': { 'changed': 0, - 'failures': 1, + 'failures': 0, 'ignored': 0, 'ok': 0, 'rescued': 0, - 'skipped': 0, + 'skipped': 1, 'unreachable': 0}}, 'validation_output': results + [no_match_result] } diff --git a/validations_libs/tests/fakes.py b/validations_libs/tests/fakes.py index e539fa12..114ea337 100644 --- a/validations_libs/tests/fakes.py +++ b/validations_libs/tests/fakes.py @@ -131,6 +131,44 @@ FAILED_VALIDATIONS_LOGS_CONTENTS_LIST = [{ ] }] +NO_HOST_MATCHED_VALIDATIONS_LOGS_CONTENTS_LIST = { + "plays": [ + { + "play": { + "duration": { + "start": "2023-09-12T15:02:40.134341Z" + }, + "host": "Controller", + "id": "96ebffe3-5312-4dbc-b04c-9039db80a160", + "validation_id": "controller-ulimits", + "validation_path": "/usr/share/ansible/validation-playbooks" + }, + "tasks": [] + } + ], + "stats": { + "No host matched": { + "changed": 0, + "failures": 0, + "ignored": 0, + "ok": 0, + "rescued": 0, + "skipped": 1, + "unreachable": 0 + } + }, + "validation_output": [ + { + "task": { + "hosts": {}, + "info": "None of the hosts specified were matched in the inventory file", + "name": "No tasks run", + "status": "SKIPPED" + } + } + ] +} + FAILED_VALIDATIONS_LOGS_WRONG_MSG_LIST = [{ 'stats': { 'undercloud': { diff --git a/validations_libs/tests/test_validation_log.py b/validations_libs/tests/test_validation_log.py index c9b0557b..cac0a59d 100644 --- a/validations_libs/tests/test_validation_log.py +++ b/validations_libs/tests/test_validation_log.py @@ -153,6 +153,15 @@ class TestValidationLog(TestCase): status = val.get_status self.assertEqual(status, 'FAILED') + @mock.patch('json.load', + return_value=fakes.NO_HOST_MATCHED_VALIDATIONS_LOGS_CONTENTS_LIST) + @mock.patch('builtins.open') + def test_get_status_no_host_matched(self, mock_open, mock_json): + val = ValidationLog( + logfile='/tmp/123_foo_2020-03-30T13:17:22.447857Z.json') + status = val.get_status + self.assertEqual(status, 'SKIPPED') + @mock.patch('json.load', return_value=fakes.BAD_VALIDATIONS_LOGS_CONTENTS_LIST[0]) @mock.patch('builtins.open') @@ -189,6 +198,15 @@ class TestValidationLog(TestCase): host_group = val.get_hosts_status self.assertEqual(host_group, 'undercloud,FAILED') + @mock.patch('json.load', + return_value=fakes.NO_HOST_MATCHED_VALIDATIONS_LOGS_CONTENTS_LIST) + @mock.patch('builtins.open') + def test_get_hosts_status_no_host_match(self, mock_open, mock_json): + val = ValidationLog( + logfile='/tmp/123_foo_2020-03-30T13:17:22.447857Z.json') + host_group = val.get_hosts_status + self.assertEqual(host_group, 'No host matched,SKIPPED') + @mock.patch('json.load', return_value=fakes.BAD_VALIDATIONS_LOGS_CONTENTS_LIST[0]) @mock.patch('builtins.open') diff --git a/validations_libs/validation_logs.py b/validations_libs/validation_logs.py index 3d0d54db..23e94d3f 100644 --- a/validations_libs/validation_logs.py +++ b/validations_libs/validation_logs.py @@ -199,7 +199,9 @@ class ValidationLog: """Return validation status :return: 'FAILED' if there are any failed or unreachable validations, - 'PASSED' if not. + 'SKIPPED' if skipped is True and ok is false which means that + the entire validation has been ignored because no host matched, + 'PASSED' if none of those conditions. :rtype: ``string`` """ failure_states = ['failures', 'unreachable'] @@ -207,6 +209,8 @@ class ValidationLog: for v_stats in self.content['stats'].values(): if any([v_stats[failure] != 0 for failure in failure_states]): return 'FAILED' + if v_stats['skipped'] and not v_stats['ok']: + return 'SKIPPED' return 'PASSED' @property @@ -239,6 +243,8 @@ class ValidationLog: hosts.append('{},{}'.format(h, 'FAILED')) elif self.content['stats'][h].get('unreachable'): hosts.append('{},{}'.format(h, 'UNREACHABLE')) + elif self.content['stats'][h].get('skipped') and not self.content['stats'][h].get('ok'): + hosts.append('{},{}'.format(h, 'SKIPPED')) else: hosts.append('{},{}'.format(h, 'PASSED')) return ', '.join(hosts)