Merge "Add skip list option in order to provide a black list for validation"

This commit is contained in:
Zuul 2021-02-18 09:03:46 +00:00 committed by Gerrit Code Review
commit 58c757cdee
2 changed files with 223 additions and 28 deletions

View File

@ -45,6 +45,111 @@ class TestValidationActions(TestCase):
'My Validation Two Name', 'My Validation Two Name',
['prep', 'pre-introspection'])])) ['prep', 'pre-introspection'])]))
@mock.patch('validations_libs.utils.get_validations_playbook',
return_value=['/tmp/foo/fake.yaml'])
def test_validation_skip_validation(self, mock_validation_play):
playbook = ['fake.yaml']
inventory = 'tmp/inventory.yaml'
skip_list = {'fake': {'hosts': 'ALL',
'reason': None,
'lp': None
}
}
run = ValidationActions()
run_return = run.run_validations(playbook, inventory,
validations_dir='/tmp/foo',
skip_list=skip_list,
limit_hosts=None)
self.assertEqual(run_return, [])
@mock.patch('validations_libs.utils.get_validations_playbook',
return_value=['/tmp/foo/fake.yaml'])
@mock.patch('validations_libs.ansible.Ansible.run')
@mock.patch('validations_libs.utils.create_artifacts_dir',
return_value=('1234', '/tmp/'))
def test_validation_skip_on_specific_host(self, mock_tmp, mock_ansible_run,
mock_validation_play):
mock_ansible_run.return_value = ('fake.yaml', 0, 'successful')
run_called_args = {
'workdir': '/tmp/',
'playbook': '/tmp/foo/fake.yaml',
'base_dir': '/usr/share/ansible/',
'playbook_dir': '/tmp/foo',
'parallel_run': True,
'inventory': 'tmp/inventory.yaml',
'output_callback': 'validation_stdout',
'quiet': True,
'extra_vars': None,
'limit_hosts': '!cloud1',
'ansible_artifact_path': '/tmp/',
'extra_env_variables': None,
'ansible_cfg': None,
'gathering_policy': 'explicit',
'log_path': None,
'run_async': False,
'python_interpreter': None
}
playbook = ['fake.yaml']
inventory = 'tmp/inventory.yaml'
skip_list = {'fake': {'hosts': 'cloud1',
'reason': None,
'lp': None
}
}
run = ValidationActions()
run_return = run.run_validations(playbook, inventory,
validations_dir='/tmp/foo',
skip_list=skip_list,
limit_hosts=None)
mock_ansible_run.assert_called_with(**run_called_args)
@mock.patch('validations_libs.utils.get_validations_playbook',
return_value=['/tmp/foo/fake.yaml'])
@mock.patch('validations_libs.ansible.Ansible.run')
@mock.patch('validations_libs.utils.create_artifacts_dir',
return_value=('1234', '/tmp/'))
def test_validation_skip_with_limit_host(self, mock_tmp, mock_ansible_run,
mock_validation_play):
mock_ansible_run.return_value = ('fake.yaml', 0, 'successful')
run_called_args = {
'workdir': '/tmp/',
'playbook': '/tmp/foo/fake.yaml',
'base_dir': '/usr/share/ansible/',
'playbook_dir': '/tmp/foo',
'parallel_run': True,
'inventory': 'tmp/inventory.yaml',
'output_callback': 'validation_stdout',
'quiet': True,
'extra_vars': None,
'limit_hosts': '!cloud1,cloud,!cloud2',
'ansible_artifact_path': '/tmp/',
'extra_env_variables': None,
'ansible_cfg': None,
'gathering_policy': 'explicit',
'log_path': None,
'run_async': False,
'python_interpreter': None
}
playbook = ['fake.yaml']
inventory = 'tmp/inventory.yaml'
skip_list = {'fake': {'hosts': 'cloud1',
'reason': None,
'lp': None
}
}
run = ValidationActions()
run_return = run.run_validations(playbook, inventory,
validations_dir='/tmp/foo',
skip_list=skip_list,
limit_hosts='cloud,cloud1,!cloud2')
mock_ansible_run.assert_called_with(**run_called_args)
@mock.patch('validations_libs.validation_logs.ValidationLogs.get_results') @mock.patch('validations_libs.validation_logs.ValidationLogs.get_results')
@mock.patch('validations_libs.utils.parse_all_validations_on_disk') @mock.patch('validations_libs.utils.parse_all_validations_on_disk')
@mock.patch('validations_libs.ansible.Ansible.run') @mock.patch('validations_libs.ansible.Ansible.run')

View File

