Prevent redfish-virtual-media from being used with Dell nodes

Indicate that idrac-redfish-virtual-media must be used instead,
otherwise a confusing failure will happen.

Change-Id: I3b6ced6dcf03580903f5ea7237fc057f372999f9
This commit is contained in:
Dmitry Tantsur 2021-01-20 11:58:44 +01:00
parent f079531b98
commit cf22604c58
6 changed files with 103 additions and 1 deletions

View File

@ -178,6 +178,12 @@ BIOS boot mode, it suffice to set ironic boot interface to
baremetal node set --boot-interface redfish-virtual-media node-0
.. warning::
Dell hardware requires a non-standard Redfish call to boot from virtual
media, thus you **must** use the ``idrac`` hardware type and the
``idrac-redfish-virtual-media`` boot interface with it instead. See
:doc:`/admin/drivers/idrac` for more details on this hardware type.
If UEFI boot mode is desired, the user should additionally supply EFI
System Partition image (ESP_), see `Configuring an ESP image`_ for details.

View File

@ -70,6 +70,9 @@ class DracRedfishVirtualMediaBoot(redfish_boot.RedfishVirtualMediaBoot):
boot_devices.CDROM: sushy.VIRTUAL_MEDIA_CD
}
def _validate_vendor(self, task):
pass # assume people are doing the right thing
@classmethod
def _set_boot_device(cls, task, device, persistent=False):
"""Set boot device for a node.

View File

@ -374,6 +374,19 @@ class RedfishVirtualMediaBoot(base.BootInterface):
deploy_utils.validate_image_properties(task.context, d_info, props)
def _validate_vendor(self, task):
vendor = task.node.properties.get('vendor')
if not vendor:
return
if 'Dell' in vendor.split():
raise exception.InvalidParameterValue(
_("The %(iface)s boot interface is not suitable for node "
"%(node)s with vendor %(vendor)s, use "
"idrac-redfish-virtual-media instead")
% {'iface': task.node.boot_interface,
'node': task.node.uuid, 'vendor': vendor})
def validate(self, task):
"""Validate the deployment information for the task's node.
@ -385,6 +398,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
:raises: InvalidParameterValue on malformed parameter(s)
:raises: MissingParameterValue on missing parameter(s)
"""
self._validate_vendor(task)
self._validate_driver_info(task)
if task.driver.storage.should_write_image(task):

View File

@ -25,13 +25,15 @@ from oslo_utils import importutils
from ironic.common import boot_devices
from ironic.common import exception
from ironic.conductor import task_manager
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules.drac import boot as drac_boot
from ironic.tests.unit.db import utils as db_utils
from ironic.tests.unit.drivers.modules.drac import utils as test_utils
from ironic.tests.unit.objects import utils as obj_utils
sushy = importutils.try_import('sushy')
INFO_DICT = test_utils.INFO_DICT
INFO_DICT = dict(db_utils.get_test_redfish_info(), **test_utils.INFO_DICT)
@mock.patch.object(drac_boot, 'redfish_utils', autospec=True)
@ -42,6 +44,28 @@ class DracBootTestCase(test_utils.BaseDracTest):
self.node = obj_utils.create_test_node(
self.context, driver='idrac', driver_info=INFO_DICT)
@mock.patch.object(deploy_utils, 'validate_image_properties',
autospec=True)
def test_validate_correct_vendor(self, mock_redfish_utils,
mock_validate_image_properties):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.node.instance_info.update(
{'kernel': 'kernel',
'ramdisk': 'ramdisk',
'image_source': 'http://image/source'}
)
task.node.driver_info.update(
{'deploy_kernel': 'kernel',
'deploy_ramdisk': 'ramdisk',
'bootloader': 'bootloader'}
)
task.node.properties['vendor'] = "Dell Inc."
task.driver.boot.validate(task)
def test__set_boot_device_persistent(self, mock_redfish_utils):
mock_system = mock_redfish_utils.get_system.return_value

View File

@ -292,6 +292,55 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_validate_image_properties.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY)
@mock.patch.object(redfish_utils, 'parse_driver_info', autospec=True)
@mock.patch.object(deploy_utils, 'validate_image_properties',
autospec=True)
def test_validate_correct_vendor(self, mock_validate_image_properties,
mock_parse_driver_info):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.node.instance_info.update(
{'kernel': 'kernel',
'ramdisk': 'ramdisk',
'image_source': 'http://image/source'}
)
task.node.driver_info.update(
{'deploy_kernel': 'kernel',
'deploy_ramdisk': 'ramdisk',
'bootloader': 'bootloader'}
)
task.node.properties['vendor'] = "Ironic Co."
task.driver.boot.validate(task)
@mock.patch.object(redfish_utils, 'parse_driver_info', autospec=True)
@mock.patch.object(deploy_utils, 'validate_image_properties',
autospec=True)
def test_validate_incompatible_with_idrac(self,
mock_validate_image_properties,
mock_parse_driver_info):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.node.instance_info.update(
{'kernel': 'kernel',
'ramdisk': 'ramdisk',
'image_source': 'http://image/source'}
)
task.node.driver_info.update(
{'deploy_kernel': 'kernel',
'deploy_ramdisk': 'ramdisk',
'bootloader': 'bootloader'}
)
task.node.properties['vendor'] = "Dell Inc."
self.assertRaisesRegex(exception.InvalidParameterValue,
"with vendor Dell Inc.",
task.driver.boot.validate, task)
@mock.patch.object(redfish_utils, 'parse_driver_info', autospec=True)
@mock.patch.object(deploy_utils, 'validate_image_properties',
autospec=True)

View File

@ -0,0 +1,6 @@
---
fixes:
- |
The ``redfish-virtual-media`` boot interface no longer passes validation
for Dell nodes. The ``idrac-redfish-virtual-media`` boot interface must
be used for these nodes instead.