Add Products metadata key management
This patch adds the management of the new `products` metadata key in the validation playbooks. We can now filter the validations by their groups, by their categories or by their products while listing or running them. The `list` sub command has now a new --product argument. When filtering by groups, by categories or by products (see the example below), the `list` sub command will return all the validation playbooks belonging to the 'prep' group OR all the validation playbooks belonging to the 'os' and/or 'system' categories OR all the validation playbooks to the 'tripleo' product: $ validation list -h $ validation list --group prep --category os,system --product tripleo The `run` sub command has also its new --product argument. Note that this new argument is mutually exclusive with the --validation, --group and --category arguments: $ validation run -h $ validation run --product tripleo --inventory /etc/ansible/hosts The `show parameter` sub command has the same new argument which is also mutually exclusive with the --validation, --group and the --category arguments: $ validation show parameter -h $ validation show parameter --product tripleo Change-Id: Ief13e506c2bee18da47b31f1c2d5c0dbb1ad1ecf Signed-off-by: Gael Chamoulaud (Strider) <gchamoul@redhat.com>
This commit is contained in:
parent
3928305329
commit
c46c90394c
@ -43,6 +43,13 @@ class ValidationList(Lister):
|
|||||||
help=("List specific category of validations, "
|
help=("List specific category of validations, "
|
||||||
"if more than one category is required "
|
"if more than one category is required "
|
||||||
"separate the category names with commas."))
|
"separate the category names with commas."))
|
||||||
|
parser.add_argument('--product',
|
||||||
|
metavar='<product_id>[,<product_id>,...]',
|
||||||
|
action=CommaListAction,
|
||||||
|
default=[],
|
||||||
|
help=("List specific product of validations, "
|
||||||
|
"if more than one product is required "
|
||||||
|
"separate the product names with commas."))
|
||||||
parser.add_argument('--validation-dir', dest='validation_dir',
|
parser.add_argument('--validation-dir', dest='validation_dir',
|
||||||
default=constants.ANSIBLE_VALIDATION_DIR,
|
default=constants.ANSIBLE_VALIDATION_DIR,
|
||||||
help=("Path where the validation playbooks "
|
help=("Path where the validation playbooks "
|
||||||
@ -54,8 +61,10 @@ class ValidationList(Lister):
|
|||||||
|
|
||||||
group = parsed_args.group
|
group = parsed_args.group
|
||||||
category = parsed_args.category
|
category = parsed_args.category
|
||||||
|
product = parsed_args.product
|
||||||
validation_dir = parsed_args.validation_dir
|
validation_dir = parsed_args.validation_dir
|
||||||
|
|
||||||
v_actions = ValidationActions(validation_path=validation_dir)
|
v_actions = ValidationActions(validation_path=validation_dir)
|
||||||
return (v_actions.list_validations(groups=group,
|
return (v_actions.list_validations(groups=group,
|
||||||
categories=category))
|
categories=category,
|
||||||
|
products=product))
|
||||||
|
@ -148,6 +148,15 @@ class Run(BaseCommand):
|
|||||||
"if more than one category is required "
|
"if more than one category is required "
|
||||||
"separate the category names with commas."))
|
"separate the category names with commas."))
|
||||||
|
|
||||||
|
ex_group.add_argument(
|
||||||
|
'--product',
|
||||||
|
metavar='<product_id>[,<product_id>,...]',
|
||||||
|
action=CommaListAction,
|
||||||
|
default=[],
|
||||||
|
help=("Run specific validations by product, "
|
||||||
|
"if more than one product is required "
|
||||||
|
"separate the product names with commas."))
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
@ -178,6 +187,7 @@ class Run(BaseCommand):
|
|||||||
limit_hosts=parsed_args.limit,
|
limit_hosts=parsed_args.limit,
|
||||||
group=parsed_args.group,
|
group=parsed_args.group,
|
||||||
category=parsed_args.category,
|
category=parsed_args.category,
|
||||||
|
product=parsed_args.product,
|
||||||
extra_vars=extra_vars,
|
extra_vars=extra_vars,
|
||||||
validations_dir=parsed_args.validation_dir,
|
validations_dir=parsed_args.validation_dir,
|
||||||
base_dir=parsed_args.ansible_base_dir,
|
base_dir=parsed_args.ansible_base_dir,
|
||||||
|
@ -118,6 +118,15 @@ class ShowParameter(ShowOne):
|
|||||||
"if more than one category is required "
|
"if more than one category is required "
|
||||||
"separate the category names with commas."))
|
"separate the category names with commas."))
|
||||||
|
|
||||||
|
ex_group.add_argument(
|
||||||
|
'--product',
|
||||||
|
metavar='<product_id>[,<product_id>,...]',
|
||||||
|
action=CommaListAction,
|
||||||
|
default=[],
|
||||||
|
help=("List specific validations by product, "
|
||||||
|
"if more than one product is required "
|
||||||
|
"separate the product names with commas."))
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--download',
|
'--download',
|
||||||
action='store',
|
action='store',
|
||||||
@ -146,6 +155,7 @@ class ShowParameter(ShowOne):
|
|||||||
validations=parsed_args.validation_name,
|
validations=parsed_args.validation_name,
|
||||||
groups=parsed_args.group,
|
groups=parsed_args.group,
|
||||||
categories=parsed_args.category,
|
categories=parsed_args.category,
|
||||||
|
products=parsed_args.product,
|
||||||
output_format=parsed_args.format_output,
|
output_format=parsed_args.format_output,
|
||||||
download_file=parsed_args.download)
|
download_file=parsed_args.download)
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ class TestList(BaseCommand):
|
|||||||
{'description': 'My Validation One Description',
|
{'description': 'My Validation One Description',
|
||||||
'groups': ['prep', 'pre-deployment'],
|
'groups': ['prep', 'pre-deployment'],
|
||||||
'categories': ['os', 'system', 'ram'],
|
'categories': ['os', 'system', 'ram'],
|
||||||
|
'products': ['product1'],
|
||||||
'id': 'my_val1',
|
'id': 'my_val1',
|
||||||
'name': 'My Validation One Name',
|
'name': 'My Validation One Name',
|
||||||
'parameters': {}
|
'parameters': {}
|
||||||
@ -47,6 +48,7 @@ class TestList(BaseCommand):
|
|||||||
'description': 'My Validation Two Description',
|
'description': 'My Validation Two Description',
|
||||||
'groups': ['prep', 'pre-introspection'],
|
'groups': ['prep', 'pre-introspection'],
|
||||||
'categories': ['networking'],
|
'categories': ['networking'],
|
||||||
|
'products': ['product1'],
|
||||||
'id': 'my_val2',
|
'id': 'my_val2',
|
||||||
'name': 'My Validation Two Name',
|
'name': 'My Validation Two Name',
|
||||||
'parameters': {'min_value': 8}
|
'parameters': {'min_value': 8}
|
||||||
@ -92,3 +94,16 @@ class TestList(BaseCommand):
|
|||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
result = self.cmd.take_action(parsed_args)
|
result = self.cmd.take_action(parsed_args)
|
||||||
self.assertEqual(result, val_list)
|
self.assertEqual(result, val_list)
|
||||||
|
|
||||||
|
@mock.patch('validations_libs.utils.parse_all_validations_on_disk',
|
||||||
|
return_value=fakes.VALIDATIONS_LIST_GROUP)
|
||||||
|
def test_list_validations_by_product(self, mock_list):
|
||||||
|
arglist = ['--validation-dir', 'foo', '--product', 'product1']
|
||||||
|
verifylist = [('validation_dir', 'foo'),
|
||||||
|
('product', ['product1'])]
|
||||||
|
|
||||||
|
val_list = fakes.VALIDATION_LIST_RESULT
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
result = self.cmd.take_action(parsed_args)
|
||||||
|
self.assertEqual(result, val_list)
|
||||||
|
@ -72,6 +72,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': {'key': 'value'},
|
'extra_vars': {'key': 'value'},
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -105,6 +106,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': {'key': 'value2'},
|
'extra_vars': {'key': 'value2'},
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -151,6 +153,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': {'key': 'value'},
|
'extra_vars': {'key': 'value'},
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -182,6 +185,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': None,
|
'extra_vars': None,
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -218,6 +222,7 @@ class TestRun(BaseCommand):
|
|||||||
'quiet': False,
|
'quiet': False,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': None,
|
'extra_vars': None,
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -248,6 +253,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': None,
|
'extra_vars': None,
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -283,6 +289,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': {'key': 'value'},
|
'extra_vars': {'key': 'value'},
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -325,6 +332,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': None,
|
'extra_vars': None,
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
@ -352,6 +360,7 @@ class TestRun(BaseCommand):
|
|||||||
'limit_hosts': None,
|
'limit_hosts': None,
|
||||||
'group': [],
|
'group': [],
|
||||||
'category': [],
|
'category': [],
|
||||||
|
'product': [],
|
||||||
'extra_vars': {'key': 'value'},
|
'extra_vars': {'key': 'value'},
|
||||||
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
'validations_dir': '/usr/share/ansible/validation-playbooks',
|
||||||
'base_dir': '/usr/share/ansible',
|
'base_dir': '/usr/share/ansible',
|
||||||
|
@ -98,3 +98,11 @@ class TestShowParameter(BaseCommand):
|
|||||||
verifylist = [('category', ['os'])]
|
verifylist = [('category', ['os'])]
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
@mock.patch('validations_libs.validation_actions.ValidationActions.'
|
||||||
|
'show_validations_parameters')
|
||||||
|
def test_show_validations_parameters_by_products(self, mock_show):
|
||||||
|
arglist = ['--product', 'product1']
|
||||||
|
verifylist = [('product', ['product1'])]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
@ -19,6 +19,7 @@ VALIDATIONS_LIST = [{
|
|||||||
'description': 'My Validation One Description',
|
'description': 'My Validation One Description',
|
||||||
'groups': ['prep', 'pre-deployment'],
|
'groups': ['prep', 'pre-deployment'],
|
||||||
'categories': ['os', 'system', 'ram'],
|
'categories': ['os', 'system', 'ram'],
|
||||||
|
'products': ['product1'],
|
||||||
'id': 'my_val1',
|
'id': 'my_val1',
|
||||||
'name': 'My Validation One Name',
|
'name': 'My Validation One Name',
|
||||||
'parameters': {}
|
'parameters': {}
|
||||||
@ -26,6 +27,7 @@ VALIDATIONS_LIST = [{
|
|||||||
'description': 'My Validation Two Description',
|
'description': 'My Validation Two Description',
|
||||||
'groups': ['prep', 'pre-introspection'],
|
'groups': ['prep', 'pre-introspection'],
|
||||||
'categories': ['networking'],
|
'categories': ['networking'],
|
||||||
|
'products': ['product1'],
|
||||||
'id': 'my_val2',
|
'id': 'my_val2',
|
||||||
'name': 'My Validation Two Name',
|
'name': 'My Validation Two Name',
|
||||||
'parameters': {'min_value': 8}
|
'parameters': {'min_value': 8}
|
||||||
@ -35,16 +37,18 @@ VALIDATIONS_LIST_GROUP = [{
|
|||||||
'description': 'My Validation Two Description',
|
'description': 'My Validation Two Description',
|
||||||
'groups': ['prep', 'pre-introspection'],
|
'groups': ['prep', 'pre-introspection'],
|
||||||
'categories': ['networking'],
|
'categories': ['networking'],
|
||||||
|
'products': ['product1'],
|
||||||
'id': 'my_val2',
|
'id': 'my_val2',
|
||||||
'name': 'My Validation Two Name',
|
'name': 'My Validation Two Name',
|
||||||
'parameters': {'min_value': 8}
|
'parameters': {'min_value': 8}
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
|
||||||
VALIDATION_LIST_RESULT = (('ID', 'Name', 'Groups', 'Categories'),
|
VALIDATION_LIST_RESULT = (('ID', 'Name', 'Groups', 'Categories', 'Products'),
|
||||||
[('my_val2', 'My Validation Two Name',
|
[('my_val2', 'My Validation Two Name',
|
||||||
['prep', 'pre-introspection'],
|
['prep', 'pre-introspection'],
|
||||||
['networking'])])
|
['networking'],
|
||||||
|
['product1'])])
|
||||||
|
|
||||||
GROUPS_LIST = [
|
GROUPS_LIST = [
|
||||||
('group1', 'Group1 description'),
|
('group1', 'Group1 description'),
|
||||||
@ -214,6 +218,7 @@ VALIDATIONS_LOGS_CONTENTS_LIST = [{
|
|||||||
VALIDATIONS_DATA = {'Description': 'My Validation One Description',
|
VALIDATIONS_DATA = {'Description': 'My Validation One Description',
|
||||||
'Groups': ['prep', 'pre-deployment'],
|
'Groups': ['prep', 'pre-deployment'],
|
||||||
'categories': ['os', 'system', 'ram'],
|
'categories': ['os', 'system', 'ram'],
|
||||||
|
'products': ['product1'],
|
||||||
'ID': 'my_val1',
|
'ID': 'my_val1',
|
||||||
'Name': 'My Validation One Name',
|
'Name': 'My Validation One Name',
|
||||||
'parameters': {}}
|
'parameters': {}}
|
||||||
@ -229,6 +234,7 @@ FAKE_WRONG_PLAYBOOK = [{
|
|||||||
'description': 'foo',
|
'description': 'foo',
|
||||||
'groups': ['prep', 'pre-deployment'],
|
'groups': ['prep', 'pre-deployment'],
|
||||||
'categories': ['os', 'storage'],
|
'categories': ['os', 'storage'],
|
||||||
|
'products': ['product1'],
|
||||||
'name': 'Advanced Format 512e Support'
|
'name': 'Advanced Format 512e Support'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,6 +245,7 @@ FAKE_PLAYBOOK = [{'hosts': 'undercloud',
|
|||||||
'vars': {'metadata': {'description': 'foo',
|
'vars': {'metadata': {'description': 'foo',
|
||||||
'groups': ['prep', 'pre-deployment'],
|
'groups': ['prep', 'pre-deployment'],
|
||||||
'categories': ['os', 'storage'],
|
'categories': ['os', 'storage'],
|
||||||
|
'products': ['product1'],
|
||||||
'name':
|
'name':
|
||||||
'Advanced Format 512e Support'}}}]
|
'Advanced Format 512e Support'}}}]
|
||||||
|
|
||||||
@ -247,6 +254,7 @@ FAKE_PLAYBOOK2 = [{'hosts': 'undercloud',
|
|||||||
'vars': {'metadata': {'description': 'foo',
|
'vars': {'metadata': {'description': 'foo',
|
||||||
'groups': ['prep', 'pre-deployment'],
|
'groups': ['prep', 'pre-deployment'],
|
||||||
'categories': ['os', 'storage'],
|
'categories': ['os', 'storage'],
|
||||||
|
'products': ['product1'],
|
||||||
'name':
|
'name':
|
||||||
'Advanced Format 512e Support'},
|
'Advanced Format 512e Support'},
|
||||||
'foo': 'bar'}}]
|
'foo': 'bar'}}]
|
||||||
@ -264,11 +272,13 @@ FAKE_METADATA = {'id': 'foo',
|
|||||||
'description': 'foo',
|
'description': 'foo',
|
||||||
'groups': ['prep', 'pre-deployment'],
|
'groups': ['prep', 'pre-deployment'],
|
||||||
'categories': ['os', 'storage'],
|
'categories': ['os', 'storage'],
|
||||||
|
'products': ['product1'],
|
||||||
'name': 'Advanced Format 512e Support'}
|
'name': 'Advanced Format 512e Support'}
|
||||||
|
|
||||||
FORMATED_DATA = {'Description': 'foo',
|
FORMATED_DATA = {'Description': 'foo',
|
||||||
'Groups': ['prep', 'pre-deployment'],
|
'Groups': ['prep', 'pre-deployment'],
|
||||||
'Categories': ['os', 'storage'],
|
'Categories': ['os', 'storage'],
|
||||||
|
'Products': ['product1'],
|
||||||
'ID': 'foo',
|
'ID': 'foo',
|
||||||
'Name': 'Advanced Format 512e Support'}
|
'Name': 'Advanced Format 512e Support'}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ class TestUtils(TestCase):
|
|||||||
output = {'Name': 'Advanced Format 512e Support',
|
output = {'Name': 'Advanced Format 512e Support',
|
||||||
'Description': 'foo', 'Groups': ['prep', 'pre-deployment'],
|
'Description': 'foo', 'Groups': ['prep', 'pre-deployment'],
|
||||||
'Categories': ['os', 'storage'],
|
'Categories': ['os', 'storage'],
|
||||||
|
'Products': ['product1'],
|
||||||
'ID': '512e',
|
'ID': '512e',
|
||||||
'Parameters': {}}
|
'Parameters': {}}
|
||||||
res = utils.get_validations_data('512e')
|
res = utils.get_validations_data('512e')
|
||||||
@ -76,6 +77,12 @@ class TestUtils(TestCase):
|
|||||||
path='/foo/playbook',
|
path='/foo/playbook',
|
||||||
categories='foo1,foo2')
|
categories='foo1,foo2')
|
||||||
|
|
||||||
|
def test_parse_all_validations_on_disk_wrong_products_type(self):
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
utils.parse_all_validations_on_disk,
|
||||||
|
path='/foo/playbook',
|
||||||
|
products='foo1,foo2')
|
||||||
|
|
||||||
def test_get_validations_playbook_wrong_validation_id_type(self):
|
def test_get_validations_playbook_wrong_validation_id_type(self):
|
||||||
self.assertRaises(TypeError,
|
self.assertRaises(TypeError,
|
||||||
utils.get_validations_playbook,
|
utils.get_validations_playbook,
|
||||||
@ -94,6 +101,12 @@ class TestUtils(TestCase):
|
|||||||
path='/foo/playbook',
|
path='/foo/playbook',
|
||||||
categories='foo1,foo2')
|
categories='foo1,foo2')
|
||||||
|
|
||||||
|
def test_get_validations_playbook_wrong_products_type(self):
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
utils.get_validations_playbook,
|
||||||
|
path='/foo/playbook',
|
||||||
|
products='foo1,foo2')
|
||||||
|
|
||||||
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
||||||
@mock.patch('six.moves.builtins.open')
|
@mock.patch('six.moves.builtins.open')
|
||||||
@mock.patch('glob.glob')
|
@mock.patch('glob.glob')
|
||||||
@ -123,6 +136,18 @@ class TestUtils(TestCase):
|
|||||||
utils.get_validations_playbook,
|
utils.get_validations_playbook,
|
||||||
path=['/foo/playbook'])
|
path=['/foo/playbook'])
|
||||||
|
|
||||||
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
||||||
|
@mock.patch('six.moves.builtins.open')
|
||||||
|
@mock.patch('glob.glob')
|
||||||
|
def test_parse_all_validations_on_disk_by_product(self, mock_glob,
|
||||||
|
mock_open,
|
||||||
|
mock_load):
|
||||||
|
mock_glob.return_value = \
|
||||||
|
['/foo/playbook/foo.yaml']
|
||||||
|
result = utils.parse_all_validations_on_disk('/foo/playbook',
|
||||||
|
products=['product1'])
|
||||||
|
self.assertEqual(result, [fakes.FAKE_METADATA])
|
||||||
|
|
||||||
@mock.patch('os.path.isfile')
|
@mock.patch('os.path.isfile')
|
||||||
@mock.patch('os.listdir')
|
@mock.patch('os.listdir')
|
||||||
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
||||||
@ -173,6 +198,18 @@ class TestUtils(TestCase):
|
|||||||
categories=['os', 'storage'])
|
categories=['os', 'storage'])
|
||||||
self.assertEqual(result, ['/foo/playbook/foo.yaml'])
|
self.assertEqual(result, ['/foo/playbook/foo.yaml'])
|
||||||
|
|
||||||
|
@mock.patch('os.path.isfile')
|
||||||
|
@mock.patch('os.listdir')
|
||||||
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
||||||
|
@mock.patch('six.moves.builtins.open')
|
||||||
|
def test_get_validations_playbook_by_product(self, mock_open, mock_load,
|
||||||
|
mock_listdir, mock_isfile):
|
||||||
|
mock_listdir.return_value = ['foo.yaml']
|
||||||
|
mock_isfile.return_value = True
|
||||||
|
result = utils.get_validations_playbook('/foo/playbook',
|
||||||
|
products=['product1'])
|
||||||
|
self.assertEqual(result, ['/foo/playbook/foo.yaml'])
|
||||||
|
|
||||||
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
||||||
@mock.patch('six.moves.builtins.open')
|
@mock.patch('six.moves.builtins.open')
|
||||||
def test_get_validation_parameters(self, mock_open, mock_load):
|
def test_get_validation_parameters(self, mock_open, mock_load):
|
||||||
|
@ -125,6 +125,28 @@ class TestValidation(TestCase):
|
|||||||
categories = val.categories
|
categories = val.categories
|
||||||
self.assertEqual(categories, [])
|
self.assertEqual(categories, [])
|
||||||
|
|
||||||
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
||||||
|
@mock.patch('six.moves.builtins.open')
|
||||||
|
def test_products(self, mock_open, mock_yaml):
|
||||||
|
val = Validation('/tmp/foo')
|
||||||
|
products = val.products
|
||||||
|
self.assertEqual(products, ['product1'])
|
||||||
|
|
||||||
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_WRONG_PLAYBOOK)
|
||||||
|
@mock.patch('six.moves.builtins.open')
|
||||||
|
def test_products_with_no_metadata(self, mock_open, mock_yaml):
|
||||||
|
with self.assertRaises(NameError) as exc_mgr:
|
||||||
|
Validation('/tmp/foo').products
|
||||||
|
self.assertEqual('No metadata found in validation foo',
|
||||||
|
str(exc_mgr.exception))
|
||||||
|
|
||||||
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK3)
|
||||||
|
@mock.patch('six.moves.builtins.open')
|
||||||
|
def test_products_with_no_existing_products(self, mock_open, mock_yaml):
|
||||||
|
val = Validation('/tmp/foo')
|
||||||
|
products = val.products
|
||||||
|
self.assertEqual(products, [])
|
||||||
|
|
||||||
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
@mock.patch('yaml.safe_load', return_value=fakes.FAKE_PLAYBOOK)
|
||||||
@mock.patch('six.moves.builtins.open')
|
@mock.patch('six.moves.builtins.open')
|
||||||
def test_get_ordered_dict(self, mock_open, mock_yaml):
|
def test_get_ordered_dict(self, mock_open, mock_yaml):
|
||||||
|
@ -30,7 +30,7 @@ class TestValidationActions(TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidationActions, self).setUp()
|
super(TestValidationActions, self).setUp()
|
||||||
self.column_name = ('ID', 'Name', 'Groups', 'Categories')
|
self.column_name = ('ID', 'Name', 'Groups', 'Categories', 'Products')
|
||||||
|
|
||||||
@mock.patch('validations_libs.utils.parse_all_validations_on_disk',
|
@mock.patch('validations_libs.utils.parse_all_validations_on_disk',
|
||||||
return_value=fakes.VALIDATIONS_LIST)
|
return_value=fakes.VALIDATIONS_LIST)
|
||||||
@ -41,11 +41,13 @@ class TestValidationActions(TestCase):
|
|||||||
(self.column_name, [('my_val1',
|
(self.column_name, [('my_val1',
|
||||||
'My Validation One Name',
|
'My Validation One Name',
|
||||||
['prep', 'pre-deployment'],
|
['prep', 'pre-deployment'],
|
||||||
['os', 'system', 'ram']),
|
['os', 'system', 'ram'],
|
||||||
|
['product1']),
|
||||||
('my_val2',
|
('my_val2',
|
||||||
'My Validation Two Name',
|
'My Validation Two Name',
|
||||||
['prep', 'pre-introspection'],
|
['prep', 'pre-introspection'],
|
||||||
['networking'])]))
|
['networking'],
|
||||||
|
['product1'])]))
|
||||||
|
|
||||||
@mock.patch('validations_libs.utils.os.access', return_value=True)
|
@mock.patch('validations_libs.utils.os.access', return_value=True)
|
||||||
@mock.patch('validations_libs.utils.os.path.exists', return_value=True)
|
@mock.patch('validations_libs.utils.os.path.exists', return_value=True)
|
||||||
@ -351,6 +353,7 @@ class TestValidationActions(TestCase):
|
|||||||
data = {'Name': 'Advanced Format 512e Support',
|
data = {'Name': 'Advanced Format 512e Support',
|
||||||
'Description': 'foo', 'Groups': ['prep', 'pre-deployment'],
|
'Description': 'foo', 'Groups': ['prep', 'pre-deployment'],
|
||||||
'Categories': ['os', 'storage'],
|
'Categories': ['os', 'storage'],
|
||||||
|
'Products': ['product1'],
|
||||||
'ID': '512e',
|
'ID': '512e',
|
||||||
'Parameters': {}}
|
'Parameters': {}}
|
||||||
data.update({'Last execution date': '2019-11-25 13:40:14',
|
data.update({'Last execution date': '2019-11-25 13:40:14',
|
||||||
@ -402,6 +405,13 @@ class TestValidationActions(TestCase):
|
|||||||
v_actions.show_validations_parameters,
|
v_actions.show_validations_parameters,
|
||||||
categories={'foo': 'bar'})
|
categories={'foo': 'bar'})
|
||||||
|
|
||||||
|
@mock.patch('six.moves.builtins.open')
|
||||||
|
def test_show_validations_parameters_wrong_products_type(self, mock_open):
|
||||||
|
v_actions = ValidationActions()
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
v_actions.show_validations_parameters,
|
||||||
|
products={'foo': 'bar'})
|
||||||
|
|
||||||
@mock.patch('validations_libs.utils.get_validations_playbook',
|
@mock.patch('validations_libs.utils.get_validations_playbook',
|
||||||
return_value=['/foo/playbook/foo.yaml'])
|
return_value=['/foo/playbook/foo.yaml'])
|
||||||
@mock.patch('validations_libs.utils.get_validations_parameters')
|
@mock.patch('validations_libs.utils.get_validations_parameters')
|
||||||
|
@ -128,9 +128,12 @@ def create_artifacts_dir(log_path=constants.VALIDATIONS_LOG_BASEDIR,
|
|||||||
raise RuntimeError()
|
raise RuntimeError()
|
||||||
|
|
||||||
|
|
||||||
def parse_all_validations_on_disk(path, groups=None, categories=None):
|
def parse_all_validations_on_disk(path,
|
||||||
"""Return a list of validations metadata which can be sorted by Groups or by
|
groups=None,
|
||||||
Categories.
|
categories=None,
|
||||||
|
products=None):
|
||||||
|
"""Return a list of validations metadata which can be sorted by Groups, by
|
||||||
|
Categories or by Products.
|
||||||
|
|
||||||
:param path: The absolute path of the validations directory
|
:param path: The absolute path of the validations directory
|
||||||
:type path: `string`
|
:type path: `string`
|
||||||
@ -141,6 +144,9 @@ def parse_all_validations_on_disk(path, groups=None, categories=None):
|
|||||||
:param categories: Categories of validations
|
:param categories: Categories of validations
|
||||||
:type categories: `list`
|
:type categories: `list`
|
||||||
|
|
||||||
|
:param products: Products of validations
|
||||||
|
:type products: `list`
|
||||||
|
|
||||||
:return: A list of validations metadata.
|
:return: A list of validations metadata.
|
||||||
:rtype: `list`
|
:rtype: `list`
|
||||||
|
|
||||||
@ -149,11 +155,13 @@ def parse_all_validations_on_disk(path, groups=None, categories=None):
|
|||||||
>>> path = '/foo/bar'
|
>>> path = '/foo/bar'
|
||||||
>>> parse_all_validations_on_disk(path)
|
>>> parse_all_validations_on_disk(path)
|
||||||
[{'categories': ['storage'],
|
[{'categories': ['storage'],
|
||||||
|
'products': ['product1'],
|
||||||
'description': 'Detect whether the node disks use Advanced Format.',
|
'description': 'Detect whether the node disks use Advanced Format.',
|
||||||
'groups': ['prep', 'pre-deployment'],
|
'groups': ['prep', 'pre-deployment'],
|
||||||
'id': '512e',
|
'id': '512e',
|
||||||
'name': 'Advanced Format 512e Support'},
|
'name': 'Advanced Format 512e Support'},
|
||||||
{'categories': ['system'],
|
{'categories': ['system'],
|
||||||
|
'products': ['product1'],
|
||||||
'description': 'Make sure that the server has enough CPU cores.',
|
'description': 'Make sure that the server has enough CPU cores.',
|
||||||
'groups': ['prep', 'pre-introspection'],
|
'groups': ['prep', 'pre-introspection'],
|
||||||
'id': 'check-cpu',
|
'id': 'check-cpu',
|
||||||
@ -172,6 +180,11 @@ def parse_all_validations_on_disk(path, groups=None, categories=None):
|
|||||||
elif not isinstance(categories, list):
|
elif not isinstance(categories, list):
|
||||||
raise TypeError("The 'categories' argument must be a List")
|
raise TypeError("The 'categories' argument must be a List")
|
||||||
|
|
||||||
|
if not products:
|
||||||
|
products = []
|
||||||
|
elif not isinstance(products, list):
|
||||||
|
raise TypeError("The 'products' argument must be a List")
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
validations_abspath = glob.glob("{path}/*.yaml".format(path=path))
|
validations_abspath = glob.glob("{path}/*.yaml".format(path=path))
|
||||||
|
|
||||||
@ -179,18 +192,20 @@ def parse_all_validations_on_disk(path, groups=None, categories=None):
|
|||||||
"Attempting to parse validations by:\n"
|
"Attempting to parse validations by:\n"
|
||||||
" - groups: {}\n"
|
" - groups: {}\n"
|
||||||
" - categories: {}\n"
|
" - categories: {}\n"
|
||||||
"from {}".format(groups, categories, validations_abspath)
|
" - products: {}\n"
|
||||||
|
"from {}".format(groups, categories, products, validations_abspath)
|
||||||
)
|
)
|
||||||
|
|
||||||
for playbook in validations_abspath:
|
for playbook in validations_abspath:
|
||||||
val = Validation(playbook)
|
val = Validation(playbook)
|
||||||
|
|
||||||
if not groups and not categories:
|
if not groups and not categories and not products:
|
||||||
results.append(val.get_metadata)
|
results.append(val.get_metadata)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if set(groups).intersection(val.groups) or \
|
if set(groups).intersection(val.groups) or \
|
||||||
set(categories).intersection(val.categories):
|
set(categories).intersection(val.categories) or \
|
||||||
|
set(products).intersection(val.products):
|
||||||
results.append(val.get_metadata)
|
results.append(val.get_metadata)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@ -199,9 +214,10 @@ def parse_all_validations_on_disk(path, groups=None, categories=None):
|
|||||||
def get_validations_playbook(path,
|
def get_validations_playbook(path,
|
||||||
validation_id=None,
|
validation_id=None,
|
||||||
groups=None,
|
groups=None,
|
||||||
categories=None):
|
categories=None,
|
||||||
|
products=None):
|
||||||
"""Get a list of validations playbooks paths either by their names,
|
"""Get a list of validations playbooks paths either by their names,
|
||||||
their groups or by their categories.
|
their groups, by their categories or by their products.
|
||||||
|
|
||||||
:param path: Path of the validations playbooks
|
:param path: Path of the validations playbooks
|
||||||
:type path: `string`
|
:type path: `string`
|
||||||
@ -215,6 +231,9 @@ def get_validations_playbook(path,
|
|||||||
:param categories: List of validation category
|
:param categories: List of validation category
|
||||||
:type categories: `list`
|
:type categories: `list`
|
||||||
|
|
||||||
|
:param products: List of validation product
|
||||||
|
:type products: `list`
|
||||||
|
|
||||||
:return: A list of absolute validations playbooks path
|
:return: A list of absolute validations playbooks path
|
||||||
:rtype: `list`
|
:rtype: `list`
|
||||||
|
|
||||||
@ -224,7 +243,12 @@ def get_validations_playbook(path,
|
|||||||
>>> validation_id = ['512e','check-cpu']
|
>>> validation_id = ['512e','check-cpu']
|
||||||
>>> groups = None
|
>>> groups = None
|
||||||
>>> categories = None
|
>>> categories = None
|
||||||
>>> get_validations_playbook(path, validation_id, groups, categories)
|
>>> products = None
|
||||||
|
>>> get_validations_playbook(path=path,
|
||||||
|
validation_id=validation_id,
|
||||||
|
groups=groups,
|
||||||
|
categories=categories,
|
||||||
|
products=products)
|
||||||
['/usr/share/ansible/validation-playbooks/512e.yaml',
|
['/usr/share/ansible/validation-playbooks/512e.yaml',
|
||||||
'/usr/share/ansible/validation-playbooks/check-cpu.yaml',]
|
'/usr/share/ansible/validation-playbooks/check-cpu.yaml',]
|
||||||
"""
|
"""
|
||||||
@ -246,6 +270,11 @@ def get_validations_playbook(path,
|
|||||||
elif not isinstance(categories, list):
|
elif not isinstance(categories, list):
|
||||||
raise TypeError("The 'categories' argument must be a List")
|
raise TypeError("The 'categories' argument must be a List")
|
||||||
|
|
||||||
|
if not products:
|
||||||
|
products = []
|
||||||
|
elif not isinstance(products, list):
|
||||||
|
raise TypeError("The 'products' argument must be a List")
|
||||||
|
|
||||||
pl = []
|
pl = []
|
||||||
for f in os.listdir(path):
|
for f in os.listdir(path):
|
||||||
pl_path = join(path, f)
|
pl_path = join(path, f)
|
||||||
@ -262,6 +291,9 @@ def get_validations_playbook(path,
|
|||||||
if categories:
|
if categories:
|
||||||
if set(categories).intersection(val.categories):
|
if set(categories).intersection(val.categories):
|
||||||
pl.append(pl_path)
|
pl.append(pl_path)
|
||||||
|
if products:
|
||||||
|
if set(products).intersection(val.products):
|
||||||
|
pl.append(pl_path)
|
||||||
return pl
|
return pl
|
||||||
|
|
||||||
|
|
||||||
@ -326,6 +358,7 @@ def get_validations_details(validation):
|
|||||||
{'description': 'Verify that the server has enough something.',
|
{'description': 'Verify that the server has enough something.',
|
||||||
'groups': ['group1', 'group2'],
|
'groups': ['group1', 'group2'],
|
||||||
'categories': ['category1', 'category2'],
|
'categories': ['category1', 'category2'],
|
||||||
|
'products': ['product1', 'product2'],
|
||||||
'id': 'check-something',
|
'id': 'check-something',
|
||||||
'name': 'Verify the server fits the something requirements'}
|
'name': 'Verify the server fits the something requirements'}
|
||||||
"""
|
"""
|
||||||
@ -360,6 +393,7 @@ def get_validations_data(validation, path=constants.ANSIBLE_VALIDATION_DIR):
|
|||||||
{'Description': 'Verify that the server has enough something',
|
{'Description': 'Verify that the server has enough something',
|
||||||
'Groups': ['group1', 'group2'],
|
'Groups': ['group1', 'group2'],
|
||||||
'Categories': ['category1', 'category2'],
|
'Categories': ['category1', 'category2'],
|
||||||
|
'products': ['product1', 'product2'],
|
||||||
'ID': 'check-something',
|
'ID': 'check-something',
|
||||||
'Name': 'Verify the server fits the something requirements',
|
'Name': 'Verify the server fits the something requirements',
|
||||||
'Parameters': {'param1': 24}}
|
'Parameters': {'param1': 24}}
|
||||||
@ -386,18 +420,26 @@ def get_validations_data(validation, path=constants.ANSIBLE_VALIDATION_DIR):
|
|||||||
def get_validations_parameters(validations_data,
|
def get_validations_parameters(validations_data,
|
||||||
validation_name=None,
|
validation_name=None,
|
||||||
groups=None,
|
groups=None,
|
||||||
categories=None):
|
categories=None,
|
||||||
|
products=None):
|
||||||
"""Return parameters for a list of validations
|
"""Return parameters for a list of validations
|
||||||
|
|
||||||
|
|
||||||
:param validations_data: A list of absolute validations playbooks path
|
:param validations_data: A list of absolute validations playbooks path
|
||||||
:type validations_data: `list`
|
:type validations_data: `list`
|
||||||
|
|
||||||
:param validation_name: A list of validation name
|
:param validation_name: A list of validation name
|
||||||
:type validation_name: `list`
|
:type validation_name: `list`
|
||||||
|
|
||||||
:param groups: A list of validation groups
|
:param groups: A list of validation groups
|
||||||
:type groups: `list`
|
:type groups: `list`
|
||||||
|
|
||||||
:param categories: A list of validation categories
|
:param categories: A list of validation categories
|
||||||
:type categories: `list`
|
:type categories: `list`
|
||||||
|
|
||||||
|
:param products: A list of validation products
|
||||||
|
:type products: `list`
|
||||||
|
|
||||||
:return: a dictionary containing the current parameters for
|
:return: a dictionary containing the current parameters for
|
||||||
each `validation_name` or `groups`
|
each `validation_name` or `groups`
|
||||||
:rtype: `dict`
|
:rtype: `dict`
|
||||||
@ -429,12 +471,18 @@ def get_validations_parameters(validations_data,
|
|||||||
elif not isinstance(categories, list):
|
elif not isinstance(categories, list):
|
||||||
raise TypeError("The 'categories' argument must be a List")
|
raise TypeError("The 'categories' argument must be a List")
|
||||||
|
|
||||||
|
if not products:
|
||||||
|
products = []
|
||||||
|
elif not isinstance(products, list):
|
||||||
|
raise TypeError("The 'products' argument must be a List")
|
||||||
|
|
||||||
params = {}
|
params = {}
|
||||||
for val in validations_data:
|
for val in validations_data:
|
||||||
v = Validation(val)
|
v = Validation(val)
|
||||||
if v.id in validation_name or \
|
if v.id in validation_name or \
|
||||||
set(groups).intersection(v.groups) or \
|
set(groups).intersection(v.groups) or \
|
||||||
set(categories).intersection(v.categories):
|
set(categories).intersection(v.categories) or \
|
||||||
|
set(products).intersection(v.products):
|
||||||
params[v.id] = {
|
params[v.id] = {
|
||||||
'parameters': v.get_vars
|
'parameters': v.get_vars
|
||||||
}
|
}
|
||||||
|
@ -49,13 +49,14 @@ class Validation(object):
|
|||||||
``metadata`` section to read validation's name and description. These
|
``metadata`` section to read validation's name and description. These
|
||||||
values are then reported by the API.
|
values are then reported by the API.
|
||||||
|
|
||||||
The validations can be grouped together by specifying a ``groups``
|
The validations can be grouped together by specifying a ``groups``, a
|
||||||
and a ``categories`` metadata. ``groups`` are the deployment stage the
|
``categories`` and a ``products`` metadata. ``groups`` are the deployment
|
||||||
validations should run on and ``categories`` are the technical
|
stage the validations should run on, ``categories`` are the technical
|
||||||
classification for the validations.
|
classification for the validations and ``products`` are the specific
|
||||||
|
validations which should be executed against a specific product.
|
||||||
|
|
||||||
Groups and Categories function similar to tags and a validation can thus be
|
Groups, Categories and Products function similar to tags and a validation
|
||||||
part of many groups and many categories.
|
can thus be part of many groups and many categories.
|
||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
@ -74,12 +75,16 @@ class Validation(object):
|
|||||||
- networking
|
- networking
|
||||||
- storage
|
- storage
|
||||||
- security
|
- security
|
||||||
|
products:
|
||||||
|
- product1
|
||||||
|
- product2
|
||||||
roles:
|
roles:
|
||||||
- hello_world
|
- hello_world
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_col_keys = ['ID', 'Name', 'Description', 'Groups', 'Categories']
|
_col_keys = ['ID', 'Name', 'Description',
|
||||||
|
'Groups', 'Categories', 'Products']
|
||||||
|
|
||||||
def __init__(self, validation_path):
|
def __init__(self, validation_path):
|
||||||
self.dict = self._get_content(validation_path)
|
self.dict = self._get_content(validation_path)
|
||||||
@ -111,6 +116,9 @@ class Validation(object):
|
|||||||
- networking
|
- networking
|
||||||
- storage
|
- storage
|
||||||
- security
|
- security
|
||||||
|
products:
|
||||||
|
- product1
|
||||||
|
- product2
|
||||||
roles:
|
roles:
|
||||||
- hello_world
|
- hello_world
|
||||||
|
|
||||||
@ -138,6 +146,9 @@ class Validation(object):
|
|||||||
- networking
|
- networking
|
||||||
- storage
|
- storage
|
||||||
- security
|
- security
|
||||||
|
products:
|
||||||
|
- product1
|
||||||
|
- product2
|
||||||
roles:
|
roles:
|
||||||
- hello_world
|
- hello_world
|
||||||
|
|
||||||
@ -163,6 +174,7 @@ class Validation(object):
|
|||||||
{'description': 'Val1 desc.',
|
{'description': 'Val1 desc.',
|
||||||
'groups': ['group1', 'group2'],
|
'groups': ['group1', 'group2'],
|
||||||
'categories': ['category1', 'category2'],
|
'categories': ['category1', 'category2'],
|
||||||
|
'products': ['product1', 'product2'],
|
||||||
'id': 'val1',
|
'id': 'val1',
|
||||||
'name': 'The validation val1\'s name'}
|
'name': 'The validation val1\'s name'}
|
||||||
"""
|
"""
|
||||||
@ -219,6 +231,7 @@ class Validation(object):
|
|||||||
'vars': {'metadata': {'description': 'description of val ',
|
'vars': {'metadata': {'description': 'description of val ',
|
||||||
'groups': ['group1', 'group2'],
|
'groups': ['group1', 'group2'],
|
||||||
'categories': ['category1', 'category2'],
|
'categories': ['category1', 'category2'],
|
||||||
|
'products': ['product1', 'product2'],
|
||||||
'name': 'validation one'},
|
'name': 'validation one'},
|
||||||
'var_name1': 'value1'}}
|
'var_name1': 'value1'}}
|
||||||
"""
|
"""
|
||||||
@ -270,6 +283,29 @@ class Validation(object):
|
|||||||
"No metadata found in validation {}".format(self.id)
|
"No metadata found in validation {}".format(self.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def products(self):
|
||||||
|
"""Get the validation list of products
|
||||||
|
|
||||||
|
:return: A list of products for the validation
|
||||||
|
:rtype: `list` or `None` if no metadata has been found
|
||||||
|
:raise: A `NameError` exception if no metadata has been found in the
|
||||||
|
playbook
|
||||||
|
|
||||||
|
:Example:
|
||||||
|
|
||||||
|
>>> pl = '/foo/bar/val.yaml'
|
||||||
|
>>> val = Validation(pl)
|
||||||
|
>>> print(val.products)
|
||||||
|
['product1', 'product2']
|
||||||
|
"""
|
||||||
|
if self.has_metadata_dict:
|
||||||
|
return self.dict['vars']['metadata'].get('products', [])
|
||||||
|
else:
|
||||||
|
raise NameError(
|
||||||
|
"No metadata found in validation {}".format(self.id)
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_id(self):
|
def get_id(self):
|
||||||
"""Get the validation id
|
"""Get the validation id
|
||||||
@ -313,6 +349,7 @@ class Validation(object):
|
|||||||
>>> val = Validation(pl)
|
>>> val = Validation(pl)
|
||||||
>>> print(val.get_formated_data)
|
>>> print(val.get_formated_data)
|
||||||
{'Categories': ['category1', 'category2'],
|
{'Categories': ['category1', 'category2'],
|
||||||
|
'Products': ['product1', 'product2'],
|
||||||
'Description': 'description of val',
|
'Description': 'description of val',
|
||||||
'Groups': ['group1', 'group2'],
|
'Groups': ['group1', 'group2'],
|
||||||
'ID': 'val',
|
'ID': 'val',
|
||||||
|
@ -47,9 +47,13 @@ class ValidationActions(object):
|
|||||||
self.validation_path = (validation_path if validation_path
|
self.validation_path = (validation_path if validation_path
|
||||||
else constants.ANSIBLE_VALIDATION_DIR)
|
else constants.ANSIBLE_VALIDATION_DIR)
|
||||||
|
|
||||||
def list_validations(self, groups=None, categories=None):
|
def list_validations(self,
|
||||||
|
groups=None,
|
||||||
|
categories=None,
|
||||||
|
products=None):
|
||||||
"""Get a list of the validations selected by group membership or by
|
"""Get a list of the validations selected by group membership or by
|
||||||
category. With their names, group membership information and categories.
|
category. With their names, group membership information, categories and
|
||||||
|
products.
|
||||||
|
|
||||||
This is used to print table from python ``Tuple`` with ``PrettyTable``.
|
This is used to print table from python ``Tuple`` with ``PrettyTable``.
|
||||||
|
|
||||||
@ -59,18 +63,21 @@ class ValidationActions(object):
|
|||||||
:param categories: List of validation categories.
|
:param categories: List of validation categories.
|
||||||
:type categories: `list`
|
:type categories: `list`
|
||||||
|
|
||||||
|
:param products: List of validation products.
|
||||||
|
:type products: `list`
|
||||||
|
|
||||||
:return: Column names and a list of the selected validations
|
:return: Column names and a list of the selected validations
|
||||||
:rtype: `tuple`
|
:rtype: `tuple`
|
||||||
|
|
||||||
.. code:: text
|
.. code:: text
|
||||||
|
|
||||||
-------+-----------+----------------------+---------------+
|
-------+-----------+----------------------+---------------+--------------+
|
||||||
| ID | Name | Groups | Categories |
|
| ID | Name | Groups | Categories | Products |
|
||||||
+------+-----------+----------------------+---------------+
|
+------+-----------+----------------------+---------------+--------------+
|
||||||
| val1 | val_name1 | ['group1'] | ['category1'] |
|
| val1 | val_name1 | ['group1'] | ['category1'] | ['product1'] |
|
||||||
| val2 | val_name2 | ['group1', 'group2'] | ['category2'] |
|
| val2 | val_name2 | ['group1', 'group2'] | ['category2'] | ['product2'] |
|
||||||
| val3 | val_name3 | ['group4'] | ['category3'] |
|
| val3 | val_name3 | ['group4'] | ['category3'] | ['product3'] |
|
||||||
+------+-----------+----------------------+---------------+
|
+------+-----------+----------------------+---------------+--------------+
|
||||||
|
|
||||||
:Example:
|
:Example:
|
||||||
|
|
||||||
@ -81,16 +88,26 @@ class ValidationActions(object):
|
|||||||
>>> results = action.list_validations(groups=groups,
|
>>> results = action.list_validations(groups=groups,
|
||||||
categories=categories)
|
categories=categories)
|
||||||
>>> print(results
|
>>> print(results
|
||||||
(('ID', 'Name', 'Groups', 'Categories'),
|
(('ID', 'Name', 'Groups', 'Categories', 'Products'),
|
||||||
[('val1', 'val_name1', ['group1'], ['category1']),
|
[('val1',
|
||||||
('val2', 'val_name2', ['group1', 'group2'], ['category2'])])
|
'val_name1',
|
||||||
|
['group1'],
|
||||||
|
['category1'],
|
||||||
|
['product1']),
|
||||||
|
('val2',
|
||||||
|
'val_name2',
|
||||||
|
['group1', 'group2'],
|
||||||
|
['category2'],
|
||||||
|
['product2'])])
|
||||||
"""
|
"""
|
||||||
self.log = logging.getLogger(__name__ + ".list_validations")
|
self.log = logging.getLogger(__name__ + ".list_validations")
|
||||||
|
|
||||||
validations = v_utils.parse_all_validations_on_disk(
|
validations = v_utils.parse_all_validations_on_disk(
|
||||||
path=self.validation_path,
|
path=self.validation_path,
|
||||||
groups=groups,
|
groups=groups,
|
||||||
categories=categories)
|
categories=categories,
|
||||||
|
products=products
|
||||||
|
)
|
||||||
|
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
"Parsed {} validations.".format(len(validations))
|
"Parsed {} validations.".format(len(validations))
|
||||||
@ -98,10 +115,11 @@ class ValidationActions(object):
|
|||||||
|
|
||||||
return_values = [
|
return_values = [
|
||||||
(val.get('id'), val.get('name'),
|
(val.get('id'), val.get('name'),
|
||||||
val.get('groups'), val.get('categories'))
|
val.get('groups'), val.get('categories'),
|
||||||
|
val.get('products'))
|
||||||
for val in validations]
|
for val in validations]
|
||||||
|
|
||||||
column_names = ('ID', 'Name', 'Groups', 'Categories')
|
column_names = ('ID', 'Name', 'Groups', 'Categories', 'Products')
|
||||||
|
|
||||||
return (column_names, return_values)
|
return (column_names, return_values)
|
||||||
|
|
||||||
@ -241,17 +259,17 @@ class ValidationActions(object):
|
|||||||
return [path[1] for path in logs[-history_limit:]]
|
return [path[1] for path in logs[-history_limit:]]
|
||||||
|
|
||||||
def run_validations(self, validation_name=None, inventory='localhost',
|
def run_validations(self, validation_name=None, inventory='localhost',
|
||||||
group=None, category=None, extra_vars=None,
|
group=None, category=None, product=None,
|
||||||
validations_dir=None, extra_env_vars=None,
|
extra_vars=None, validations_dir=None,
|
||||||
ansible_cfg=None, quiet=True, workdir=None,
|
extra_env_vars=None, ansible_cfg=None, quiet=True,
|
||||||
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=constants.VALIDATIONS_LOG_BASEDIR,
|
log_path=constants.VALIDATIONS_LOG_BASEDIR,
|
||||||
python_interpreter=None, skip_list=None,
|
python_interpreter=None, skip_list=None,
|
||||||
callback_whitelist=None,
|
callback_whitelist=None,
|
||||||
output_callback='validation_stdout',
|
output_callback='validation_stdout', ssh_user=None):
|
||||||
ssh_user=None):
|
"""Run one or multiple validations by name(s), by group(s) or by
|
||||||
"""Run one or multiple validations by name(s) or by group(s)
|
product(s)
|
||||||
|
|
||||||
:param validation_name: A list of validation names
|
:param validation_name: A list of validation names
|
||||||
:type validation_name: ``list``
|
:type validation_name: ``list``
|
||||||
@ -262,6 +280,8 @@ class ValidationActions(object):
|
|||||||
:type group: ``list``
|
:type group: ``list``
|
||||||
:param category: A list of category names
|
:param category: A list of category names
|
||||||
:type category: ``list``
|
:type category: ``list``
|
||||||
|
:param product: A list of product names
|
||||||
|
:type product: ``list``
|
||||||
:param extra_vars: Set additional variables as a Dict or the absolute
|
:param extra_vars: Set additional variables as a Dict or the absolute
|
||||||
path of a JSON or YAML file type.
|
path of a JSON or YAML file type.
|
||||||
:type extra_vars: Either a Dict or the absolute path of JSON or YAML
|
:type extra_vars: Either a Dict or the absolute path of JSON or YAML
|
||||||
@ -345,20 +365,22 @@ class ValidationActions(object):
|
|||||||
playbooks = []
|
playbooks = []
|
||||||
validations_dir = (validations_dir if validations_dir
|
validations_dir = (validations_dir if validations_dir
|
||||||
else self.validation_path)
|
else self.validation_path)
|
||||||
if group or category:
|
if group or category or product:
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
"Getting the validations list by:\n"
|
"Getting the validations list by:\n"
|
||||||
" - groups: {}\n"
|
" - groups: {}\n"
|
||||||
" - categories: {}".format(group, category)
|
" - categories: {}\n"
|
||||||
|
" - products: {}".format(group, category, product)
|
||||||
)
|
)
|
||||||
validations = v_utils.parse_all_validations_on_disk(
|
validations = v_utils.parse_all_validations_on_disk(
|
||||||
path=validations_dir, groups=group, categories=category)
|
path=validations_dir, groups=group,
|
||||||
|
categories=category, products=product
|
||||||
|
)
|
||||||
for val in validations:
|
for val in validations:
|
||||||
playbooks.append(val.get('id') + '.yaml')
|
playbooks.append(val.get('id') + '.yaml')
|
||||||
elif validation_name:
|
elif validation_name:
|
||||||
playbooks = v_utils.get_validations_playbook(validations_dir,
|
playbooks = v_utils.get_validations_playbook(validations_dir,
|
||||||
validation_name,
|
validation_name)
|
||||||
group)
|
|
||||||
|
|
||||||
if not playbooks or len(validation_name) != len(playbooks):
|
if not playbooks or len(validation_name) != len(playbooks):
|
||||||
p = []
|
p = []
|
||||||
@ -495,11 +517,12 @@ class ValidationActions(object):
|
|||||||
validations=None,
|
validations=None,
|
||||||
groups=None,
|
groups=None,
|
||||||
categories=None,
|
categories=None,
|
||||||
|
products=None,
|
||||||
output_format='json',
|
output_format='json',
|
||||||
download_file=None):
|
download_file=None):
|
||||||
"""
|
"""
|
||||||
Return Validations Parameters for one or several validations by their
|
Return Validations Parameters for one or several validations by their
|
||||||
names, their groups or by their categories.
|
names, their groups, by their categories or by their products.
|
||||||
|
|
||||||
:param validations: List of validation name(s)
|
:param validations: List of validation name(s)
|
||||||
:type validations: `list`
|
:type validations: `list`
|
||||||
@ -510,6 +533,9 @@ class ValidationActions(object):
|
|||||||
:param categories: List of validation category(ies)
|
:param categories: List of validation category(ies)
|
||||||
:type categories: `list`
|
:type categories: `list`
|
||||||
|
|
||||||
|
:param products: List of validation product(s)
|
||||||
|
:type products: `list`
|
||||||
|
|
||||||
:param output_format: Output format (Supported format are JSON or YAML)
|
:param output_format: Output format (Supported format are JSON or YAML)
|
||||||
:type output_format: `string`
|
:type output_format: `string`
|
||||||
|
|
||||||
@ -525,9 +551,10 @@ class ValidationActions(object):
|
|||||||
>>> validations = ['check-cpu', 'check-ram']
|
>>> validations = ['check-cpu', 'check-ram']
|
||||||
>>> groups = None
|
>>> groups = None
|
||||||
>>> categories = None
|
>>> categories = None
|
||||||
|
>>> products = None
|
||||||
>>> output_format = 'json'
|
>>> output_format = 'json'
|
||||||
>>> show_validations_parameters(validations, groups,
|
>>> show_validations_parameters(validations, groups,
|
||||||
categories, output_format)
|
categories, products, output_format)
|
||||||
{
|
{
|
||||||
"check-cpu": {
|
"check-cpu": {
|
||||||
"parameters": {
|
"parameters": {
|
||||||
@ -556,6 +583,11 @@ class ValidationActions(object):
|
|||||||
elif not isinstance(categories, list):
|
elif not isinstance(categories, list):
|
||||||
raise TypeError("The 'categories' argument must be a List")
|
raise TypeError("The 'categories' argument must be a List")
|
||||||
|
|
||||||
|
if not products:
|
||||||
|
products = []
|
||||||
|
elif not isinstance(products, list):
|
||||||
|
raise TypeError("The 'products' argument must be a List")
|
||||||
|
|
||||||
supported_format = ['json', 'yaml']
|
supported_format = ['json', 'yaml']
|
||||||
|
|
||||||
if output_format not in supported_format:
|
if output_format not in supported_format:
|
||||||
@ -565,13 +597,17 @@ class ValidationActions(object):
|
|||||||
path=self.validation_path,
|
path=self.validation_path,
|
||||||
validation_id=validations,
|
validation_id=validations,
|
||||||
groups=groups,
|
groups=groups,
|
||||||
categories=categories)
|
categories=categories,
|
||||||
|
products=products
|
||||||
|
)
|
||||||
|
|
||||||
params = v_utils.get_validations_parameters(
|
params = v_utils.get_validations_parameters(
|
||||||
validations_data=validation_playbooks,
|
validations_data=validation_playbooks,
|
||||||
validation_name=validations,
|
validation_name=validations,
|
||||||
groups=groups,
|
groups=groups,
|
||||||
categories=categories)
|
categories=categories,
|
||||||
|
products=products
|
||||||
|
)
|
||||||
|
|
||||||
if download_file:
|
if download_file:
|
||||||
params_only = {}
|
params_only = {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user