Allow usage of multiple power drivers at once
* Deprecated power_management parameter. * Added power_managements to configuration. * Removed power_management variable from NodeCollection and Service. * Added PowerManager class that controls running of power drivers. * Updated docs. Change-Id: Idabcb1fb907022f0d556667cbf3c36326f526a08
This commit is contained in:
parent
8bbbc75bdb
commit
3954065549
README.rst
doc/source
examples
os_faults
24
README.rst
24
README.rst
@ -45,12 +45,26 @@ library:
|
||||
'username': 'root',
|
||||
}
|
||||
},
|
||||
'power_management': {
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': 'qemu+unix:///system',
|
||||
'power_managements': [
|
||||
{
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': 'qemu+unix:///system',
|
||||
}
|
||||
},
|
||||
{
|
||||
'driver': 'ipmi',
|
||||
'args': {
|
||||
'mac_to_bmc': {
|
||||
'aa:bb:cc:dd:ee:01': {
|
||||
'address': '55.55.55.55',
|
||||
'username': 'foo',
|
||||
'password': 'bar',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Establish a connection to the cloud and verify it:
|
||||
|
@ -19,12 +19,14 @@ library:
|
||||
'username': 'root',
|
||||
}
|
||||
},
|
||||
'power_management': {
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': 'qemu+unix:///system',
|
||||
'power_managements': [
|
||||
{
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': 'qemu+unix:///system',
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Establish a connection to the cloud and verify it:
|
||||
|
@ -25,18 +25,20 @@ def main():
|
||||
'username': 'root',
|
||||
}
|
||||
},
|
||||
'power_management': {
|
||||
'driver': 'ipmi',
|
||||
'args': {
|
||||
'mac_to_bmc': {
|
||||
'00:00:00:00:00:00': {
|
||||
'address': '55.55.55.55',
|
||||
'username': 'foo',
|
||||
'password': 'bar',
|
||||
'power_managements': [
|
||||
{
|
||||
'driver': 'ipmi',
|
||||
'args': {
|
||||
'mac_to_bmc': {
|
||||
'00:00:00:00:00:00': {
|
||||
'address': '55.55.55.55',
|
||||
'username': 'foo',
|
||||
'password': 'bar',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
logging.info('Create connection to the cluster')
|
||||
|
@ -25,12 +25,14 @@ def main():
|
||||
'username': 'root',
|
||||
}
|
||||
},
|
||||
'power_management': {
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': "qemu+ssh://ubuntu@host.local/system"
|
||||
'power_managements': [
|
||||
{
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': "qemu+ssh://ubuntu@host.local/system"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
logging.info('Create connection to the cluster')
|
||||
|
@ -26,12 +26,14 @@ def main():
|
||||
'private_key_file': '~/.ssh/os_faults',
|
||||
}
|
||||
},
|
||||
'power_management': {
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': 'qemu+ssh://ubuntu@host.local/system'
|
||||
'power_managements': [
|
||||
{
|
||||
'driver': 'libvirt',
|
||||
'args': {
|
||||
'connection_uri': 'qemu+ssh://ubuntu@host.local/system'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
logging.info('# Create connection to the cloud')
|
||||
|
@ -80,7 +80,20 @@ CONFIG_SCHEMA = {
|
||||
},
|
||||
'required': ['driver', 'args'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
},
|
||||
'power_managements': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'driver': {'type': 'string'},
|
||||
'args': {'type': 'object'},
|
||||
},
|
||||
'required': ['driver', 'args'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'minItems': 1,
|
||||
},
|
||||
},
|
||||
'required': ['cloud_management'],
|
||||
}
|
||||
@ -126,10 +139,22 @@ def connect(cloud_config=None, config_filename=None):
|
||||
node_discover = _init_driver(node_discover_conf)
|
||||
cloud_management.set_node_discover(node_discover)
|
||||
|
||||
power_managements_conf = cloud_config.get('power_managements')
|
||||
if power_managements_conf:
|
||||
for pm_conf in power_managements_conf:
|
||||
pm = _init_driver(pm_conf)
|
||||
cloud_management.add_power_management(pm)
|
||||
|
||||
power_management_conf = cloud_config.get('power_management')
|
||||
if power_management_conf:
|
||||
if power_managements_conf:
|
||||
raise error.OSFError('Please use only power_managements')
|
||||
else:
|
||||
LOG.warning('power_management is deprecated, use '
|
||||
'power_managements instead.')
|
||||
|
||||
power_management = _init_driver(power_management_conf)
|
||||
cloud_management.set_power_management(power_management)
|
||||
cloud_management.add_power_management(power_management)
|
||||
|
||||
return cloud_management
|
||||
|
||||
|
@ -19,6 +19,7 @@ import six
|
||||
from os_faults.api import base_driver
|
||||
from os_faults.api import error
|
||||
from os_faults.api import node_collection
|
||||
from os_faults.api import power_management
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -31,11 +32,11 @@ class CloudManagement(base_driver.BaseDriver):
|
||||
NODE_CLS = node_collection.NodeCollection
|
||||
|
||||
def __init__(self):
|
||||
self.power_management = None
|
||||
self.power_manager = power_management.PowerManager()
|
||||
self.node_discover = None
|
||||
|
||||
def set_power_management(self, power_management):
|
||||
self.power_management = power_management
|
||||
def add_power_management(self, driver):
|
||||
self.power_manager.add_driver(driver)
|
||||
|
||||
def set_node_discover(self, node_discover):
|
||||
self.node_discover = node_discover
|
||||
@ -60,9 +61,7 @@ class CloudManagement(base_driver.BaseDriver):
|
||||
'node_discover is not specified and "{}" '
|
||||
'driver does not support discovering'.format(self.NAME))
|
||||
hosts = self.node_discover.discover_hosts()
|
||||
nodes = self.NODE_CLS(cloud_management=self,
|
||||
power_management=self.power_management,
|
||||
hosts=hosts)
|
||||
nodes = self.NODE_CLS(cloud_management=self, hosts=hosts)
|
||||
|
||||
if fqdns:
|
||||
LOG.debug('Trying to find nodes with FQDNs: %s', fqdns)
|
||||
@ -78,9 +77,7 @@ class CloudManagement(base_driver.BaseDriver):
|
||||
"""
|
||||
if name in self.SERVICE_NAME_TO_CLASS:
|
||||
klazz = self.SERVICE_NAME_TO_CLASS[name]
|
||||
return klazz(node_cls=self.NODE_CLS,
|
||||
cloud_management=self,
|
||||
power_management=self.power_management)
|
||||
return klazz(node_cls=self.NODE_CLS, cloud_management=self)
|
||||
raise error.ServiceError(
|
||||
'{} driver does not support {!r} service'.format(
|
||||
self.NAME.title(), name))
|
||||
|
@ -26,10 +26,8 @@ Host = collections.namedtuple('Host', ['ip', 'mac', 'fqdn'])
|
||||
|
||||
class NodeCollection(object):
|
||||
|
||||
def __init__(self, cloud_management=None, power_management=None,
|
||||
hosts=None):
|
||||
def __init__(self, cloud_management=None, hosts=None):
|
||||
self.cloud_management = cloud_management
|
||||
self.power_management = power_management
|
||||
self._hosts = set(hosts)
|
||||
|
||||
@property
|
||||
@ -52,11 +50,6 @@ class NodeCollection(object):
|
||||
'NodeCollections have different cloud_managements: '
|
||||
'{} and {}'.format(self.cloud_management,
|
||||
other.cloud_management))
|
||||
if self.power_management is not other.power_management:
|
||||
raise error.NodeCollectionError(
|
||||
'NodeCollections have different power_managements: '
|
||||
'{} and {}'.format(self.power_management,
|
||||
other.power_management))
|
||||
|
||||
def __add__(self, other):
|
||||
return self.__or__(other)
|
||||
@ -86,7 +79,6 @@ class NodeCollection(object):
|
||||
|
||||
def _make_instance(self, hosts):
|
||||
return self.__class__(cloud_management=self.cloud_management,
|
||||
power_management=self.power_management,
|
||||
hosts=hosts)
|
||||
|
||||
def get_ips(self):
|
||||
@ -155,7 +147,7 @@ class NodeCollection(object):
|
||||
|
||||
"""
|
||||
LOG.info('Power off nodes: %s', self)
|
||||
self.power_management.poweroff(self.get_macs())
|
||||
self.cloud_management.power_manager.poweroff(self.hosts)
|
||||
|
||||
@public
|
||||
def poweron(self):
|
||||
@ -163,7 +155,7 @@ class NodeCollection(object):
|
||||
|
||||
"""
|
||||
LOG.info('Power on nodes: %s', self)
|
||||
self.power_management.poweron(self.get_macs())
|
||||
self.cloud_management.power_manager.poweron(self.hosts)
|
||||
|
||||
@public
|
||||
def reset(self):
|
||||
@ -171,21 +163,23 @@ class NodeCollection(object):
|
||||
|
||||
"""
|
||||
LOG.info('Reset nodes: %s', self)
|
||||
self.power_management.reset(self.get_macs())
|
||||
self.cloud_management.power_manager.reset(self.hosts)
|
||||
|
||||
def snapshot(self, snapshot_name, suspend=True):
|
||||
"""Create snapshot for all nodes
|
||||
|
||||
"""
|
||||
LOG.info('Create snapshot "%s" for nodes: %s', snapshot_name, self)
|
||||
self.power_management.snapshot(self.get_macs(), snapshot_name, suspend)
|
||||
self.cloud_management.power_manager.snapshot(
|
||||
self.hosts, snapshot_name, suspend)
|
||||
|
||||
def revert(self, snapshot_name, resume=True):
|
||||
"""Revert snapshot for all nodes
|
||||
|
||||
"""
|
||||
LOG.info('Revert snapshot "%s" for nodes: %s', snapshot_name, self)
|
||||
self.power_management.revert(self.get_macs(), snapshot_name, resume)
|
||||
self.cloud_management.power_manager.revert(
|
||||
self.hosts, snapshot_name, resume)
|
||||
|
||||
@public
|
||||
def disconnect(self, network_name):
|
||||
|
@ -16,25 +16,82 @@ import abc
|
||||
import six
|
||||
|
||||
from os_faults.api import base_driver
|
||||
from os_faults.api import error
|
||||
from os_faults import utils
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class PowerManagement(base_driver.BaseDriver):
|
||||
class PowerDriver(base_driver.BaseDriver):
|
||||
|
||||
@abc.abstractmethod
|
||||
def supports(host):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def poweroff(self, host):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def poweron(self, host):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def reset(self, host):
|
||||
pass
|
||||
|
||||
def snapshot(self, host, snapshot_name, suspend=True):
|
||||
raise NotImplementedError
|
||||
|
||||
def revert(self, host, snapshot_name, resume=True):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class PowerManager(object):
|
||||
|
||||
def __init__(self):
|
||||
self.power_drivers = []
|
||||
|
||||
def add_driver(self, driver):
|
||||
self.power_drivers.append(driver)
|
||||
|
||||
def _map_hosts_to_driver(self, hosts):
|
||||
driver_host_pairs = []
|
||||
for host in hosts:
|
||||
for power_driver in self.power_drivers:
|
||||
if power_driver.supports(host):
|
||||
driver_host_pairs.append((power_driver, host))
|
||||
break
|
||||
else:
|
||||
raise error.PowerManagementError(
|
||||
"No supported driver found for host {}".format(host))
|
||||
return driver_host_pairs
|
||||
|
||||
def _run_command(self, cmd, hosts, **kwargs):
|
||||
driver_host_pairs = self._map_hosts_to_driver(hosts)
|
||||
tw = utils.ThreadsWrapper()
|
||||
for driver, host in driver_host_pairs:
|
||||
kwargs['host'] = host
|
||||
fn = getattr(driver, cmd)
|
||||
tw.start_thread(fn, **kwargs)
|
||||
tw.join_threads()
|
||||
if tw.errors:
|
||||
raise error.PowerManagementError(
|
||||
'There are some errors when working the driver. '
|
||||
'Please, check logs for more details.')
|
||||
|
||||
def poweroff(self, hosts):
|
||||
pass
|
||||
self._run_command('poweroff', hosts)
|
||||
|
||||
@abc.abstractmethod
|
||||
def poweron(self, hosts):
|
||||
pass
|
||||
self._run_command('poweron', hosts)
|
||||
|
||||
@abc.abstractmethod
|
||||
def reset(self, hosts):
|
||||
pass
|
||||
self._run_command('reset', hosts)
|
||||
|
||||
def snapshot(self, hosts, snapshot_name, suspend=True):
|
||||
raise NotImplementedError
|
||||
self._run_command('snapshot', hosts,
|
||||
snapshot_name=snapshot_name, suspend=suspend)
|
||||
|
||||
def revert(self, hosts, snapshot_name, resume=True):
|
||||
raise NotImplementedError
|
||||
self._run_command('revert', hosts,
|
||||
snapshot_name=snapshot_name, resume=resume)
|
||||
|
@ -24,10 +24,9 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
class ServiceAsProcess(service.Service):
|
||||
|
||||
def __init__(self, node_cls, cloud_management=None, power_management=None):
|
||||
def __init__(self, node_cls, cloud_management=None):
|
||||
self.node_cls = node_cls
|
||||
self.cloud_management = cloud_management
|
||||
self.power_management = power_management
|
||||
|
||||
def _run_task(self, task, nodes):
|
||||
ips = nodes.get_ips()
|
||||
@ -55,7 +54,6 @@ class ServiceAsProcess(service.Service):
|
||||
if r.status == executor.STATUS_OK]
|
||||
hosts = [h for h in nodes.hosts if h.ip in success_ips]
|
||||
return self.node_cls(cloud_management=self.cloud_management,
|
||||
power_management=self.power_management,
|
||||
hosts=hosts)
|
||||
|
||||
@utils.require_variables('RESTART_CMD', 'SERVICE_NAME')
|
||||
|
@ -23,7 +23,7 @@ from os_faults import utils
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IPMIDriver(power_management.PowerManagement):
|
||||
class IPMIDriver(power_management.PowerDriver):
|
||||
NAME = 'ipmi'
|
||||
DESCRIPTION = 'IPMI power management driver'
|
||||
CONFIG_SCHEMA = {
|
||||
@ -51,6 +51,7 @@ class IPMIDriver(power_management.PowerManagement):
|
||||
|
||||
def __init__(self, params):
|
||||
self.mac_to_bmc = params['mac_to_bmc']
|
||||
# TODO(astudenov): make macs lowercased
|
||||
|
||||
def _find_bmc_by_mac_address(self, mac_address):
|
||||
if mac_address not in self.mac_to_bmc:
|
||||
@ -80,36 +81,26 @@ class IPMIDriver(power_management.PowerManagement):
|
||||
mac_address))
|
||||
raise error.PowerManagementError(msg)
|
||||
|
||||
def _poweroff(self, mac_address):
|
||||
LOG.debug('Power off Node with MAC address: %s', mac_address)
|
||||
self._run_set_power_cmd(
|
||||
mac_address, cmd='off', expected_state='off')
|
||||
LOG.info('Node powered off: %s', mac_address)
|
||||
def supports(self, host):
|
||||
try:
|
||||
self._find_bmc_by_mac_address(host.mac)
|
||||
except error.PowerManagementError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _poweron(self, mac_address):
|
||||
LOG.debug('Power on Node with MAC address: %s', mac_address)
|
||||
self._run_set_power_cmd(
|
||||
mac_address, cmd='on', expected_state='on')
|
||||
LOG.info('Node powered on: %s', mac_address)
|
||||
def poweroff(self, host):
|
||||
LOG.debug('Power off Node with MAC address: %s', host.mac)
|
||||
self._run_set_power_cmd(host.mac, cmd='off', expected_state='off')
|
||||
LOG.info('Node powered off: %s', host.mac)
|
||||
|
||||
def _reset(self, mac_address):
|
||||
LOG.debug('Reset Node with MAC address: %s', mac_address)
|
||||
def poweron(self, host):
|
||||
LOG.debug('Power on Node with MAC address: %s', host.mac)
|
||||
self._run_set_power_cmd(host.mac, cmd='on', expected_state='on')
|
||||
LOG.info('Node powered on: %s', host.mac)
|
||||
|
||||
def reset(self, host):
|
||||
LOG.debug('Reset Node with MAC address: %s', host.mac)
|
||||
# boot -- If system is off, then 'on', else 'reset'
|
||||
self._run_set_power_cmd(mac_address, cmd='boot')
|
||||
self._run_set_power_cmd(host.mac, cmd='boot')
|
||||
# NOTE(astudenov): This command does not wait for node to boot
|
||||
LOG.info('Node reset: %s', mac_address)
|
||||
|
||||
def poweroff(self, mac_addresses_list):
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweroff, kwargs_list)
|
||||
|
||||
def poweron(self, mac_addresses_list):
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweron, kwargs_list)
|
||||
|
||||
def reset(self, mac_addresses_list):
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._reset, kwargs_list)
|
||||
LOG.info('Node reset: %s', host.mac)
|
||||
|
@ -15,12 +15,11 @@ import logging
|
||||
|
||||
from os_faults.api import error
|
||||
from os_faults.api import power_management
|
||||
from os_faults import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LibvirtDriver(power_management.PowerManagement):
|
||||
class LibvirtDriver(power_management.PowerDriver):
|
||||
NAME = 'libvirt'
|
||||
DESCRIPTION = 'Libvirt power management driver'
|
||||
CONFIG_SCHEMA = {
|
||||
@ -60,28 +59,35 @@ class LibvirtDriver(power_management.PowerManagement):
|
||||
raise error.PowerManagementError(
|
||||
'Domain with MAC address %s not found!' % mac_address)
|
||||
|
||||
def _poweroff(self, mac_address):
|
||||
LOG.debug('Power off domain with MAC address: %s', mac_address)
|
||||
domain = self._find_domain_by_mac_address(mac_address)
|
||||
def supports(self, host):
|
||||
try:
|
||||
self._find_domain_by_mac_address(host.mac)
|
||||
except error.PowerManagementError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def poweroff(self, host):
|
||||
LOG.debug('Power off domain with MAC address: %s', host.mac)
|
||||
domain = self._find_domain_by_mac_address(host.mac)
|
||||
domain.destroy()
|
||||
LOG.info('Domain powered off: %s', mac_address)
|
||||
LOG.info('Domain powered off: %s', host.mac)
|
||||
|
||||
def _poweron(self, mac_address):
|
||||
LOG.debug('Power on domain with MAC address: %s', mac_address)
|
||||
domain = self._find_domain_by_mac_address(mac_address)
|
||||
def poweron(self, host):
|
||||
LOG.debug('Power on domain with MAC address: %s', host.mac)
|
||||
domain = self._find_domain_by_mac_address(host.mac)
|
||||
domain.create()
|
||||
LOG.info('Domain powered on: %s', mac_address)
|
||||
LOG.info('Domain powered on: %s', host.mac)
|
||||
|
||||
def _reset(self, mac_address):
|
||||
LOG.debug('Reset domain with MAC address: %s', mac_address)
|
||||
domain = self._find_domain_by_mac_address(mac_address)
|
||||
def reset(self, host):
|
||||
LOG.debug('Reset domain with MAC address: %s', host.mac)
|
||||
domain = self._find_domain_by_mac_address(host.mac)
|
||||
domain.reset()
|
||||
LOG.info('Domain reset: %s', mac_address)
|
||||
LOG.info('Domain reset: %s', host.mac)
|
||||
|
||||
def _snapshot(self, mac_address, snapshot_name, suspend):
|
||||
def snapshot(self, host, snapshot_name, suspend):
|
||||
LOG.debug('Create snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
domain = self._find_domain_by_mac_address(mac_address)
|
||||
snapshot_name, host.mac)
|
||||
domain = self._find_domain_by_mac_address(host.mac)
|
||||
if suspend:
|
||||
domain.suspend()
|
||||
domain.snapshotCreateXML(
|
||||
@ -90,12 +96,12 @@ class LibvirtDriver(power_management.PowerManagement):
|
||||
if suspend:
|
||||
domain.resume()
|
||||
LOG.debug('Created snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
snapshot_name, host.mac)
|
||||
|
||||
def _revert(self, mac_address, snapshot_name, resume):
|
||||
def revert(self, host, snapshot_name, resume):
|
||||
LOG.debug('Revert snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
domain = self._find_domain_by_mac_address(mac_address)
|
||||
snapshot_name, host.mac)
|
||||
domain = self._find_domain_by_mac_address(host.mac)
|
||||
snapshot = domain.snapshotLookupByName(snapshot_name)
|
||||
if domain.isActive():
|
||||
domain.destroy()
|
||||
@ -103,33 +109,4 @@ class LibvirtDriver(power_management.PowerManagement):
|
||||
if resume:
|
||||
domain.resume()
|
||||
LOG.debug('Reverted snapshot "%s" for domain with MAC address: %s',
|
||||
snapshot_name, mac_address)
|
||||
|
||||
def poweroff(self, mac_addresses_list):
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweroff, kwargs_list)
|
||||
|
||||
def poweron(self, mac_addresses_list):
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._poweron, kwargs_list)
|
||||
|
||||
def reset(self, mac_addresses_list):
|
||||
kwargs_list = [dict(mac_address=mac_address)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._reset, kwargs_list)
|
||||
|
||||
def snapshot(self, mac_addresses_list, snapshot_name, suspend=True):
|
||||
kwargs_list = [dict(mac_address=mac_address,
|
||||
snapshot_name=snapshot_name,
|
||||
suspend=suspend)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._snapshot, kwargs_list)
|
||||
|
||||
def revert(self, mac_addresses_list, snapshot_name, resume=True):
|
||||
kwargs_list = [dict(mac_address=mac_address,
|
||||
snapshot_name=snapshot_name,
|
||||
resume=resume)
|
||||
for mac_address in mac_addresses_list]
|
||||
utils.run(self._revert, kwargs_list)
|
||||
snapshot_name, host.mac)
|
||||
|
@ -33,8 +33,9 @@ class NodeCollectionTestCase(test.TestCase):
|
||||
super(NodeCollectionTestCase, self).setUp()
|
||||
self.mock_cloud_management = mock.Mock(
|
||||
spec=cloud_management.CloudManagement)
|
||||
self.mock_power_management = mock.Mock(
|
||||
spec=power_management.PowerManagement)
|
||||
self.mock_power_manager = mock.Mock(
|
||||
spec=power_management.PowerManager)
|
||||
self.mock_cloud_management.power_manager = self.mock_power_manager
|
||||
self.hosts = [
|
||||
node_collection.Host(ip='10.0.0.2', mac='09:7b:74:90:63:c1',
|
||||
fqdn='node1.com'),
|
||||
@ -48,7 +49,6 @@ class NodeCollectionTestCase(test.TestCase):
|
||||
|
||||
self.node_collection = node_collection.NodeCollection(
|
||||
cloud_management=self.mock_cloud_management,
|
||||
power_management=self.mock_power_management,
|
||||
hosts=copy.deepcopy(self.hosts))
|
||||
|
||||
self.hosts2 = [
|
||||
@ -64,26 +64,17 @@ class NodeCollectionTestCase(test.TestCase):
|
||||
|
||||
self.node_collection2 = node_collection.NodeCollection(
|
||||
cloud_management=self.mock_cloud_management,
|
||||
power_management=self.mock_power_management,
|
||||
hosts=copy.deepcopy(self.hosts2))
|
||||
|
||||
def test_check_types_wrong_type(self):
|
||||
collection = MyNodeCollection(None, None, [])
|
||||
collection = MyNodeCollection(None, [])
|
||||
self.assertRaises(TypeError, self.node_collection._check_nodes_types,
|
||||
collection)
|
||||
self.assertRaises(TypeError, collection._check_nodes_types,
|
||||
self.node_collection)
|
||||
|
||||
def test_check_types_wrong_cloud_management(self):
|
||||
collection = node_collection.NodeCollection(None, None, [])
|
||||
self.assertRaises(error.NodeCollectionError,
|
||||
self.node_collection._check_nodes_types, collection)
|
||||
self.assertRaises(error.NodeCollectionError,
|
||||
collection._check_nodes_types, self.node_collection)
|
||||
|
||||
def test_check_types_wrong_power_management(self):
|
||||
collection = node_collection.NodeCollection(
|
||||
self.mock_cloud_management, None, [])
|
||||
collection = node_collection.NodeCollection(None, [])
|
||||
self.assertRaises(error.NodeCollectionError,
|
||||
self.node_collection._check_nodes_types, collection)
|
||||
self.assertRaises(error.NodeCollectionError,
|
||||
@ -187,21 +178,15 @@ class NodeCollectionTestCase(test.TestCase):
|
||||
|
||||
def test_poweroff(self):
|
||||
self.node_collection.poweroff()
|
||||
self.mock_power_management.poweroff.assert_called_once_with(
|
||||
['09:7b:74:90:63:c1', '09:7b:74:90:63:c2',
|
||||
'09:7b:74:90:63:c3', '09:7b:74:90:63:c4'])
|
||||
self.mock_power_manager.poweroff.assert_called_once_with(self.hosts)
|
||||
|
||||
def test_poweron(self):
|
||||
self.node_collection.poweron()
|
||||
self.mock_power_management.poweron.assert_called_once_with(
|
||||
['09:7b:74:90:63:c1', '09:7b:74:90:63:c2',
|
||||
'09:7b:74:90:63:c3', '09:7b:74:90:63:c4'])
|
||||
self.mock_power_manager.poweron.assert_called_once_with(self.hosts)
|
||||
|
||||
def test_reset(self):
|
||||
self.node_collection.reset()
|
||||
self.mock_power_management.reset.assert_called_once_with(
|
||||
['09:7b:74:90:63:c1', '09:7b:74:90:63:c2',
|
||||
'09:7b:74:90:63:c3', '09:7b:74:90:63:c4'])
|
||||
self.mock_power_manager.reset.assert_called_once_with(self.hosts)
|
||||
|
||||
def test_reboot(self):
|
||||
self.node_collection.reboot()
|
||||
@ -211,12 +196,10 @@ class NodeCollectionTestCase(test.TestCase):
|
||||
|
||||
def test_snapshot(self):
|
||||
self.node_collection.snapshot('foo')
|
||||
self.mock_power_management.snapshot.assert_called_once_with(
|
||||
['09:7b:74:90:63:c1', '09:7b:74:90:63:c2',
|
||||
'09:7b:74:90:63:c3', '09:7b:74:90:63:c4'], 'foo', True)
|
||||
self.mock_power_manager.snapshot.assert_called_once_with(
|
||||
self.hosts, 'foo', True)
|
||||
|
||||
def test_revert(self):
|
||||
self.node_collection.revert('foo')
|
||||
self.mock_power_management.revert.assert_called_once_with(
|
||||
['09:7b:74:90:63:c1', '09:7b:74:90:63:c2',
|
||||
'09:7b:74:90:63:c3', '09:7b:74:90:63:c4'], 'foo', True)
|
||||
self.mock_power_manager.revert.assert_called_once_with(
|
||||
self.hosts, 'foo', True)
|
||||
|
107
os_faults/tests/unit/api/test_power_management.py
Normal file
107
os_faults/tests/unit/api/test_power_management.py
Normal file
@ -0,0 +1,107 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from os_faults.api import error
|
||||
from os_faults.api import node_collection
|
||||
from os_faults.api import power_management
|
||||
from os_faults.tests.unit import test
|
||||
|
||||
|
||||
class PowerManagerTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(PowerManagerTestCase, self).setUp()
|
||||
|
||||
self.dummy_driver1 = mock.Mock(spec=power_management.PowerDriver)
|
||||
self.dummy_driver1.supports.side_effect = lambda host: 'c1' in host.mac
|
||||
|
||||
self.dummy_driver2 = mock.Mock(spec=power_management.PowerDriver)
|
||||
self.dummy_driver2.supports.side_effect = lambda host: 'c2' in host.mac
|
||||
|
||||
self.dummy_drivers = [self.dummy_driver1, self.dummy_driver2]
|
||||
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'),
|
||||
]
|
||||
self.pm = power_management.PowerManager()
|
||||
self.pm.add_driver(self.dummy_driver1)
|
||||
self.pm.add_driver(self.dummy_driver2)
|
||||
|
||||
def test_poweroff(self):
|
||||
self.pm.poweroff(self.hosts)
|
||||
|
||||
self.dummy_driver1.poweroff.called_once_with(host=self.hosts[0])
|
||||
self.dummy_driver2.poweroff.called_once_with(host=self.hosts[1])
|
||||
|
||||
def test_poweron(self):
|
||||
self.pm.poweron(self.hosts)
|
||||
|
||||
self.dummy_driver1.poweron.called_once_with(host=self.hosts[0])
|
||||
self.dummy_driver2.poweron.called_once_with(host=self.hosts[1])
|
||||
|
||||
def test_reset(self):
|
||||
self.pm.reset(self.hosts)
|
||||
|
||||
self.dummy_driver1.reset.called_once_with(host=self.hosts[0])
|
||||
self.dummy_driver2.reset.called_once_with(host=self.hosts[1])
|
||||
|
||||
def test_snapshot(self):
|
||||
self.pm.snapshot(self.hosts, 'snap1', suspend=False)
|
||||
|
||||
self.dummy_driver1.snapshot.called_once_with(host=self.hosts[0],
|
||||
snapshot_name='snap1',
|
||||
suspend=False)
|
||||
self.dummy_driver2.snapshot.called_once_with(host=self.hosts[1],
|
||||
snapshot_name='snap1',
|
||||
suspend=False)
|
||||
|
||||
def test_revert(self):
|
||||
self.pm.revert(self.hosts, 'snap1', resume=False)
|
||||
|
||||
self.dummy_driver1.revert.called_once_with(host=self.hosts[0],
|
||||
snapshot_name='snap1',
|
||||
resume=False)
|
||||
self.dummy_driver2.revert.called_once_with(host=self.hosts[1],
|
||||
snapshot_name='snap1',
|
||||
resume=False)
|
||||
|
||||
def test_run_error(self):
|
||||
self.dummy_driver2.reset.side_effect = Exception()
|
||||
|
||||
exc = self.assertRaises(error.PowerManagementError,
|
||||
self.pm.reset, self.hosts)
|
||||
self.assertEqual("There are some errors when working the driver. "
|
||||
"Please, check logs for more details.", str(exc))
|
||||
|
||||
def test_run_no_supported_driver(self):
|
||||
self.dummy_driver2.supports.side_effect = None
|
||||
self.dummy_driver2.supports.return_value = False
|
||||
|
||||
exc = self.assertRaises(error.PowerManagementError,
|
||||
self.pm.reset, self.hosts)
|
||||
self.assertEqual("No supported driver found for host "
|
||||
"Host(ip='10.0.0.3', mac='09:7b:74:90:63:c2', "
|
||||
"fqdn='node2.com')", str(exc))
|
||||
|
||||
def test_run_no_drivers(self):
|
||||
self.pm = power_management.PowerManager()
|
||||
|
||||
exc = self.assertRaises(error.PowerManagementError,
|
||||
self.pm.reset, self.hosts)
|
||||
self.assertEqual("No supported driver found for host "
|
||||
"Host(ip='10.0.0.2', mac='09:7b:74:90:63:c1', "
|
||||
"fqdn='node1.com')", str(exc))
|
@ -17,7 +17,6 @@ import ddt
|
||||
import mock
|
||||
|
||||
from os_faults.api import node_collection
|
||||
from os_faults.api import power_management
|
||||
from os_faults.drivers import devstack
|
||||
from os_faults.tests.unit import fakes
|
||||
from os_faults.tests.unit import test
|
||||
@ -29,14 +28,11 @@ class DevStackNodeTestCase(test.TestCase):
|
||||
super(DevStackNodeTestCase, self).setUp()
|
||||
self.mock_cloud_management = mock.Mock(
|
||||
spec=devstack.DevStackManagement)
|
||||
self.mock_power_management = mock.Mock(
|
||||
spec=power_management.PowerManagement)
|
||||
self.host = node_collection.Host(
|
||||
ip='10.0.0.2', mac='09:7b:74:90:63:c1', fqdn='')
|
||||
|
||||
self.node_collection = devstack.DevStackNode(
|
||||
cloud_management=self.mock_cloud_management,
|
||||
power_management=self.mock_power_management,
|
||||
hosts=[copy.deepcopy(self.host)])
|
||||
|
||||
def test_connect(self):
|
||||
|
@ -16,7 +16,6 @@ import copy
|
||||
import mock
|
||||
|
||||
from os_faults.api import node_collection
|
||||
from os_faults.api import power_management
|
||||
from os_faults.drivers import fuel
|
||||
from os_faults.tests.unit import test
|
||||
|
||||
@ -26,8 +25,6 @@ class FuelNodeCollectionTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(FuelNodeCollectionTestCase, self).setUp()
|
||||
self.mock_cloud_management = mock.Mock(spec=fuel.FuelManagement)
|
||||
self.mock_power_management = mock.Mock(
|
||||
spec=power_management.PowerManagement)
|
||||
self.hosts = [
|
||||
node_collection.Host(ip='10.0.0.2', mac='09:7b:74:90:63:c1',
|
||||
fqdn='node1.com'),
|
||||
@ -41,7 +38,6 @@ class FuelNodeCollectionTestCase(test.TestCase):
|
||||
|
||||
self.node_collection = fuel.FuelNodeCollection(
|
||||
cloud_management=self.mock_cloud_management,
|
||||
power_management=self.mock_power_management,
|
||||
hosts=copy.deepcopy(self.hosts))
|
||||
|
||||
def test_connect(self):
|
||||
|
@ -15,6 +15,7 @@ import ddt
|
||||
import mock
|
||||
from pyghmi import exceptions as pyghmi_exc
|
||||
|
||||
from os_faults.api import node_collection
|
||||
from os_faults.drivers import ipmi
|
||||
from os_faults import error
|
||||
from os_faults.tests.unit import test
|
||||
@ -36,11 +37,21 @@ class IPMIDriverTestCase(test.TestCase):
|
||||
}
|
||||
}
|
||||
self.driver = ipmi.IPMIDriver(self.params)
|
||||
self.host = node_collection.Host(
|
||||
ip='10.0.0.2', mac='00:00:00:00:00:00', fqdn='node1.com')
|
||||
|
||||
def test__find_bmc_by_mac_address(self):
|
||||
bmc = self.driver._find_bmc_by_mac_address('00:00:00:00:00:00')
|
||||
self.assertEqual(bmc, self.params['mac_to_bmc']['00:00:00:00:00:00'])
|
||||
|
||||
def test_supports(self):
|
||||
self.assertTrue(self.driver.supports(self.host))
|
||||
|
||||
def test_supports_false(self):
|
||||
host = node_collection.Host(
|
||||
ip='10.0.0.2', mac='00:00:00:00:00:01', fqdn='node1.com')
|
||||
self.assertFalse(self.driver.supports(host))
|
||||
|
||||
def test__find_bmc_by_mac_address_mac_address_not_found(self):
|
||||
self.assertRaises(error.PowerManagementError,
|
||||
self.driver._find_bmc_by_mac_address,
|
||||
@ -74,22 +85,12 @@ class IPMIDriverTestCase(test.TestCase):
|
||||
'00:00:00:00:00:00', 'off', expected_state='off')
|
||||
|
||||
@mock.patch('os_faults.drivers.ipmi.IPMIDriver._run_set_power_cmd')
|
||||
@ddt.data(('_poweroff', 'off'), ('_poweron', 'on'), ('_reset', 'boot'))
|
||||
def test__driver_actions(self, actions, mock__run_set_power_cmd):
|
||||
getattr(self.driver, actions[0])('00:00:00:00:00:00')
|
||||
if actions[0] in ('_poweroff', '_poweron'):
|
||||
@ddt.data(('poweroff', 'off'), ('poweron', 'on'), ('reset', 'boot'))
|
||||
def test_driver_actions(self, actions, mock__run_set_power_cmd):
|
||||
getattr(self.driver, actions[0])(self.host)
|
||||
if actions[0] in ('poweroff', 'poweron'):
|
||||
mock__run_set_power_cmd.assert_called_once_with(
|
||||
'00:00:00:00:00:00', cmd=actions[1], expected_state=actions[1])
|
||||
else:
|
||||
mock__run_set_power_cmd.assert_called_once_with(
|
||||
'00:00:00:00:00:00', cmd=actions[1])
|
||||
|
||||
@mock.patch('os_faults.utils.run')
|
||||
@ddt.data('poweroff', 'poweron', 'reset')
|
||||
def test_driver_actions(self, action, mock_run):
|
||||
macs_list = ['00:00:00:00:00:00', '00:00:00:00:00:01']
|
||||
getattr(self.driver, action)(macs_list)
|
||||
mock_run.assert_called_once_with(
|
||||
getattr(self.driver, '_%s' % action),
|
||||
[{'mac_address': '00:00:00:00:00:00'},
|
||||
{'mac_address': '00:00:00:00:00:01'}])
|
||||
|
@ -14,6 +14,7 @@
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from os_faults.api import node_collection
|
||||
from os_faults.drivers import libvirt_driver
|
||||
from os_faults import error
|
||||
from os_faults.tests.unit import test
|
||||
@ -30,6 +31,8 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
|
||||
self.params = {'connection_uri': 'fake_connection_uri'}
|
||||
self.driver = libvirt_driver.LibvirtDriver(self.params)
|
||||
self.host = node_collection.Host(
|
||||
ip='10.0.0.2', mac='00:00:00:00:00:00', fqdn='node1.com')
|
||||
|
||||
@mock.patch('libvirt.open')
|
||||
def test__get_connection_no_cached_connection(self, mock_libvirt_open):
|
||||
@ -69,24 +72,40 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
self.driver._find_domain_by_mac_address,
|
||||
'00:00:00:00:00:01')
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._get_connection')
|
||||
def test_supports(self, mock__get_connection):
|
||||
domain1 = mock.MagicMock()
|
||||
domain1.XMLDesc.return_value = '52:54:00:ab:64:42'
|
||||
domain2 = mock.MagicMock()
|
||||
domain2.XMLDesc.return_value = '00:00:00:00:00:00'
|
||||
self.driver.conn.listAllDomains.return_value = [domain1, domain2]
|
||||
|
||||
self.assertTrue(self.driver.supports(self.host))
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._get_connection')
|
||||
def test_supports_false(self, mock__get_connection):
|
||||
self.driver.conn.listAllDomains.return_value = []
|
||||
|
||||
self.assertFalse(self.driver.supports(self.host))
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
@ddt.data(('_poweroff', 'destroy'), ('_poweron', 'create'),
|
||||
('_reset', 'reset'))
|
||||
def test__driver_actions(self, actions, mock__find_domain_by_mac_address):
|
||||
getattr(self.driver, actions[0])('52:54:00:f9:b8:f9')
|
||||
@ddt.data(('poweroff', 'destroy'), ('poweron', 'create'),
|
||||
('reset', 'reset'))
|
||||
def test_driver_actions(self, actions, mock__find_domain_by_mac_address):
|
||||
getattr(self.driver, actions[0])(self.host)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
getattr(domain, actions[1]).assert_called_once_with()
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__snapshot(self, mock__find_domain_by_mac_address):
|
||||
self.driver._snapshot('52:54:00:f9:b8:f9', 'foo', suspend=False)
|
||||
def test_snapshot(self, mock__find_domain_by_mac_address):
|
||||
self.driver.snapshot(self.host, 'foo', suspend=False)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
domain.snapshotCreateXML.assert_called_once_with(
|
||||
'<domainsnapshot><name>foo</name></domainsnapshot>')
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__snapshot_suspend(self, mock__find_domain_by_mac_address):
|
||||
self.driver._snapshot('52:54:00:f9:b8:f9', 'foo', suspend=True)
|
||||
def test_snapshot_suspend(self, mock__find_domain_by_mac_address):
|
||||
self.driver.snapshot(self.host, 'foo', suspend=True)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
domain.assert_has_calls((
|
||||
mock.call.suspend(),
|
||||
@ -96,8 +115,8 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
))
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__revert(self, mock__find_domain_by_mac_address):
|
||||
self.driver._revert('52:54:00:f9:b8:f9', 'foo', resume=False)
|
||||
def test_revert(self, mock__find_domain_by_mac_address):
|
||||
self.driver.revert(self.host, 'foo', resume=False)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
snapshot = domain.snapshotLookupByName.return_value
|
||||
domain.snapshotLookupByName.assert_called_once_with('foo')
|
||||
@ -105,8 +124,8 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
self.assertFalse(domain.resume.called)
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__revert_resume(self, mock__find_domain_by_mac_address):
|
||||
self.driver._revert('52:54:00:f9:b8:f9', 'foo', resume=True)
|
||||
def test_revert_resume(self, mock__find_domain_by_mac_address):
|
||||
self.driver.revert(self.host, 'foo', resume=True)
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
snapshot = domain.snapshotLookupByName.return_value
|
||||
domain.snapshotLookupByName.assert_called_once_with('foo')
|
||||
@ -114,51 +133,15 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
domain.resume.assert_called_once_with()
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__revert_destroy(self, mock__find_domain_by_mac_address):
|
||||
def test_revert_destroy(self, mock__find_domain_by_mac_address):
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
domain.isActive.return_value = True
|
||||
self.driver._revert('52:54:00:f9:b8:f9', 'foo', resume=True)
|
||||
self.driver.revert(self.host, 'foo', resume=True)
|
||||
domain.destroy.assert_called_once_with()
|
||||
|
||||
@mock.patch(DRIVER_PATH + '.LibvirtDriver._find_domain_by_mac_address')
|
||||
def test__revert_destroy_nonactive(self, mock__find_domain_by_mac_address):
|
||||
def test_revert_destroy_nonactive(self, mock__find_domain_by_mac_address):
|
||||
domain = mock__find_domain_by_mac_address.return_value
|
||||
domain.isActive.return_value = False
|
||||
self.driver._revert('52:54:00:f9:b8:f9', 'foo', resume=True)
|
||||
self.driver.revert(self.host, 'foo', resume=True)
|
||||
self.assertFalse(domain.destroy.called)
|
||||
|
||||
@mock.patch('os_faults.utils.run')
|
||||
@ddt.data('poweroff', 'poweron', 'reset')
|
||||
def test_driver_actions(self, action, mock_run):
|
||||
macs_list = ['52:54:00:f9:b8:f9', '52:54:00:ab:64:42']
|
||||
getattr(self.driver, action)(macs_list)
|
||||
mock_run.assert_called_once_with(
|
||||
getattr(self.driver, '_%s' % action),
|
||||
[{'mac_address': '52:54:00:f9:b8:f9'},
|
||||
{'mac_address': '52:54:00:ab:64:42'}])
|
||||
|
||||
@mock.patch('os_faults.utils.run')
|
||||
def test_driver_snapshot(self, mock_run):
|
||||
macs_list = ['52:54:00:f9:b8:f9', '52:54:00:ab:64:42']
|
||||
self.driver.snapshot(macs_list, 'foo_snap')
|
||||
mock_run.assert_called_once_with(
|
||||
self.driver._snapshot,
|
||||
[{'mac_address': '52:54:00:f9:b8:f9',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'suspend': True},
|
||||
{'mac_address': '52:54:00:ab:64:42',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'suspend': True}])
|
||||
|
||||
@mock.patch('os_faults.utils.run')
|
||||
def test_driver_revert(self, mock_run):
|
||||
macs_list = ['52:54:00:f9:b8:f9', '52:54:00:ab:64:42']
|
||||
self.driver.revert(macs_list, 'foo_snap', resume=False)
|
||||
mock_run.assert_called_once_with(
|
||||
self.driver._revert,
|
||||
[{'mac_address': '52:54:00:f9:b8:f9',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'resume': False},
|
||||
{'mac_address': '52:54:00:ab:64:42',
|
||||
'snapshot_name': 'foo_snap',
|
||||
'resume': False}])
|
||||
|
@ -66,10 +66,11 @@ class OSFaultsTestCase(test.TestCase):
|
||||
destructor = os_faults.connect(self.cloud_config)
|
||||
self.assertIsInstance(destructor, fuel.FuelManagement)
|
||||
self.assertIsInstance(destructor.node_discover, fuel.FuelManagement)
|
||||
self.assertIsInstance(destructor.power_management,
|
||||
self.assertEqual(1, len(destructor.power_manager.power_drivers))
|
||||
self.assertIsInstance(destructor.power_manager.power_drivers[0],
|
||||
libvirt_driver.LibvirtDriver)
|
||||
|
||||
def test_connect_fuel_with_ipmi_and_node_list(self):
|
||||
def test_connect_fuel_with_ipmi_libvirt_and_node_list(self):
|
||||
cloud_config = {
|
||||
'node_discover': {
|
||||
'driver': 'node_list',
|
||||
@ -91,24 +92,35 @@ class OSFaultsTestCase(test.TestCase):
|
||||
'username': 'root',
|
||||
},
|
||||
},
|
||||
'power_management': {
|
||||
'driver': 'ipmi',
|
||||
'args': {
|
||||
'mac_to_bmc': {
|
||||
'00:00:00:00:00:00': {
|
||||
'address': '55.55.55.55',
|
||||
'username': 'foo',
|
||||
'password': 'bar',
|
||||
'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.assertIsInstance(destructor.power_management, ipmi.IPMIDriver)
|
||||
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_driver.LibvirtDriver)
|
||||
|
||||
def test_connect_driver_not_found(self):
|
||||
cloud_config = {
|
||||
@ -132,7 +144,8 @@ class OSFaultsTestCase(test.TestCase):
|
||||
with mock.patch('os_faults.open', mock_os_faults_open, create=True):
|
||||
destructor = os_faults.connect()
|
||||
self.assertIsInstance(destructor, fuel.FuelManagement)
|
||||
self.assertIsInstance(destructor.power_management,
|
||||
self.assertEqual(1, len(destructor.power_manager.power_drivers))
|
||||
self.assertIsInstance(destructor.power_manager.power_drivers[0],
|
||||
libvirt_driver.LibvirtDriver)
|
||||
|
||||
@mock.patch.dict(os.environ, {'OS_FAULTS_CONFIG': '/my/conf.yaml'})
|
||||
@ -143,7 +156,8 @@ class OSFaultsTestCase(test.TestCase):
|
||||
with mock.patch('os_faults.open', mock_os_faults_open, create=True):
|
||||
destructor = os_faults.connect()
|
||||
self.assertIsInstance(destructor, fuel.FuelManagement)
|
||||
self.assertIsInstance(destructor.power_management,
|
||||
self.assertEqual(1, len(destructor.power_manager.power_drivers))
|
||||
self.assertIsInstance(destructor.power_manager.power_drivers[0],
|
||||
libvirt_driver.LibvirtDriver)
|
||||
mock_os_faults_open.assert_called_once_with('/my/conf.yaml')
|
||||
|
||||
|
@ -14,7 +14,6 @@ import threading
|
||||
|
||||
import mock
|
||||
|
||||
from os_faults.api import error
|
||||
from os_faults.tests.unit import test
|
||||
from os_faults import utils
|
||||
|
||||
@ -25,25 +24,12 @@ class MyException(Exception):
|
||||
|
||||
class UtilsTestCase(test.TestCase):
|
||||
|
||||
def test_run(self):
|
||||
target = mock.Mock()
|
||||
utils.run(target, [{'mac_address': '01'}, {'mac_address': '02'}])
|
||||
target.assert_has_calls([mock.call(mac_address='01'),
|
||||
mock.call(mac_address='02')], any_order=True)
|
||||
|
||||
def test_run_raise_exception(self):
|
||||
target = mock.Mock()
|
||||
target.side_effect = MyException()
|
||||
self.assertRaises(error.PowerManagementError,
|
||||
utils.run, target, [{'mac_address': '01'},
|
||||
{'mac_address': '02'}])
|
||||
|
||||
def test_start_thread(self):
|
||||
target = mock.Mock()
|
||||
target_params = {'param1': 'val1', 'param2': 'val2'}
|
||||
|
||||
tw = utils.ThreadsWrapper(target)
|
||||
tw.start_thread(**target_params)
|
||||
tw = utils.ThreadsWrapper()
|
||||
tw.start_thread(target, **target_params)
|
||||
tw.join_threads()
|
||||
|
||||
target.assert_has_calls([mock.call(param1='val1', param2='val2')])
|
||||
@ -54,18 +40,17 @@ class UtilsTestCase(test.TestCase):
|
||||
target = mock.Mock()
|
||||
target.side_effect = MyException()
|
||||
|
||||
tw = utils.ThreadsWrapper(target)
|
||||
tw.start_thread()
|
||||
tw = utils.ThreadsWrapper()
|
||||
tw.start_thread(target)
|
||||
tw.join_threads()
|
||||
|
||||
self.assertEqual(type(tw.errors[0]), MyException)
|
||||
|
||||
def test_join_threads(self):
|
||||
target = mock.Mock()
|
||||
thread_1 = mock.Mock()
|
||||
thread_2 = mock.Mock()
|
||||
|
||||
tw = utils.ThreadsWrapper(target)
|
||||
tw = utils.ThreadsWrapper()
|
||||
tw.threads = [thread_1, thread_2]
|
||||
tw.join_threads()
|
||||
|
||||
|
@ -15,40 +15,26 @@ import functools
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from os_faults.api import error
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MACADDR_REGEXP = '^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$'
|
||||
|
||||
|
||||
def run(target, kwargs_list):
|
||||
tw = ThreadsWrapper(target)
|
||||
for kwargs in kwargs_list:
|
||||
tw.start_thread(**kwargs)
|
||||
tw.join_threads()
|
||||
|
||||
if tw.errors:
|
||||
raise error.PowerManagementError(
|
||||
'There are some errors when working the driver. '
|
||||
'Please, check logs for more details.')
|
||||
|
||||
|
||||
class ThreadsWrapper(object):
|
||||
def __init__(self, target):
|
||||
self.target = target
|
||||
def __init__(self):
|
||||
self.threads = []
|
||||
self.errors = []
|
||||
|
||||
def _target(self, **kwargs):
|
||||
def _target(self, fn, **kwargs):
|
||||
try:
|
||||
self.target(**kwargs)
|
||||
fn(**kwargs)
|
||||
except Exception as exc:
|
||||
LOG.error('Target raised exception: %s', exc)
|
||||
LOG.error('%s raised exception: %s', fn, exc)
|
||||
self.errors.append(exc)
|
||||
|
||||
def start_thread(self, **kwargs):
|
||||
thread = threading.Thread(target=self._target, kwargs=kwargs)
|
||||
def start_thread(self, fn, **kwargs):
|
||||
thread = threading.Thread(target=self._target,
|
||||
args=(fn, ), kwargs=kwargs)
|
||||
thread.start()
|
||||
self.threads.append(thread)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user