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
This commit is contained in:
Naohiro Tamura 2016-03-19 19:06:01 +09:00
parent 8e81b964a5
commit 03fe93abfe
3 changed files with 151 additions and 76 deletions

View File

@ -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)
if device not in self.get_supported_boot_devices(task):
raise exception.InvalidParameterValue(_(
"Invalid boot device %s specified.") % device)
# 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)
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.

View File

@ -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 0xa0 0x14 0x00 0x00 0x00")
"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 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]

View File

@ -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.