Redfish: Adds drive_rotational_<speed>_rpm attribute to server capabilities

Change-Id: Id99d2b232ab8c915855c3aafe966d77fd162f1cc
This commit is contained in:
Nisha Agarwal 2017-08-04 00:40:22 -07:00
parent 9d1f856ffc
commit 9a7735aea2
14 changed files with 266 additions and 4 deletions

View File

@ -688,6 +688,11 @@ class RedfishOperations(operations.IloOperations):
[('logical_raid_level_' + x, True)
for x in sushy_system.smart_storage.logical_raid_levels])
all_key_to_value_expression_tuples += (
[('drive_rotational_' + str(x) + '_rpm', True)
for x in
common_storage.get_drive_rotational_speed_rpm(sushy_system)])
capabilities.update(
{key: 'true'
for (key, value) in all_key_to_value_expression_tuples

View File

@ -75,6 +75,7 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
_has_ssd = None
_has_rotational = None
_logical_raid_levels = None
_drive_rotational_speed_rpm = None
@property
def _resource_type(self):
@ -141,6 +142,17 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
member.logical_drives.logical_raid_levels)
return self._logical_raid_levels
@property
def drive_rotational_speed_rpm(self):
"""Gets the set of rotational speed of the HDD drives"""
if self._drive_rotational_speed_rpm is None:
self._drive_rotational_speed_rpm = set()
for member in self.get_members():
self._drive_rotational_speed_rpm.update(
member.physical_drives.drive_rotational_speed_rpm)
return self._drive_rotational_speed_rpm
def refresh(self):
super(HPEArrayControllerCollection, self).refresh()
self._logical_drives_maximum_size_mib = None
@ -148,3 +160,4 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
self._has_ssd = None
self._has_rotational = None
self._logical_raid_levels = None
self._drive_rotational_speed_rpm = None

View File

@ -175,3 +175,21 @@ def has_nvme_ssd(system_obj):
storage_resource, 'has_nvme_ssd', default=False)
return storage_value
def get_drive_rotational_speed_rpm(system_obj):
"""Gets the set of rotational speed rpms of the disks.
:param system_obj: The HPESystem object.
:returns the set of rotational speed rpms of the HDD devices.
"""
speed = set()
smart_resource = _get_attribute_value_of(system_obj, 'smart_storage')
if smart_resource is not None:
speed.update(_get_attribute_value_of(
smart_resource, 'drive_rotational_speed_rpm', default=set()))
storage_resource = _get_attribute_value_of(system_obj, 'storages')
if storage_resource is not None:
speed.update(_get_attribute_value_of(
storage_resource, 'drive_rotational_speed_rpm', default=set()))
return speed

View File

@ -42,6 +42,7 @@ class HPEPhysicalDriveCollection(base.ResourceCollectionBase):
_maximum_size_mib = None
_has_ssd = None
_has_rotational = None
_drive_rotational_speed_rpm = None
@property
def _resource_type(self):
@ -83,8 +84,21 @@ class HPEPhysicalDriveCollection(base.ResourceCollectionBase):
break
return self._has_rotational
@property
def drive_rotational_speed_rpm(self):
"""Gets the set of rotational speed of the HDD drives"""
if self._drive_rotational_speed_rpm is None:
self._drive_rotational_speed_rpm = set()
for member in self.get_members():
if member.rotational_speed_rpm is not None:
self._drive_rotational_speed_rpm.add(
member.rotational_speed_rpm)
return self._drive_rotational_speed_rpm
def refresh(self):
super(HPEPhysicalDriveCollection, self).refresh()
self._maximum_size_mib = None
self._has_ssd = None
self._has_rotational = None
self._drive_rotational_speed_rpm = None

View File