@ -129,13 +129,89 @@ class ValidationActions(object):
data.update(data_format) data.update(data_format)
return data return data
def _skip_hosts(self, skip_list, playbook, limit_hosts=None):
"""Check Ansible Hosts and return an updated limit_hosts
:param skip_list: The list of the validation to skip
:type validation_name: ``dict``
:param playbook: The name of the playbook
:type base_dir: ``string``
:param limit_hosts: Limit the execution to the hosts.
:type limit_hosts: ``string``
:return the limit hosts according the skip_list or None if the
validation should be skipped on ALL hosts.
:example
limit_hosts = 'cloud1,cloud2'
skip_list = {'xyz': {'hosts': 'cloud1',
'reason': None,
'lp': None}
}
>>> _skip_hosts(skip_list, playbook, limit_hosts='cloud1,cloud2')
'cloud2,!cloud1'
"""
hosts = skip_list[playbook].get('hosts')
if hosts == 'ALL' or hosts is None:
return None
else:
_hosts = ['!{}'.format(hosts)]
if limit_hosts:
# check if skipped hosts is already in limit host
_hosts.extend([limit for limit in limit_hosts.split(',')
if hosts not in limit])
return ','.join(_hosts)
def _skip_playbook(self, skip_list, playbook, limit_hosts=None):
"""Check if playbook is in the ski plist
:param skip_list: The list of the validation to skip
:type validation_name: ``dict``
:param playbook: The name of the playbook
:type base_dir: ``string``
:param limit_hosts: Limit the execution to the hosts.
:type limit_hosts: ``string``
:return a tuple of playbook and hosts
:example
skip_list = {'xyz': {'hosts': 'cloud1',
'reason': None,
'lp': None}
}
If playbook not in skip list:
>>> _skip_playbook(skip_list, 'foo', None)
('foo', None)
If playbook in the skip list, but with restriction only on
host cloud1:
>>> _skip_playbook(skip_list, 'xyz', None)
('xyz', '!cloud1')
If playbook in the skip list, and should be skip on ALL hosts:
skip_list = {'xyz': {'hosts': 'ALL',
'reason': None,
'lp': None}
}
>>> _skip_playbook(skip_list, 'xyz', None)
(None, None)
"""
if skip_list:
if playbook in skip_list.keys():
_hosts = self._skip_hosts(skip_list, playbook,
limit_hosts)
if _hosts:
return playbook, _hosts
else:
return None, _hosts
return playbook, limit_hosts
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,
workdir=None, limit_hosts=None, run_async=False, workdir=None, limit_hosts=None, run_async=False,
base_dir=constants.DEFAULT_VALIDATIONS_BASEDIR, base_dir=constants.DEFAULT_VALIDATIONS_BASEDIR,
log_path=None, python_interpreter=None, log_path=None, python_interpreter=None,
output_callback='validation_stdout'): output_callback='validation_stdout',
skip_list=None):
"""Run one or multiple validations by name(s) or by group(s) """Run one or multiple validations by name(s) or by group(s)
:param validation_name: A list of validation names :param validation_name: A list of validation names
@ -181,6 +257,11 @@ class ValidationActions(object):
:param output_callback: The Callback plugin to use. :param output_callback: The Callback plugin to use.
(Defaults to 'validation_stdout') (Defaults to 'validation_stdout')
:type output_callback: ``string`` :type output_callback: ``string``
:param skip_list: List of validations to skip during the Run form as
{'xyz': {'hosts': 'ALL', 'reason': None, 'lp': None}
}
(Defaults to 'None')
:type skip_list: ``dict``
:return: A list of dictionary containing the informations of the :return: A list of dictionary containing the informations of the
validations executions (Validations, Duration, Host_Group, validations executions (Validations, Duration, Host_Group,
@ -248,33 +329,42 @@ class ValidationActions(object):
self.log.debug('Running the validations with Ansible') self.log.debug('Running the validations with Ansible')
results = [] results = []
for playbook in playbooks: for playbook in playbooks:
validation_uuid, artifacts_dir = v_utils.create_artifacts_dir( # Check if playbook should be skipped and on which hosts
dir_path=log_path, prefix=os.path.basename(playbook)) play_name = os.path.basename(os.path.splitext(playbook)[0])
run_ansible = v_ansible(validation_uuid) _play, _hosts = self._skip_playbook(skip_list,
_playbook, _rc, _status = run_ansible.run( play_name,
workdir=artifacts_dir, limit_hosts)
playbook=playbook, if _play:
base_dir=base_dir, validation_uuid, artifacts_dir = v_utils.create_artifacts_dir(
playbook_dir=validations_dir, dir_path=log_path, prefix=os.path.basename(playbook))
parallel_run=True, run_ansible = v_ansible(validation_uuid)
inventory=inventory, _playbook, _rc, _status = run_ansible.run(
output_callback=output_callback, workdir=artifacts_dir,
quiet=quiet, playbook=playbook,
extra_vars=extra_vars, base_dir=base_dir,
limit_hosts=limit_hosts, playbook_dir=validations_dir,
extra_env_variables=extra_env_vars, parallel_run=True,
ansible_cfg=ansible_cfg, inventory=inventory,
gathering_policy='explicit', output_callback=output_callback,
ansible_artifact_path=artifacts_dir, quiet=quiet,
log_path=log_path, extra_vars=extra_vars,
run_async=run_async, limit_hosts=_hosts,
python_interpreter=python_interpreter) extra_env_variables=extra_env_vars,
results.append({'playbook': _playbook, ansible_cfg=ansible_cfg,
'rc_code': _rc, gathering_policy='explicit',
'status': _status, ansible_artifact_path=artifacts_dir,
'validations': _playbook.split('.')[0], log_path=log_path,
'UUID': validation_uuid, run_async=run_async,
}) python_interpreter=python_interpreter)
results.append({'playbook': _playbook,
'rc_code': _rc,
'status': _status,
'validations': _playbook.split('.')[0],
'UUID': validation_uuid,
})
else:
self.log.debug('Skipping Validations: {}'.format(playbook))
if run_async: if run_async:
return results return results
# Return log results # Return log results