From 935856cb21b35ec0cb602370c4b4ed1897ad2d8d Mon Sep 17 00:00:00 2001 From: abregman Date: Wed, 5 Jun 2019 12:23:31 +0300 Subject: [PATCH] Refine tobiko faults * Setup proper logging * Extend os-faults configuration template with more services * Add unit tests initial files (Python API and CLI) * Add proper doc explaining how to use tobiko faults Change-Id: I6d528981fea6c76d20f4da095a86189748038f77 --- .gitignore | 3 ++ doc/source/user/index.rst | 1 + doc/source/user/run-faults.rst | 51 +++++++++++++++++++++++++ tobiko/cmd/fault.py | 12 +++++- tobiko/fault/config.py | 2 +- tobiko/fault/constants.py | 4 +- tobiko/fault/executor.py | 17 +++++---- tobiko/fault/templates/os-faults.yml.j2 | 1 - tobiko/tests/unit/cmd/test_fault.py | 48 +++++++++++++++++++++++ tobiko/tests/unit/fault/__init__.py | 0 tobiko/tests/unit/fault/test_fault.py | 33 ++++++++++++++++ 11 files changed, 160 insertions(+), 12 deletions(-) create mode 100644 doc/source/user/run-faults.rst create mode 100644 tobiko/tests/unit/cmd/test_fault.py create mode 100644 tobiko/tests/unit/fault/__init__.py create mode 100644 tobiko/tests/unit/fault/test_fault.py diff --git a/.gitignore b/.gitignore index f11932ef6..57e19048e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ zuul/versioninfo # Files created by releasenotes build releasenotes/build + +Pipfile.lock +tobiko.conf diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst index f701079ec..205df02a9 100644 --- a/doc/source/user/index.rst +++ b/doc/source/user/index.rst @@ -11,3 +11,4 @@ Tobiko User Guide install config run-test-cases + run-faults diff --git a/doc/source/user/run-faults.rst b/doc/source/user/run-faults.rst new file mode 100644 index 000000000..e1eb2ccfb --- /dev/null +++ b/doc/source/user/run-faults.rst @@ -0,0 +1,51 @@ +.. _tobiko-faults-execution-guide: + +================================= +Tobiko Faults Execution Guide +================================= + +This document describes how to execute faults with Tobiko. + +.. sidebar:: See also + + For a quick and simpler start you can jump to the + :ref:`tobiko-quick-start-guide`. + + To install Tobiko inside a virutalenv please read + :ref:`tobiko-installation-guide`. + + To configure Tobiko please read :ref:`tobiko-configuration-guide`. + + +Requirements +~~~~~~~~~~~~ + +In order to be able faults with Tobiko you need an RC file +for your OpenStack hosts (not the instances which run on OpenStack hosts) +Using this RC file, Tobiko will be able to generate an os-faults configuration +for you automatically. If you already have os-faults configuration file, you +don't need this requirement. + +CLI +~~~ + +In order to restart openvswitch service, run the following command: + + tobiko-fault "restart openvswitch service" + +Python API +~~~~~~~~~~ +You can also use faults in your tests. Warning: running a fault in a test +while other tests are running in parallel might have negative affect on your +other tests. + + from tobiko.fault.executor import FaultExecutor + fault = FaultExecutor() + fault.execute("restart openvswitch service") + +Missing services & containers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +What to do if the service or the container I'm trying to control +is not part of os-faults configuration? In that case please submit a patch +to Tobiko to add it to tobiko/fault/templates/os-faults.yml.j2 template. diff --git a/tobiko/cmd/fault.py b/tobiko/cmd/fault.py index 3433877c2..f9ce80532 100644 --- a/tobiko/cmd/fault.py +++ b/tobiko/cmd/fault.py @@ -32,8 +32,7 @@ class FaultCMD(object): def get_parser(self): parser = argparse.ArgumentParser(add_help=True) parser.add_argument( - '--fault', - required=True, + 'fault', help="The fault to execute (e.g. restart neutron service).\n") return parser @@ -43,8 +42,17 @@ class FaultCMD(object): fault_exec.execute(self.args.fault) +def setup_logging(debug=None): + """Sets the logging.""" + # pylint: disable=W0622 + format = '%(message)s' + level = logging.DEBUG if debug else logging.INFO + logging.basicConfig(level=level, format=format) + + def main(): """Run CLI main entry.""" + setup_logging() fault_cli = FaultCMD() fault_cli.run() diff --git a/tobiko/fault/config.py b/tobiko/fault/config.py index 27fabf008..c5b87d945 100644 --- a/tobiko/fault/config.py +++ b/tobiko/fault/config.py @@ -67,7 +67,7 @@ class FaultConfig(object): containers=fault_const.CONTAINERS) def get_nodes(self): - """Returns a list of dictonaries with nodes name and address.""" + """Returns a list of dictionaries with nodes name and address.""" client = nova.get_nova_client() return [{'name': server.name, 'address': server.addresses['ctlplane'][0]['addr']} diff --git a/tobiko/fault/constants.py b/tobiko/fault/constants.py index ab3dccc47..d89d99b60 100644 --- a/tobiko/fault/constants.py +++ b/tobiko/fault/constants.py @@ -13,5 +13,7 @@ # under the License. from __future__ import absolute_import -SERVICES = ['openvsiwtch'] +SERVICES = ['openvswitch', 'tripleo_cinder_api', 'tripleo_cinder_api_cron', + 'tripleo_cinder_scheduler', 'tripleo_clustercheck', + 'tripleo_glance_api', 'tripleo_horizon'] CONTAINERS = ['neutron_ovs_agent', 'neutron_metadata_agent', 'neutron_api'] diff --git a/tobiko/fault/executor.py b/tobiko/fault/executor.py index 4944ea566..687e7f0a3 100644 --- a/tobiko/fault/executor.py +++ b/tobiko/fault/executor.py @@ -13,8 +13,11 @@ # under the License. from __future__ import absolute_import +import sys + from oslo_log import log +import jsonschema import os_faults from tobiko.fault.config import FaultConfig @@ -25,14 +28,9 @@ LOG = log.getLogger(__name__) class FaultExecutor(object): """Responsible for executing faults.""" - def __init__(self, conf_file=None): + def __init__(self, conf_file=None, cloud=None): self.config = FaultConfig(conf_file=conf_file) - try: - self.connect() - LOG.info("os-faults connected.") - except os_faults.api.error.OSFError: - msg = "Unable to connect. Please check your configuration." - raise RuntimeError(msg) + self.cloud = cloud def connect(self): """Connect to the cloud using os-faults.""" @@ -43,7 +41,12 @@ class FaultExecutor(object): except os_faults.ansible.executor.AnsibleExecutionUnreachable: LOG.warning("Couldn't verify connectivity to the" " cloud with os-faults configuration") + except jsonschema.exceptions.ValidationError: + LOG.error("Wrong os-fault configuration format. Exiting...") + sys.exit(2) def execute(self, fault): """Executes given fault using os-faults human API.""" + LOG.info("Using %s" % self.config.conf_file) + self.connect() os_faults.human_api(self.cloud, fault) diff --git a/tobiko/fault/templates/os-faults.yml.j2 b/tobiko/fault/templates/os-faults.yml.j2 index 428707891..024bd4397 100644 --- a/tobiko/fault/templates/os-faults.yml.j2 +++ b/tobiko/fault/templates/os-faults.yml.j2 @@ -10,7 +10,6 @@ node_discover: auth: username: heat-admin private_key_file: /home/stack/.ssh/id_rsa - become: true {% endfor %} services: diff --git a/tobiko/tests/unit/cmd/test_fault.py b/tobiko/tests/unit/cmd/test_fault.py new file mode 100644 index 000000000..5dc1b92e0 --- /dev/null +++ b/tobiko/tests/unit/cmd/test_fault.py @@ -0,0 +1,48 @@ +# Copyright (c) 2018 Red Hat +# All Rights Reserved. +# +# 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. +from __future__ import absolute_import + +import argparse +import sys + +from tobiko.cmd import fault as _fault +from tobiko.tests import unit + + +class FaultCMDTest(unit.TobikoUnitTest): + + command_name = 'tobiko-fault' + command_class = _fault.FaultCMD + default_fault = ["some_fault"] + + def setUp(self): + super(FaultCMDTest, self).setUp() + self.mock_error = self.patch(argparse.ArgumentParser, 'error', + side_effect=self.fail) + + def patch_argv(self, arguments=None): + """Patch argv""" + arguments = list(arguments or []) + if not arguments: + arguments = self.default_fault + return self.patch(sys, 'argv', + [self.command_name] + arguments) + + def test_init(self, arguments=None): + self.patch_argv(arguments=arguments) + command = self.command_class() + self.mock_error.assert_not_called() + args = command.args + self.assertIsNotNone(args) diff --git a/tobiko/tests/unit/fault/__init__.py b/tobiko/tests/unit/fault/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tobiko/tests/unit/fault/test_fault.py b/tobiko/tests/unit/fault/test_fault.py new file mode 100644 index 000000000..3fc6ee012 --- /dev/null +++ b/tobiko/tests/unit/fault/test_fault.py @@ -0,0 +1,33 @@ +# Copyright (c) 2019 Red Hat, Inc. +# +# All Rights Reserved. +# +# 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. +from __future__ import absolute_import + +from tobiko.tests import unit +from tobiko.fault import executor + + +class FaultTest(unit.TobikoUnitTest): + + conf_file = "/some/conf/file" + fault = "some_fault" + + def setUp(self): + super(FaultTest, self).setUp() + self.fault_exec = executor.FaultExecutor(conf_file=self.conf_file) + + def test_init(self): + self.assertEqual(self.fault_exec.config.conf_file, self.conf_file) + self.assertEqual(self.fault_exec.cloud, None)