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:
paresh-sao 2019-06-24 06:59:38 +00:00
parent eff34b56d8
commit 5b6fc3d7d0
11 changed files with 227 additions and 19 deletions

View File

@ -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')

View File

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

View File

@ -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()

View File

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

View File

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

View File

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

View File

@ -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):

View File

@ -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'))

View File

@ -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"])

View File

@ -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')

View File

@ -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())