Merge "Implement the SeaMicro Power driver"
This commit is contained in:
commit
cc62836787
@ -868,6 +868,20 @@
|
||||
#topics=notifications
|
||||
|
||||
|
||||
[seamicro]
|
||||
|
||||
#
|
||||
# Options defined in ironic.drivers.modules.seamicro
|
||||
#
|
||||
|
||||
# Maximum retries for SeaMicro operations (integer value)
|
||||
#max_retry=3
|
||||
|
||||
# Seconds to wait for power action to be completed (integer
|
||||
# value)
|
||||
#action_timeout=10
|
||||
|
||||
|
||||
[ssh]
|
||||
|
||||
#
|
||||
|
@ -22,6 +22,7 @@ from ironic.drivers.modules import fake
|
||||
from ironic.drivers.modules import ipminative
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.drivers.modules import pxe
|
||||
from ironic.drivers.modules import seamicro
|
||||
from ironic.drivers.modules import ssh
|
||||
|
||||
|
||||
@ -72,3 +73,15 @@ class FakeIPMINativeDriver(base.BaseDriver):
|
||||
self.power = ipminative.NativeIPMIPower()
|
||||
self.deploy = fake.FakeDeploy()
|
||||
self.vendor = ipminative.VendorPassthru()
|
||||
|
||||
|
||||
class FakeSeaMicroDriver(base.BaseDriver):
|
||||
"""Fake SeaMicro driver."""
|
||||
|
||||
def __init__(self):
|
||||
self.power = seamicro.Power()
|
||||
self.deploy = fake.FakeDeploy()
|
||||
self.rescue = self.deploy
|
||||
a = fake.FakeVendorA()
|
||||
b = fake.FakeVendorB()
|
||||
self.vendor = fake.MultipleVendorInterface(a, b)
|
||||
|
309
ironic/drivers/modules/seamicro.py
Normal file
309
ironic/drivers/modules/seamicro.py
Normal file
@ -0,0 +1,309 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Ironic SeaMicro interfaces.
|
||||
|
||||
Provides basic power control of servers in SeaMicro chassis via
|
||||
python-seamicroclient.
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
from seamicroclient import client as seamicro_client
|
||||
from seamicroclient import exceptions as seamicro_client_exception
|
||||
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.drivers import base
|
||||
from ironic.openstack.common import log as logging
|
||||
from ironic.openstack.common import loopingcall
|
||||
|
||||
opts = [
|
||||
cfg.IntOpt('max_retry',
|
||||
default=3,
|
||||
help='Maximum retries for SeaMicro operations'),
|
||||
cfg.IntOpt('action_timeout',
|
||||
default=10,
|
||||
help='Seconds to wait for power action to be completed')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
opt_group = cfg.OptGroup(name='seamicro',
|
||||
title='Options for the seamicro power driver')
|
||||
CONF.register_group(opt_group)
|
||||
CONF.register_opts(opts, opt_group)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_client(*args, **kwargs):
|
||||
"""Creates the python-seamicro_client
|
||||
|
||||
:param kwargs: A dict of keyword arguments to be passed to the method,
|
||||
which should contain: 'username', 'password',
|
||||
'auth_url', 'api_version' parameters.
|
||||
:returns: SeaMicro API client.
|
||||
"""
|
||||
|
||||
cl_kwargs = {'username': kwargs['username'],
|
||||
'password': kwargs['password'],
|
||||
'auth_url': kwargs['api_endpoint']}
|
||||
return seamicro_client.Client(kwargs['api_version'], **cl_kwargs)
|
||||
|
||||
|
||||
def _parse_driver_info(node):
|
||||
"""Parses and creates seamicro driver info
|
||||
|
||||
:param node: An Ironic node object.
|
||||
:returns: SeaMicro driver info.
|
||||
"""
|
||||
|
||||
info = node.get('driver_info', {})
|
||||
api_endpoint = info.get('seamicro_api_endpoint', None)
|
||||
username = info.get('seamicro_username', None)
|
||||
password = info.get('seamicro_password', None)
|
||||
server_id = info.get('seamicro_server_id', None)
|
||||
api_version = info.get('seamicro_api_version', "2")
|
||||
|
||||
if not api_endpoint:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"SeaMicro driver requires api_endpoint be set"))
|
||||
|
||||
if not username or not password:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"SeaMicro driver requires both username and password be set"))
|
||||
|
||||
if not server_id:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"SeaMicro driver requires server_id be set"))
|
||||
|
||||
res = {'username': username,
|
||||
'password': password,
|
||||
'api_endpoint': api_endpoint,
|
||||
'server_id': server_id,
|
||||
'api_version': api_version,
|
||||
'uuid': node.get('uuid')}
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def _get_server(driver_info):
|
||||
"""Get server from server_id."""
|
||||
|
||||
s_client = _get_client(**driver_info)
|
||||
return s_client.servers.get(driver_info['server_id'])
|
||||
|
||||
|
||||
def _get_power_status(node):
|
||||
"""Get current power state of this node
|
||||
|
||||
:param node: Ironic node one of :class:`ironic.db.models.Node`
|
||||
:returns: Power state of the given node
|
||||
"""
|
||||
|
||||
seamicro_info = _parse_driver_info(node)
|
||||
try:
|
||||
server = _get_server(seamicro_info)
|
||||
if not hasattr(server, 'active') or server.active is None:
|
||||
return states.ERROR
|
||||
if not server.active:
|
||||
return states.POWER_OFF
|
||||
elif server.active:
|
||||
return states.POWER_ON
|
||||
|
||||
except seamicro_client_exception.NotFound:
|
||||
raise exception.NodeNotFound(node=seamicro_info['uuid'])
|
||||
except seamicro_client_exception.ClientException as ex:
|
||||
LOG.error(_("SeaMicro client exception %(msg)s for node %(uuid)s"),
|
||||
{'msg': ex.message, 'uuid': seamicro_info['uuid']})
|
||||
raise exception.ServiceUnavailable(message=ex.message)
|
||||
|
||||
|
||||
def _power_on(node, timeout=None):
|
||||
"""Power ON this node
|
||||
|
||||
:param node: An Ironic node object.
|
||||
:param timeout: Time in seconds to wait till power on is complete.
|
||||
:returns: Power state of the given node.
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = CONF.seamicro.action_timeout
|
||||
state = [None]
|
||||
retries = [0]
|
||||
seamicro_info = _parse_driver_info(node)
|
||||
server = _get_server(seamicro_info)
|
||||
|
||||
def _wait_for_power_on(state, retries):
|
||||
"""Called at an interval until the node is powered on."""
|
||||
|
||||
state[0] = _get_power_status(node)
|
||||
if state[0] == states.POWER_ON:
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
if retries[0] > CONF.seamicro.max_retry:
|
||||
state[0] = states.ERROR
|
||||
raise loopingcall.LoopingCallDone()
|
||||
try:
|
||||
retries[0] += 1
|
||||
server.power_on()
|
||||
except seamicro_client_exception.ClientException:
|
||||
LOG.warning(_("Power-on failed for node %s."),
|
||||
seamicro_info['uuid'])
|
||||
|
||||
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_on,
|
||||
state, retries)
|
||||
timer.start(interval=timeout).wait()
|
||||
return state[0]
|
||||
|
||||
|
||||
def _power_off(node, timeout=None):
|
||||
"""Power OFF this node
|
||||
|
||||
:param node: Ironic node one of :class:`ironic.db.models.Node`
|
||||
:param timeout: Time in seconds to wait till power off is compelete
|
||||
:returns: Power state of the given node
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = CONF.seamicro.action_timeout
|
||||
state = [None]
|
||||
retries = [0]
|
||||
seamicro_info = _parse_driver_info(node)
|
||||
server = _get_server(seamicro_info)
|
||||
|
||||
def _wait_for_power_off(state, retries):
|
||||
"""Called at an interval until the node is powered off."""
|
||||
|
||||
state[0] = _get_power_status(node)
|
||||
if state[0] == states.POWER_OFF:
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
if retries[0] > CONF.seamicro.max_retry:
|
||||
state[0] = states.ERROR
|
||||
raise loopingcall.LoopingCallDone()
|
||||
try:
|
||||
retries[0] += 1
|
||||
server.power_off()
|
||||
except seamicro_client_exception.ClientException:
|
||||
LOG.warning(_("Power-off failed for node %s."),
|
||||
seamicro_info['uuid'])
|
||||
|
||||
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_off,
|
||||
state, retries)
|
||||
timer.start(interval=timeout).wait()
|
||||
return state[0]
|
||||
|
||||
|
||||
def _reboot(node, timeout=None):
|
||||
"""Reboot this node
|
||||
:param node: Ironic node one of :class:`ironic.db.models.Node`
|
||||
:param timeout: Time in seconds to wait till reboot is compelete
|
||||
:returns: Power state of the given node
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = CONF.seamicro.action_timeout
|
||||
state = [None]
|
||||
retries = [0]
|
||||
seamicro_info = _parse_driver_info(node)
|
||||
server = _get_server(seamicro_info)
|
||||
|
||||
def _wait_for_reboot(state, retries):
|
||||
"""Called at an interval until the node is rebooted successfully."""
|
||||
|
||||
state[0] = _get_power_status(node)
|
||||
if state[0] == states.POWER_ON:
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
if retries[0] > CONF.seamicro.max_retry:
|
||||
state[0] = states.ERROR
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
try:
|
||||
retries[0] += 1
|
||||
server.reset()
|
||||
except seamicro_client_exception.ClientException:
|
||||
LOG.warning(_("Reboot failed for node %s."),
|
||||
seamicro_info['uuid'])
|
||||
|
||||
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_reboot,
|
||||
state, retries)
|
||||
server.reset()
|
||||
timer.start(interval=timeout).wait()
|
||||
return state[0]
|
||||
|
||||
|
||||
class Power(base.PowerInterface):
|
||||
"""SeaMicro Power Interface.
|
||||
|
||||
This PowerInterface class provides a mechanism for controlling the power
|
||||
state of servers in a seamicro chassis.
|
||||
"""
|
||||
|
||||
def validate(self, node):
|
||||
"""Check that node 'driver_info' is valid.
|
||||
|
||||
Check that node 'driver_info' contains the required fields.
|
||||
|
||||
:param node: Single node object.
|
||||
:raises: InvalidParameterValue
|
||||
"""
|
||||
_parse_driver_info(node)
|
||||
|
||||
def get_power_state(self, task, node):
|
||||
"""Get the current power state.
|
||||
|
||||
Poll the host for the current power state of the node.
|
||||
|
||||
:param task: A instance of `ironic.manager.task_manager.TaskManager`.
|
||||
:param node: A single node.
|
||||
|
||||
:returns: power state. One of :class:`ironic.common.states`.
|
||||
"""
|
||||
return _get_power_status(node)
|
||||
|
||||
@task_manager.require_exclusive_lock
|
||||
def set_power_state(self, task, node, pstate):
|
||||
"""Turn the power on or off.
|
||||
|
||||
Set the power state of a node.
|
||||
|
||||
:param task: A instance of `ironic.manager.task_manager.TaskManager`.
|
||||
:param node: A single node.
|
||||
:param pstate: Either POWER_ON or POWER_OFF from :class:
|
||||
`ironic.common.states`.
|
||||
"""
|
||||
|
||||
if pstate == states.POWER_ON:
|
||||
state = _power_on(node)
|
||||
elif pstate == states.POWER_OFF:
|
||||
state = _power_off(node)
|
||||
else:
|
||||
raise exception.IronicException(_(
|
||||
"set_power_state called with invalid power state."))
|
||||
|
||||
if state != pstate:
|
||||
raise exception.PowerStateFailure(pstate=pstate)
|
||||
|
||||
@task_manager.require_exclusive_lock
|
||||
def reboot(self, task, node):
|
||||
"""Cycles the power to a node.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:param node: An Ironic node object.
|
||||
|
||||
"""
|
||||
state = _reboot(node)
|
||||
|
||||
if state != states.POWER_ON:
|
||||
raise exception.PowerStateFailure(pstate=states.POWER_ON)
|
@ -21,6 +21,7 @@ from ironic.drivers import base
|
||||
from ironic.drivers.modules import ipminative
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.drivers.modules import pxe
|
||||
from ironic.drivers.modules import seamicro
|
||||
from ironic.drivers.modules import ssh
|
||||
|
||||
|
||||
@ -75,3 +76,21 @@ class PXEAndIPMINativeDriver(base.BaseDriver):
|
||||
self.deploy = pxe.PXEDeploy()
|
||||
self.rescue = self.deploy
|
||||
self.vendor = pxe.VendorPassthru()
|
||||
|
||||
|
||||
class PXEAndSeaMicroDriver(base.BaseDriver):
|
||||
"""PXE + SeaMicro driver.
|
||||
|
||||
This driver implements the `core` functionality, combining
|
||||
:class:ironic.drivers.modules.seamicro.Power for power
|
||||
on/off and reboot with
|
||||
:class:ironic.driver.modules.pxe.PXE for image deployment.
|
||||
Implementations are in those respective classes;
|
||||
this class is merely the glue between them.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.power = seamicro.Power()
|
||||
self.deploy = pxe.PXEDeploy()
|
||||
self.rescue = self.deploy
|
||||
self.vendor = pxe.VendorPassthru()
|
||||
|
@ -45,6 +45,15 @@ def get_test_pxe_info():
|
||||
}
|
||||
|
||||
|
||||
def get_test_seamicro_info():
|
||||
return {
|
||||
"seamicro_api_endpoint": "http://1.2.3.4",
|
||||
"seamicro_username": "admin",
|
||||
"seamicro_password": "fake",
|
||||
"seamicro_server_id": "0/0",
|
||||
}
|
||||
|
||||
|
||||
def get_test_node(**kw):
|
||||
properties = {
|
||||
"cpu_arch": "x86_64",
|
||||
|
269
ironic/tests/drivers/test_seamicro.py
Normal file
269
ironic/tests/drivers/test_seamicro.py
Normal file
@ -0,0 +1,269 @@
|
||||
# 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.
|
||||
|
||||
"""Test class for Ironic SeaMicro driver."""
|
||||
|
||||
import mock
|
||||
|
||||
from ironic.common import driver_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.db import api as dbapi
|
||||
from ironic.drivers.modules import seamicro
|
||||
from ironic.tests import base
|
||||
from ironic.tests.conductor import utils as mgr_utils
|
||||
from ironic.tests.db import base as db_base
|
||||
from ironic.tests.db import utils as db_utils
|
||||
|
||||
INFO_DICT = db_utils.get_test_seamicro_info()
|
||||
|
||||
|
||||
class Fake_Server():
|
||||
def __init__(self, active=False, *args, **kwargs):
|
||||
self.active = active
|
||||
|
||||
def power_on(self):
|
||||
self.active = True
|
||||
|
||||
def power_off(self, force=False):
|
||||
self.active = False
|
||||
|
||||
def reset(self):
|
||||
self.active = True
|
||||
|
||||
|
||||
class SeaMicroValidateParametersTestCase(base.TestCase):
|
||||
|
||||
def test__parse_driver_info_good(self):
|
||||
# make sure we get back the expected things
|
||||
node = db_utils.get_test_node(driver='fake_seamicro',
|
||||
driver_info=INFO_DICT)
|
||||
info = seamicro._parse_driver_info(node)
|
||||
self.assertIsNotNone(info.get('api_endpoint'))
|
||||
self.assertIsNotNone(info.get('username'))
|
||||
self.assertIsNotNone(info.get('password'))
|
||||
self.assertIsNotNone(info.get('server_id'))
|
||||
self.assertIsNotNone(info.get('uuid'))
|
||||
|
||||
def test__parse_driver_info_missing_api_endpoint(self):
|
||||
# make sure error is raised when info is missing
|
||||
info = dict(INFO_DICT)
|
||||
del info['seamicro_api_endpoint']
|
||||
node = db_utils.get_test_node(driver_info=info)
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
seamicro._parse_driver_info,
|
||||
node)
|
||||
|
||||
def test__parse_driver_info_missing_username(self):
|
||||
# make sure error is raised when info is missing
|
||||
info = dict(INFO_DICT)
|
||||
del info['seamicro_username']
|
||||
node = db_utils.get_test_node(driver_info=info)
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
seamicro._parse_driver_info,
|
||||
node)
|
||||
|
||||
def test__parse_driver_info_missing_password(self):
|
||||
# make sure error is raised when info is missing
|
||||
info = dict(INFO_DICT)
|
||||
del info['seamicro_password']
|
||||
node = db_utils.get_test_node(driver_info=info)
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
seamicro._parse_driver_info,
|
||||
node)
|
||||
|
||||
def test__parse_driver_info_missing_server_id(self):
|
||||
# make sure error is raised when info is missing
|
||||
info = dict(INFO_DICT)
|
||||
del info['seamicro_server_id']
|
||||
node = db_utils.get_test_node(driver_info=info)
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
seamicro._parse_driver_info,
|
||||
node)
|
||||
|
||||
|
||||
class SeaMicroPrivateMethodsTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SeaMicroPrivateMethodsTestCase, self).setUp()
|
||||
self.node = db_utils.get_test_node(driver='fake_seamicro',
|
||||
driver_info=INFO_DICT)
|
||||
|
||||
self.Server = Fake_Server
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__get_power_status_on(self, mock_get_server):
|
||||
mock_get_server.return_value = self.Server(active=True)
|
||||
pstate = seamicro._get_power_status(self.node)
|
||||
self.assertEqual(states.POWER_ON, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__get_power_status_off(self, mock_get_server):
|
||||
mock_get_server.return_value = self.Server(active=False)
|
||||
pstate = seamicro._get_power_status(self.node)
|
||||
self.assertEqual(states.POWER_OFF, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__get_power_status_error(self, mock_get_server):
|
||||
mock_get_server.return_value = self.Server(active=None)
|
||||
pstate = seamicro._get_power_status(self.node)
|
||||
self.assertEqual(states.ERROR, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__power_on_good(self, mock_get_server):
|
||||
mock_get_server.return_value = self.Server(active=False)
|
||||
pstate = seamicro._power_on(self.node, timeout=2)
|
||||
self.assertEqual(states.POWER_ON, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__power_on_fail(self, mock_get_server):
|
||||
def fake_power_on():
|
||||
return
|
||||
|
||||
server = self.Server(active=False)
|
||||
server.power_on = fake_power_on
|
||||
mock_get_server.return_value = server
|
||||
pstate = seamicro._power_on(self.node, timeout=2)
|
||||
self.assertEqual(states.ERROR, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__power_off_good(self, mock_get_server):
|
||||
mock_get_server.return_value = self.Server(active=True)
|
||||
pstate = seamicro._power_off(self.node, timeout=2)
|
||||
self.assertEqual(states.POWER_OFF, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__power_off_fail(self, mock_get_server):
|
||||
def fake_power_off():
|
||||
return
|
||||
server = self.Server(active=True)
|
||||
server.power_off = fake_power_off
|
||||
mock_get_server.return_value = server
|
||||
pstate = seamicro._power_off(self.node, timeout=2)
|
||||
self.assertEqual(states.ERROR, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__reboot_good(self, mock_get_server):
|
||||
mock_get_server.return_value = self.Server(active=True)
|
||||
pstate = seamicro._reboot(self.node, timeout=2)
|
||||
self.assertEqual(states.POWER_ON, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__reboot_fail(self, mock_get_server):
|
||||
def fake_reboot():
|
||||
return
|
||||
server = self.Server(active=False)
|
||||
server.reset = fake_reboot
|
||||
mock_get_server.return_value = server
|
||||
pstate = seamicro._reboot(self.node, timeout=2)
|
||||
self.assertEqual(states.ERROR, pstate)
|
||||
|
||||
|
||||
class SeaMicroPowerDriverTestCase(db_base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SeaMicroPowerDriverTestCase, self).setUp()
|
||||
mgr_utils.mock_the_extension_manager(driver='fake_seamicro')
|
||||
self.driver = driver_factory.get_driver('fake_seamicro')
|
||||
self.node = db_utils.get_test_node(driver='fake_seamicro',
|
||||
driver_info=INFO_DICT)
|
||||
self.dbapi = dbapi.get_instance()
|
||||
self.dbapi.create_node(self.node)
|
||||
self.parse_drv_info_patcher = mock.patch.object(seamicro,
|
||||
'_parse_driver_info')
|
||||
self.parse_drv_info_mock = None
|
||||
self.get_server_patcher = mock.patch.object(seamicro, '_get_server')
|
||||
|
||||
self.get_server_mock = None
|
||||
self.Server = Fake_Server
|
||||
|
||||
@mock.patch.object(seamicro, '_reboot')
|
||||
def test_reboot(self, mock_reboot):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
|
||||
mock_reboot.return_value = states.POWER_ON
|
||||
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
task.resources[0].driver.power.reboot(task, self.node)
|
||||
|
||||
mock_reboot.assert_called_once_with(self.node)
|
||||
|
||||
def test_set_power_state_bad_state(self):
|
||||
info = seamicro ._parse_driver_info(self.node)
|
||||
self.get_server_mock = self.get_server_patcher.start()
|
||||
self.get_server_mock.return_value = self.Server()
|
||||
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
self.assertRaises(exception.IronicException,
|
||||
task.resources[0].driver.power.set_power_state,
|
||||
task, self.node, "BAD_PSTATE")
|
||||
self.get_server_patcher.stop()
|
||||
|
||||
@mock.patch.object(seamicro, '_power_on')
|
||||
def test_set_power_state_on_good(self, mock_power_on):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
|
||||
mock_power_on.return_value = states.POWER_ON
|
||||
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
task.resources[0].driver.power.set_power_state(task,
|
||||
self.node,
|
||||
states.POWER_ON)
|
||||
|
||||
mock_power_on.assert_called_once_with(self.node)
|
||||
|
||||
@mock.patch.object(seamicro, '_power_on')
|
||||
def test_set_power_state_on_fail(self, mock_power_on):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
|
||||
mock_power_on.return_value = states.POWER_OFF
|
||||
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
self.assertRaises(exception.PowerStateFailure,
|
||||
task.resources[0]
|
||||
.driver.power.set_power_state,
|
||||
task, self.node, states.POWER_ON)
|
||||
|
||||
mock_power_on.assert_called_once_with(self.node)
|
||||
|
||||
@mock.patch.object(seamicro, '_power_off')
|
||||
def test_set_power_state_off_good(self, mock_power_off):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
|
||||
mock_power_off.return_value = states.POWER_OFF
|
||||
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
task.resources[0].driver.power.\
|
||||
set_power_state(task, self.node, states.POWER_OFF)
|
||||
|
||||
mock_power_off.assert_called_once_with(self.node)
|
||||
|
||||
@mock.patch.object(seamicro, '_power_off')
|
||||
def test_set_power_state_off_fail(self, mock_power_off):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
|
||||
mock_power_off.return_value = states.POWER_ON
|
||||
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
self.assertRaises(exception.PowerStateFailure,
|
||||
task.resources[0]
|
||||
.driver.power.set_power_state,
|
||||
task, self.node, states.POWER_OFF)
|
||||
|
||||
mock_power_off.assert_called_once_with(self.node)
|
@ -28,3 +28,4 @@ jsonpatch>=1.1
|
||||
WSME>=0.6
|
||||
Jinja2
|
||||
pyghmi>=0.5.8
|
||||
python-seamicroclient>=0.1.0,<2.0
|
||||
|
@ -35,9 +35,11 @@ ironic.drivers =
|
||||
fake_ipminative = ironic.drivers.fake:FakeIPMINativeDriver
|
||||
fake_ssh = ironic.drivers.fake:FakeSSHDriver
|
||||
fake_pxe = ironic.drivers.fake:FakePXEDriver
|
||||
fake_seamicro = ironic.drivers.fake:FakeSeaMicroDriver
|
||||
pxe_ipmitool = ironic.drivers.pxe:PXEAndIPMIToolDriver
|
||||
pxe_ipminative = ironic.drivers.pxe:PXEAndIPMINativeDriver
|
||||
pxe_ssh = ironic.drivers.pxe:PXEAndSSHDriver
|
||||
pxe_seamicro = ironic.drivers.pxe:PXEAndSeaMicroDriver
|
||||
|
||||
[pbr]
|
||||
autodoc_index_modules = True
|
||||
|
Loading…
x
Reference in New Issue
Block a user