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
This commit is contained in:
matbu 2023-09-12 16:37:50 +02:00
parent fbd4983d56
commit 8d9e1b5dfd
5 changed files with 69 additions and 7 deletions

View File

@ -189,7 +189,7 @@ class CallbackModule(CallbackBase):
def v2_playbook_on_no_hosts_matched(self): def v2_playbook_on_no_hosts_matched(self):
no_match_result = self._val_task('No tasks run') 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'] = ( no_match_result['task']['info'] = (
"None of the hosts specified" "None of the hosts specified"
" were matched in the inventory file") " were matched in the inventory file")
@ -199,11 +199,11 @@ class CallbackModule(CallbackBase):
'stats': { 'stats': {
'No host matched': { 'No host matched': {
'changed': 0, 'changed': 0,
'failures': 1, 'failures': 0,
'ignored': 0, 'ignored': 0,
'ok': 0, 'ok': 0,
'rescued': 0, 'rescued': 0,
'skipped': 0, 'skipped': 1,
'unreachable': 0}}, 'unreachable': 0}},
'validation_output': self.simple_results + [no_match_result] 'validation_output': self.simple_results + [no_match_result]
} }

View File

@ -382,7 +382,7 @@ class TestValidationJson(base.BaseTestCase):
dummy_stats.processed['foohost'] = 5 dummy_stats.processed['foohost'] = 5
no_match_result = validation_task no_match_result = validation_task
no_match_result['task']['status'] = "FAILED" no_match_result['task']['status'] = "SKIPPED"
no_match_result['task']['info'] = ( no_match_result['task']['info'] = (
"None of the hosts specified" "None of the hosts specified"
" were matched in the inventory file") " were matched in the inventory file")
@ -392,11 +392,11 @@ class TestValidationJson(base.BaseTestCase):
'stats': { 'stats': {
'No host matched': { 'No host matched': {
'changed': 0, 'changed': 0,
'failures': 1, 'failures': 0,
'ignored': 0, 'ignored': 0,
'ok': 0, 'ok': 0,
'rescued': 0, 'rescued': 0,
'skipped': 0, 'skipped': 1,
'unreachable': 0}}, 'unreachable': 0}},
'validation_output': results + [no_match_result] 'validation_output': results + [no_match_result]
} }

View File

@ -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 = [{ FAILED_VALIDATIONS_LOGS_WRONG_MSG_LIST = [{
'stats': { 'stats': {
'undercloud': { 'undercloud': {

View File

@ -153,6 +153,15 @@ class TestValidationLog(TestCase):
status = val.get_status status = val.get_status
self.assertEqual(status, 'FAILED') 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', @mock.patch('json.load',
return_value=fakes.BAD_VALIDATIONS_LOGS_CONTENTS_LIST[0]) return_value=fakes.BAD_VALIDATIONS_LOGS_CONTENTS_LIST[0])
@mock.patch('builtins.open') @mock.patch('builtins.open')
@ -189,6 +198,15 @@ class TestValidationLog(TestCase):
host_group = val.get_hosts_status host_group = val.get_hosts_status
self.assertEqual(host_group, 'undercloud,FAILED') 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', @mock.patch('json.load',
return_value=fakes.BAD_VALIDATIONS_LOGS_CONTENTS_LIST[0]) return_value=fakes.BAD_VALIDATIONS_LOGS_CONTENTS_LIST[0])
@mock.patch('builtins.open') @mock.patch('builtins.open')

View File

@ -199,7 +199,9 @@ class ValidationLog:
"""Return validation status """Return validation status
:return: 'FAILED' if there are any failed or unreachable validations, :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`` :rtype: ``string``
""" """
failure_states = ['failures', 'unreachable'] failure_states = ['failures', 'unreachable']
@ -207,6 +209,8 @@ class ValidationLog:
for v_stats in self.content['stats'].values(): for v_stats in self.content['stats'].values():
if any([v_stats[failure] != 0 for failure in failure_states]): if any([v_stats[failure] != 0 for failure in failure_states]):
return 'FAILED' return 'FAILED'
if v_stats['skipped'] and not v_stats['ok']:
return 'SKIPPED'
return 'PASSED' return 'PASSED'
@property @property
@ -239,6 +243,8 @@ class ValidationLog:
hosts.append('{},{}'.format(h, 'FAILED')) hosts.append('{},{}'.format(h, 'FAILED'))
elif self.content['stats'][h].get('unreachable'): elif self.content['stats'][h].get('unreachable'):
hosts.append('{},{}'.format(h, '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: else:
hosts.append('{},{}'.format(h, 'PASSED')) hosts.append('{},{}'.format(h, 'PASSED'))
return ', '.join(hosts) return ', '.join(hosts)