From 8cce4bfd64d28aba89a22d4885215616ab277c57 Mon Sep 17 00:00:00 2001 From: Mathieu Bultel Date: Tue, 3 Mar 2020 16:55:20 +0100 Subject: [PATCH] Add utils functions and validations List object --- validations_libs/constants.py | 26 ++++ validations_libs/list.py | 42 ++++++ validations_libs/run.py | 0 validations_libs/show.py | 0 validations_libs/tests/__init__.py | 0 validations_libs/tests/fakes.py | 141 ++++++++++++++++++ .../tests/test_validations_list.py | 40 +++++ validations_libs/utils.py | 94 ++++++++++++ 8 files changed, 343 insertions(+) create mode 100644 validations_libs/constants.py create mode 100644 validations_libs/list.py create mode 100644 validations_libs/run.py create mode 100644 validations_libs/show.py create mode 100644 validations_libs/tests/__init__.py create mode 100644 validations_libs/tests/fakes.py create mode 100644 validations_libs/tests/test_validations_list.py create mode 100644 validations_libs/utils.py diff --git a/validations_libs/constants.py b/validations_libs/constants.py new file mode 100644 index 00000000..17380f3c --- /dev/null +++ b/validations_libs/constants.py @@ -0,0 +1,26 @@ +# Copyright 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import os + +DEFAULT_VALIDATIONS_BASEDIR = '/usr/share/validations-common' + +ANSIBLE_VALIDATION_DIR = '/usr/share/validations-common/playbooks' + +VALIDATION_GROUPS_INFO = '%s/groups.yaml' % DEFAULT_VALIDATIONS_BASEDIR + +VALIDATION_GROUPS = ['no-op', + 'prep', + 'post'] diff --git a/validations_libs/list.py b/validations_libs/list.py new file mode 100644 index 00000000..7f57f320 --- /dev/null +++ b/validations_libs/list.py @@ -0,0 +1,42 @@ +# Copyright 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import constants +import logging +import utils as validations_utils + +LOG = logging.getLogger(__name__ + ".list") + + +class List(object): + + def __init__(self, group, validations_dir=None): + self.log = logging.getLogger(__name__ + ".List") + self.validations_dir = (validations_dir if validations_dir + else constants.ANSIBLE_VALIDATION_DIR) + self.group = group + + def list_validations(self): + """List the available validations""" + validations = validations_utils.parse_all_validations_on_disk( + self.validations_dir, self.group) + + return_values = [] + column_name = ('ID', 'Name', 'Groups') + + for val in validations: + return_values.append((val.get('id'), val.get('name'), + val.get('groups'))) + return (column_name, return_values) diff --git a/validations_libs/run.py b/validations_libs/run.py new file mode 100644 index 00000000..e69de29b diff --git a/validations_libs/show.py b/validations_libs/show.py new file mode 100644 index 00000000..e69de29b diff --git a/validations_libs/tests/__init__.py b/validations_libs/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/validations_libs/tests/fakes.py b/validations_libs/tests/fakes.py new file mode 100644 index 00000000..bb2752b5 --- /dev/null +++ b/validations_libs/tests/fakes.py @@ -0,0 +1,141 @@ +# Copyright 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + + +VALIDATIONS_LIST = [{ + 'description': 'My Validation One Description', + 'groups': ['prep', 'pre-deployment'], + 'id': 'my_val1', + 'name': 'My Validition One Name', + 'parameters': {} +}, { + 'description': 'My Validation Two Description', + 'groups': ['prep', 'pre-introspection'], + 'id': 'my_val2', + 'name': 'My Validition Two Name', + 'parameters': {'min_value': 8} +}] + +GROUPS_LIST = [ + ('group1', 'Group1 description'), + ('group2', 'Group2 description'), + ('group3', 'Group3 description'), +] + +VALIDATIONS_LOGS_CONTENTS_LIST = [{ + 'plays': [{ + 'play': { + 'duration': { + 'end': '2019-11-25T13:40:17.538611Z', + 'start': '2019-11-25T13:40:14.404623Z', + 'time_elapsed': '0:00:03.753' + }, + 'host': 'undercloud', + 'id': '008886df-d297-1eaa-2a74-000000000008', + 'validation_id': '512e', + 'validation_path': + '/usr/share/openstack-tripleo-validations/playbooks' + }, + 'tasks': [ + { + 'hosts': { + 'undercloud': { + '_ansible_no_log': False, + 'action': 'command', + 'changed': False, + 'cmd': [u'ls', '/sys/class/block/'], + 'delta': '0:00:00.018913', + 'end': '2019-11-25 13:40:17.120368', + 'invocation': { + 'module_args': { + '_raw_params': 'ls /sys/class/block/', + '_uses_shell': False, + 'argv': None, + 'chdir': None, + 'creates': None, + 'executable': None, + 'removes': None, + 'stdin': None, + 'stdin_add_newline': True, + 'strip_empty_ends': True, + 'warn': True + } + }, + 'rc': 0, + 'start': '2019-11-25 13:40:17.101455', + 'stderr': '', + 'stderr_lines': [], + 'stdout': 'vda', + 'stdout_lines': [u'vda'] + } + }, + 'task': { + 'duration': { + 'end': '2019-11-25T13:40:17.336687Z', + 'start': '2019-11-25T13:40:14.529880Z' + }, + 'id': + '008886df-d297-1eaa-2a74-00000000000d', + 'name': + 'advanced-format-512e-support : List the available drives' + } + }, + { + 'hosts': { + 'undercloud': { + 'action': + 'advanced_format', + 'changed': False, + 'msg': + 'All items completed', + 'results': [{ + '_ansible_item_label': 'vda', + '_ansible_no_log': False, + 'ansible_loop_var': 'item', + 'changed': False, + 'item': 'vda', + 'skip_reason': 'Conditional result was False', + 'skipped': True + }], + 'skipped': True + } + }, + 'task': { + 'duration': { + 'end': '2019-11-25T13:40:17.538611Z', + 'start': '2019-11-25T13:40:17.341704Z' + }, + 'id': '008886df-d297-1eaa-2a74-00000000000e', + 'name': + 'advanced-format-512e-support: Detect the drive' + } + } + ] + }], + 'stats': { + 'undercloud': { + 'changed': 0, + 'failures': 0, + 'ignored': 0, + 'ok': 1, + 'rescued': 0, + 'skipped': 1, + 'unreachable': 0 + } + }, + 'validation_output': [] +}] diff --git a/validations_libs/tests/test_validations_list.py b/validations_libs/tests/test_validations_list.py new file mode 100644 index 00000000..992ef9b2 --- /dev/null +++ b/validations_libs/tests/test_validations_list.py @@ -0,0 +1,40 @@ +# Copyright 2018 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock +import unittest + +from validations_libs.tests import fakes +from validations_libs.list import List + + +class TestValidatorList(unittest.TestCase): + + def setUp(self): + super(TestValidatorList, self).setUp() + self.column_name = ('ID', 'Name', 'Groups') + + @mock.patch('validations_libs.utils.parse_all_validations_on_disk', + return_value=fakes.VALIDATIONS_LIST) + def test_validation_list(self, mock_validation_dir): + validations_list = List(fakes.GROUPS_LIST, '/tmp/foo') + + self.assertEqual(validations_list.list_validations(), + (self.column_name, [('my_val1', + 'My Validition One Name', + ['prep', 'pre-deployment']), + ('my_val2', + 'My Validition Two Name', + ['prep', 'pre-introspection'])])) diff --git a/validations_libs/utils.py b/validations_libs/utils.py new file mode 100644 index 00000000..d8646b28 --- /dev/null +++ b/validations_libs/utils.py @@ -0,0 +1,94 @@ +# Copyright 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import constants +import glob +import logging +import os +import yaml + +LOG = logging.getLogger(__name__ + ".utils") + + +def parse_all_validations_on_disk(path, groups=None): + results = [] + validations_abspath = glob.glob("{path}/*.yaml".format(path=path)) + + for pl in validations_abspath: + validation_id, ext = os.path.splitext(os.path.basename(pl)) + + with open(pl, 'r') as val_playbook: + contents = yaml.safe_load(val_playbook) + + validation_groups = get_validation_metadata(contents, 'groups') or [] + if not groups or set.intersection(set(groups), set(validation_groups)): + results.append({ + 'id': validation_id, + 'name': get_validation_metadata(contents, 'name'), + 'groups': get_validation_metadata(contents, 'groups'), + 'description': get_validation_metadata(contents, + 'description'), + 'parameters': get_validation_parameters(contents) + }) + + return results + + +def parse_all_validation_groups_on_disk(groups_file_path=None): + results = [] + + if not groups_file_path: + groups_file_path = constants.VALIDATION_GROUPS_INFO + + if not os.path.exists(groups_file_path): + return results + + with open(groups_file_path, 'r') as grps: + contents = yaml.safe_load(grps) + + for grp_name, grp_desc in sorted(contents.items()): + results.append((grp_name, grp_desc[0].get('description'))) + + return results + + +def get_validation_metadata(validation, key): + default_metadata = { + 'name': 'Unnamed', + 'description': 'No description', + 'stage': 'No stage', + 'groups': [], + } + + try: + return validation[0]['vars']['metadata'].get(key, + default_metadata[key]) + except KeyError: + LOG.exception("Key '{key}' not even found in " + "default metadata").format(key=key) + except TypeError: + LOG.exception("Failed to get validation metadata.") + + +def get_validation_parameters(validation): + try: + return { + k: v + for k, v in validation[0]['vars'].items() + if k != 'metadata' + } + except KeyError: + LOG.debug("No parameters found for this validation") + return dict()