diff options
author | Naohiro Tamura <naohirot@jp.fujitsu.com> | 2016-03-19 19:06:01 +0900 |
---|---|---|
committer | Naohiro Tamura <naohirot@jp.fujitsu.com> | 2016-04-13 14:25:49 +0900 |
commit | d18e2f36dd54616db8d853b340d564a5ca96749d (patch) | |
tree | fae12fa1cfdb4e94a1cb1c0e805a7cf347adf670 | |
parent | 4c7b1f9a426f5017b7bc4f9c2fdd6ac3800e3551 (diff) | |
download | ironic-d18e2f36dd54616db8d853b340d564a5ca96749d.tar.gz |
Force iRMC vmedia boot from remotely connected CD/DVD
This patch forces iRMC vmedia boot from remotely connected
(redirected) CD/DVD using 'ipmitool raw' command instead of 'ipmitool
chassis bootdev cdrom'.
Closes-Bug: #1561852
Change-Id: I606e4d3a630ddc4eed071773afcb5274ee64a439
(cherry picked from commit 03fe93abfe5779f27c0eee5495f189e0104a5184)
3 files changed, 153 insertions, 78 deletions
diff --git a/ironic/drivers/modules/irmc/management.py b/ironic/drivers/modules/irmc/management.py index 077ebf7e5..c46cfd10c 100644 --- a/ironic/drivers/modules/irmc/management.py +++ b/ironic/drivers/modules/irmc/management.py @@ -35,7 +35,12 @@ LOG = logging.getLogger(__name__) # Set/Get System Boot Options Command, IPMI spec v2.0. _BOOTPARAM5_DATA2 = {boot_devices.PXE: '0x04', boot_devices.DISK: '0x08', - boot_devices.CDROM: '0x14', + # note (naohirot) + # boot_devices.CDROM is tentatively set to '0x20' rather + # than '0x14' as a work-around to force iRMC vmedia boot. + # 0x14 = Force boot from default CD/DVD + # 0x20 = Force boot from remotely connected CD/DVD + boot_devices.CDROM: '0x20', boot_devices.BIOS: '0x18', boot_devices.SAFE: '0x0c', } @@ -141,33 +146,37 @@ class IRMCManagement(ipmitool.IPMIManagement): :raises: IPMIFailure on an error from ipmitool. """ - if driver_utils.get_node_capability(task.node, 'boot_mode') == 'uefi': - if device not in self.get_supported_boot_devices(task): - raise exception.InvalidParameterValue(_( - "Invalid boot device %s specified.") % device) - timeout_disable = "0x00 0x08 0x03 0x08" - ipmitool.send_raw(task, timeout_disable) - - # note(naohirot): As of ipmitool version 1.8.13, - # in case of chassis command, the efiboot option doesn't - # get set with persistent at the same time. - # $ ipmitool chassis bootdev pxe options=efiboot,persistent - # In case of raw command, however, both can be set at the - # same time. - # $ ipmitool raw 0x00 0x08 0x05 0xe0 0x04 0x00 0x00 0x00 - # data1^^ ^^data2 - # ipmi cmd '0x08' : Set System Boot Options - # data1 '0xe0' : persistent and uefi - # data1 '0xa0' : next boot only and uefi - # - data1 = '0xe0' if persistent else '0xa0' - bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00' - cmd08 = bootparam5 % (data1, _BOOTPARAM5_DATA2[device]) - ipmitool.send_raw(task, cmd08) - + if device not in self.get_supported_boot_devices(task): + raise exception.InvalidParameterValue(_( + "Invalid boot device %s specified.") % device) + + uefi_mode = ( + driver_utils.get_node_capability(task.node, 'boot_mode') == 'uefi') + + # disable 60 secs timer + timeout_disable = "0x00 0x08 0x03 0x08" + ipmitool.send_raw(task, timeout_disable) + + # note(naohirot): + # Set System Boot Options : ipmi cmd '0x08', bootparam '0x05' + # + # $ ipmitool raw 0x00 0x08 0x05 data1 data2 0x00 0x00 0x00 + # + # data1 : '0xe0' persistent + uefi + # '0xc0' persistent + bios + # '0xa0' next only + uefi + # '0x80' next only + bios + # data2 : boot device defined in the dict _BOOTPARAM5_DATA2 + + bootparam5 = '0x00 0x08 0x05 %s %s 0x00 0x00 0x00' + if persistent: + data1 = '0xe0' if uefi_mode else '0xc0' else: - super(IRMCManagement, self).set_boot_device( - task, device, persistent) + data1 = '0xa0' if uefi_mode else '0x80' + data2 = _BOOTPARAM5_DATA2[device] + + cmd8 = bootparam5 % (data1, data2) + ipmitool.send_raw(task, cmd8) def get_sensors_data(self, task): """Get sensors data method. diff --git a/ironic/tests/unit/drivers/modules/irmc/test_management.py b/ironic/tests/unit/drivers/modules/irmc/test_management.py index 687ea1f54..fb75b394f 100644 --- a/ironic/tests/unit/drivers/modules/irmc/test_management.py +++ b/ironic/tests/unit/drivers/modules/irmc/test_management.py @@ -86,108 +86,169 @@ class IRMCManagementTestCase(db_base.DbTestCase): self.assertEqual(sorted(expected), sorted(task.driver.management. get_supported_boot_devices(task))) - @mock.patch.object(ipmitool.IPMIManagement, 'set_boot_device', - spec_set=True, autospec=True) - def test_management_interface_set_boot_device_no_mode_ok( - self, - set_boot_device_mock): - """no boot mode specified.""" - with task_manager.acquire(self.context, self.node.uuid, - shared=False) as task: - task.driver.management.set_boot_device(task, boot_devices.PXE) - set_boot_device_mock.assert_called_once_with( - task.driver.management, task, - boot_devices.PXE, - False) - - @mock.patch.object(ipmitool.IPMIManagement, 'set_boot_device', - spec_set=True, autospec=True) - def test_management_interface_set_boot_device_bios_ok( - self, - set_boot_device_mock): - """bios mode specified.""" - with task_manager.acquire(self.context, self.node.uuid) as task: - driver_utils.add_node_capability(task, 'boot_mode', 'bios') - task.driver.management.set_boot_device(task, boot_devices.PXE) - set_boot_device_mock.assert_called_once_with( - task.driver.management, task, - boot_devices.PXE, - False) - @mock.patch.object(irmc_management.ipmitool, "send_raw", spec_set=True, autospec=True) - def _test_management_interface_set_boot_device_uefi_ok(self, params, - expected_raw_code, - send_raw_mock): + def _test_management_interface_set_boot_device_ok( + self, boot_mode, params, expected_raw_code, send_raw_mock): send_raw_mock.return_value = [None, None] with task_manager.acquire(self.context, self.node.uuid) as task: task.node.properties['capabilities'] = '' - driver_utils.add_node_capability(task, 'boot_mode', 'uefi') + if boot_mode: + driver_utils.add_node_capability(task, 'boot_mode', boot_mode) self.driver.management.set_boot_device(task, **params) send_raw_mock.assert_has_calls([ mock.call(task, "0x00 0x08 0x03 0x08"), mock.call(task, expected_raw_code)]) - def test_management_interface_set_boot_device_uefi_ok_pxe(self): + def test_management_interface_set_boot_device_ok_pxe(self): params = {'device': boot_devices.PXE, 'persistent': False} - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0x80 0x04 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0x80 0x04 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xa0 0x04 0x00 0x00 0x00") params['persistent'] = True - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0xc0 0x04 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0xc0 0x04 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xe0 0x04 0x00 0x00 0x00") - def test_management_interface_set_boot_device_uefi_ok_disk(self): + def test_management_interface_set_boot_device_ok_disk(self): params = {'device': boot_devices.DISK, 'persistent': False} - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0x80 0x08 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0x80 0x08 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xa0 0x08 0x00 0x00 0x00") params['persistent'] = True - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0xc0 0x08 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0xc0 0x08 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xe0 0x08 0x00 0x00 0x00") - def test_management_interface_set_boot_device_uefi_ok_cdrom(self): + def test_management_interface_set_boot_device_ok_cdrom(self): params = {'device': boot_devices.CDROM, 'persistent': False} - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0x80 0x20 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0x80 0x20 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, - "0x00 0x08 0x05 0xa0 0x14 0x00 0x00 0x00") + "0x00 0x08 0x05 0xa0 0x20 0x00 0x00 0x00") params['persistent'] = True - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, params, - "0x00 0x08 0x05 0xe0 0x14 0x00 0x00 0x00") + "0x00 0x08 0x05 0xc0 0x20 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0xc0 0x20 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', + params, + "0x00 0x08 0x05 0xe0 0x20 0x00 0x00 0x00") - def test_management_interface_set_boot_device_uefi_ok_bios(self): + def test_management_interface_set_boot_device_ok_bios(self): params = {'device': boot_devices.BIOS, 'persistent': False} - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0x80 0x18 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0x80 0x18 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xa0 0x18 0x00 0x00 0x00") params['persistent'] = True - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0xc0 0x18 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0xc0 0x18 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xe0 0x18 0x00 0x00 0x00") - def test_management_interface_set_boot_device_uefi_ok_safe(self): + def test_management_interface_set_boot_device_ok_safe(self): params = {'device': boot_devices.SAFE, 'persistent': False} - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0x80 0x0c 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0x80 0x0c 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xa0 0x0c 0x00 0x00 0x00") params['persistent'] = True - self._test_management_interface_set_boot_device_uefi_ok( + self._test_management_interface_set_boot_device_ok( + None, + params, + "0x00 0x08 0x05 0xc0 0x0c 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'bios', + params, + "0x00 0x08 0x05 0xc0 0x0c 0x00 0x00 0x00") + self._test_management_interface_set_boot_device_ok( + 'uefi', params, "0x00 0x08 0x05 0xe0 0x0c 0x00 0x00 0x00") @mock.patch.object(irmc_management.ipmitool, "send_raw", spec_set=True, autospec=True) - def test_management_interface_set_boot_device_uefi_ng(self, - send_raw_mock): + def test_management_interface_set_boot_device_ng(self, send_raw_mock): """uefi mode, next boot only, unknown device.""" send_raw_mock.return_value = [None, None] diff --git a/releasenotes/notes/update-irmc-set-boot-device-fd50d9dce42aaa89.yaml b/releasenotes/notes/update-irmc-set-boot-device-fd50d9dce42aaa89.yaml new file mode 100644 index 000000000..c758b7223 --- /dev/null +++ b/releasenotes/notes/update-irmc-set-boot-device-fd50d9dce42aaa89.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - This forces iRMC vmedia boot from remotely connected (redirected) + CD/DVD instead of default CD/DVD. See + https://bugs.launchpad.net/ironic/+bug/1561852 for details. |