summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-07-18 10:08:02 +0000
committerGerrit Code Review <review@openstack.org>2014-07-18 10:08:02 +0000
commit40a188a01050faa6b12850018c55099674b8bc74 (patch)
treebb0b66c43719aabe5dbb08263946d4b23fb0bcc0
parent95ee78f8898c3e0e82f13ed610a768c25fbd9704 (diff)
parentae8508194efbc3fa501e63460d695a9afa8130a6 (diff)
downloadironic-40a188a01050faa6b12850018c55099674b8bc74.tar.gz
Merge "Add methods to ipmitool driver"
-rw-r--r--ironic/drivers/modules/ipmitool.py70
-rw-r--r--ironic/tests/drivers/test_ipmitool.py115
2 files changed, 185 insertions, 0 deletions
diff --git a/ironic/drivers/modules/ipmitool.py b/ironic/drivers/modules/ipmitool.py
index 915bb0edb..1cf17afd8 100644
--- a/ironic/drivers/modules/ipmitool.py
+++ b/ironic/drivers/modules/ipmitool.py
@@ -460,6 +460,62 @@ class VendorPassthru(base.VendorInterface):
except Exception:
raise exception.IPMIFailure(cmd=cmd)
+ @task_manager.require_exclusive_lock
+ def _send_raw_bytes(self, task, raw_bytes):
+ """Send raw bytes to the BMC. Bytes should be a string of bytes.
+
+ :param task: a TaskManager instance.
+ :param raw_bytes: a string of raw bytes to send, e.g. '0x00 0x01'
+ :raises: IPMIFailure on an error from ipmitool.
+
+ """
+ node_uuid = task.node.uuid
+ LOG.debug('Sending node %(node)s raw bytes %(bytes)s',
+ {'bytes': raw_bytes, 'node': node_uuid})
+ driver_info = _parse_driver_info(task.node)
+ cmd = 'raw %s' % raw_bytes
+
+ try:
+ out, err = _exec_ipmitool(driver_info, cmd)
+ LOG.debug('send raw bytes returned stdout: %(stdout)s, stderr:'
+ ' %(stderr)s', {'stdout': out, 'stderr': err})
+ except Exception as e:
+ LOG.exception(_('IPMI "raw bytes" failed for node %(node_id)s '
+ 'with error: %(error)s.'),
+ {'node_id': node_uuid, 'error': e})
+ raise exception.IPMIFailure(cmd=cmd)
+
+ @task_manager.require_exclusive_lock
+ def _bmc_reset(self, task, warm=True):
+ """Reset BMC with IPMI command 'bmc reset (warm|cold)'.
+
+ :param task: a TaskManager instance.
+ :param warm: boolean parameter to decide on warm or cold reset.
+ :raises: IPMIFailure on an error from ipmitool.
+
+ """
+ node_uuid = task.node.uuid
+
+ if warm:
+ warm_param = 'warm'
+ else:
+ warm_param = 'cold'
+
+ LOG.debug('Doing %(warm)s BMC reset on node %(node)s',
+ {'warm': warm_param, 'node': node_uuid})
+ driver_info = _parse_driver_info(task.node)
+ cmd = 'bmc reset %s' % warm_param
+
+ try:
+ out, err = _exec_ipmitool(driver_info, cmd)
+ LOG.debug('bmc reset returned stdout: %(stdout)s, stderr:'
+ ' %(stderr)s', {'stdout': out, 'stderr': err})
+ except Exception as e:
+ LOG.exception(_('IPMI "bmc reset" failed for node %(node_id)s '
+ 'with error: %(error)s.'),
+ {'node_id': node_uuid, 'error': e})
+ raise exception.IPMIFailure(cmd=cmd)
+
def validate(self, task, **kwargs):
method = kwargs['method']
if method == 'set_boot_device':
@@ -467,6 +523,14 @@ class VendorPassthru(base.VendorInterface):
if device not in VALID_BOOT_DEVICES:
raise exception.InvalidParameterValue(_(
"Invalid boot device %s specified.") % device)
+ elif method == 'send_raw':
+ if not kwargs.get('raw_bytes'):
+ raise exception.InvalidParameterValue(_(
+ 'Parameter raw_bytes (string of bytes) was not '
+ 'specified.'))
+ elif method == 'bmc_reset':
+ # no additional parameters needed
+ pass
else:
raise exception.InvalidParameterValue(_(
"Unsupported method (%s) passed to IPMItool driver.")
@@ -480,6 +544,12 @@ class VendorPassthru(base.VendorInterface):
task,
kwargs.get('device'),
kwargs.get('persistent', False))
+ elif method == 'send_raw':
+ return self._send_raw_bytes(task,
+ kwargs.get('raw_bytes'))
+ elif method == 'bmc_reset':
+ return self._bmc_reset(task,
+ warm=kwargs.get('warm', True))
class IPMIShellinaboxConsole(base.ConsoleInterface):
diff --git a/ironic/tests/drivers/test_ipmitool.py b/ironic/tests/drivers/test_ipmitool.py
index a668002ad..ae69218a4 100644
--- a/ironic/tests/drivers/test_ipmitool.py
+++ b/ironic/tests/drivers/test_ipmitool.py
@@ -583,6 +583,57 @@ class IPMIToolDriverTestCase(db_base.DbTestCase):
task,
'fake-device')
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test__send_raw_bytes_ok(self, mock_exec):
+ mock_exec.return_value = [None, None]
+
+ with task_manager.acquire(self.context,
+ self.node['uuid']) as task:
+ self.driver.vendor._send_raw_bytes(task, '0x00 0x01')
+
+ mock_exec.assert_called_once_with(self.info, 'raw 0x00 0x01')
+
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test__send_raw_bytes_fail(self, mock_exec):
+ mock_exec.side_effect = Exception
+
+ with task_manager.acquire(self.context,
+ self.node['uuid']) as task:
+ self.assertRaises(exception.IPMIFailure,
+ self.driver.vendor._send_raw_bytes,
+ task,
+ '0x00 0x01')
+
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test__bmc_reset_ok(self, mock_exec):
+ mock_exec.return_value = [None, None]
+
+ with task_manager.acquire(self.context,
+ self.node['uuid']) as task:
+ self.driver.vendor._bmc_reset(task)
+
+ mock_exec.assert_called_once_with(self.info, 'bmc reset warm')
+
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test__bmc_reset_cold(self, mock_exec):
+ mock_exec.return_value = [None, None]
+
+ with task_manager.acquire(self.context,
+ self.node['uuid']) as task:
+ self.driver.vendor._bmc_reset(task, warm=False)
+
+ mock_exec.assert_called_once_with(self.info, 'bmc reset cold')
+
+ @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
+ def test__bmc_reset_fail(self, mock_exec):
+ mock_exec.side_effect = Exception
+
+ with task_manager.acquire(self.context,
+ self.node['uuid']) as task:
+ self.assertRaises(exception.IPMIFailure,
+ self.driver.vendor._bmc_reset,
+ task)
+
@mock.patch.object(ipmi, '_power_off', autospec=False)
@mock.patch.object(ipmi, '_power_on', autospec=False)
def test_reboot_ok(self, mock_on, mock_off):
@@ -671,6 +722,70 @@ class IPMIToolDriverTestCase(db_base.DbTestCase):
device='pxe')
boot_mock.assert_called_once_with(task, 'pxe', False)
+ def test_vendor_passthru_validate__send_raw_bytes_good(self):
+ with task_manager.acquire(self.context, self.node['uuid']) as task:
+ self.driver.vendor.validate(task,
+ method='send_raw',
+ raw_bytes='0x00 0x01')
+
+ def test_vendor_passthru_validate__send_raw_bytes_fail(self):
+ with task_manager.acquire(self.context, self.node['uuid']) as task:
+ self.assertRaises(exception.InvalidParameterValue,
+ self.driver.vendor.validate,
+ task, method='send_raw')
+
+ @mock.patch.object(ipmi.VendorPassthru, '_send_raw_bytes')
+ def test_vendor_passthru_call_send_raw_bytes(self, raw_bytes_mock):
+ with task_manager.acquire(self.context, self.node['uuid'],
+ shared=False) as task:
+ self.driver.vendor.vendor_passthru(task,
+ method='send_raw',
+ raw_bytes='0x00 0x01')
+ raw_bytes_mock.assert_called_once_with(task, '0x00 0x01')
+
+ def test_vendor_passthru_validate__bmc_reset_good(self):
+ with task_manager.acquire(self.context, self.node['uuid']) as task:
+ self.driver.vendor.validate(task,
+ method='bmc_reset')
+
+ def test_vendor_passthru_validate__bmc_reset_warm_good(self):
+ with task_manager.acquire(self.context, self.node['uuid']) as task:
+ self.driver.vendor.validate(task,
+ method='bmc_reset',
+ warm=True)
+
+ def test_vendor_passthru_validate__bmc_reset_cold_good(self):
+ with task_manager.acquire(self.context, self.node['uuid']) as task:
+ self.driver.vendor.validate(task,
+ method='bmc_reset',
+ warm=False)
+
+ @mock.patch.object(ipmi.VendorPassthru, '_bmc_reset')
+ def test_vendor_passthru_call_bmc_reset(self, bmc_mock):
+ with task_manager.acquire(self.context, self.node['uuid'],
+ shared=False) as task:
+ self.driver.vendor.vendor_passthru(task,
+ method='bmc_reset')
+ bmc_mock.assert_called_once_with(task, warm=True)
+
+ @mock.patch.object(ipmi.VendorPassthru, '_bmc_reset')
+ def test_vendor_passthru_call_bmc_reset_warm(self, bmc_mock):
+ with task_manager.acquire(self.context, self.node['uuid'],
+ shared=False) as task:
+ self.driver.vendor.vendor_passthru(task,
+ method='bmc_reset',
+ warm=True)
+ bmc_mock.assert_called_once_with(task, warm=True)
+
+ @mock.patch.object(ipmi.VendorPassthru, '_bmc_reset')
+ def test_vendor_passthru_call_bmc_reset_cold(self, bmc_mock):
+ with task_manager.acquire(self.context, self.node['uuid'],
+ shared=False) as task:
+ self.driver.vendor.vendor_passthru(task,
+ method='bmc_reset',
+ warm=False)
+ bmc_mock.assert_called_once_with(task, warm=False)
+
@mock.patch.object(console_utils, 'start_shellinabox_console',
autospec=True)
def test_start_console(self, mock_exec):