@ -36,6 +36,7 @@ class HPESmartStorage(base.ResourceBase):
_has_ssd = None
_has_rotational = None
_logical_raid_levels = None
_drive_rotational_speed_rpm = None
@property
def array_controllers(self):
@ -115,6 +116,17 @@ class HPESmartStorage(base.ResourceBase):
member.logical_drives.logical_raid_levels)
return self._logical_raid_levels
@property
def drive_rotational_speed_rpm(self):
"""Gets the list of rotational speed of the HDD drives"""
if self._drive_rotational_speed_rpm is None:
self._drive_rotational_speed_rpm = set()
for member in self.array_controllers.get_members():
self._drive_rotational_speed_rpm.update(
member.physical_drives.drive_rotational_speed_rpm)
return self._drive_rotational_speed_rpm
def refresh(self):
super(HPESmartStorage, self).refresh()
self._logical_drives_maximum_size_mib = None
@ -123,3 +135,4 @@ class HPESmartStorage(base.ResourceBase):
self._has_ssd = None
self._has_rotational = None
self._logical_raid_levels = None
self._drive_rotational_speed_rpm = None

View File

@ -44,6 +44,7 @@ class Storage(base.ResourceBase):
_has_ssd = None
_has_rotational = None
_has_nvme_ssd = None
_drive_rotational_speed_rpm = None
@property
def volumes(self):
@ -116,6 +117,18 @@ class Storage(base.ResourceBase):
self._has_nvme_ssd = True
return self._has_nvme_ssd
@property
def drive_rotational_speed_rpm(self):
"""Gets set of rotational speed of the disks"""
if self._drive_rotational_speed_rpm is None:
self._drive_rotational_speed_rpm = set()
for member in self._drives_list():
if member.rotation_speed_rpm is not None:
self._drive_rotational_speed_rpm.add(
member.rotation_speed_rpm)
return self._drive_rotational_speed_rpm
def refresh(self):
super(Storage, self).refresh()
self._drives_maximum_size_bytes = None
@ -123,6 +136,7 @@ class Storage(base.ResourceBase):
self._has_ssd = None
self._has_rotational = None
self._has_nvme_ssd = None
self._drive_rotational_speed_rpm = None
class StorageCollection(base.ResourceCollectionBase):
@ -133,6 +147,7 @@ class StorageCollection(base.ResourceCollectionBase):
_has_ssd = None
_has_rotational = None
_has_nvme_ssd = None
_drive_rotational_speed_rpm = None
@property
def _resource_type(self):
@ -198,6 +213,17 @@ class StorageCollection(base.ResourceCollectionBase):
break
return self._has_nvme_ssd
@property
def drive_rotational_speed_rpm(self):
"""Gets set of rotational speed of the disks"""
if self._drive_rotational_speed_rpm is None:
self._drive_rotational_speed_rpm = set()
for member in self.get_members():
self._drive_rotational_speed_rpm.update(
member.drive_rotational_speed_rpm)
return self._drive_rotational_speed_rpm
def refresh(self):
super(StorageCollection, self).refresh()
self._volumes_maximum_size_bytes = None
@ -205,3 +231,4 @@ class StorageCollection(base.ResourceCollectionBase):
self._has_ssd = None
self._has_rotational = None
self._has_nvme_ssd = None
self._drive_rotational_speed_rpm = None

View File

@ -77,5 +77,46 @@
},
"@odata.context": "/redfish/v1/$metadata#Drive.Drive",
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/3F5A8C54207B7233"
},
"drive3": {
"@odata.type": "#Drive.v1_1_0.Drive",
"IndicatorLED": "Lit",
"Model": "C123",
"Revision": "100A",
"Status": {
"State": "Enabled",
"Health": "OK"
},
"CapacityBytes": 899527000000,
"FailurePredicted": false,
"Protocol": "SAS",
"MediaType": "HDD",
"Manufacturer": "Contoso",
"SerialNumber": "1234567",
"PartNumber": "C123-1111",
"Identifiers": [{
"DurableNameFormat": "NAA",
"DurableName": "35D38F11ACEF7BD3"
}],
"HotspareType": "None",
"EncryptionAbility": "SelfEncryptingDrive",
"EncryptionStatus": "Unlocked",
"RotationSpeedRPM": 10000,
"BlockSizeBytes": 512,
"CapableSpeedGbs": 12,
"NegotiatedSpeedGbs": 12,
"Links": {
"Volumes": [{
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1"
}]
},
"Actions": {
"#Drive.SecureErase": {
"Target": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/35D38F11ACEF7BD3/Actions/Drive.SecureErase"
}
},
"@odata.context": "/redfish/v1/$metadata#Drive.Drive",
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/35D38F11ACEF7BD3"
}
}

View File

