Fix Redfish RAID interface_type physical disk hint
Map between sushy's protocol and RAID config schema's interface_type constants. Not supporting `scsi` from RAID schema as Redfish does not support it in Protocol property. Change-Id: Ic042f0a87ff0723f313adb3888c24c5963624182
This commit is contained in:
parent
416a0951c8
commit
c41ed8414d
@ -22,6 +22,16 @@ from ironic.common.i18n import _
|
|||||||
from ironic.common import utils
|
from ironic.common import utils
|
||||||
|
|
||||||
|
|
||||||
|
SATA = 'sata'
|
||||||
|
"Serial AT Attachment"
|
||||||
|
|
||||||
|
SCSI = 'scsi'
|
||||||
|
"Small Computer System Interface"
|
||||||
|
|
||||||
|
SAS = 'sas'
|
||||||
|
"Serial Attached SCSI"
|
||||||
|
|
||||||
|
|
||||||
def _check_and_return_root_volumes(raid_config):
|
def _check_and_return_root_volumes(raid_config):
|
||||||
"""Returns root logical disks after validating RAID config.
|
"""Returns root logical disks after validating RAID config.
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ from oslo_utils import units
|
|||||||
|
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common.i18n import _
|
from ironic.common.i18n import _
|
||||||
|
from ironic.common import raid
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
from ironic.conductor import task_manager
|
from ironic.conductor import task_manager
|
||||||
from ironic.conductor import utils as manager_utils
|
from ironic.conductor import utils as manager_utils
|
||||||
@ -90,6 +91,12 @@ RAID_LEVELS = {
|
|||||||
|
|
||||||
sushy = importutils.try_import('sushy')
|
sushy = importutils.try_import('sushy')
|
||||||
|
|
||||||
|
if sushy:
|
||||||
|
PROTOCOL_MAP = {
|
||||||
|
sushy.PROTOCOL_TYPE_SAS: raid.SAS,
|
||||||
|
sushy.PROTOCOL_TYPE_SATA: raid.SATA
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def convert_drive_units(logical_disks, node):
|
def convert_drive_units(logical_disks, node):
|
||||||
"""Convert size in logical_disks from gb to bytes"""
|
"""Convert size in logical_disks from gb to bytes"""
|
||||||
@ -393,7 +400,7 @@ def _assign_disks_to_volume(logical_disks, physical_disks_by_type,
|
|||||||
continue
|
continue
|
||||||
if ('interface_type' in logical_disk
|
if ('interface_type' in logical_disk
|
||||||
and logical_disk['interface_type'].lower()
|
and logical_disk['interface_type'].lower()
|
||||||
!= protocol.lower()):
|
!= PROTOCOL_MAP[protocol].lower()):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# filter out disks without free disk space
|
# filter out disks without free disk space
|
||||||
@ -715,6 +722,24 @@ class RedfishRAID(base.RAIDInterface):
|
|||||||
self._validate_vendor(task)
|
self._validate_vendor(task)
|
||||||
super(RedfishRAID, self).validate(task)
|
super(RedfishRAID, self).validate(task)
|
||||||
|
|
||||||
|
def validate_raid_config(self, task, raid_config):
|
||||||
|
"""Validates the given RAID configuration.
|
||||||
|
|
||||||
|
:param task: A TaskManager instance.
|
||||||
|
:param raid_config: The RAID configuration to validate.
|
||||||
|
:raises: InvalidParameterValue, if the RAID configuration is invalid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
super(RedfishRAID, self).validate_raid_config(task, raid_config)
|
||||||
|
|
||||||
|
# Check if any interface_type is scsi that is not supported by Redfish
|
||||||
|
scsi_disks = ([x for x in raid_config['logical_disks']
|
||||||
|
if x.get('interface_type') == raid.SCSI])
|
||||||
|
|
||||||
|
if len(scsi_disks) > 0:
|
||||||
|
raise exception.InvalidParameterValue(
|
||||||
|
_('interface type `scsi` not supported by Redfish RAID'))
|
||||||
|
|
||||||
@base.deploy_step(priority=0,
|
@base.deploy_step(priority=0,
|
||||||
argsinfo=base.RAID_APPLY_CONFIGURATION_ARGSINFO)
|
argsinfo=base.RAID_APPLY_CONFIGURATION_ARGSINFO)
|
||||||
def apply_configuration(self, task, raid_config, create_root_volume=True,
|
def apply_configuration(self, task, raid_config, create_root_volume=True,
|
||||||
|
@ -89,11 +89,13 @@ class RedfishRAIDTestCase(db_base.DbTestCase):
|
|||||||
self.drive_id4]:
|
self.drive_id4]:
|
||||||
mock_drives.append(_mock_drive(
|
mock_drives.append(_mock_drive(
|
||||||
identity=i, block_size_bytes=512, capacity_bytes=899527000000,
|
identity=i, block_size_bytes=512, capacity_bytes=899527000000,
|
||||||
media_type='HDD', name='Drive', protocol='SAS'))
|
media_type='HDD', name='Drive',
|
||||||
|
protocol='Serial Attached SCSI'))
|
||||||
for i in [self.drive_id5, self.drive_id6, self.drive_id7]:
|
for i in [self.drive_id5, self.drive_id6, self.drive_id7]:
|
||||||
mock_drives.append(_mock_drive(
|
mock_drives.append(_mock_drive(
|
||||||
identity=i, block_size_bytes=512, capacity_bytes=479559942144,
|
identity=i, block_size_bytes=512, capacity_bytes=479559942144,
|
||||||
media_type='SSD', name='Solid State Drive', protocol='SATA'))
|
media_type='SSD', name='Solid State Drive',
|
||||||
|
protocol='Serial AT Attachment'))
|
||||||
self.mock_storage.drives = mock_drives
|
self.mock_storage.drives = mock_drives
|
||||||
mock_identifier = mock.Mock()
|
mock_identifier = mock.Mock()
|
||||||
mock_identifier.durable_name = '345C59DBD970859C'
|
mock_identifier.durable_name = '345C59DBD970859C'
|
||||||
@ -767,6 +769,79 @@ class RedfishRAIDTestCase(db_base.DbTestCase):
|
|||||||
task.driver.raid.create_configuration(task)
|
task.driver.raid.create_configuration(task)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot, 'prepare_ramdisk',
|
||||||
|
spec_set=True, autospec=True)
|
||||||
|
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
|
||||||
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||||
|
@mock.patch.object(deploy_utils, 'get_async_step_return_state',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(deploy_utils, 'set_async_step_flags', autospec=True)
|
||||||
|
def test_create_config_interface_type(
|
||||||
|
self,
|
||||||
|
mock_set_async_step_flags,
|
||||||
|
mock_get_async_step_return_state,
|
||||||
|
mock_node_power_action,
|
||||||
|
mock_build_agent_options,
|
||||||
|
mock_prepare_ramdisk,
|
||||||
|
mock_get_system):
|
||||||
|
|
||||||
|
target_raid_config = {
|
||||||
|
'logical_disks': [
|
||||||
|
{
|
||||||
|
'size_gb': 100,
|
||||||
|
'raid_level': '5',
|
||||||
|
'is_root_volume': True,
|
||||||
|
'interface_type': 'sata'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'size_gb': 500,
|
||||||
|
'raid_level': '1',
|
||||||
|
'interface_type': 'sas'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
mock_get_system.return_value.storage.get_members.return_value = [
|
||||||
|
self.mock_storage]
|
||||||
|
self.node.target_raid_config = target_raid_config
|
||||||
|
self.node.save()
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.raid.create_configuration(task)
|
||||||
|
pre = '/redfish/v1/Systems/1/Storage/1/Drives/'
|
||||||
|
expected_payload1 = {
|
||||||
|
'Encrypted': False,
|
||||||
|
'VolumeType': 'StripedWithParity',
|
||||||
|
'RAIDType': 'RAID5',
|
||||||
|
'CapacityBytes': 107374182400,
|
||||||
|
'Links': {
|
||||||
|
'Drives': [
|
||||||
|
{'@odata.id': pre + self.drive_id5},
|
||||||
|
{'@odata.id': pre + self.drive_id6},
|
||||||
|
{'@odata.id': pre + self.drive_id7}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expected_payload2 = {
|
||||||
|
'Encrypted': False,
|
||||||
|
'VolumeType': 'Mirrored',
|
||||||
|
'RAIDType': 'RAID1',
|
||||||
|
'CapacityBytes': 536870912000,
|
||||||
|
'Links': {
|
||||||
|
'Drives': [
|
||||||
|
{'@odata.id': pre + self.drive_id1},
|
||||||
|
{'@odata.id': pre + self.drive_id2}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.assertEqual(
|
||||||
|
self.mock_storage.volumes.create.call_count, 2)
|
||||||
|
self.mock_storage.volumes.create.assert_any_call(
|
||||||
|
expected_payload1, apply_time=None
|
||||||
|
)
|
||||||
|
self.mock_storage.volumes.create.assert_any_call(
|
||||||
|
expected_payload2, apply_time=None
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot, 'prepare_ramdisk',
|
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot, 'prepare_ramdisk',
|
||||||
spec_set=True, autospec=True)
|
spec_set=True, autospec=True)
|
||||||
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
|
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
|
||||||
@ -900,6 +975,50 @@ class RedfishRAIDTestCase(db_base.DbTestCase):
|
|||||||
"with vendor Dell.Inc.",
|
"with vendor Dell.Inc.",
|
||||||
task.driver.raid.validate, task)
|
task.driver.raid.validate, task)
|
||||||
|
|
||||||
|
def test_validate_raid_config(self, mock_get_system):
|
||||||
|
raid_config = {
|
||||||
|
'logical_disks': [
|
||||||
|
{
|
||||||
|
'size_gb': 500,
|
||||||
|
'raid_level': '1+0',
|
||||||
|
'interface_type': 'sata'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'size_gb': 100,
|
||||||
|
'raid_level': '5',
|
||||||
|
'is_root_volume': True,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.raid.validate_raid_config(task, raid_config)
|
||||||
|
|
||||||
|
def test_validate_raid_config_scsi(self, mock_get_system):
|
||||||
|
raid_config = {
|
||||||
|
'logical_disks': [
|
||||||
|
{
|
||||||
|
'size_gb': 500,
|
||||||
|
'raid_level': '1+0',
|
||||||
|
'interface_type': 'sata'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'size_gb': 100,
|
||||||
|
'raid_level': '5',
|
||||||
|
'is_root_volume': True,
|
||||||
|
'interface_type': 'scsi'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
self.assertRaisesRegex(
|
||||||
|
exception.InvalidParameterValue,
|
||||||
|
"interface type `scsi` not supported by Redfish RAID",
|
||||||
|
task.driver.raid.validate_raid_config, task, raid_config)
|
||||||
|
|
||||||
def test_get_physical_disks(self, mock_get_system):
|
def test_get_physical_disks(self, mock_get_system):
|
||||||
nonraid_controller = mock.Mock()
|
nonraid_controller = mock.Mock()
|
||||||
nonraid_controller.raid_types = []
|
nonraid_controller.raid_types = []
|
||||||
|
@ -150,6 +150,9 @@ SUSHY_SPEC = (
|
|||||||
'PROCESSOR_ARCH_ARM',
|
'PROCESSOR_ARCH_ARM',
|
||||||
'PROCESSOR_ARCH_MIPS',
|
'PROCESSOR_ARCH_MIPS',
|
||||||
'PROCESSOR_ARCH_OEM',
|
'PROCESSOR_ARCH_OEM',
|
||||||
|
'PROTOCOL_TYPE_iSCSI',
|
||||||
|
'PROTOCOL_TYPE_SAS',
|
||||||
|
'PROTOCOL_TYPE_SATA',
|
||||||
'STATE_ENABLED',
|
'STATE_ENABLED',
|
||||||
'STATE_DISABLED',
|
'STATE_DISABLED',
|
||||||
'STATE_ABSENT',
|
'STATE_ABSENT',
|
||||||
|
@ -212,6 +212,9 @@ if not sushy:
|
|||||||
PROCESSOR_ARCH_ARM='ARM',
|
PROCESSOR_ARCH_ARM='ARM',
|
||||||
PROCESSOR_ARCH_MIPS='MIPS',
|
PROCESSOR_ARCH_MIPS='MIPS',
|
||||||
PROCESSOR_ARCH_OEM='OEM-defined',
|
PROCESSOR_ARCH_OEM='OEM-defined',
|
||||||
|
PROTOCOL_TYPE_iSCSI='Internet SCSI',
|
||||||
|
PROTOCOL_TYPE_SAS='Serial Attached SCSI',
|
||||||
|
PROTOCOL_TYPE_SATA='Serial AT Attachment',
|
||||||
STATE_ENABLED='enabled',
|
STATE_ENABLED='enabled',
|
||||||
STATE_DISABLED='disabled',
|
STATE_DISABLED='disabled',
|
||||||
STATE_ABSENT='absent',
|
STATE_ABSENT='absent',
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixes configuring Redfish RAID using ``interface_type`` when error "failed
|
||||||
|
to find matching physical disks for all logical disks" occurs.
|
Loading…
Reference in New Issue
Block a user