Adds support to get disk types
This commit adds support for getting all the disk types available in the server. Also its a follow-up patch for out-of-band disk erase. Change-Id: Ib5c30efbe48b20120757f763e20305b295e0c270
This commit is contained in:
parent
eff34b56d8
commit
5b6fc3d7d0
|
@ -86,6 +86,7 @@ SUPPORTED_REDFISH_METHODS = [
|
|||
'hold_pwr_btn',
|
||||
'get_bios_settings_result',
|
||||
'get_current_bios_settings',
|
||||
'get_available_disk_types',
|
||||
'get_default_bios_settings',
|
||||
'get_pending_bios_settings',
|
||||
'set_bios_settings',
|
||||
|
@ -836,3 +837,11 @@ class IloClient(operations.IloOperations):
|
|||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
return self._call_method('do_disk_erase', disk_type, pattern)
|
||||
|
||||
def get_available_disk_types(self):
|
||||
"""Get the list of all disk type available in server
|
||||
|
||||
:returns: A list containing disk types.
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
return self._call_method('get_available_disk_types')
|
||||
|
|
|
@ -521,3 +521,13 @@ class IloOperations(object):
|
|||
not supported on the server.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
||||
def get_available_disk_types(self):
|
||||
"""Get the list of all disk type available in server
|
||||
|
||||
:returns: List of disk types available in the server.
|
||||
:raises: IloError, on an error from iLO.
|
||||
:raises: IloCommandNotSupportedError, if the command is
|
||||
not supported on the server.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
|
|
@ -1250,3 +1250,12 @@ class RedfishOperations(operations.IloOperations):
|
|||
raise exception.IloError(msg)
|
||||
status = "failed" if len(settings_result) > 1 else "success"
|
||||
return {"status": status, "results": settings_result}
|
||||
|
||||
def get_available_disk_types(self):
|
||||
"""Get the list of all disk type available in server
|
||||
|
||||
:returns: A list containing disk types
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID)
|
||||
return sushy_system.get_disk_types()
|
||||
|
|
|
@ -208,7 +208,7 @@ class HPESmartStorageConfig(base.ResourceBase):
|
|||
self._conn.patch(self.settings_uri, data=data)
|
||||
|
||||
def get_drives_has_raid(self):
|
||||
"""Return the list of drives have raid
|
||||
"""Return the list of physical drives have raid
|
||||
|
||||
:return: List of disk drives
|
||||
"""
|
||||
|
|
|
@ -34,12 +34,16 @@ class HPEPhysicalDrive(base.ResourceBase):
|
|||
|
||||
capacity_mib = base.Field('CapacityMiB', adapter=int)
|
||||
|
||||
capacity_gb = base.Field('CapacityGB', adapter=int)
|
||||
|
||||
location = base.Field('Location')
|
||||
|
||||
media_type = base.MappedField('MediaType', mappings.MEDIA_TYPE_MAP)
|
||||
|
||||
rotational_speed_rpm = base.Field('RotationalSpeedRpm', adapter=int)
|
||||
|
||||
serial_number = base.Field('SerialNumber')
|
||||
|
||||
|
||||
class HPEPhysicalDriveCollection(base.ResourceCollectionBase):
|
||||
"""This class represents the collection of HPEPhysicalDrives resource"""
|
||||
|
@ -115,3 +119,18 @@ class HPEPhysicalDriveCollection(base.ResourceCollectionBase):
|
|||
if member.media_type == constants.MEDIA_TYPE_SSD:
|
||||
ssds.append(member.location)
|
||||
return ssds
|
||||
|
||||
def get_disk_properties_by_drive_location(self, location):
|
||||
"""Returns disk property of physical drive
|
||||
|
||||
:returns: Disk property of drive.
|
||||
"""
|
||||
for member in self.get_members():
|
||||
if member.location == location:
|
||||
prop = {
|
||||
'Serial number': member.serial_number,
|
||||
'Size(GB)': member.capacity_gb,
|
||||
'Media type': mappings.MEDIA_TYPE_MAP_REV[
|
||||
member.media_type],
|
||||
'Location': member.location}
|
||||
return prop
|
||||
|
|
|
@ -339,6 +339,19 @@ class HPESystem(system.System):
|
|||
drives.extend(ssc_obj.get_drives_has_raid())
|
||||
return drives
|
||||
|
||||
def _get_disk_properties_by_drive_location(self, location):
|
||||
controllers = (
|
||||
self.smart_storage.array_controllers.get_all_controllers_model())
|
||||
for controller in controllers:
|
||||
controller_obj = (
|
||||
self.smart_storage.array_controllers.array_controller_by_model(
|
||||
controller))
|
||||
properties = (
|
||||
controller_obj.physical_drives.
|
||||
get_disk_properties_by_drive_location(location))
|
||||
if properties:
|
||||
return properties
|
||||
|
||||
def do_disk_erase(self, disk_type, pattern):
|
||||
"""Performs out-of-band sanitize disk erase on the hardware.
|
||||
|
||||
|
@ -376,25 +389,25 @@ class HPESystem(system.System):
|
|||
|
||||
assigned_disks = self._get_drives_has_raid()
|
||||
|
||||
unassigned_disks = []
|
||||
|
||||
not_erasable_disks = []
|
||||
|
||||
for disk in disks:
|
||||
if disk in assigned_disks:
|
||||
not_erasable_disks.append(disk)
|
||||
else:
|
||||
unassigned_disks.append(disk)
|
||||
unassigned_disks = list(set(disks) - set(assigned_disks))
|
||||
|
||||
if unassigned_disks:
|
||||
ssc_obj.disk_erase(unassigned_disks, disk_type,
|
||||
pattern)
|
||||
|
||||
if not_erasable_disks:
|
||||
LOG.info("This disks have raid in it: %(disks)s, "
|
||||
"skipping disks since can't erase disks "
|
||||
"with raid."
|
||||
% {'disks': not_erasable_disks})
|
||||
if assigned_disks:
|
||||
disk_list = []
|
||||
for disk in assigned_disks:
|
||||
disk_prop = (
|
||||
self._get_disk_properties_by_drive_location(
|
||||
disk))
|
||||
if disk_prop['Media type'] is disk_type:
|
||||
disk_list.append(disk_prop)
|
||||
|
||||
if disk_list:
|
||||
LOG.warn("Skipping disk erase of %(disk_list)s "
|
||||
"with logical volumes on them."
|
||||
% {'disk_list': disk_list})
|
||||
else:
|
||||
LOG.warn("Smart array controller: %(controller)s, doesn't "
|
||||
"support sanitize disk erase. All the disks of "
|
||||
|
@ -588,3 +601,29 @@ class HPESystem(system.System):
|
|||
# passed by user then
|
||||
result = self._post_delete_read_raid()
|
||||
return result
|
||||
|
||||
def get_disk_types(self):
|
||||
"""Get the list of all disk type available in server
|
||||
|
||||
:returns: A list containing disk types
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
disk_types = []
|
||||
try:
|
||||
controllers = (self.smart_storage.array_controllers.
|
||||
get_all_controllers_model())
|
||||
for controller in controllers:
|
||||
controller_obj = (self.smart_storage.array_controllers.
|
||||
array_controller_by_model(controller))
|
||||
if controller_obj.physical_drives.has_rotational:
|
||||
disk_types.append(storage_map.MEDIA_TYPE_MAP_REV[
|
||||
storage_const.MEDIA_TYPE_HDD])
|
||||
if controller_obj.physical_drives.has_ssd:
|
||||
disk_types.append(storage_map.MEDIA_TYPE_MAP_REV[
|
||||
storage_const.MEDIA_TYPE_SSD])
|
||||
return list(set(disk_types))
|
||||
except sushy.exceptions.SushyError as e:
|
||||
msg = ('The Redfish controller failed to get list of disk types. '
|
||||
'Error: %(error)s'
|
||||
% {'error': str(e)})
|
||||
raise exception.IloError(msg)
|
||||
|
|
|
@ -1279,6 +1279,27 @@ class IloClientTestCase(testtools.TestCase):
|
|||
'not supported',
|
||||
self.client.get_bios_settings_result)
|
||||
|
||||
@mock.patch.object(client.IloClient, '_call_method')
|
||||
def test_get_available_disk_types(self, call_mock):
|
||||
self.client.get_available_disk_types()
|
||||
call_mock.assert_called_once_with('get_available_disk_types')
|
||||
|
||||
@mock.patch.object(ris.RISOperations, 'get_product_name')
|
||||
def test_get_available_disk_types_gen9(self, get_product_mock):
|
||||
self.client.model = 'Gen9'
|
||||
get_product_mock.return_value = 'ProLiant BL460c Gen9'
|
||||
self.assertRaisesRegexp(exception.IloCommandNotSupportedError,
|
||||
'not supported',
|
||||
self.client.get_available_disk_types)
|
||||
|
||||
@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name')
|
||||
def test_get_available_disk_types_gen8(self, get_product_mock):
|
||||
self.client.model = 'Gen8'
|
||||
get_product_mock.return_value = 'ProLiant DL380 G8'
|
||||
self.assertRaisesRegexp(exception.IloCommandNotSupportedError,
|
||||
'not supported',
|
||||
self.client.get_available_disk_types)
|
||||
|
||||
|
||||
class IloRedfishClientTestCase(testtools.TestCase):
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ class HPEPhysicalDriveTestCase(testtools.TestCase):
|
|||
def test__parse_attributes(self):
|
||||
self.sys_stor._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.sys_stor.redfish_version)
|
||||
self.assertEqual(600, self.sys_stor.capacity_gb)
|
||||
self.assertEqual('KWGER73R', self.sys_stor.serial_number)
|
||||
|
||||
|
||||
class HPEPhysicalDriveCollectionTestCase(testtools.TestCase):
|
||||
|
@ -179,3 +181,21 @@ class HPEPhysicalDriveCollectionTestCase(testtools.TestCase):
|
|||
expected = set([10000])
|
||||
self.assertEqual(expected,
|
||||
self.sys_stor_col.drive_rotational_speed_rpm)
|
||||
|
||||
def test_get_disk_properties_by_drive_location(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
path = ('proliantutils/tests/redfish/json_samples/'
|
||||
'disk_drive.json')
|
||||
with open(path, 'r') as f:
|
||||
dr_json = json.loads(f.read())
|
||||
val = [dr_json['drive1'], dr_json['drive2']]
|
||||
self.conn.get.return_value.json.side_effect = val
|
||||
result = {
|
||||
'Serial number': 'KWGER73R',
|
||||
'Size(GB)': 600,
|
||||
'Media type': 'HDD',
|
||||
'Location': '1I:0:1'}
|
||||
self.assertEqual(result,
|
||||
self.sys_stor_col.
|
||||
get_disk_properties_by_drive_location(
|
||||
'1I:0:1'))
|
||||
|
|
|
@ -237,5 +237,13 @@ class HPESmartStorageConfigTestCase(testtools.TestCase):
|
|||
data=data)
|
||||
|
||||
def test_get_drives_has_raid(self):
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/smart_storage_config.json', 'r') as f:
|
||||
ssc_json = json.loads(f.read())
|
||||
ld_mock = mock.MagicMock(
|
||||
spec=smart_storage_config.LogicalDriveListField)
|
||||
ld_mock.data_drives = ssc_json['LogicalDrives'][0]['DataDrives']
|
||||
type(self.ssc_inst).logical_drives = mock.PropertyMock(
|
||||
return_value=[ld_mock])
|
||||
result = self.ssc_inst.get_drives_has_raid()
|
||||
self.assertEqual(result, ["2I:1:2", "2I:1:1"])
|
||||
|
|
|
@ -949,7 +949,9 @@ class HPESystemTestCase(testtools.TestCase):
|
|||
(get_ssc_by_controller_model_mock.return_value.
|
||||
disk_erase.assert_called_once_with(['2I:1:1'], 'SSD', None))
|
||||
|
||||
@mock.patch.object(system.LOG, 'info', autospec=True)
|
||||
@mock.patch.object(system.LOG, 'warn', autospec=True)
|
||||
@mock.patch.object(system.HPESystem,
|
||||
'_get_disk_properties_by_drive_location')
|
||||
@mock.patch.object(system.HPESystem,
|
||||
'_get_drives_has_raid')
|
||||
@mock.patch.object(array_controller.HPEArrayControllerCollection,
|
||||
|
@ -962,7 +964,7 @@ class HPESystemTestCase(testtools.TestCase):
|
|||
self, array_controller_by_model_mock,
|
||||
get_ssc_by_controller_model_mock,
|
||||
get_all_controllers_model_mock,
|
||||
drives_raid_mock,
|
||||
drives_raid_mock, get_disk_prop_mock,
|
||||
system_log_mock):
|
||||
get_all_controllers_model_mock.return_value = [
|
||||
'HPE Smart Array P408i-p SR Gen10']
|
||||
|
@ -977,14 +979,24 @@ class HPESystemTestCase(testtools.TestCase):
|
|||
self.conn.get.return_value.json.side_effect = [ss_json, acc_json]
|
||||
(array_controller_by_model_mock.return_value.physical_drives.
|
||||
get_all_hdd_drives_locations.return_value) = ['2I:1:1', '2I:1:2']
|
||||
get_disk_prop_mock.return_value = {
|
||||
'Serial number': 'KWGER73R',
|
||||
'Size(GB)': 600,
|
||||
'Media type': 'HDD',
|
||||
'Location': '2I:1:2'}
|
||||
self.sys_inst.do_disk_erase('HDD', None)
|
||||
get_ssc_by_controller_model_mock.assert_called_once_with(
|
||||
'HPE Smart Array P408i-p SR Gen10')
|
||||
(get_ssc_by_controller_model_mock.return_value.
|
||||
disk_erase.assert_called_once_with(['2I:1:1'], 'HDD', None))
|
||||
disk_prop = {'Serial number': 'KWGER73R',
|
||||
'Size(GB)': 600,
|
||||
'Media type': 'HDD',
|
||||
'Location': '2I:1:2'}
|
||||
system_log_mock.assert_called_once_with(
|
||||
"This disks have raid in it: ['2I:1:2'], skipping disks since "
|
||||
"can't erase disks with raid.")
|
||||
"Skipping disk erase of %(disk_list)s "
|
||||
"with logical volumes on them."
|
||||
% {'disk_list': [disk_prop]})
|
||||
|
||||
@mock.patch.object(system.HPESystem,
|
||||
'_get_drives_has_raid')
|
||||
|
@ -1061,3 +1073,57 @@ class HPESystemTestCase(testtools.TestCase):
|
|||
result = self.sys_inst._get_drives_has_raid()
|
||||
self.assertEqual(result, ["2I:1:2", "2I:1:1"])
|
||||
get_smart_storage_config_mock.assert_called_once_with(config_id[0])
|
||||
|
||||
@mock.patch.object(array_controller.HPEArrayControllerCollection,
|
||||
'get_all_controllers_model')
|
||||
@mock.patch.object(array_controller.HPEArrayControllerCollection,
|
||||
'array_controller_by_model')
|
||||
def test__get_disk_properties_by_drive_location(
|
||||
self, array_controller_by_model_mock,
|
||||
get_all_controllers_model_mock):
|
||||
get_all_controllers_model_mock.return_value = [
|
||||
'HPE Smart Array P408i-p SR Gen10']
|
||||
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]
|
||||
prop = {
|
||||
'Serial number': 'KWGER73R',
|
||||
'Size(GB)': 600,
|
||||
'Media type': 'HDD',
|
||||
'Location': '2I:1:2'}
|
||||
(array_controller_by_model_mock.return_value.physical_drives.
|
||||
get_disk_properties_by_drive_location.return_value) = prop
|
||||
result = self.sys_inst._get_disk_properties_by_drive_location(
|
||||
'2I:1:1')
|
||||
self.assertEqual(result, prop)
|
||||
|
||||
@mock.patch.object(array_controller.HPEArrayControllerCollection,
|
||||
'get_all_controllers_model')
|
||||
@mock.patch.object(array_controller.HPEArrayControllerCollection,
|
||||
'array_controller_by_model')
|
||||
def test_get_disk_types(
|
||||
self, array_controller_by_model_mock,
|
||||
get_all_controllers_model_mock):
|
||||
get_all_controllers_model_mock.return_value = [
|
||||
'HPE Smart Array P408i-p SR Gen10']
|
||||
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]
|
||||
(array_controller_by_model_mock.return_value.physical_drives.
|
||||
has_hdd.return_value) = True
|
||||
(array_controller_by_model_mock.return_value.physical_drives.
|
||||
has_ssd.return_value) = False
|
||||
types = ['HDD', 'SSD']
|
||||
self.assertEqual(list(set(types)), self.sys_inst.get_disk_types())
|
||||
array_controller_by_model_mock.assert_called_once_with(
|
||||
'HPE Smart Array P408i-p SR Gen10')
|
||||
|
|
|
@ -1808,3 +1808,10 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
actual = self.rf_client.get_bios_settings_result()
|
||||
expected = {"status": "success", "results": actual_settings}
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_system')
|
||||
def test_get_available_disk_types(self, get_system_mock):
|
||||
get_system_mock.return_value.get_disk_types.return_value = ['HDD',
|
||||
'SSD']
|
||||
self.assertEqual(
|
||||
['HDD', 'SSD'], self.rf_client.get_available_disk_types())
|
||||
|
|
Loading…
Reference in New Issue