@ -40,6 +40,8 @@
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/35D38F11ACEF7BD3"
}, {
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/3F5A8C54207B7233"
}, {
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/3F5A8C54207B7234"
}],
"Volumes": {
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes"

View File

@ -223,3 +223,26 @@ class HPEArrayControllerCollectionTestCase(testtools.TestCase):
val.append(dr_json['drive2'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor_col.has_rotational)
def test_drive_rotational_speed_rpm(self):
self.assertIsNone(self.sys_stor_col._drive_rotational_speed_rpm)
self.conn.get.return_value.json.reset_mock()
val = []
path = ('proliantutils/tests/redfish/json_samples/'
'array_controller.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
path = ('proliantutils/tests/redfish/json_samples/'
'disk_drive_collection.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
path = ('proliantutils/tests/redfish/json_samples/'
'disk_drive.json')
with open(path, 'r') as f:
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
self.conn.get.return_value.json.side_effect = val
expected = set([10000])
self.assertEqual(expected,
self.sys_stor_col.drive_rotational_speed_rpm)

View File

@ -134,3 +134,18 @@ class CommonMethodsTestCase(testtools.TestCase):
self._mock_property(storage_value))
actual = common.has_nvme_ssd(system_obj)
self.assertEqual(expected, actual)
@ddt.data((set([10000]), set([15000]), set([10000, 15000])),
(set([10000]), set(), set([10000])),
(set(), set([15000]), set([15000])),
(set(), set(), set()))
@ddt.unpack
def test_get_drive_rotational_speed_rpm(self, smart_value,
storage_value, expected):
system_obj = self.system_obj
type(system_obj.smart_storage).drive_rotational_speed_rpm = (
self._mock_property(smart_value))
type(system_obj.storages).drive_rotational_speed_rpm = (
self._mock_property(storage_value))
actual = common.get_drive_rotational_speed_rpm(system_obj)
self.assertEqual(expected, actual)

View File

@ -128,3 +128,16 @@ class HPEPhysicalDriveCollectionTestCase(testtools.TestCase):
val = [dr_json['drive1'], dr_json['drive2']]
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor_col.has_rotational)
def test_drive_rotational_speed_rpm(self):
self.assertIsNone(self.sys_stor_col._drive_rotational_speed_rpm)
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
expected = set([10000])
self.assertEqual(expected,
self.sys_stor_col.drive_rotational_speed_rpm)

View File

@ -182,3 +182,30 @@ class HPESmartStorageTestCase(testtools.TestCase):
val.append(dr_json['drive2'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor.has_rotational)
def test_drive_rotational_speed_rpm(self):
self.assertIsNone(self.sys_stor._drive_rotational_speed_rpm)
self.conn.get.return_value.json.reset_mock()
val = []
path = ('proliantutils/tests/redfish/json_samples/'
'array_controller_collection.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
path = ('proliantutils/tests/redfish/json_samples/'
'array_controller.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
path = ('proliantutils/tests/redfish/json_samples/'
'disk_drive_collection.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
path = ('proliantutils/tests/redfish/json_samples/'
'disk_drive.json')
with open(path, 'r') as f:
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
self.conn.get.return_value.json.side_effect = val
expected = set([10000])
self.assertEqual(expected,
self.sys_stor.drive_rotational_speed_rpm)

View File

@ -68,7 +68,8 @@ class StorageTestCase(testtools.TestCase):
'json_samples/drive.json') as f:
dr_json = json.loads(f.read())
self.conn.get.return_value.json.side_effect = [dr_json['drive1'],
dr_json['drive2']]
dr_json['drive2'],
dr_json['drive3']]
actual_dr = self.sys_stor._drives_list()
self.assertIsInstance(actual_dr, list)
@ -82,6 +83,7 @@ class StorageTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
expected = 899527000000
actual = self.sys_stor.drives_maximum_size_bytes
@ -97,6 +99,7 @@ class StorageTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor.has_ssd)
@ -110,6 +113,7 @@ class StorageTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor.has_rotational)
@ -123,9 +127,26 @@ class StorageTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor.has_nvme_ssd)
def test_drive_rotational_speed_rpm(self):
self.assertIsNone(self.sys_stor._drive_rotational_speed_rpm)
self.conn.get.return_value.json.reset_mock()
val = []
path = ('proliantutils/tests/redfish/json_samples/'
'drive.json')
with open(path, 'r') as f:
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
expected = set([15000, 10000])
self.assertEqual(expected,
self.sys_stor.drive_rotational_speed_rpm)
class StorageCollectionTestCase(testtools.TestCase):
@ -203,6 +224,7 @@ class StorageCollectionTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
expected = 899527000000
actual = self.sys_stor_col.drives_maximum_size_bytes
@ -222,6 +244,7 @@ class StorageCollectionTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor_col.has_ssd)
@ -239,6 +262,7 @@ class StorageCollectionTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor_col.has_rotational)
@ -256,5 +280,26 @@ class StorageCollectionTestCase(testtools.TestCase):
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor_col.has_nvme_ssd)
def test_drive_rotational_speed_rpm(self):
self.assertIsNone(self.sys_stor_col._drive_rotational_speed_rpm)
self.conn.get.return_value.json.reset_mock()
val = []
path = ('proliantutils/tests/redfish/json_samples/'
'storage.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
path = ('proliantutils/tests/redfish/json_samples/'
'drive.json')
with open(path, 'r') as f:
dr_json = json.loads(f.read())
val.append(dr_json['drive1'])
val.append(dr_json['drive2'])
val.append(dr_json['drive3'])
self.conn.get.return_value.json.side_effect = val
expected = set([15000, 10000])
self.assertEqual(expected,
self.sys_stor_col.drive_rotational_speed_rpm)

View File

@ -684,6 +684,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
'The Redfish controller failed to get the supported boot modes.',
self.rf_client.get_supported_boot_mode)
@mock.patch.object(common_storage, 'get_drive_rotational_speed_rpm')
@mock.patch.object(common_storage, 'has_nvme_ssd')
@mock.patch.object(common_storage, 'has_rotational')
@mock.patch.object(common_storage, 'has_ssd')
@ -691,7 +692,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
def test_get_server_capabilities(self, get_manager_mock, get_system_mock,
ssd_mock, rotational_mock,
nvme_mock):
nvme_mock, speed_mock):
type(get_system_mock.return_value.pci_devices).gpu_devices = (
[mock.MagicMock(spec=pci_device.PCIDevice)])
type(get_system_mock.return_value.bios_settings).sriov = (
@ -734,6 +735,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
raid_mock = mock.PropertyMock(return_value=set(['0', '1']))
type(get_system_mock.return_value.
smart_storage).logical_raid_levels = (raid_mock)
speed_mock.return_value = set(['10000', '15000'])
actual = self.rf_client.get_server_capabilities()
expected = {'pci_gpu_devices': 1, 'sriov_enabled': 'true',
'secure_boot': 'true', 'cpu_vt': 'true',
@ -752,9 +754,12 @@ class RedfishOperationsTestCase(testtools.TestCase):
'has_rotational': 'true',
'has_nvme_ssd': 'true',
'logical_raid_level_0': 'true',
'logical_raid_level_1': 'true'}
'logical_raid_level_1': 'true',
'drive_rotational_10000_rpm': 'true',
'drive_rotational_15000_rpm': 'true'}
self.assertEqual(expected, actual)
@mock.patch.object(common_storage, 'get_drive_rotational_speed_rpm')
@mock.patch.object(common_storage, 'has_nvme_ssd')
@mock.patch.object(common_storage, 'has_rotational')
@mock.patch.object(common_storage, 'has_ssd')
@ -762,7 +767,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
def test_get_server_capabilities_optional_capabilities_absent(
self, get_manager_mock, get_system_mock, ssd_mock,
rotational_mock, nvme_mock):
rotational_mock, nvme_mock, speed_mock):
type(get_system_mock.return_value.pci_devices).gpu_devices = (
[mock.MagicMock(spec=pci_device.PCIDevice)])
type(get_system_mock.return_value.bios_settings).sriov = (
@ -806,6 +811,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
raid_mock = mock.PropertyMock(return_value=set())
type(get_system_mock.return_value.
smart_storage).logical_raid_levels = (raid_mock)
speed_mock.return_value = set()
actual = self.rf_client.get_server_capabilities()
expected = {'pci_gpu_devices': 1,
'rom_firmware_version': 'U31 v1.00 (03/11/2017)',