return power state ERROR instead of an exception

iboot's _power_status() could raise an exception if it doesn't get the
expected response from the iboot command. A new IBootOperationError is raised
if the response isn't a list, and we return ERROR power state if the returned
list doesn't have the power status information.

Change-Id: I4b88c24a77a4f46464cf36224878b4e3205f646c
Partial-Bug: #1267693
This commit is contained in:
Ruby Loo 2014-08-19 14:10:34 +00:00
parent ab314d7040
commit 7c765279a4
3 changed files with 97 additions and 1 deletions

View File

@ -404,6 +404,10 @@ class PasswordFileFailedToCreate(IronicException):
message = _("Failed to create the password file. %(error)s")
class IBootOperationError(IronicException):
pass
class IloOperationError(IronicException):
message = _("%(operation)s failed, error: %(error)s")

View File

@ -22,6 +22,7 @@ Ironic iBoot PDU power manager.
from oslo.utils import importutils
from ironic.common import exception
from ironic.common import i18n
from ironic.common import states
from ironic.conductor import task_manager
from ironic.drivers import base
@ -29,6 +30,9 @@ from ironic.openstack.common import log as logging
iboot = importutils.try_import('iboot')
_LW = i18n._LW
LOG = logging.getLogger(__name__)
REQUIRED_PROPERTIES = {
@ -98,7 +102,23 @@ def _switch(driver_info, enabled):
def _power_status(driver_info):
conn = _get_connection(driver_info)
relay_id = driver_info['relay_id']
status = conn.get_relays()[relay_id - 1]
try:
response = conn.get_relays()
status = response[relay_id - 1]
except TypeError:
msg = (_("Cannot get power status for node '%(node)s'. iBoot "
"get_relays() returned '%(resp)s'.")
% {'node': driver_info['uuid'], 'resp': response})
LOG.error(msg)
raise exception.IBootOperationError(message=msg)
except IndexError:
LOG.warning(_LW("Cannot get power status for node '%(node)s' at relay "
"'%(relay)s'. iBoot get_relays() returned "
"'%(resp)s'."),
{'node': driver_info['uuid'], 'relay': relay_id,
'resp': response})
return states.ERROR
if status:
return states.POWER_ON
else:
@ -136,6 +156,7 @@ class IBootPower(base.PowerInterface):
:param task: a TaskManager instance containing the node to act on.
:returns: one of ironic.common.states POWER_OFF, POWER_ON or ERROR.
:raises: IBootOperationError on an error from iBoot.
:raises: InvalidParameterValue if iboot parameters are invalid.
:raises: MissingParameterValue if required iboot parameters are
missing.
@ -151,6 +172,7 @@ class IBootPower(base.PowerInterface):
:param task: a TaskManager instance containing the node to act on.
:param pstate: The desired power state, one of ironic.common.states
POWER_ON, POWER_OFF.
:raises: IBootOperationError on an error from iBoot.
:raises: InvalidParameterValue if iboot parameters are invalid or if
an invalid power state was specified.
:raises: MissingParameterValue if required iboot parameters are
@ -177,6 +199,7 @@ class IBootPower(base.PowerInterface):
"""Cycles the power to the task's node.
:param task: a TaskManager instance containing the node to act on.
:raises: IBootOperationError on an error from iBoot.
:raises: InvalidParameterValue if iboot parameters are invalid.
:raises: MissingParameterValue if required iboot parameters are
missing.

View File

@ -130,6 +130,75 @@ class IBootPrivateMethodTestCase(base.TestCase):
iboot._parse_driver_info,
node)
@mock.patch.object(iboot, '_get_connection')
def test__power_status_on(self, mock_get_conn):
mock_connection = mock.Mock()
mock_connection.get_relays.return_value = [True]
mock_get_conn.return_value = mock_connection
node = obj_utils.create_test_node(
self.context,
driver='fake_iboot',
driver_info=INFO_DICT)
info = iboot._parse_driver_info(node)
status = iboot._power_status(info)
self.assertEqual(states.POWER_ON, status)
mock_get_conn.assert_called_once_with(info)
mock_connection.get_relays.assert_called_once_with()
@mock.patch.object(iboot, '_get_connection')
def test__power_status_off(self, mock_get_conn):
mock_connection = mock.Mock()
mock_connection.get_relays.return_value = [False]
mock_get_conn.return_value = mock_connection
node = obj_utils.create_test_node(
self.context,
driver='fake_iboot',
driver_info=INFO_DICT)
info = iboot._parse_driver_info(node)
status = iboot._power_status(info)
self.assertEqual(states.POWER_OFF, status)
mock_get_conn.assert_called_once_with(info)
mock_connection.get_relays.assert_called_once_with()
@mock.patch.object(iboot, '_get_connection')
def test__power_status_exception(self, mock_get_conn):
mock_connection = mock.Mock()
mock_connection.get_relays.return_value = None
mock_get_conn.return_value = mock_connection
node = obj_utils.create_test_node(
self.context,
driver='fake_iboot',
driver_info=INFO_DICT)
info = iboot._parse_driver_info(node)
self.assertRaises(exception.IBootOperationError,
iboot._power_status,
info)
mock_get_conn.assert_called_once_with(info)
mock_connection.get_relays.assert_called_once_with()
@mock.patch.object(iboot, '_get_connection')
def test__power_status_error(self, mock_get_conn):
mock_connection = mock.Mock()
mock_connection.get_relays.return_value = list()
mock_get_conn.return_value = mock_connection
node = obj_utils.create_test_node(
self.context,
driver='fake_iboot',
driver_info=INFO_DICT)
info = iboot._parse_driver_info(node)
status = iboot._power_status(info)
self.assertEqual(states.ERROR, status)
mock_get_conn.assert_called_once_with(info)
mock_connection.get_relays.assert_called_once_with()
class IBootDriverTestCase(db_base.DbTestCase):