diff --git a/README.rst b/README.rst index af00413..f75e0a2 100644 --- a/README.rst +++ b/README.rst @@ -57,8 +57,9 @@ Connection to DevStack can be specified using the following YAML file: driver: devstack args: address: devstack.local - username: stack - private_key_file: cloud_key + auth: + username: stack + private_key_file: cloud_key iface: enp0s8 OS-Faults library will connect to DevStack by address `devstack.local` with user `stack` diff --git a/doc/ext/driver_doc.py b/doc/ext/driver_doc.py index 0ec4940..6984929 100644 --- a/doc/ext/driver_doc.py +++ b/doc/ext/driver_doc.py @@ -48,8 +48,9 @@ class CloudDriverDocDirective(rst.Directive): subcat = utils.subcategory('{} [{}]'.format(drv_name, types)) subcat.extend(utils.parse_text(doc)) - subcat.extend(utils.parse_text('**Default services:**')) - subcat.extend(utils.rstlist(services)) + if services: + subcat.extend(utils.parse_text('**Default services:**')) + subcat.extend(utils.rstlist(services)) return [subcat] diff --git a/doc/source/drivers.rst b/doc/source/drivers.rst index 8529de5..cac57b6 100644 --- a/doc/source/drivers.rst +++ b/doc/source/drivers.rst @@ -5,16 +5,12 @@ Drivers Cloud management ---------------- -.. cloud_driver_doc:: devstack_systemd - .. cloud_driver_doc:: universal -.. cloud_driver_doc:: fuel +.. cloud_driver_doc:: devstack .. cloud_driver_doc:: tcpcloud -.. cloud_driver_doc:: devstack - Power management ---------------- @@ -37,18 +33,8 @@ Service drivers .. driver_doc:: system_service -.. driver_doc:: linux_service - -.. driver_doc:: screen - -.. driver_doc:: systemd_service - .. driver_doc:: salt_service -.. driver_doc:: pcs_service - -.. driver_doc:: pcs_or_linux_service - Container drivers ----------------- diff --git a/doc/source/index.rst b/doc/source/index.rst index 4f0a241..a9926d1 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -4,10 +4,11 @@ OS-Faults |release| **OpenStack fault-injection library** -The library does destructive actions inside an OpenStack cloud. It provides -an abstraction layer over different types of cloud deployments. The actions -are implemented as drivers (e.g. DevStack driver, Fuel driver, Libvirt driver, -IPMI driver). +OS-Faults library provides an unified abstract API for performing +destructive actions against OpenStack cloud. The library is extendable +using drivers. Basic drivers for DevStack, Linux services and power +management are already included. + Contents ======== diff --git a/doc/source/quickstart/api.rst b/doc/source/quickstart/api.rst index a650634..809704e 100644 --- a/doc/source/quickstart/api.rst +++ b/doc/source/quickstart/api.rst @@ -2,10 +2,10 @@ API === -The library operates with 2 types of objects: +The library operates with different types of objects: * `service` - is a software that runs in the cloud, e.g. `nova-api` - * `containers` - is a software that runs in the cloud, e.g. `neutron-api` + * `containers` - is a container that runs in the cloud, e.g. `neutron-api` * `nodes` - nodes that host the cloud, e.g. a hardware server with a hostname diff --git a/doc/source/quickstart/basics.rst b/doc/source/quickstart/basics.rst index ca3aa9f..ddf815d 100644 --- a/doc/source/quickstart/basics.rst +++ b/doc/source/quickstart/basics.rst @@ -13,9 +13,10 @@ The cloud deployment configuration schema has simple YAML/JSON format: cloud_management: driver: devstack args: - address: devstack.local - username: stack - private_key_file: cloud_key + address: 192.168.1.240 + auth: + username: stack + private_key_file: cloud_key iface: enp0s8 power_managements: @@ -24,22 +25,22 @@ The cloud deployment configuration schema has simple YAML/JSON format: connection_uri: qemu+ssh://ubuntu@10.0.1.50/system -By default, the library reads configuration from a file and the file can be in -the following three formats: ``os-faults.{json,yaml,yml}``. The configuration -file will be searched in the default locations: +By default, the library reads configuration from a file with one of +the following names: ``os-faults.{json,yaml,yml}``. The configuration +file is searched in one of default locations: * current directory * ~/.config/os-faults * /etc/openstack -Also, the configuration file can be specified in the ``OS_FAULTS_CONFIG`` -environment variable:: +Also, the name of the configuration file can be specified in the +``OS_FAULTS_CONFIG`` environment variable:: $ export OS_FAULTS_CONFIG=/home/alex/my-os-faults-config.yaml -Running -------- +Execution +--------- Establish a connection to the cloud and verify it: @@ -55,7 +56,7 @@ or via CLI:: $ os-faults verify -c os-faults.yaml -Make some destructive actions: +Make some destructive action: .. code-block:: python diff --git a/doc/source/quickstart/config_spec.rst b/doc/source/quickstart/config_spec.rst index 97b1901..b3e3128 100644 --- a/doc/source/quickstart/config_spec.rst +++ b/doc/source/quickstart/config_spec.rst @@ -20,8 +20,9 @@ Example configuration: driver: devstack args: address: 192.168.1.240 - username: ubuntu - iface: enp0s3 + auth: + username: ubuntu + iface: enp0s3 power_managements: - driver: libvirt @@ -72,12 +73,13 @@ and contains arguments such as SSH username/password/key/proxy. driver: devstack # name of the driver args: # arguments for the driver address: 192.168.1.240 - username: ubuntu - iface: enp0s3 + auth: + username: ubuntu + iface: enp0s3 -Also, such drivers can support discovering of cloud nodes. For example, -``fuel``, ``tcpcloud`` drives allow discovering information about nodes +Drivers can support discovering of cloud nodes. For example, +``tcpcloud`` drives allow discovering information about nodes through master/config node of the cloud. List of supported drivers for cloud_management: :ref:`Cloud management` diff --git a/doc/source/quickstart/installation.rst b/doc/source/quickstart/installation.rst index ab94a72..3880538 100644 --- a/doc/source/quickstart/installation.rst +++ b/doc/source/quickstart/installation.rst @@ -15,3 +15,8 @@ The library contains optional libvirt driver, if you plan to use it, please use the following command to install os-faults with extra dependencies:: pip install os-faults[libvirt] + + +The library relies on Ansible which needs to be installed separately. +Please refer to [https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html] +for installation instructions. diff --git a/doc/source/quickstart/rally.rst b/doc/source/quickstart/rally.rst index 1a5394f..9b538f5 100644 --- a/doc/source/quickstart/rally.rst +++ b/doc/source/quickstart/rally.rst @@ -59,4 +59,4 @@ More on reliability testing of OpenStack: .. _Fault Injection Hook: http://docs.xrally.xyz/projects/openstack/en/0.10.0/plugins/plugin_reference.html?highlight=fault_injection#fault-injection-hook-action .. _Reliability Test Plan: https://docs.openstack.org/performance-docs/latest/test_plans/reliability/version_2/plan.html .. _Keystone authentication with restart memcached report: https://docs.openstack.org/performance-docs/latest/test_results/reliability/version_2/reports/keystone/authenticate_with_restart_memcached_service_on_one_node/index.html -.. _Introduction into reliability metrics: https://www.youtube.com/watch?v=9puoDd14IxU +.. _Introduction into reliability metrics: https://youtu.be/MIj4clkKtfY diff --git a/os_faults/cmd/cmd.py b/os_faults/cmd/cmd.py index 5505295..42a2c64 100644 --- a/os_faults/cmd/cmd.py +++ b/os_faults/cmd/cmd.py @@ -97,6 +97,8 @@ def _list_items(group, items): textwrap.wrap(', '.join(sorted(items)), subsequent_indent=' ' * (len(group) + 8), break_on_hyphens=False)) + if not s: + s = '/no built-in support/' return ' %s: %s' % (group, s) @@ -106,7 +108,7 @@ def _make_epilog(): networks_strings = [] driver_descriptions = [] - for driver_name, driver in drivers.items(): + for driver_name, driver in sorted(drivers.items(), key=lambda x: x[0]): driver_descriptions.append( ' %s - %s' % (driver_name, driver.get_driver_description())) diff --git a/os_faults/drivers/cloud/devstack.py b/os_faults/drivers/cloud/devstack.py index 4cb57b3..f80da45 100644 --- a/os_faults/drivers/cloud/devstack.py +++ b/os_faults/drivers/cloud/devstack.py @@ -17,13 +17,12 @@ from os_faults.ansible import executor from os_faults.api import cloud_management from os_faults.api import node_collection from os_faults.api import node_discover -from os_faults.drivers.services import process +from os_faults.drivers import shared_schemas LOG = logging.getLogger(__name__) class DevStackNode(node_collection.NodeCollection): - def connect(self, network_name): raise NotImplementedError @@ -31,72 +30,11 @@ class DevStackNode(node_collection.NodeCollection): raise NotImplementedError -class ServiceInScreen(process.ServiceAsProcess): - """Service in Screen - - This driver controls service that is started in a window of - `screen` tool. - - **Example configuration:** - - .. code-block:: yaml - - services: - app: - driver: screen - args: - window_name: app - grep: my_app - port: ['tcp', 4242] - - parameters: - - - **window_name** - name of a service - - **grep** - regexp for grep to find process PID - - **port** - tuple with two values - protocol, port number (optional) - - """ - NAME = 'screen' - DESCRIPTION = 'Service in screen' - CONFIG_SCHEMA = { - 'type': 'object', - 'properties': { - 'window_name': {'type': 'string'}, - 'grep': {'type': 'string'}, - 'port': process.PORT_SCHEMA, - }, - 'required': ['grep', 'window_name'], - 'additionalProperties': False, - } - - def __init__(self, *args, **kwargs): - super(ServiceInScreen, self).__init__(*args, **kwargs) - self.window_name = self.config['window_name'] - - # sends ctr+c, arrow up key, enter key - self.restart_cmd = ( - "screen -S stack -p {window_name} -X " - "stuff $'\\003'$'\\033[A'$(printf \\\\r)").format( - window_name=self.window_name) - - # sends ctr+c - self.terminate_cmd = ( - "screen -S stack -p {window_name} -X " - "stuff $'\\003'").format( - window_name=self.window_name) - - # sends arrow up key, enter key - self.start_cmd = ( - "screen -S stack -p {window_name} -X " - "stuff $'\\033[A'$(printf \\\\r)").format( - window_name=self.window_name) - - class DevStackManagement(cloud_management.CloudManagement, node_discover.NodeDiscover): - """Devstack driver (**deprecated**). + """Driver for DevStack. - This driver requires devstack installed in screen mode (USE_SCREEN=True). + This driver requires DevStack installed with Systemd (USE_SCREEN=False). Supports discovering of node MAC addresses. **Example configuration:** @@ -107,9 +45,10 @@ class DevStackManagement(cloud_management.CloudManagement, driver: devstack args: address: 192.168.1.10 - username: ubuntu - password: ubuntu_pass - private_key_file: ~/.ssh/id_rsa_devstack + auth: + username: ubuntu + password: ubuntu_pass + private_key_file: ~/.ssh/id_rsa_devstack slaves: - 192.168.1.11 - 192.168.1.12 @@ -128,77 +67,134 @@ class DevStackManagement(cloud_management.CloudManagement, """ NAME = 'devstack' - DESCRIPTION = 'DevStack management driver' + DESCRIPTION = 'DevStack management driver using Systemd' NODE_CLS = DevStackNode SERVICES = { - 'keystone': { - 'driver': 'process', + 'cinder-api': { + 'driver': 'system_service', 'args': { - 'grep': 'keystone-', - 'restart_cmd': 'sudo service apache2 restart', - 'terminate_cmd': 'sudo service apache2 stop', - 'start_cmd': 'sudo service apache2 start', + 'grep': 'cinder-api', + 'service_name': 'devstack@c-api', } }, - 'mysql': { - 'driver': 'process', + 'cinder-scheduler': { + 'driver': 'system_service', 'args': { - 'grep': 'mysqld', - 'restart_cmd': 'sudo service mysql restart', - 'terminate_cmd': 'sudo service mysql stop', - 'start_cmd': 'sudo service mysql start', - 'port': ['tcp', 3307], + 'grep': 'cinder-schedule', + 'service_name': 'devstack@c-sch', } }, - 'rabbitmq': { - 'driver': 'process', + 'cinder-volume': { + 'driver': 'system_service', 'args': { - 'grep': 'rabbitmq-server', - 'restart_cmd': 'sudo service rabbitmq-server restart', - 'terminate_cmd': 'sudo service rabbitmq-server stop', - 'start_cmd': 'sudo service rabbitmq-server start', - } - }, - 'nova-api': { - 'driver': 'screen', - 'args': { - 'grep': 'nova-api', - 'window_name': 'n-api', + 'grep': 'cinder-volume', + 'service_name': 'devstack@c-vol', } }, 'glance-api': { - 'driver': 'screen', + 'driver': 'system_service', 'args': { 'grep': 'glance-api', - 'window_name': 'g-api', + 'service_name': 'devstack@g-api', + } + }, + 'heat-api': { + 'driver': 'system_service', + 'args': { + 'grep': 'heat-api', + 'service_name': 'devstack@h-api', + } + }, + 'heat-engine': { + 'driver': 'system_service', + 'args': { + 'grep': 'heat-engine', + 'service_name': 'devstack@h-eng', + } + }, + 'keystone': { + 'driver': 'system_service', + 'args': { + 'grep': 'keystone', + 'service_name': 'devstack@keystone', + } + }, + 'mysql': { + 'driver': 'system_service', + 'args': { + 'grep': 'mysqld', + 'service_name': 'mariadb', + 'port': ['tcp', 3307], + } + }, + 'neutron-dhcp-agent': { + 'driver': 'system_service', + 'args': { + 'grep': 'neutron-dhcp-agent', + 'service_name': 'devstack@q-dhcp', + } + }, + 'neutron-l3-agent': { + 'driver': 'system_service', + 'args': { + 'grep': 'neutron-l3-agent', + 'service_name': 'devstack@q-l3', + } + }, + 'neutron-meta-agent': { + 'driver': 'system_service', + 'args': { + 'grep': 'neutron-meta-agent', + 'service_name': 'devstack@q-meta', + } + }, + 'neutron-openvswitch-agent': { + 'driver': 'system_service', + 'args': { + 'grep': 'neutron-openvswitch-agent', + 'service_name': 'devstack@q-agt', + } + }, + 'neutron-server': { + 'driver': 'system_service', + 'args': { + 'grep': 'neutron-server', + 'service_name': 'devstack@q-svc', + } + }, + 'nova-api': { + 'driver': 'system_service', + 'args': { + 'grep': 'nova-api', + 'service_name': 'devstack@n-api', } }, 'nova-compute': { - 'driver': 'screen', + 'driver': 'system_service', 'args': { 'grep': 'nova-compute', - 'window_name': 'n-cpu', + 'service_name': 'devstack@n-cpu', } }, 'nova-scheduler': { - 'driver': 'screen', + 'driver': 'system_service', 'args': { 'grep': 'nova-scheduler', - 'window_name': 'n-sch', + 'service_name': 'devstack@n-sch', } }, - 'ironic-api': { - 'driver': 'screen', + 'placement-api': { + 'driver': 'system_service', 'args': { - 'grep': 'ironic-api', - 'window_name': 'ir-api', + 'grep': 'placement', + 'service_name': 'devstack@placement-api', } }, - 'ironic-conductor': { - 'driver': 'screen', + 'rabbitmq': { + 'driver': 'system_service', 'args': { - 'grep': 'ironic-conductor', - 'window_name': 'ir-cond', + 'grep': 'rabbitmq_server', + 'service_name': 'rabbitmq-server', } }, } @@ -208,9 +204,7 @@ class DevStackManagement(cloud_management.CloudManagement, '$schema': 'http://json-schema.org/draft-04/schema#', 'properties': { 'address': {'type': 'string'}, - 'username': {'type': 'string'}, - 'password': {'type': 'string'}, - 'private_key_file': {'type': 'string'}, + 'auth': shared_schemas.AUTH_SCHEMA, 'slaves': { 'type': 'array', 'items': {'type': 'string'}, @@ -218,7 +212,7 @@ class DevStackManagement(cloud_management.CloudManagement, 'iface': {'type': 'string'}, 'serial': {'type': 'integer', 'minimum': 1}, }, - 'required': ['address', 'username'], + 'required': ['address', 'auth'], 'additionalProperties': False, } @@ -226,22 +220,21 @@ class DevStackManagement(cloud_management.CloudManagement, super(DevStackManagement, self).__init__() self.node_discover = self # supports discovering - self.address = cloud_management_params['address'] - self.username = cloud_management_params['username'] - self.private_key_file = cloud_management_params.get('private_key_file') - self.slaves = cloud_management_params.get('slaves', []) + address = cloud_management_params['address'] + auth = cloud_management_params['auth'] + slaves = cloud_management_params.get('slaves', []) self.iface = cloud_management_params.get('iface', 'eth0') - self.serial = cloud_management_params.get('serial') self.cloud_executor = executor.AnsibleRunner( - remote_user=self.username, private_key_file=self.private_key_file, - password=cloud_management_params.get('password'), - become=False, serial=self.serial) + remote_user=auth['username'], + private_key_file=auth.get('private_key_file'), + password=auth.get('password'), + serial=(cloud_management_params.get('serial'))) - self.hosts = [node_collection.Host(ip=self.address)] - if self.slaves: + self.hosts = [node_collection.Host(ip=address)] + if slaves: self.hosts.extend([node_collection.Host(ip=h) - for h in self.slaves]) + for h in slaves]) self.nodes = None def verify(self): diff --git a/os_faults/drivers/cloud/devstack_systemd.py b/os_faults/drivers/cloud/devstack_systemd.py deleted file mode 100644 index 3b4391a..0000000 --- a/os_faults/drivers/cloud/devstack_systemd.py +++ /dev/null @@ -1,128 +0,0 @@ -# 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 logging - -from os_faults.drivers.cloud import devstack - -LOG = logging.getLogger(__name__) - - -class DevStackSystemdManagement(devstack.DevStackManagement): - """Driver for modern DevStack based on Systemd. - - This driver requires DevStack installed with Systemd (USE_SCREEN=False). - Supports discovering of node MAC addresses. - - **Example configuration:** - - .. code-block:: yaml - - cloud_management: - driver: devstack_systemd - args: - address: 192.168.1.10 - username: ubuntu - password: ubuntu_pass - private_key_file: ~/.ssh/id_rsa_devstack_systemd - slaves: - - 192.168.1.11 - - 192.168.1.12 - iface: eth1 - - parameters: - - - **address** - ip address of any devstack node - - **username** - username for all nodes - - **password** - password for all nodes (optional) - - **private_key_file** - path to key file (optional) - - **slaves** - list of ips for additional nodes (optional) - - **iface** - network interface name to retrieve mac address (optional) - - **serial** - how many hosts Ansible should manage at a single time. - (optional) default: 10 - """ - - NAME = 'devstack_systemd' - DESCRIPTION = 'DevStack management driver using Systemd' - # NODE_CLS = DevStackNode - SERVICES = { - 'keystone': { - 'driver': 'systemd_service', - 'args': { - 'grep': 'keystone-uwsgi', - 'systemd_service': 'devstack@keystone', - } - }, - 'mysql': { - 'driver': 'systemd_service', - 'args': { - 'grep': 'mysqld', - 'systemd_service': 'mariadb', - 'port': ['tcp', 3307], - } - }, - 'rabbitmq': { - 'driver': 'systemd_service', - 'args': { - 'grep': 'rabbitmq_server', - 'systemd_service': 'rabbitmq-server', - } - }, - 'nova-api': { - 'driver': 'systemd_service', - 'args': { - 'grep': 'nova-api', - 'systemd_service': 'devstack@n-api', - } - }, - 'glance-api': { - 'driver': 'systemd_service', - 'args': { - 'grep': 'glance-api', - 'systemd_service': 'devstack@g-api', - } - }, - 'nova-compute': { - 'driver': 'systemd_service', - 'args': { - 'grep': 'nova-compute', - 'systemd_service': 'devstack@n-cpu', - } - }, - 'nova-scheduler': { - 'driver': 'systemd_service', - 'args': { - 'grep': 'nova-scheduler', - 'systemd_service': 'devstack@n-sch', - } - }, - } - SUPPORTED_NETWORKS = ['all-in-one'] - CONFIG_SCHEMA = { - 'type': 'object', - '$schema': 'http://json-schema.org/draft-04/schema#', - 'properties': { - 'address': {'type': 'string'}, - 'username': {'type': 'string'}, - 'password': {'type': 'string'}, - 'private_key_file': {'type': 'string'}, - 'slaves': { - 'type': 'array', - 'items': {'type': 'string'}, - }, - 'iface': {'type': 'string'}, - 'serial': {'type': 'integer', 'minimum': 1}, - }, - 'required': ['address', 'username'], - 'additionalProperties': False, - } diff --git a/os_faults/drivers/cloud/fuel.py b/os_faults/drivers/cloud/fuel.py deleted file mode 100644 index 224ecf3..0000000 --- a/os_faults/drivers/cloud/fuel.py +++ /dev/null @@ -1,459 +0,0 @@ -# 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 json -import logging - -from os_faults.ansible import executor -from os_faults.api import cloud_management -from os_faults.api import node_collection -from os_faults.api import node_discover - -LOG = logging.getLogger(__name__) - - -class FuelNodeCollection(node_collection.NodeCollection): - - def connect(self, network_name): - LOG.info("Connect network '%s' on nodes: %s", network_name, self) - task = {'fuel_network_mgmt': { - 'network_name': network_name, - 'operation': 'up', - }} - self.cloud_management.execute_on_cloud(self.hosts, task) - - def disconnect(self, network_name): - LOG.info("Disconnect network '%s' on nodes: %s", - network_name, self) - task = {'fuel_network_mgmt': { - 'network_name': network_name, - 'operation': 'down', - }} - self.cloud_management.execute_on_cloud(self.hosts, task) - - -class FuelManagement(cloud_management.CloudManagement, - node_discover.NodeDiscover): - """OpenStack Fuel driver. - - Cloud deployed by Fuel. Supports discovering of slave nodes. - - **Example configuration:** - - .. code-block:: yaml - - cloud_management: - driver: fuel - args: - address: 192.168.1.10 - username: root - private_key_file: ~/.ssh/id_rsa_fuel - slave_direct_ssh: True - - parameters: - - - **address** - ip address of fuel master node - - **username** - username for fuel master and slave nodes - - **private_key_file** - path to key file (optional) - - **slave_direct_ssh** - if *False* then fuel master is used as ssh proxy - (optional) - - **serial** - how many hosts Ansible should manage at a single time. - (optional) default: 10 - """ - - NAME = 'fuel' - DESCRIPTION = 'Fuel 9.x cloud management driver' - NODE_CLS = FuelNodeCollection - SERVICES = { - 'keystone': { - 'driver': 'linux_service', - 'args': { - 'grep': 'keystone', - 'linux_service': 'apache2', - } - }, - 'horizon': { - 'driver': 'linux_service', - 'args': { - 'grep': 'apache2', - 'linux_service': 'apache2', - } - }, - 'memcached': { - 'driver': 'linux_service', - 'args': { - 'grep': 'memcached', - 'linux_service': 'memcached', - } - }, - 'mysql': { - 'driver': 'pcs_service', - 'args': { - 'grep': 'mysqld', - 'pcs_service': 'p_mysqld', - 'port': ['tcp', 3307], - } - }, - 'rabbitmq': { - 'driver': 'pcs_service', - 'args': { - 'grep': 'rabbit tcp_listeners', - 'pcs_service': 'p_rabbitmq-server', - } - }, - 'glance-api': { - 'driver': 'linux_service', - 'args': { - 'grep': 'glance-api', - 'linux_service': 'glance-api', - } - }, - 'glance-glare': { - 'driver': 'linux_service', - 'args': { - 'grep': 'glance-glare', - 'linux_service': 'glance-glare', - } - }, - 'glance-registry': { - 'driver': 'linux_service', - 'args': { - 'grep': 'glance-registry', - 'linux_service': 'glance-registry', - } - }, - 'nova-api': { - 'driver': 'linux_service', - 'args': { - 'grep': 'nova-api', - 'linux_service': 'nova-api', - } - }, - 'nova-compute': { - 'driver': 'linux_service', - 'args': { - 'grep': 'nova-compute', - 'linux_service': 'nova-compute', - } - }, - 'nova-scheduler': { - 'driver': 'linux_service', - 'args': { - 'grep': 'nova-scheduler', - 'linux_service': 'nova-scheduler', - } - }, - 'nova-cert': { - 'driver': 'linux_service', - 'args': { - 'grep': 'nova-cert', - 'linux_service': 'nova-cert', - } - }, - 'nova-conductor': { - 'driver': 'linux_service', - 'args': { - 'grep': 'nova-conductor', - 'linux_service': 'nova-conductor', - } - }, - 'nova-consoleauth': { - 'driver': 'linux_service', - 'args': { - 'grep': 'nova-consoleauth', - 'linux_service': 'nova-consoleauth', - } - }, - 'nova-novncproxy': { - 'driver': 'linux_service', - 'args': { - 'grep': 'nova-novncproxy', - 'linux_service': 'nova-novncproxy', - } - }, - 'neutron-server': { - 'driver': 'linux_service', - 'args': { - 'grep': 'neutron-server', - 'linux_service': 'neutron-server', - } - }, - 'neutron-dhcp-agent': { - 'driver': 'pcs_service', - 'args': { - 'grep': 'neutron-dhcp-agent', - 'pcs_service': 'neutron-dhcp-agent', - } - }, - 'neutron-metadata-agent': { - 'driver': 'pcs_or_linux_service', - 'args': { - 'grep': 'neutron-metadata-agent', - 'pcs_service': 'neutron-metadata-agent', - 'linux_service': 'neutron-metadata-agent', - } - }, - 'neutron-openvswitch-agent': { - 'driver': 'pcs_or_linux_service', - 'args': { - 'grep': 'neutron-openvswitch-agent', - 'pcs_service': 'neutron-openvswitch-agent', - 'linux_service': 'neutron-openvswitch-agent', - } - }, - 'neutron-l3-agent': { - 'driver': 'pcs_or_linux_service', - 'args': { - 'grep': 'neutron-l3-agent', - 'pcs_service': 'neutron-l3-agent', - 'linux_service': 'neutron-l3-agent', - } - }, - 'heat-api': { - 'driver': 'linux_service', - 'args': { - 'grep': 'heat-api', - 'linux_service': 'heat-api', - } - }, - 'heat-engine': { - 'driver': 'pcs_service', - 'args': { - 'grep': 'heat-engine', - 'pcs_service': 'p_heat-engine', - } - }, - 'cinder-api': { - 'driver': 'linux_service', - 'args': { - 'grep': 'cinder-api', - 'linux_service': 'cinder-api', - } - }, - 'cinder-scheduler': { - 'driver': 'linux_service', - 'args': { - 'grep': 'cinder-scheduler', - 'linux_service': 'cinder-scheduler', - } - }, - 'cinder-volume': { - 'driver': 'linux_service', - 'args': { - 'grep': 'cinder-volume', - 'linux_service': 'cinder-volume', - } - }, - 'cinder-backup': { - 'driver': 'linux_service', - 'args': { - 'grep': 'cinder-backup', - 'linux_service': 'cinder-backup', - } - }, - 'ironic-api': { - 'driver': 'linux_service', - 'args': { - 'grep': 'ironic-api', - 'linux_service': 'ironic-api', - } - }, - 'ironic-conductor': { - 'driver': 'linux_service', - 'args': { - 'grep': 'ironic-conductor', - 'linux_service': 'ironic-conductor', - } - }, - 'swift-account': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-account', - 'linux_service': 'swift-account', - } - }, - 'swift-account-auditor': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-account-auditor', - 'linux_service': 'swift-account-auditor', - } - }, - 'swift-account-reaper': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-account-reaper', - 'linux_service': 'swift-account-reaper', - } - }, - 'swift-account-replicator': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-account-replicator', - 'linux_service': 'swift-account-replicator', - } - }, - 'swift-container': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-container', - 'linux_service': 'swift-container', - } - }, - 'swift-container-auditor': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-container-auditor', - 'linux_service': 'swift-container-auditor', - } - }, - 'swift-container-replicator': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-container-replicator', - 'linux_service': 'swift-container-replicator', - } - }, - 'swift-container-sync': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-container-sync', - 'linux_service': 'swift-container-sync', - } - }, - 'swift-container-updater': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-container-updater', - 'linux_service': 'swift-container-updater', - } - }, - 'swift-object': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-object', - 'linux_service': 'swift-object', - } - }, - 'swift-object-auditor': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-object-auditor', - 'linux_service': 'swift-object-auditor', - } - }, - 'swift-object-replicator': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-object-replicator', - 'linux_service': 'swift-object-replicator', - } - }, - 'swift-object-updater': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-object-updater', - 'linux_service': 'swift-object-updater', - } - }, - 'swift-proxy': { - 'driver': 'linux_service', - 'args': { - 'grep': 'swift-proxy', - 'linux_service': 'swift-proxy', - } - }, - } - SUPPORTED_NETWORKS = ['management', 'private', 'public', 'storage'] - CONFIG_SCHEMA = { - 'type': 'object', - '$schema': 'http://json-schema.org/draft-04/schema#', - 'properties': { - 'address': {'type': 'string'}, - 'username': {'type': 'string'}, - 'private_key_file': {'type': 'string'}, - 'slave_direct_ssh': {'type': 'boolean'}, - 'serial': {'type': 'integer', 'minimum': 1}, - }, - 'required': ['address', 'username'], - 'additionalProperties': False, - } - - def __init__(self, cloud_management_params): - super(FuelManagement, self).__init__() - self.node_discover = self # supports discovering - - self.master_node_address = cloud_management_params['address'] - self._master_host = node_collection.Host(ip=self.master_node_address) - self.username = cloud_management_params['username'] - self.private_key_file = cloud_management_params.get('private_key_file') - self.slave_direct_ssh = cloud_management_params.get( - 'slave_direct_ssh', False) - self.serial = cloud_management_params.get('serial') - - self.master_node_executor = executor.AnsibleRunner( - remote_user=self.username, private_key_file=self.private_key_file) - - jump_host = self.master_node_address - if self.slave_direct_ssh: - jump_host = None - - self.cloud_executor = executor.AnsibleRunner( - remote_user=self.username, private_key_file=self.private_key_file, - jump_host=jump_host, serial=self.serial) - - self.cached_cloud_hosts = list() - - def verify(self): - """Verify connection to the cloud.""" - nodes = self.get_nodes() - LOG.debug('Cloud nodes: %s', nodes) - - task = {'command': 'hostname'} - task_result = self.execute_on_cloud(nodes.hosts, task) - LOG.debug('Hostnames of cloud nodes: %s', - [r.payload['stdout'] for r in task_result]) - - LOG.info('Connected to cloud successfully!') - - def discover_hosts(self): - if not self.cached_cloud_hosts: - task = {'command': 'fuel node --json'} - result = self._execute_on_master_node(task) - for r in json.loads(result[0].payload['stdout']): - host = node_collection.Host(ip=r['ip'], mac=r['mac'], - fqdn=r['fqdn']) - self.cached_cloud_hosts.append(host) - - return self.cached_cloud_hosts - - def _execute_on_master_node(self, task): - """Execute task on Fuel master node. - - :param task: Ansible task - :return: Ansible execution result (list of records) - """ - return self.master_node_executor.execute([self._master_host], task) - - def execute_on_cloud(self, hosts, task, raise_on_error=True): - """Execute task on specified hosts within the cloud. - - :param hosts: List of host FQDNs - :param task: Ansible task - :param raise_on_error: throw exception in case of error - :return: Ansible execution result (list of records) - """ - if raise_on_error: - return self.cloud_executor.execute(hosts, task) - else: - return self.cloud_executor.execute(hosts, task, []) diff --git a/os_faults/drivers/cloud/universal.py b/os_faults/drivers/cloud/universal.py index c477a3a..06813a9 100644 --- a/os_faults/drivers/cloud/universal.py +++ b/os_faults/drivers/cloud/universal.py @@ -47,7 +47,6 @@ class UniversalCloudManagement(cloud_management.CloudManagement, auth: username: ubuntu private_key_file: devstack_key - become: true become_password: my_secret_password iface: eth1 serial: 10 @@ -68,7 +67,6 @@ class UniversalCloudManagement(cloud_management.CloudManagement, auth: username: developer private_key_file: cloud_key - become: true become_password: my_secret_password parameters: @@ -79,7 +77,6 @@ class UniversalCloudManagement(cloud_management.CloudManagement, - **username** - SSH username (optional) - **password** - SSH password (optional) - **private_key_file** - SSH key file (optional) - - **become** - True if privilege escalation is used (optional) - **become_password** - privilege escalation password (optional) - **jump** - SSH proxy parameters (optional): - **host** - SSH proxy host diff --git a/os_faults/drivers/nodes/node_list.py b/os_faults/drivers/nodes/node_list.py index c4f811b..7f63b59 100644 --- a/os_faults/drivers/nodes/node_list.py +++ b/os_faults/drivers/nodes/node_list.py @@ -22,9 +22,7 @@ AUTH_SCHEMA = { 'properties': { 'username': {'type': 'string'}, 'password': {'type': 'string'}, - 'sudo': {'type': 'boolean'}, 'private_key_file': {'type': 'string'}, - 'become': {'type': 'boolean'}, 'become_password': {'type': 'string'}, 'jump': { 'type': 'object', @@ -70,7 +68,6 @@ class NodeListDiscover(node_discover.NodeDiscover): - ip: 10.0.0.53 mac: aa:bb:cc:dd:ee:03 fqdn: node3.local - become: true become_password: my_secret_password node parameters: @@ -84,7 +81,6 @@ class NodeListDiscover(node_discover.NodeDiscover): - **username** - SSH username (optional) - **password** - SSH password (optional) - **private_key_file** - SSH key file (optional) - - **become** - True if privilege escalation is used (optional) - **become_password** - privilege escalation password (optional) - **jump** - SSH proxy parameters (optional): - **host** - SSH proxy host diff --git a/os_faults/drivers/services/linux.py b/os_faults/drivers/services/linux.py deleted file mode 100644 index 2952d51..0000000 --- a/os_faults/drivers/services/linux.py +++ /dev/null @@ -1,61 +0,0 @@ -# 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 os_faults.drivers.services import process - - -class LinuxService(process.ServiceAsProcess): - """Linux service (**deprecated**, use `system_service` instead) - - Service that is defined in init.d and can be controlled by `service` - CLI tool. - - **Example configuration:** - - .. code-block:: yaml - - services: - app: - driver: linux_service - args: - linux_service: app - grep: my_app - port: ['tcp', 4242] - - parameters: - - - **linux_service** - name of a service - - **grep** - regexp for grep to find process PID - - **port** - tuple with two values - protocol, port number (optional) - - """ - NAME = 'linux_service' - DESCRIPTION = 'Service in init.d' - CONFIG_SCHEMA = { - 'type': 'object', - 'properties': { - 'linux_service': {'type': 'string'}, - 'grep': {'type': 'string'}, - 'port': process.PORT_SCHEMA, - }, - 'required': ['grep', 'linux_service'], - 'additionalProperties': False, - } - - def __init__(self, *args, **kwargs): - super(LinuxService, self).__init__(*args, **kwargs) - self.linux_service = self.config['linux_service'] - - self.restart_cmd = 'service {} restart'.format(self.linux_service) - self.terminate_cmd = 'service {} stop'.format(self.linux_service) - self.start_cmd = 'service {} start'.format(self.linux_service) diff --git a/os_faults/drivers/services/pcs.py b/os_faults/drivers/services/pcs.py deleted file mode 100644 index beec348..0000000 --- a/os_faults/drivers/services/pcs.py +++ /dev/null @@ -1,135 +0,0 @@ -# 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 logging - -from os_faults.drivers.services import process - -LOG = logging.getLogger(__name__) - - -class PcsService(process.ServiceAsProcess): - """Service as a resource in Pacemaker - - Service that can be controlled by `pcs resource` CLI tool. - - **Example configuration:** - - .. code-block:: yaml - - services: - app: - driver: pcs_service - args: - pcs_service: app - grep: my_app - port: ['tcp', 4242] - - parameters: - - - **pcs_service** - name of a service - - **grep** - regexp for grep to find process PID - - **port** - tuple with two values - protocol, port number (optional) - """ - - NAME = 'pcs_service' - DESCRIPTION = 'Service in pacemaker' - CONFIG_SCHEMA = { - 'type': 'object', - 'properties': { - 'pcs_service': {'type': 'string'}, - 'grep': {'type': 'string'}, - 'port': process.PORT_SCHEMA, - }, - 'required': ['grep', 'pcs_service'], - 'additionalProperties': False, - } - - def __init__(self, *args, **kwargs): - super(PcsService, self).__init__(*args, **kwargs) - self.pcs_service = self.config['pcs_service'] - - self.restart_cmd = 'pcs resource restart {} $(hostname)'.format( - self.pcs_service) - self.terminate_cmd = 'pcs resource ban {} $(hostname)'.format( - self.pcs_service) - self.start_cmd = 'pcs resource clear {} $(hostname)'.format( - self.pcs_service) - - -class PcsOrLinuxService(process.ServiceAsProcess): - """Service as a resource in Pacemaker or Linux service - - Service that can be controlled by `pcs resource` CLI tool or - linux `service` tool. This is a hybrid driver that tries to find - service in Pacemaker and uses linux `service` if it is not found - there. - - **Example configuration:** - - .. code-block:: yaml - - services: - app: - driver: pcs_or_linux_service - args: - pcs_service: p_app - linux_service: app - grep: my_app - port: ['tcp', 4242] - - parameters: - - - **pcs_service** - name of a service in Pacemaker - - **linux_service** - name of a service in init.d - - **grep** - regexp for grep to find process PID - - **port** - tuple with two values - protocol, port number (optional) - """ - - NAME = 'pcs_or_linux_service' - DESCRIPTION = 'Service in pacemaker or init.d' - CONFIG_SCHEMA = { - 'type': 'object', - 'properties': { - 'pcs_service': {'type': 'string'}, - 'linux_service': {'type': 'string'}, - 'grep': {'type': 'string'}, - 'port': process.PORT_SCHEMA, - }, - 'required': ['grep', 'pcs_service', 'linux_service'], - 'additionalProperties': False, - } - - def __init__(self, *args, **kwargs): - super(PcsOrLinuxService, self).__init__(*args, **kwargs) - self.pcs_service = self.config.get('pcs_service') - self.linux_service = self.config.get('linux_service') - - self.restart_cmd = ( - 'if pcs resource show {pcs_service}; ' - 'then pcs resource restart {pcs_service} $(hostname); ' - 'else service {linux_service} restart; fi').format( - linux_service=self.linux_service, - pcs_service=self.pcs_service) - self.terminate_cmd = ( - 'if pcs resource show {pcs_service}; ' - 'then pcs resource ban {pcs_service} $(hostname); ' - 'else service {linux_service} stop; fi').format( - linux_service=self.linux_service, - pcs_service=self.pcs_service) - self.start_cmd = ( - 'if pcs resource show {pcs_service}; ' - 'then pcs resource clear {pcs_service} $(hostname); ' - 'else service {linux_service} start; fi').format( - linux_service=self.linux_service, - pcs_service=self.pcs_service) diff --git a/os_faults/drivers/services/process.py b/os_faults/drivers/services/process.py index d253cde..3afcf66 100644 --- a/os_faults/drivers/services/process.py +++ b/os_faults/drivers/services/process.py @@ -124,19 +124,39 @@ class ServiceAsProcess(service.Service): self._run_task(nodes, {'shell': self.start_cmd}, 'Start') def kill(self, nodes=None): - task = {'kill': {'grep': self.grep, 'sig': signal.SIGKILL}} + task = { + 'kill': { + 'grep': self.grep, 'sig': signal.SIGKILL + }, + 'become': 'yes', + } self._run_task(nodes, task, 'Kill') def freeze(self, nodes=None, sec=None): if sec: - task = {'freeze': {'grep': self.grep, 'sec': sec}} + task = { + 'freeze': { + 'grep': self.grep, 'sec': sec + }, + 'become': 'yes', + } else: - task = {'kill': {'grep': self.grep, 'sig': signal.SIGSTOP}} + task = { + 'kill': { + 'grep': self.grep, 'sig': signal.SIGSTOP + }, + 'become': 'yes', + } message = "Freeze %s" % (('for %s sec ' % sec) if sec else '') self._run_task(nodes, task, message) def unfreeze(self, nodes=None): - task = {'kill': {'grep': self.grep, 'sig': signal.SIGCONT}} + task = { + 'kill': { + 'grep': self.grep, 'sig': signal.SIGCONT + }, + 'become': 'yes', + } self._run_task(nodes, task, 'Unfreeze') @utils.require_variables('port') @@ -147,7 +167,8 @@ class ServiceAsProcess(service.Service): 'iptables': { 'protocol': self.port[0], 'port': self.port[1], 'action': 'unblock', 'service': self.service_name - } + }, + 'become': 'yes', } self._run_task(nodes, task, message) @@ -159,6 +180,7 @@ class ServiceAsProcess(service.Service): 'iptables': { 'protocol': self.port[0], 'port': self.port[1], 'action': 'block', 'service': self.service_name - } + }, + 'become': 'yes', } self._run_task(nodes, task, message) diff --git a/os_faults/drivers/services/system.py b/os_faults/drivers/services/system.py index 6b537eb..6641456 100644 --- a/os_faults/drivers/services/system.py +++ b/os_faults/drivers/services/system.py @@ -63,6 +63,7 @@ class SystemService(process.ServiceAsProcess): 'service': { 'name': self.service_name, 'state': 'started' }, + 'become': 'yes', } self._run_task(nodes, task, 'Start') @@ -72,6 +73,7 @@ class SystemService(process.ServiceAsProcess): 'name': self.service_name, 'state': 'stopped', 'pattern': self.grep, }, + 'become': 'yes', } self._run_task(nodes, task, 'Terminate') @@ -80,5 +82,6 @@ class SystemService(process.ServiceAsProcess): 'service': { 'name': self.service_name, 'state': 'restarted' }, + 'become': 'yes', } self._run_task(nodes, task, 'Restart') diff --git a/os_faults/drivers/services/systemd.py b/os_faults/drivers/services/systemd.py deleted file mode 100644 index a660e3a..0000000 --- a/os_faults/drivers/services/systemd.py +++ /dev/null @@ -1,66 +0,0 @@ -# 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 os_faults.drivers.services import process - - -class SystemdService(process.ServiceAsProcess): - """Systemd service (**deprecated**, use `system_service` instead). - - Service as Systemd unit and can be controlled by `systemctl` CLI tool. - - **Example configuration:** - - .. code-block:: yaml - - services: - app: - driver: systemd_service - args: - systemd_service: app - grep: my_app - port: ['tcp', 4242] - - parameters: - - - **systemd_service** - name of a service in systemd - - **grep** - regexp for grep to find process PID - - **port** - tuple with two values - protocol, port number (optional) - - """ - NAME = 'systemd_service' - DESCRIPTION = 'Service in Systemd' - CONFIG_SCHEMA = { - 'type': 'object', - 'properties': { - 'systemd_service': {'type': 'string'}, - 'grep': {'type': 'string'}, - 'port': process.PORT_SCHEMA, - 'start_cmd': {'type': 'string'}, - 'terminate_cmd': {'type': 'string'}, - 'restart_cmd': {'type': 'string'}, - }, - 'required': ['grep', 'systemd_service'], - 'additionalProperties': False, - } - - def __init__(self, *args, **kwargs): - super(SystemdService, self).__init__(*args, **kwargs) - self.systemd_service = self.config['systemd_service'] - - self.restart_cmd = 'sudo systemctl restart {}'.format( - self.systemd_service) - self.terminate_cmd = 'sudo systemctl stop {}'.format( - self.systemd_service) - self.start_cmd = 'sudo systemctl start {}'.format( - self.systemd_service) diff --git a/os_faults/drivers/shared_schemas.py b/os_faults/drivers/shared_schemas.py index f6594c1..20576a8 100644 --- a/os_faults/drivers/shared_schemas.py +++ b/os_faults/drivers/shared_schemas.py @@ -27,9 +27,7 @@ AUTH_SCHEMA = { 'properties': { 'username': {'type': 'string'}, 'password': {'type': 'string'}, - 'sudo': {'type': 'boolean'}, # deprecated, use `become` 'private_key_file': {'type': 'string'}, - 'become': {'type': 'boolean'}, 'become_password': {'type': 'string'}, 'jump': { 'type': 'object', diff --git a/os_faults/tests/unit/drivers/cloud/test_devstack.py b/os_faults/tests/unit/drivers/cloud/test_devstack.py index fa5fdc0..246f3c3 100644 --- a/os_faults/tests/unit/drivers/cloud/test_devstack.py +++ b/os_faults/tests/unit/drivers/cloud/test_devstack.py @@ -12,7 +12,6 @@ # limitations under the License. import copy - import ddt import mock @@ -47,7 +46,7 @@ class DevStackManagementTestCase(test.TestCase): def setUp(self): super(DevStackManagementTestCase, self).setUp() - self.conf = {'address': '10.0.0.2', 'username': 'root'} + self.conf = {'address': '10.0.0.2', 'auth': {'username': 'root'}} self.host = node_collection.Host('10.0.0.2') self.discoverd_host = node_collection.Host(ip='10.0.0.2', mac='09:7b:74:90:63:c1', @@ -206,7 +205,7 @@ class DevStackServiceTestCase(test.TestCase): def setUp(self): super(DevStackServiceTestCase, self).setUp() - self.conf = {'address': '10.0.0.2', 'username': 'root'} + self.conf = {'address': '10.0.0.2', 'auth': {'username': 'stack'}} self.host = node_collection.Host('10.0.0.2') self.discoverd_host = node_collection.Host(ip='10.0.0.2', mac='09:7b:74:90:63:c1', @@ -223,7 +222,8 @@ class DevStackServiceTestCase(test.TestCase): [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')] ] - devstack_management = devstack.DevStackManagement(self.conf) + devstack_management = devstack.DevStackManagement( + self.conf) service = devstack_management.get_service(service_name) service.restart() @@ -234,7 +234,6 @@ class DevStackServiceTestCase(test.TestCase): mock.call( [self.host], {'command': 'cat /sys/class/net/eth0/address'}), mock.call([self.discoverd_host], {'command': cmd}, []), - mock.call([self.discoverd_host], {'shell': service.restart_cmd}) ]) @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) @@ -248,7 +247,8 @@ class DevStackServiceTestCase(test.TestCase): [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')] ] - devstack_management = devstack.DevStackManagement(self.conf) + devstack_management = devstack.DevStackManagement( + self.conf) service = devstack_management.get_service(service_name) service.terminate() @@ -259,7 +259,6 @@ class DevStackServiceTestCase(test.TestCase): mock.call( [self.host], {'command': 'cat /sys/class/net/eth0/address'}), mock.call([self.discoverd_host], {'command': cmd}, []), - mock.call([self.discoverd_host], {'shell': service.terminate_cmd}) ]) @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) @@ -273,7 +272,8 @@ class DevStackServiceTestCase(test.TestCase): [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')] ] - devstack_management = devstack.DevStackManagement(self.conf) + devstack_management = devstack.DevStackManagement( + self.conf) service = devstack_management.get_service(service_name) service.start() @@ -284,5 +284,4 @@ class DevStackServiceTestCase(test.TestCase): mock.call( [self.host], {'command': 'cat /sys/class/net/eth0/address'}), mock.call([self.discoverd_host], {'command': cmd}, []), - mock.call([self.discoverd_host], {'shell': service.start_cmd}) ]) diff --git a/os_faults/tests/unit/drivers/cloud/test_devstack_systemd.py b/os_faults/tests/unit/drivers/cloud/test_devstack_systemd.py deleted file mode 100644 index 5700d41..0000000 --- a/os_faults/tests/unit/drivers/cloud/test_devstack_systemd.py +++ /dev/null @@ -1,119 +0,0 @@ -# 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 ddt -import mock - -from os_faults.api import node_collection -from os_faults.drivers.cloud import devstack_systemd -from os_faults.tests.unit.drivers.cloud import test_devstack -from os_faults.tests.unit import fakes -from os_faults.tests.unit import test - - -@ddt.ddt -class DevStackSystemdManagementTestCase( - test_devstack.DevStackManagementTestCase): - - def setUp(self): - super(DevStackSystemdManagementTestCase, self).setUp() - - -@ddt.ddt -class DevStackSystemdServiceTestCase(test.TestCase): - - def setUp(self): - super(DevStackSystemdServiceTestCase, self).setUp() - self.conf = {'address': '10.0.0.2', 'username': 'root'} - self.host = node_collection.Host('10.0.0.2') - self.discoverd_host = node_collection.Host(ip='10.0.0.2', - mac='09:7b:74:90:63:c1', - fqdn='') - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*devstack_systemd.DevStackSystemdManagement.SERVICES.keys()) - def test_restart(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [fakes.FakeAnsibleResult(payload={'stdout': '09:7b:74:90:63:c1'}, - host='10.0.0.2')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')] - ] - - devstack_management = devstack_systemd.DevStackSystemdManagement( - self.conf) - - service = devstack_management.get_service(service_name) - service.restart() - - cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call( - [self.host], {'command': 'cat /sys/class/net/eth0/address'}), - mock.call([self.discoverd_host], {'command': cmd}, []), - mock.call([self.discoverd_host], {'shell': service.restart_cmd}) - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*devstack_systemd.DevStackSystemdManagement.SERVICES.keys()) - def test_terminate(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [fakes.FakeAnsibleResult(payload={'stdout': '09:7b:74:90:63:c1'}, - host='10.0.0.2')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')] - ] - - devstack_management = devstack_systemd.DevStackSystemdManagement( - self.conf) - - service = devstack_management.get_service(service_name) - service.terminate() - - cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call( - [self.host], {'command': 'cat /sys/class/net/eth0/address'}), - mock.call([self.discoverd_host], {'command': cmd}, []), - mock.call([self.discoverd_host], {'shell': service.terminate_cmd}) - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*devstack_systemd.DevStackSystemdManagement.SERVICES.keys()) - def test_start(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [fakes.FakeAnsibleResult(payload={'stdout': '09:7b:74:90:63:c1'}, - host='10.0.0.2')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, host='10.0.0.2')] - ] - - devstack_management = devstack_systemd.DevStackSystemdManagement( - self.conf) - - service = devstack_management.get_service(service_name) - service.start() - - cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call( - [self.host], {'command': 'cat /sys/class/net/eth0/address'}), - mock.call([self.discoverd_host], {'command': cmd}, []), - mock.call([self.discoverd_host], {'shell': service.start_cmd}) - ]) diff --git a/os_faults/tests/unit/drivers/cloud/test_fuel_management.py b/os_faults/tests/unit/drivers/cloud/test_fuel_management.py deleted file mode 100644 index 977dc5e..0000000 --- a/os_faults/tests/unit/drivers/cloud/test_fuel_management.py +++ /dev/null @@ -1,185 +0,0 @@ -# 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 ddt -import mock - -from os_faults.ansible import executor -from os_faults.api import error -from os_faults.api import node_collection -from os_faults.drivers.cloud import fuel -from os_faults.tests.unit import fakes -from os_faults.tests.unit import test - - -@ddt.ddt -class FuelManagementTestCase(test.TestCase): - - def setUp(self): - super(FuelManagementTestCase, self).setUp() - self.conf = { - 'address': 'fuel.local', - 'username': 'root', - } - - self.fake_ansible_result = fakes.FakeAnsibleResult( - payload={ - 'stdout': '[{"ip": "10.0.0.2", "mac": "02", "fqdn": "node-2"},' - ' {"ip": "10.0.0.3", "mac": "03", "fqdn": "node-3"}]' - }) - - self.master_host = node_collection.Host('fuel.local') - self.hosts = [ - node_collection.Host(ip='10.0.0.2', mac='02', fqdn='node-2'), - node_collection.Host(ip='10.0.0.3', mac='03', fqdn='node-3'), - ] - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(( - dict(address='fuel.local', username='root'), - (mock.call(private_key_file=None, remote_user='root'), - mock.call(private_key_file=None, remote_user='root', - jump_host='fuel.local', serial=None)) - ), ( - dict(address='fuel.local', username='root', slave_direct_ssh=True, - serial=42), - (mock.call(private_key_file=None, remote_user='root'), - mock.call(private_key_file=None, remote_user='root', - jump_host=None, serial=42)) - )) - @ddt.unpack - def test_init(self, config, expected_runner_calls, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - - fuel_managment = fuel.FuelManagement(config) - - mock_ansible_runner.assert_has_calls(expected_runner_calls) - self.assertIs(fuel_managment.master_node_executor, ansible_runner_inst) - self.assertIs(fuel_managment.cloud_executor, ansible_runner_inst) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_verify(self, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}), - fakes.FakeAnsibleResult(payload={'stdout': ''})], - ] - fuel_managment = fuel.FuelManagement(self.conf) - fuel_managment.verify() - - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': 'hostname'}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_get_nodes(self, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [[self.fake_ansible_result]] - fuel_managment = fuel.FuelManagement(self.conf) - nodes = fuel_managment.get_nodes() - - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - ]) - - self.assertEqual(nodes.hosts, self.hosts) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_get_nodes_from_discover_driver(self, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - hosts = [ - node_collection.Host(ip='10.0.2.2', mac='09:7b:74:90:63:c2', - fqdn='mynode1.local'), - node_collection.Host(ip='10.0.2.3', mac='09:7b:74:90:63:c3', - fqdn='mynode2.local'), - ] - node_discover_driver = mock.Mock() - node_discover_driver.discover_hosts.return_value = hosts - fuel_managment = fuel.FuelManagement(self.conf) - fuel_managment.set_node_discover(node_discover_driver) - nodes = fuel_managment.get_nodes() - - self.assertFalse(ansible_runner_inst.execute.called) - self.assertEqual(hosts, nodes.hosts) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_execute_on_cloud(self, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}), - fakes.FakeAnsibleResult(payload={'stdout': ''})] - ] - fuel_managment = fuel.FuelManagement(self.conf) - nodes = fuel_managment.get_nodes() - result = fuel_managment.execute_on_cloud( - nodes.hosts, {'command': 'mycmd'}, raise_on_error=False) - - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': 'mycmd'}, []), - ]) - - self.assertEqual(result, - [fakes.FakeAnsibleResult(payload={'stdout': ''}), - fakes.FakeAnsibleResult(payload={'stdout': ''})]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_get_nodes_fqdns(self, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [[self.fake_ansible_result]] - fuel_managment = fuel.FuelManagement(self.conf) - nodes = fuel_managment.get_nodes(fqdns=['node-3']) - - hosts = [ - node_collection.Host(ip='10.0.0.3', mac='03', fqdn='node-3'), - ] - self.assertEqual(nodes.hosts, hosts) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_get_service_nodes(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - status=executor.STATUS_FAILED, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - - nodes = service.get_nodes() - cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': cmd}, []), - ]) - - self.assertEqual(nodes.hosts, [self.hosts[1]]) - - def test_get_unknown_service(self): - fuel_managment = fuel.FuelManagement(self.conf) - self.assertRaises(error.ServiceError, - fuel_managment.get_service, 'unknown') - - def test_validate_services(self): - fuel_managment = fuel.FuelManagement(self.conf) - fuel_managment.validate_services() diff --git a/os_faults/tests/unit/drivers/cloud/test_fuel_node_collection.py b/os_faults/tests/unit/drivers/cloud/test_fuel_node_collection.py deleted file mode 100644 index 337f188..0000000 --- a/os_faults/tests/unit/drivers/cloud/test_fuel_node_collection.py +++ /dev/null @@ -1,53 +0,0 @@ -# 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 copy - -import mock - -from os_faults.api import node_collection -from os_faults.drivers.cloud import fuel -from os_faults.tests.unit import test - - -class FuelNodeCollectionTestCase(test.TestCase): - - def setUp(self): - super(FuelNodeCollectionTestCase, self).setUp() - self.mock_cloud_management = mock.Mock(spec=fuel.FuelManagement) - self.hosts = [ - node_collection.Host(ip='10.0.0.2', mac='09:7b:74:90:63:c1', - fqdn='node1.com'), - node_collection.Host(ip='10.0.0.3', mac='09:7b:74:90:63:c2', - fqdn='node2.com'), - node_collection.Host(ip='10.0.0.4', mac='09:7b:74:90:63:c3', - fqdn='node3.com'), - node_collection.Host(ip='10.0.0.5', mac='09:7b:74:90:63:c4', - fqdn='node4.com'), - ] - - self.node_collection = fuel.FuelNodeCollection( - cloud_management=self.mock_cloud_management, - hosts=copy.deepcopy(self.hosts)) - - def test_connect(self): - self.node_collection.connect(network_name='storage') - self.mock_cloud_management.execute_on_cloud.assert_called_once_with( - self.hosts, {'fuel_network_mgmt': {'operation': 'up', - 'network_name': 'storage'}}) - - def test_disconnect(self): - self.node_collection.disconnect(network_name='storage') - self.mock_cloud_management.execute_on_cloud.assert_called_once_with( - self.hosts, {'fuel_network_mgmt': {'operation': 'down', - 'network_name': 'storage'}}) diff --git a/os_faults/tests/unit/drivers/cloud/test_fuel_service.py b/os_faults/tests/unit/drivers/cloud/test_fuel_service.py deleted file mode 100644 index 3d45423..0000000 --- a/os_faults/tests/unit/drivers/cloud/test_fuel_service.py +++ /dev/null @@ -1,338 +0,0 @@ -# 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 ddt -import mock - -from os_faults.ansible import executor -from os_faults.api import error -from os_faults.api import node_collection -from os_faults.drivers.cloud import fuel -from os_faults.tests.unit import fakes -from os_faults.tests.unit import test - - -@ddt.ddt -class FuelServiceTestCase(test.TestCase): - - def setUp(self): - super(FuelServiceTestCase, self).setUp() - self.conf = {'address': 'fuel.local', 'username': 'root'} - self.fake_ansible_result = fakes.FakeAnsibleResult( - payload={ - 'stdout': '[{"ip": "10.0.0.2", "mac": "02", "fqdn": "node-2"},' - ' {"ip": "10.0.0.3", "mac": "03", "fqdn": "node-3"}]' - }) - self.master_host = node_collection.Host('fuel.local') - self.hosts = [ - node_collection.Host(ip='10.0.0.2', mac='02', fqdn='node-2'), - node_collection.Host(ip='10.0.0.3', mac='03', fqdn='node-3'), - ] - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_kill(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.kill() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, {'kill': {'grep': service.grep, 'sig': 9}}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_freeze(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.freeze() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, {'kill': {'grep': service.grep, 'sig': 19}}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_freeze_sec(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - delay_sec = 10 - service.freeze(nodes=None, sec=delay_sec) - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, {'freeze': {'grep': service.grep, - 'sec': delay_sec}}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_unfreeze(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.unfreeze() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, {'kill': {'grep': service.grep, 'sig': 18}}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data('mysql') - def test_unplug(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.unplug() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, - {'iptables': {'protocol': service.port[0], - 'port': service.port[1], - 'action': 'block', - 'service': service.service_name}}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data('mysql') - def test_plug(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.plug() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, - {'iptables': {'protocol': service.port[0], - 'port': service.port[1], - 'action': 'unblock', - 'service': service.service_name}}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_restart(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.restart() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, {'shell': service.restart_cmd}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_terminate(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.terminate() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, {'shell': service.terminate_cmd}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @ddt.data(*fuel.FuelManagement.SERVICES.keys()) - def test_start(self, service_name, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2'), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3')] - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service(service_name) - service.start() - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - mock.call(self.hosts, {'shell': service.start_cmd}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_run_node_collection_empty(self, mock_ansible_runner): - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [self.fake_ansible_result], - [fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.2', - status=executor.STATUS_FAILED), - fakes.FakeAnsibleResult(payload={'stdout': ''}, - host='10.0.0.3', - status=executor.STATUS_FAILED)], - ] - - fuel_managment = fuel.FuelManagement(self.conf) - - service = fuel_managment.get_service('keystone') - exception = self.assertRaises(error.ServiceError, service.restart) - self.assertEqual('Service keystone is not found on any nodes', - str(exception)) - - get_nodes_cmd = 'bash -c "ps ax | grep -v grep | grep \'{}\'"'.format( - service.grep) - ansible_runner_inst.execute.assert_has_calls([ - mock.call([self.master_host], {'command': 'fuel node --json'}), - mock.call(self.hosts, {'command': get_nodes_cmd}, []), - ]) diff --git a/os_faults/tests/unit/drivers/cloud/test_tcpcloud.py b/os_faults/tests/unit/drivers/cloud/test_tcpcloud.py index f95c721..049fc97 100644 --- a/os_faults/tests/unit/drivers/cloud/test_tcpcloud.py +++ b/os_faults/tests/unit/drivers/cloud/test_tcpcloud.py @@ -261,10 +261,10 @@ class TCPCloudManagementTestCase(test.TestCase): @ddt.ddt -class TcpServiceTestCase(test.TestCase): +class TCPCloudServiceTestCase(test.TestCase): def setUp(self): - super(TcpServiceTestCase, self).setUp() + super(TCPCloudServiceTestCase, self).setUp() self.fake_ansible_result = fakes.FakeAnsibleResult( payload={ 'stdout': 'cmp01.mk20.local:\n' diff --git a/os_faults/tests/unit/test_os_faults.py b/os_faults/tests/unit/test_os_faults.py index bc85e0f..902197f 100644 --- a/os_faults/tests/unit/test_os_faults.py +++ b/os_faults/tests/unit/test_os_faults.py @@ -10,11 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. -import os - import jsonschema import mock -import yaml import os_faults from os_faults.ansible import executor @@ -23,10 +20,7 @@ from os_faults.api import error from os_faults.api import node_collection from os_faults.api import service from os_faults.drivers.cloud import devstack -from os_faults.drivers.cloud import devstack_systemd -from os_faults.drivers.cloud import fuel -from os_faults.drivers.nodes import node_list -from os_faults.drivers.power import ipmi +from os_faults.drivers.cloud import universal from os_faults.drivers.power import libvirt from os_faults.tests.unit import test @@ -37,11 +31,13 @@ class OSFaultsTestCase(test.TestCase): super(OSFaultsTestCase, self).setUp() self.cloud_config = { 'cloud_management': { - 'driver': 'fuel', + 'driver': 'universal', 'args': { 'address': '10.30.00.5', - 'username': 'root', - 'private_key_file': '/my/path/pk.key', + 'auth': { + 'username': 'root', + 'private_key_file': '/my/path/pk.key', + }, } }, 'power_management': { @@ -58,29 +54,16 @@ class OSFaultsTestCase(test.TestCase): 'driver': 'devstack', 'args': { 'address': 'devstack.local', - 'username': 'developer', - 'private_key_file': '/my/path/pk.key', + 'auth': { + 'username': 'developer', + 'private_key_file': '/my/path/pk.key', + }, } } } destructor = os_faults.connect(cloud_config) self.assertIsInstance(destructor, devstack.DevStackManagement) - def test_connect_devstack_systemd(self): - cloud_config = { - 'cloud_management': { - 'driver': 'devstack_systemd', - 'args': { - 'address': 'devstack.local', - 'username': 'developer', - 'private_key_file': '/my/path/pk.key', - } - } - } - destructor = os_faults.connect(cloud_config) - self.assertIsInstance(destructor, - devstack_systemd.DevStackSystemdManagement) - def test_config_with_services(self): self.cloud_config['services'] = { 'app': { @@ -125,64 +108,11 @@ class OSFaultsTestCase(test.TestCase): def test_connect_fuel_with_libvirt(self): destructor = os_faults.connect(self.cloud_config) - self.assertIsInstance(destructor, fuel.FuelManagement) - self.assertIsInstance(destructor.node_discover, fuel.FuelManagement) + self.assertIsInstance(destructor, universal.UniversalCloudManagement) self.assertEqual(1, len(destructor.power_manager.power_drivers)) self.assertIsInstance(destructor.power_manager.power_drivers[0], libvirt.LibvirtDriver) - def test_connect_fuel_with_ipmi_libvirt_and_node_list(self): - cloud_config = { - 'node_discover': { - 'driver': 'node_list', - 'args': [ - { - 'ip': '10.0.0.11', - 'mac': '01:ab:cd:01:ab:cd', - 'fqdn': 'node-1' - }, { - 'ip': '10.0.0.12', - 'mac': '02:ab:cd:02:ab:cd', - 'fqdn': 'node-2'}, - ] - }, - 'cloud_management': { - 'driver': 'fuel', - 'args': { - 'address': '10.30.00.5', - 'username': 'root', - }, - }, - 'power_managements': [ - { - 'driver': 'ipmi', - 'args': { - 'mac_to_bmc': { - '00:00:00:00:00:00': { - 'address': '55.55.55.55', - 'username': 'foo', - 'password': 'bar', - } - } - } - }, { - 'driver': 'libvirt', - 'args': { - 'connection_uri': "qemu+ssh://user@10.30.20.21/system" - } - } - ] - } - destructor = os_faults.connect(cloud_config) - self.assertIsInstance(destructor, fuel.FuelManagement) - self.assertIsInstance(destructor.node_discover, - node_list.NodeListDiscover) - self.assertEqual(2, len(destructor.power_manager.power_drivers)) - self.assertIsInstance(destructor.power_manager.power_drivers[0], - ipmi.IPMIDriver) - self.assertIsInstance(destructor.power_manager.power_drivers[1], - libvirt.LibvirtDriver) - def test_connect_driver_not_found(self): cloud_config = { 'cloud_management': { @@ -198,30 +128,6 @@ class OSFaultsTestCase(test.TestCase): self.assertRaises( jsonschema.ValidationError, os_faults.connect, cloud_config) - @mock.patch('os.path.exists', return_value=True) - def test_connect_with_config_file(self, mock_os_path_exists): - mock_os_faults_open = mock.mock_open( - read_data=yaml.dump(self.cloud_config)) - with mock.patch('os_faults.open', mock_os_faults_open, create=True): - destructor = os_faults.connect() - self.assertIsInstance(destructor, fuel.FuelManagement) - self.assertEqual(1, len(destructor.power_manager.power_drivers)) - self.assertIsInstance(destructor.power_manager.power_drivers[0], - libvirt.LibvirtDriver) - - @mock.patch.dict(os.environ, {'OS_FAULTS_CONFIG': '/my/conf.yaml'}) - @mock.patch('os.path.exists', return_value=True) - def test_connect_with_env_config(self, mock_os_path_exists): - mock_os_faults_open = mock.mock_open( - read_data=yaml.dump(self.cloud_config)) - with mock.patch('os_faults.open', mock_os_faults_open, create=True): - destructor = os_faults.connect() - self.assertIsInstance(destructor, fuel.FuelManagement) - self.assertEqual(1, len(destructor.power_manager.power_drivers)) - self.assertIsInstance(destructor.power_manager.power_drivers[0], - libvirt.LibvirtDriver) - mock_os_faults_open.assert_called_once_with('/my/conf.yaml') - @mock.patch('os.path.exists', return_value=False) def test_connect_no_config_files(self, mock_os_path_exists): self.assertRaises(error.OSFError, os_faults.connect)