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',
['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.utils.parse_all_validations_on_disk')
@mock.patch('validations_libs.ansible.Ansible.run')

View File

@ -129,13 +129,89 @@ class ValidationActions(object):
data.update(data_format)
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',
group=None, extra_vars=None, validations_dir=None,
extra_env_vars=None, ansible_cfg=None, quiet=True,
workdir=None, limit_hosts=None, run_async=False,
base_dir=constants.DEFAULT_VALIDATIONS_BASEDIR,
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)
:param validation_name: A list of validation names
@ -181,6 +257,11 @@ class ValidationActions(object):
:param output_callback: The Callback plugin to use.
(Defaults to 'validation_stdout')
: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
validations executions (Validations, Duration, Host_Group,
@ -248,33 +329,42 @@ class ValidationActions(object):
self.log.debug('Running the validations with Ansible')
results = []
for playbook in playbooks:
validation_uuid, artifacts_dir = v_utils.create_artifacts_dir(
dir_path=log_path, prefix=os.path.basename(playbook))
run_ansible = v_ansible(validation_uuid)
_playbook, _rc, _status = run_ansible.run(
workdir=artifacts_dir,
playbook=playbook,
base_dir=base_dir,
playbook_dir=validations_dir,
parallel_run=True,
inventory=inventory,
output_callback=output_callback,
quiet=quiet,
extra_vars=extra_vars,
limit_hosts=limit_hosts,
extra_env_variables=extra_env_vars,
ansible_cfg=ansible_cfg,
gathering_policy='explicit',
ansible_artifact_path=artifacts_dir,
log_path=log_path,
run_async=run_async,
python_interpreter=python_interpreter)
results.append({'playbook': _playbook,
'rc_code': _rc,
'status': _status,
'validations': _playbook.split('.')[0],
'UUID': validation_uuid,
})
# Check if playbook should be skipped and on which hosts
play_name = os.path.basename(os.path.splitext(playbook)[0])
_play, _hosts = self._skip_playbook(skip_list,
play_name,
limit_hosts)
if _play:
validation_uuid, artifacts_dir = v_utils.create_artifacts_dir(
dir_path=log_path, prefix=os.path.basename(playbook))
run_ansible = v_ansible(validation_uuid)
_playbook, _rc, _status = run_ansible.run(
workdir=artifacts_dir,
playbook=playbook,
base_dir=base_dir,
playbook_dir=validations_dir,
parallel_run=True,
inventory=inventory,
output_callback=output_callback,
quiet=quiet,
extra_vars=extra_vars,
limit_hosts=_hosts,
extra_env_variables=extra_env_vars,
ansible_cfg=ansible_cfg,
gathering_policy='explicit',
ansible_artifact_path=artifacts_dir,
log_path=log_path,
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:
return results
# Return log results