Redfish: Adds `create_raid_configuration` API to create raid.
This commit adds functionality to create logical drives in a SmartStorageConfig redfish systems. Co-Authored-By: Paresh Sao <paresh.sao@hpe.com> Change-Id: I679deac7e6b15d7a0de980fb16c9e283780fca80 Closes-Bug: 1716329
This commit is contained in:
parent
87a311cfa4
commit
8bda342451
|
@ -25,6 +25,7 @@ from proliantutils.redfish import redfish
|
|||
SUPPORTED_RIS_METHODS = [
|
||||
'activate_license',
|
||||
'clear_secure_boot_keys',
|
||||
'create_raid_configuration',
|
||||
'delete_raid_configuration',
|
||||
'eject_virtual_media',
|
||||
'get_current_bios_settings',
|
||||
|
@ -69,6 +70,7 @@ SUPPORTED_RIS_METHODS = [
|
|||
]
|
||||
|
||||
SUPPORTED_REDFISH_METHODS = [
|
||||
'create_raid_configuration',
|
||||
'delete_raid_configuration',
|
||||
'get_product_name',
|
||||
'get_host_post_state',
|
||||
|
@ -652,6 +654,21 @@ class IloClient(operations.IloOperations):
|
|||
"""
|
||||
return self._call_method('delete_raid_configuration')
|
||||
|
||||
def create_raid_configuration(self, raid_config):
|
||||
"""Create the raid configuration on the hardware.
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'physical_disks': ['6I:1:5'],
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
:raises: IloError, on an error from iLO.
|
||||
:raises: IloCommandNotSupportedError, if the command is not supported
|
||||
on the server
|
||||
"""
|
||||
return self._call_method('create_raid_configuration', raid_config)
|
||||
|
||||
def update_firmware(self, firmware_url, component_type):
|
||||
"""Updates the given firmware on the server
|
||||
|
||||
|
|
|
@ -454,3 +454,18 @@ class IloOperations(object):
|
|||
not supported on the server.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
||||
def create_raid_configuration(self, raid_config):
|
||||
"""Create the raid configuration on the hardware.
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'controller':
|
||||
'HPE Smart Array P408i-p SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
:raises: IloError, on an error from iLO.
|
||||
:raises: IloCommandNotSupportedError, if the command is
|
||||
not supported on the server.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
|
|
@ -1215,11 +1215,25 @@ class RIBCLOperations(operations.IloOperations):
|
|||
Loops through each SmartStorageConfig controller and clears the
|
||||
raid configuration.
|
||||
|
||||
:raises: IloError, on an error from iLO
|
||||
:raises: IloCommandNotSupportedError
|
||||
"""
|
||||
self._raise_command_not_supported("delete_raid_configuration")
|
||||
|
||||
def create_raid_configuration(self, raid_config):
|
||||
"""Create the raid configuration on the hardware.
|
||||
|
||||
Based on user raid_config input, it will create raid
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'physical_disks': ['6I:1:5'],
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
:raises: IloCommandNotSupportedError
|
||||
"""
|
||||
self._raise_command_not_supported("create_raid_configuration")
|
||||
|
||||
|
||||
# The below block of code is there only for backward-compatibility
|
||||
# reasons (before commit 47608b6 for ris-support).
|
||||
|
|
|
@ -1987,7 +1987,21 @@ class RISOperations(rest.RestConnectorBase, operations.IloOperations):
|
|||
Loops through each SmartStorageConfig controller and clears the
|
||||
raid configuration.
|
||||
|
||||
:raises: IloError, on an error from iLO
|
||||
:raises: IloCommandNotSupportedError
|
||||
"""
|
||||
self._raise_command_not_supported("delete_raid_configuration")
|
||||
|
||||
def create_raid_configuration(self, raid_config):
|
||||
"""Create the raid configuration on the hardware.
|
||||
|
||||
Based on user raid_config input, it will create raid
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'physical_disks': ['6I:1:5'],
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
:raises: IloCommandNotSupportedError
|
||||
"""
|
||||
self._raise_command_not_supported("create_raid_configuration")
|
||||
|
|
|
@ -1168,3 +1168,19 @@ class RedfishOperations(operations.IloOperations):
|
|||
return common_utils.apply_bios_properties_filter(
|
||||
settings, ilo_cons.SUPPORTED_REDFISH_BIOS_PROPERTIES)
|
||||
return settings
|
||||
|
||||
def create_raid_configuration(self, raid_config):
|
||||
"""Create the raid configuration on the hardware.
|
||||
|
||||
Based on user raid_config input, it will create raid
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'physical_disks': ['6I:1:5'],
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID)
|
||||
sushy_system.create_raid(raid_config)
|
||||
|
|
|
@ -16,6 +16,9 @@ from proliantutils import exception
|
|||
from proliantutils import log
|
||||
from sushy.resources import base
|
||||
|
||||
from proliantutils.hpssa import constants
|
||||
from proliantutils.hpssa import manager
|
||||
|
||||
|
||||
LOG = log.get_logger(__name__)
|
||||
|
||||
|
@ -32,6 +35,8 @@ class HPESmartStorageConfig(base.ResourceBase):
|
|||
|
||||
logical_drives = LogicalDriveListField("LogicalDrives", default=[])
|
||||
|
||||
location = base.Field("Location")
|
||||
|
||||
settings_uri = base.Field(["@Redfish.Settings",
|
||||
"SettingsObject", "@odata.id"])
|
||||
|
||||
|
@ -53,3 +58,47 @@ class HPESmartStorageConfig(base.ResourceBase):
|
|||
|
||||
data = {'LogicalDrives': lds, 'DataGuard': 'Permissive'}
|
||||
self._conn.put(self.settings_uri, data=data)
|
||||
|
||||
def create_raid(self, raid_config):
|
||||
"""Create the raid configuration on the hardware.
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'physical_disks': ['6I:1:5'],
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
"""
|
||||
manager.validate(raid_config)
|
||||
logical_drives = raid_config['logical_disks']
|
||||
redfish_logical_disk = []
|
||||
for ld in logical_drives:
|
||||
ld_attr = {"Raid": "Raid" + ld["raid_level"]}
|
||||
ld_attr[
|
||||
"CapacityGiB"] = -1 if ld[
|
||||
"size_gb"] == "MAX" else int(ld["size_gb"])
|
||||
if 'physical_disks' in ld:
|
||||
ld_attr["DataDrives"] = ld["physical_disks"]
|
||||
else:
|
||||
datadrives = {}
|
||||
if 'number_of_physical_disks' in ld:
|
||||
datadrives["DataDriveCount"] = (
|
||||
ld["number_of_physical_disks"])
|
||||
else:
|
||||
datadrives["DataDriveCount"] = (constants.
|
||||
RAID_LEVEL_MIN_DISKS
|
||||
[ld["raid_level"]])
|
||||
if 'disk_type' in ld:
|
||||
datadrives["DataDriveMediaType"] = ld["disk_type"]
|
||||
if 'interface_type' in ld:
|
||||
datadrives["DataDriveInterfaceType"] = ld["interface_type"]
|
||||
ld_attr["DataDrives"] = datadrives
|
||||
if 'volume_name' in ld:
|
||||
ld_attr["LogicalDriveName"] = ld["volume_name"]
|
||||
redfish_logical_disk.append(ld_attr)
|
||||
|
||||
data = {
|
||||
"DataGuard": "Disabled",
|
||||
"LogicalDrives": redfish_logical_disk
|
||||
}
|
||||
self._conn.put(self.settings_uri, data=data)
|
||||
|
|
|
@ -34,6 +34,12 @@ class HPEArrayController(base.ResourceBase):
|
|||
description = base.Field('Description')
|
||||
"""Description"""
|
||||
|
||||
model = base.Field('Model')
|
||||
"""Controller model"""
|
||||
|
||||
location = base.Field('Location')
|
||||
"""Controller slot location"""
|
||||
|
||||
_logical_drives = None
|
||||
_physical_drives = None
|
||||
|
||||
|
@ -89,6 +95,8 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
|
|||
_has_rotational = None
|
||||
_logical_raid_levels = None
|
||||
_drive_rotational_speed_rpm = None
|
||||
_get_models = None
|
||||
_get_default_controller = None
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
|
@ -166,6 +174,34 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
|
|||
member.physical_drives.drive_rotational_speed_rpm)
|
||||
return self._drive_rotational_speed_rpm
|
||||
|
||||
@property
|
||||
def get_default_controller(self):
|
||||
"""Gets default array controller
|
||||
|
||||
:returns default array controller
|
||||
"""
|
||||
if self._get_default_controller is None:
|
||||
self._get_default_controller = self.get_members()[0]
|
||||
return self._get_default_controller
|
||||
|
||||
def array_controller_by_location(self, location):
|
||||
"""Returns array controller instance by location
|
||||
|
||||
:returns Instance of array controller
|
||||
"""
|
||||
for member in self.get_members():
|
||||
if member.location == location:
|
||||
return member
|
||||
|
||||
def array_controller_by_model(self, model):
|
||||
"""Returns array controller instance by model
|
||||
|
||||
:returns Instance of array controller
|
||||
"""
|
||||
for member in self.get_members():
|
||||
if member.model == model:
|
||||
return member
|
||||
|
||||
def _do_refresh(self, force):
|
||||
"""Do custom resource specific refresh activities
|
||||
|
||||
|
@ -179,3 +215,5 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
|
|||
self._has_rotational = None
|
||||
self._logical_raid_levels = None
|
||||
self._drive_rotational_speed_rpm = None
|
||||
self._get_models = None
|
||||
self._get_default_controller = None
|
||||
|
|
|
@ -337,6 +337,18 @@ class HPESystem(system.System):
|
|||
HPESmartStorageConfig(self._conn, smart_storage_config_url,
|
||||
redfish_version=self.redfish_version))
|
||||
|
||||
def _get_smart_storage_config_by_controller_model(self, controller_model):
|
||||
"""Returns a SmartStorageConfig Instance for controller by model.
|
||||
|
||||
:returns: SmartStorageConfig Instance for controller
|
||||
"""
|
||||
ac = self.smart_storage.array_controllers.array_controller_by_model(
|
||||
controller_model)
|
||||
for ssc_id in self.smart_storage_config_identities:
|
||||
ssc_obj = self.get_smart_storage_config(ssc_id)
|
||||
if ac.location == ssc_obj.location:
|
||||
return ssc_obj
|
||||
|
||||
def check_smart_storage_config_ids(self):
|
||||
"""Check SmartStorageConfig controllers is there in hardware.
|
||||
|
||||
|
@ -378,3 +390,67 @@ class HPESystem(system.System):
|
|||
msg = ('No logical drives are found in any controllers. Nothing '
|
||||
'to delete.')
|
||||
raise exception.IloLogicalDriveNotFoundError(msg)
|
||||
|
||||
def _parse_raid_config_data(self, raid_config):
|
||||
"""It will parse raid config data based on raid controllers
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'controller':
|
||||
'HPE Smart Array P408i-a SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
:returns: A dictionary of controllers, each containing list of
|
||||
their respected logical drives.
|
||||
"""
|
||||
default = (
|
||||
self.smart_storage.array_controllers.get_default_controller.model)
|
||||
controllers = {default: []}
|
||||
for ld in raid_config['logical_disks']:
|
||||
if 'controller' not in ld.keys():
|
||||
controllers[default].append(ld)
|
||||
else:
|
||||
ctrl = ld['controller']
|
||||
if ctrl not in controllers:
|
||||
controllers[ctrl] = []
|
||||
controllers[ctrl].append(ld)
|
||||
return controllers
|
||||
|
||||
def create_raid(self, raid_config):
|
||||
"""Create the raid configuration on the hardware.
|
||||
|
||||
:param raid_config: A dictionary containing target raid configuration
|
||||
data. This data stucture should be as follows:
|
||||
raid_config = {'logical_disks': [{'raid_level': 1,
|
||||
'size_gb': 100, 'physical_disks': ['6I:1:5'],
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'},
|
||||
<info-for-logical-disk-2>]}
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
self.check_smart_storage_config_ids()
|
||||
any_exceptions = []
|
||||
controllers = self._parse_raid_config_data(raid_config)
|
||||
# Creating raid on rest of the controllers
|
||||
for controller in controllers:
|
||||
try:
|
||||
config = {'logical_disks': controllers[controller]}
|
||||
ssc_obj = (
|
||||
self._get_smart_storage_config_by_controller_model(
|
||||
controller))
|
||||
if ssc_obj:
|
||||
ssc_obj.create_raid(config)
|
||||
else:
|
||||
members = (
|
||||
self.smart_storage.array_controllers.get_members())
|
||||
models = [member.model for member in members]
|
||||
msg = ('Controller not found. Available controllers are: '
|
||||
'%(models)s' % {'models': models})
|
||||
any_exceptions.append((controller, msg))
|
||||
except sushy.exceptions.SushyError as e:
|
||||
any_exceptions.append((controller, str(e)))
|
||||
|
||||
if any_exceptions:
|
||||
msg = ('The Redfish controller failed to create the '
|
||||
'raid configuration for one or more controllers with '
|
||||
'Error: %(error)s' % {'error': str(any_exceptions)})
|
||||
raise exception.IloError(msg)
|
||||
|
|
|
@ -779,6 +779,38 @@ class IloClientTestCase(testtools.TestCase):
|
|||
'on ProLiant DL380 G8',
|
||||
self.client.delete_raid_configuration)
|
||||
|
||||
@mock.patch.object(client.IloClient, '_call_method')
|
||||
def test_create_raid_configuration(self, call_mock):
|
||||
ld1 = {"size_gb": 150, "raid_level": '0', "is_root_volume": True}
|
||||
raid_config = {"logical_disks": [ld1]}
|
||||
self.client.create_raid_configuration(raid_config)
|
||||
call_mock.assert_called_once_with('create_raid_configuration',
|
||||
raid_config)
|
||||
|
||||
@mock.patch.object(ris.RISOperations, 'get_product_name')
|
||||
def test_create_raid_configuration_gen9(self, get_product_mock):
|
||||
self.client.model = 'Gen9'
|
||||
ld1 = {"size_gb": 150, "raid_level": '0', "is_root_volume": True}
|
||||
raid_config = {"logical_disks": [ld1]}
|
||||
get_product_mock.return_value = 'ProLiant BL460c Gen9'
|
||||
self.assertRaisesRegexp(exception.IloCommandNotSupportedError,
|
||||
'`create_raid_configuration` is not supported '
|
||||
'on ProLiant BL460c Gen9',
|
||||
self.client.create_raid_configuration,
|
||||
raid_config)
|
||||
|
||||
@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name')
|
||||
def test_create_raid_configuration_gen8(self, get_product_mock):
|
||||
self.client.model = 'Gen8'
|
||||
ld1 = {"size_gb": 150, "raid_level": '0', "is_root_volume": True}
|
||||
raid_config = {"logical_disks": [ld1]}
|
||||
get_product_mock.return_value = 'ProLiant DL380 G8'
|
||||
self.assertRaisesRegexp(exception.IloCommandNotSupportedError,
|
||||
'`create_raid_configuration` is not supported '
|
||||
'on ProLiant DL380 G8',
|
||||
self.client.create_raid_configuration,
|
||||
raid_config)
|
||||
|
||||
@mock.patch.object(ris.RISOperations, 'eject_virtual_media')
|
||||
def test_eject_virtual_media_gen9(self, eject_virtual_media_mock):
|
||||
self.client.model = 'Gen9'
|
||||
|
|
|
@ -1062,6 +1062,15 @@ class IloRibclTestCaseBeforeRisSupport(unittest.TestCase):
|
|||
'ProLiant DL380 G7',
|
||||
self.ilo.delete_raid_configuration)
|
||||
|
||||
@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name')
|
||||
def test_create_raid_configuration(self, product_name_mock):
|
||||
ld1 = {"size_gb": 150, "raid_level": '0', "is_root_volume": True}
|
||||
raid_config = {"logical_disks": [ld1]}
|
||||
product_name_mock.return_value = constants.GET_PRODUCT_NAME
|
||||
self.assertRaisesRegexp(exception.IloCommandNotSupportedError,
|
||||
'ProLiant DL380 G7',
|
||||
self.ilo.create_raid_configuration,
|
||||
raid_config)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -2558,3 +2558,13 @@ class TestRISOperationsPrivateMethods(testtools.TestCase):
|
|||
self.assertRaisesRegexp(exception.IloCommandNotSupportedError,
|
||||
'ProLiant BL460c Gen9',
|
||||
self.client.delete_raid_configuration)
|
||||
|
||||
@mock.patch.object(ris.RISOperations, 'get_product_name')
|
||||
def test_create_raid_configuration(self, product_name_mock):
|
||||
ld1 = {"size_gb": 150, "raid_level": '0', "is_root_volume": True}
|
||||
raid_config = {"logical_disks": [ld1]}
|
||||
product_name_mock.return_value = 'ProLiant BL460c Gen9'
|
||||
self.assertRaisesRegexp(exception.IloCommandNotSupportedError,
|
||||
'ProLiant BL460c Gen9',
|
||||
self.client.create_raid_configuration,
|
||||
raid_config)
|
||||
|
|
|
@ -38,6 +38,9 @@ class HPEArrayControllerTestCase(testtools.TestCase):
|
|||
def test__parse_attributes(self):
|
||||
self.sys_stor._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.sys_stor.redfish_version)
|
||||
self.assertEqual('HPE Smart Array P408i-a SR Gen10',
|
||||
self.sys_stor.model)
|
||||
self.assertEqual('Slot 0', self.sys_stor.location)
|
||||
|
||||
def test_logical_drives(self):
|
||||
log_coll = None
|
||||
|
@ -252,3 +255,33 @@ class HPEArrayControllerCollectionTestCase(testtools.TestCase):
|
|||
expected = set([10000])
|
||||
self.assertEqual(expected,
|
||||
self.sys_stor_col.drive_rotational_speed_rpm)
|
||||
|
||||
def test_get_default_controller(self):
|
||||
self.assertIsNone(self.sys_stor_col._get_default_controller)
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller.json', 'r') as f:
|
||||
ac_json = json.loads(f.read())
|
||||
self.conn.get.return_value.json.return_value = ac_json
|
||||
result_location = self.sys_stor_col.get_default_controller.location
|
||||
self.assertEqual(result_location, 'Slot 0')
|
||||
|
||||
def test_array_controller_by_location(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller.json', 'r') as f:
|
||||
ac_json = json.loads(f.read())
|
||||
self.conn.get.return_value.json.return_value = ac_json
|
||||
model_result = (
|
||||
self.sys_stor_col.array_controller_by_location('Slot 0').model)
|
||||
self.assertEqual(model_result, 'HPE Smart Array P408i-a SR Gen10')
|
||||
|
||||
def test_array_controller_by_model(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller.json', 'r') as f:
|
||||
ac_json = json.loads(f.read())
|
||||
self.conn.get.return_value.json.return_value = ac_json
|
||||
model = 'HPE Smart Array P408i-a SR Gen10'
|
||||
result_model = self.sys_stor_col.array_controller_by_model(model).model
|
||||
self.assertEqual(result_model, model)
|
||||
|
|
|
@ -19,6 +19,7 @@ import mock
|
|||
import testtools
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.hpssa import manager
|
||||
from proliantutils.redfish.resources.system import smart_storage_config
|
||||
|
||||
|
||||
|
@ -38,6 +39,7 @@ class HPESmartStorageConfigTestCase(testtools.TestCase):
|
|||
|
||||
def test_attributes(self):
|
||||
self.assertEqual('smartstorageconfig', self.ssc_inst.controller_id)
|
||||
self.assertEqual('Slot 0', self.ssc_inst.location)
|
||||
self.assertEqual(
|
||||
'600508B1001C045A9BAAC9F4F49498AE',
|
||||
self.ssc_inst.logical_drives[0].volume_unique_identifier)
|
||||
|
@ -61,3 +63,42 @@ class HPESmartStorageConfigTestCase(testtools.TestCase):
|
|||
return_value=[])
|
||||
self.assertRaises(exception.IloLogicalDriveNotFoundError,
|
||||
self.ssc_inst.delete_raid)
|
||||
|
||||
@mock.patch.object(manager, 'validate', autospec=True)
|
||||
def test_create_raid(self, validate_mock):
|
||||
settings_uri = "/redfish/v1/systems/1/smartstorageconfig/settings/"
|
||||
ld1 = {'size_gb': 50,
|
||||
'raid_level': '1',
|
||||
'physical_disks': ['5I:1:1', '5I:1:2']}
|
||||
raid_config = {'logical_disks': [ld1]}
|
||||
validate_mock.return_value = True
|
||||
self.ssc_inst.create_raid(raid_config)
|
||||
data = {"DataGuard": "Disabled",
|
||||
"LogicalDrives": [
|
||||
{"CapacityGiB": 50, "Raid": "Raid1",
|
||||
"DataDrives": ['5I:1:1', '5I:1:2']}]}
|
||||
validate_mock.assert_called_once_with(raid_config)
|
||||
self.ssc_inst._conn.put.assert_called_once_with(settings_uri,
|
||||
data=data)
|
||||
|
||||
@mock.patch.object(manager, 'validate', autospec=True)
|
||||
def test_create_raid_multiple_logical_drives(self, validate_mock):
|
||||
settings_uri = "/redfish/v1/systems/1/smartstorageconfig/settings/"
|
||||
ld1 = {'size_gb': 50,
|
||||
'raid_level': '0',
|
||||
'physical_disks': ['5I:1:1']}
|
||||
ld2 = {'size_gb': 100,
|
||||
'raid_level': '1',
|
||||
'number_of_physical_disks': 2}
|
||||
raid_config = {'logical_disks': [ld1, ld2]}
|
||||
validate_mock.return_value = True
|
||||
self.ssc_inst.create_raid(raid_config)
|
||||
data = {"DataGuard": "Disabled",
|
||||
"LogicalDrives": [
|
||||
{"CapacityGiB": 50, "Raid": "Raid0",
|
||||
"DataDrives": ['5I:1:1']},
|
||||
{"CapacityGiB": 100, "Raid": "Raid1",
|
||||
"DataDrives": {"DataDriveCount": 2}}]}
|
||||
validate_mock.assert_called_once_with(raid_config)
|
||||
self.ssc_inst._conn.put.assert_called_once_with(settings_uri,
|
||||
data=data)
|
||||
|
|
|
@ -26,6 +26,7 @@ from proliantutils.redfish.resources.system import ethernet_interface
|
|||
from proliantutils.redfish.resources.system import memory
|
||||
from proliantutils.redfish.resources.system import secure_boot
|
||||
from proliantutils.redfish.resources.system import smart_storage_config
|
||||
from proliantutils.redfish.resources.system.storage import array_controller
|
||||
from proliantutils.redfish.resources.system.storage import simple_storage
|
||||
from proliantutils.redfish.resources.system.storage import smart_storage
|
||||
from proliantutils.redfish.resources.system.storage import storage
|
||||
|
@ -560,3 +561,126 @@ class HPESystemTestCase(testtools.TestCase):
|
|||
"The Redfish controller failed to get the SmartStorageConfig "
|
||||
"controller configurations",
|
||||
self.sys_inst.check_smart_storage_config_ids)
|
||||
|
||||
@mock.patch.object(system.HPESystem, 'check_smart_storage_config_ids')
|
||||
@mock.patch.object(system.HPESystem, '_parse_raid_config_data')
|
||||
@mock.patch.object(system.HPESystem,
|
||||
'_get_smart_storage_config_by_controller_model')
|
||||
def test_create_raid(self, get_smart_storage_config_model_mock,
|
||||
parse_raid_config_mock,
|
||||
check_smart_storage_config_ids_mock):
|
||||
ld1 = {'raid_level': '0', 'is_root_volume': True,
|
||||
'size_gb': 150,
|
||||
'controller': 'HPE Smart Array P408i-p SR Gen10'}
|
||||
ld2 = {'raid_level': '1', 'size_gb': 200,
|
||||
'controller': 'HPE Smart Array P408i-p SR Gen10'}
|
||||
raid_config = {'logical_disks': [ld1, ld2]}
|
||||
parse_data = {'HPE Smart Array P408i-p SR Gen10': [ld1, ld2]}
|
||||
parse_raid_config_mock.return_value = parse_data
|
||||
check_smart_storage_config_ids_mock.return_value = None
|
||||
self.sys_inst.create_raid(raid_config)
|
||||
get_smart_storage_config_model_mock.assert_called_once_with(
|
||||
'HPE Smart Array P408i-p SR Gen10')
|
||||
(get_smart_storage_config_model_mock.return_value.
|
||||
create_raid.assert_called_once_with(raid_config))
|
||||
|
||||
@mock.patch.object(system.HPESystem, 'check_smart_storage_config_ids')
|
||||
@mock.patch.object(system.HPESystem, '_parse_raid_config_data')
|
||||
@mock.patch.object(system.HPESystem,
|
||||
'_get_smart_storage_config_by_controller_model')
|
||||
def test_create_raid_controller_not_found(
|
||||
self, get_smart_storage_config_model_mock, parse_raid_config_mock,
|
||||
check_smart_storage_config_ids_mock):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/smart_storage.json', 'r') as f:
|
||||
ss_json = json.loads(f.read())
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller_collection.json', 'r') as f:
|
||||
acc_json = json.loads(f.read())
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller.json', 'r') as f:
|
||||
ac_json = json.loads(f.read())
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
ss_json, acc_json, ac_json]
|
||||
ld1 = {'raid_level': '1', 'size_gb': 200,
|
||||
'controller': 'HPE Gen10 Controller'}
|
||||
raid_config = {'logical_disks': [ld1]}
|
||||
parse_data = {'HPE Gen10 Controller': [ld1]}
|
||||
parse_raid_config_mock.return_value = parse_data
|
||||
check_smart_storage_config_ids_mock.return_value = None
|
||||
get_smart_storage_config_model_mock.return_value = None
|
||||
self.assertRaisesRegexp(
|
||||
exception.IloError,
|
||||
"The Redfish controller failed to create the raid "
|
||||
"configuration for one or more controllers with",
|
||||
self.sys_inst.create_raid, raid_config)
|
||||
|
||||
@mock.patch.object(system.HPESystem, 'check_smart_storage_config_ids')
|
||||
@mock.patch.object(system.HPESystem, '_parse_raid_config_data')
|
||||
@mock.patch.object(system.HPESystem,
|
||||
'_get_smart_storage_config_by_controller_model')
|
||||
def test_create_raid_failed(self, get_smart_storage_config_model_mock,
|
||||
parse_raid_config_mock,
|
||||
check_smart_storage_config_ids_mock):
|
||||
ld1 = {'raid_level': '0', 'is_root_volume': True,
|
||||
'size_gb': 150,
|
||||
'controller': 'HPE Smart Array P408i-p SR Gen10'}
|
||||
ld2 = {'raid_level': '1', 'size_gb': 200,
|
||||
'controller': 'HPE Smart Array P408i-p SR Gen10'}
|
||||
raid_config = {'logical_disks': [ld1, ld2]}
|
||||
parse_data = {'HPE Smart Array P408i-p SR Gen10': [ld1, ld2]}
|
||||
check_smart_storage_config_ids_mock.return_value = None
|
||||
parse_raid_config_mock.return_value = parse_data
|
||||
(get_smart_storage_config_model_mock.
|
||||
return_value.create_raid.side_effect) = sushy.exceptions.SushyError
|
||||
self.assertRaisesRegexp(
|
||||
exception.IloError,
|
||||
"The Redfish controller failed to create the "
|
||||
"raid configuration for one or more controllers with Error:",
|
||||
self.sys_inst.create_raid, raid_config)
|
||||
|
||||
def test__parse_raid_config_data(self):
|
||||
ld1 = {'raid_level': '0', 'is_root_volume': True,
|
||||
'size_gb': 150,
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'}
|
||||
ld2 = {'raid_level': '1', 'size_gb': 200,
|
||||
'controller': 'HPE Smart Array P408i-a SR Gen10'}
|
||||
raid_config = {'logical_disks': [ld1, ld2]}
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/smart_storage.json', 'r') as f:
|
||||
ss_json = json.loads(f.read())
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller_collection.json', 'r') as f:
|
||||
acc_json = json.loads(f.read())
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller.json', 'r') as f:
|
||||
ac_json = json.loads(f.read())
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
ss_json, acc_json, ac_json]
|
||||
expected = {'HPE Smart Array P408i-a SR Gen10': [ld1, ld2]}
|
||||
self.assertEqual(expected,
|
||||
self.sys_inst._parse_raid_config_data(raid_config))
|
||||
|
||||
@mock.patch.object(array_controller.HPEArrayControllerCollection,
|
||||
'array_controller_by_model')
|
||||
@mock.patch.object(system.HPESystem, 'get_smart_storage_config')
|
||||
def test__get_smart_storage_config_by_controller_model(
|
||||
self, get_smart_storage_config_mock,
|
||||
array_controller_by_model_mock):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/smart_storage.json', 'r') as f:
|
||||
ss_json = json.loads(f.read())
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/array_controller_collection.json', 'r') as f:
|
||||
acc_json = json.loads(f.read())
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
self.conn.get.return_value.json.side_effect = [ss_json, acc_json]
|
||||
type(array_controller_by_model_mock.return_value).location = 'Slot 0'
|
||||
ssc_obj_mock = mock.Mock(location='Slot 0')
|
||||
get_smart_storage_config_mock.return_value = ssc_obj_mock
|
||||
self.assertEqual(
|
||||
ssc_obj_mock.location,
|
||||
self.sys_inst._get_smart_storage_config_by_controller_model(
|
||||
'HPE Smart Array P408i-a SR Gen10').location)
|
||||
|
|
|
@ -1675,3 +1675,11 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
def test_delete_raid_configuration(self, get_system_mock):
|
||||
self.rf_client.delete_raid_configuration()
|
||||
get_system_mock.return_value.delete_raid.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_system')
|
||||
def test_create_raid_configuration(self, get_system_mock):
|
||||
ld1 = {"size_gb": 150, "raid_level": '0', "is_root_volume": True}
|
||||
raid_config = {"logical_disks": [ld1]}
|
||||
self.rf_client.create_raid_configuration(raid_config)
|
||||
get_system_mock.return_value.create_raid.assert_called_once_with(
|
||||
raid_config)
|
||||
|
|
Loading…
Reference in New Issue