diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-07-18 10:08:02 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-07-18 10:08:02 +0000 |
commit | 40a188a01050faa6b12850018c55099674b8bc74 (patch) | |
tree | bb0b66c43719aabe5dbb08263946d4b23fb0bcc0 | |
parent | 95ee78f8898c3e0e82f13ed610a768c25fbd9704 (diff) | |
parent | ae8508194efbc3fa501e63460d695a9afa8130a6 (diff) | |
download | ironic-40a188a01050faa6b12850018c55099674b8bc74.tar.gz |
Merge "Add methods to ipmitool driver"
-rw-r--r-- | ironic/drivers/modules/ipmitool.py | 70 | ||||
-rw-r--r-- | ironic/tests/drivers/test_ipmitool.py | 115 |
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): |