Merge "Remove old drivers"
This commit is contained in:
commit
62b96dd2a4
@ -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`
|
||||
|
@ -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]
|
||||
|
||||
|
||||
|
@ -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
|
||||
-----------------
|
||||
|
@ -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
|
||||
========
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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()))
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
}
|
@ -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, [])
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
@ -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)
|
@ -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)
|
||||
|
@ -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')
|
||||
|
@ -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)
|
@ -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',
|
||||
|
@ -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})
|
||||
])
|
||||
|
@ -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})
|
||||
])
|
@ -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()
|
@ -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'}})
|
@ -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}, []),
|
||||
])
|
@ -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'
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user