Expose skip list mechanism via the CLI

The skip list feature was available only via the API, this patch
allow the user to pass a file with the list of the validations
which he wants to skip during the run, example:

check-ram: hosts: all
  reason: Wrong ram value
  lp: https://lp.fake.net
check-cpu: hosts: undercloud
  reason: Unstable validation
  lp: https://lp.fake.net
Change-Id: I04059f9339085e0dcef1f018cad1be511ee7d3c7
This commit is contained in:
matbu 2021-09-15 23:01:13 +02:00
parent 11488cd88d
commit bef53bc2f6
5 changed files with 116 additions and 21 deletions

8
skiplist-example.yaml Normal file
View File

@ -0,0 +1,8 @@
check-ram:
hosts: all
reason: Wrong ram value
lp: https://lp.fake.net
check-cpu:
hosts: undercloud
reason: Unstable validation
lp: https://lp.fake.net

View File

@ -102,16 +102,16 @@ def write_junitxml(output_junitxml, results):
output.write(to_xml_report_string([ts]))
def read_extra_vars_file(extra_vars_file):
"""Read file containing extra variables.
def read_cli_data_file(data_file):
"""Read CLI data (YAML/JSON) file.
"""
try:
with open(extra_vars_file, 'r') as env_file:
return yaml.safe_load(env_file.read())
with open(data_file, 'r') as _file:
return yaml.safe_load(_file.read())
except yaml.YAMLError as error:
error_msg = (
"The extra_vars file must be properly formatted YAML/JSON."
"Details: {}.").format(error)
"The file {} must be properly formatted YAML/JSON."
"Details: {}.").format(data_file, error)
raise RuntimeError(error_msg)

View File

@ -97,6 +97,13 @@ class Run(BaseCommand):
"KEY multiple times, the last given VALUE for that same KEY "
"will override the other(s)"))
parser.add_argument('--skiplist', dest='skip_list',
default=None,
help=("Path where the skip list is stored."
"An example of the skiplist format could "
"be found at the root the validations-libs "
"repository."))
extra_vars_group = parser.add_mutually_exclusive_group(required=False)
extra_vars_group.add_argument(
'--extra-vars',
@ -184,9 +191,15 @@ class Run(BaseCommand):
"Loading extra vars file {}".format(
parsed_args.extra_vars_file))
extra_vars = common.read_extra_vars_file(
extra_vars = common.read_cli_data_file(
parsed_args.extra_vars_file)
skip_list = None
if parsed_args.skip_list:
skip_list = common.read_cli_data_file(parsed_args.skip_list)
if not isinstance(skip_list, dict):
raise RuntimeError("Wrong format for the skiplist.")
try:
results = v_actions.run_validations(
inventory=parsed_args.inventory,
@ -203,7 +216,8 @@ class Run(BaseCommand):
quiet=quiet_mode,
ssh_user=parsed_args.ssh_user,
log_path=parsed_args.validation_log_dir,
validation_config=config)
validation_config=config,
skip_list=skip_list)
except RuntimeError as e:
raise RuntimeError(e)

View File

@ -83,7 +83,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo',
@ -121,7 +122,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo',
@ -172,7 +174,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo',
@ -208,7 +211,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo',
@ -248,7 +252,8 @@ class TestRun(BaseCommand):
'python_interpreter': sys.executable,
'quiet': False,
'ssh_user': 'doe',
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo',
@ -285,7 +290,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo',
@ -325,7 +331,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo',
@ -372,7 +379,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo']
@ -405,7 +413,8 @@ class TestRun(BaseCommand):
'python_interpreter': sys.executable,
'quiet': True,
'ssh_user': 'doe',
'validation_config': {}
'validation_config': {},
'skip_list': None
}
arglist = ['--validation', 'foo']
@ -442,7 +451,8 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
self._set_args(arglist)
@ -479,10 +489,73 @@ class TestRun(BaseCommand):
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {}
'validation_config': {},
'skip_list': None
}
self._set_args(arglist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
mock_run.assert_called_with(**run_called_args)
@mock.patch('validations_libs.constants.VALIDATIONS_LOG_BASEDIR')
@mock.patch('yaml.safe_load', return_value={'key': 'value'})
@mock.patch('six.moves.builtins.open')
@mock.patch('getpass.getuser',
return_value='doe')
@mock.patch('validations_libs.validation_actions.ValidationActions.'
'run_validations',
return_value=copy.deepcopy(fakes.FAKE_SUCCESS_RUN))
@mock.patch('validations_libs.utils.load_config', return_value={})
def test_run_command_with_skip_list(self, mock_config, mock_run,
mock_user, mock_open,
mock_yaml, mock_log_dir):
run_called_args = {
'inventory': 'localhost',
'limit_hosts': None,
'group': [],
'category': [],
'product': [],
'extra_vars': None,
'validations_dir': '/usr/share/ansible/validation-playbooks',
'base_dir': '/usr/share/ansible',
'validation_name': ['foo'],
'extra_env_vars': None,
'python_interpreter': sys.executable,
'quiet': True,
'ssh_user': 'doe',
'log_path': mock_log_dir,
'validation_config': {},
'skip_list': {'key': 'value'}
}
arglist = ['--validation', 'foo',
'--skiplist', '/foo/skip.yaml']
verifylist = [('validation_name', ['foo']),
('skip_list', '/foo/skip.yaml')]
self._set_args(arglist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
mock_run.assert_called_with(**run_called_args)
@mock.patch('validations_libs.constants.VALIDATIONS_LOG_BASEDIR')
@mock.patch('yaml.safe_load', return_value=[{'key': 'value'}])
@mock.patch('six.moves.builtins.open')
@mock.patch('getpass.getuser',
return_value='doe')
@mock.patch('validations_libs.validation_actions.ValidationActions.'
'run_validations',
return_value=copy.deepcopy(fakes.FAKE_SUCCESS_RUN))
@mock.patch('validations_libs.utils.load_config', return_value={})
def test_run_command_with_skip_list_bad_format(self, mock_config, mock_run,
mock_user, mock_open,
mock_yaml, mock_log_dir):
arglist = ['--validation', 'foo',
'--skiplist', '/foo/skip.yaml']
verifylist = [('validation_name', ['foo']),
('skip_list', '/foo/skip.yaml')]
self._set_args(arglist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(RuntimeError, self.cmd.take_action, parsed_args)

View File

@ -189,7 +189,7 @@ class ValidationActions(object):
"""
hosts = skip_list[playbook].get('hosts')
if hosts == 'ALL' or hosts is None:
if hosts.lower() == 'all' or hosts is None:
return None
else:
_hosts = ['!{}'.format(hosts)]
@ -465,7 +465,7 @@ class ValidationActions(object):
'UUID': validation_uuid,
})
else:
self.log.debug('Skipping Validations: {}'.format(playbook))
self.log.info('Skipping Validations: {}'.format(playbook))
if run_async:
return results