Remove old drivers

Remove Fuel, screen-based DevStack, Pacemaker and Linux service drivers.
Rename devstack_systemd into devstack.
Use common schema for auth parameters.

Change-Id: I38b5f82282b72e969fc08e0948109939c95cf948
This commit is contained in:
Ilya Shakhat 2018-11-26 18:48:08 +04:00
parent b2ca946296
commit 1c29ed3182
28 changed files with 212 additions and 1843 deletions

View File

@ -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`

View File

@ -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]

View File

@ -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
-----------------

View File

@ -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
========

View File

@ -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

View File

@ -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

View File

@ -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`

View File

@ -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.

View File

@ -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

View File

@ -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()))

View File

@ -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):

View File

@ -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,
}

View File

@ -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, [])

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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')

View File

@ -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)

View File

@ -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',

View File

@ -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})
])

View File

@ -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})
])

View File

@ -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()

View File

@ -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'}})

View File

@ -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}, []),
])

View File

@ -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'

View File

@ -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)