Redfish: Add has_ssd attribute to proliantutils

Change-Id: I6a5cd8738c7a7cd5ca61fbbe5242293d0da6cb72
This commit is contained in:
Nisha Agarwal 2017-08-03 01:27:17 -07:00
parent ba63ad11e6
commit aad05fdb11
15 changed files with 290 additions and 24 deletions

View File

@ -679,6 +679,8 @@ class RedfishOperations(operations.IloOperations):
('raid_support',
len(sushy_system.smart_storage.array_controllers.
members_identities) > 0),
('has_ssd',
common_storage.has_ssd(sushy_system)),
) if value})
memory_data = sushy_system.memory.details()

View File

@ -72,6 +72,7 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
_logical_drives_maximum_size_mib = None
_physical_drives_maximum_size_mib = None
_has_ssd = None
@property
def _resource_type(self):
@ -101,7 +102,20 @@ class HPEArrayControllerCollection(base.ResourceCollectionBase):
for member in self.get_members()]))
return self._physical_drives_maximum_size_mib
@property
def has_ssd(self):
"""Return true if any of the drive under ArrayControllers is ssd"""
if self._has_ssd is None:
self._has_ssd = False
for member in self.get_members():
if member.physical_drives.has_ssd:
self._has_ssd = True
break
return self._has_ssd
def refresh(self):
super(HPEArrayControllerCollection, self).refresh()
self._logical_drives_maximum_size_mib = None
self._physical_drives_maximum_size_mib = None
self._has_ssd = None

View File

@ -110,3 +110,28 @@ def get_local_gb(system_obj):
'volume could not be determined.')
LOG.debug(msg)
return local_gb
def has_ssd(system_obj):
"""Gets if the system has any drive as SSD drive
:param system_obj: The HPESystem object.
:returns True if system has SSD drives.
"""
smart_value = False
storage_value = False
smart_resource = _get_attribute_value_of(system_obj, 'smart_storage')
if smart_resource is not None:
smart_value = _get_attribute_value_of(
smart_resource, 'has_ssd', default=False)
if smart_value:
return smart_value
# Its returned before just to avoid hitting BMC if we have
# already got the SSD device above.
storage_resource = _get_attribute_value_of(system_obj, 'storages')
if storage_resource is not None:
storage_value = _get_attribute_value_of(
storage_resource, 'has_ssd', default=False)
return storage_value

View File

@ -16,6 +16,7 @@ from sushy.resources import base
from proliantutils.redfish import utils
from proliantutils.redfish.resources.system.storage import constants
from proliantutils.redfish.resources.system.storage import mappings
@ -39,6 +40,7 @@ class HPEPhysicalDriveCollection(base.ResourceCollectionBase):
"""This class represents the collection of HPEPhysicalDrives resource"""
_maximum_size_mib = None
_has_ssd = None
@property
def _resource_type(self):
@ -56,6 +58,19 @@ class HPEPhysicalDriveCollection(base.ResourceCollectionBase):
for member in self.get_members()]))
return self._maximum_size_mib
@property
def has_ssd(self):
"""Return true if the drive is ssd"""
if self._has_ssd is None:
self._has_ssd = False
for member in self.get_members():
if member.media_type == constants.MEDIA_TYPE_SSD:
self._has_ssd = True
break
return self._has_ssd
def refresh(self):
super(HPEPhysicalDriveCollection, self).refresh()
self._maximum_size_mib = None
self._has_ssd = None

View File

@ -33,6 +33,7 @@ class HPESmartStorage(base.ResourceBase):
_array_controllers = None
_logical_drives_maximum_size_mib = None
_physical_drives_maximum_size_mib = None
_has_ssd = None
@property
def array_controllers(self):
@ -75,8 +76,21 @@ class HPESmartStorage(base.ResourceBase):
for member in self.array_controllers.get_members()]))
return self._physical_drives_maximum_size_mib
@property
def has_ssd(self):
"""Return true if any of the drive under ArrayControllers is ssd"""
if self._has_ssd is None:
self._has_ssd = False
for member in self.array_controllers.get_members():
if member.physical_drives.has_ssd:
self._has_ssd = True
break
return self._has_ssd
def refresh(self):
super(HPESmartStorage, self).refresh()
self._logical_drives_maximum_size_mib = None
self._physical_drives_maximum_size_mib = None
self._array_controllers = None
self._has_ssd = None

View File

@ -14,6 +14,7 @@
import logging
from proliantutils.redfish.resources.system.storage import constants
from proliantutils.redfish.resources.system.storage import drive as sys_drives
from proliantutils.redfish.resources.system.storage \
import volume as sys_volumes
@ -40,6 +41,7 @@ class Storage(base.ResourceBase):
_volumes = None
_drives_maximum_size_bytes = None
_has_ssd = None
@property
def volumes(self):
@ -76,10 +78,23 @@ class Storage(base.ResourceBase):
for member in self._drives_list()]))
return self._drives_maximum_size_bytes
@property
def has_ssd(self):
"""Return true if any of the drive is ssd"""
if self._has_ssd is None:
self._has_ssd = False
for member in self._drives_list():
if member.media_type == constants.MEDIA_TYPE_SSD:
self._has_ssd = True
break
return self._has_ssd
def refresh(self):
super(Storage, self).refresh()
self._drives_maximum_size_bytes = None
self._volumes = None
self._has_ssd = None
class StorageCollection(base.ResourceCollectionBase):
@ -87,6 +102,7 @@ class StorageCollection(base.ResourceCollectionBase):
_volumes_maximum_size_bytes = None
_drives_maximum_size_bytes = None
_has_ssd = None
@property
def _resource_type(self):
@ -116,7 +132,20 @@ class StorageCollection(base.ResourceCollectionBase):
for member in self.get_members()]))
return self._drives_maximum_size_bytes
@property
def has_ssd(self):
"""Return true if Storage has any drive as ssd"""
if self._has_ssd is None:
self._has_ssd = False
for member in self.get_members():
if member.has_ssd:
self._has_ssd = True
break
return self._has_ssd
def refresh(self):
super(StorageCollection, self).refresh()
self._volumes_maximum_size_bytes = None
self._drives_maximum_size_bytes = None
self._has_ssd = None

View File

@ -1,4 +1,5 @@
{
"drive1": {
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/SmartStorage/ArrayControllers/Members/0/DiskDrives/Members/$entity",
"@odata.etag": "W/\"559F84DD\"",
"@odata.id": "/redfish/v1/Systems/1/SmartStorage/ArrayControllers/0/DiskDrives/3/",
@ -39,4 +40,46 @@
"Health": "Warning",
"State": "Enabled"
}
},
"drive2": {
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/SmartStorage/ArrayControllers/Members/0/DiskDrives/Members/$entity",
"@odata.etag": "W/\"559F84DD\"",
"@odata.id": "/redfish/v1/Systems/1/SmartStorage/ArrayControllers/0/DiskDrives/4/",
"@odata.type": "#HpeSmartStorageDiskDrive.v2_0_0.HpeSmartStorageDiskDrive",
"BlockSizeBytes": 512,
"CapacityGB": 600,
"CapacityLogicalBlocks": 1172123568,
"CapacityMiB": 572325,
"CarrierApplicationVersion": "0",
"CarrierAuthenticationStatus": "Fail",
"CurrentTemperatureCelsius": 29,
"Description": "HPE Smart Storage Disk Drive View",
"DiskDriveStatusReasons": [
"NonAuthenticDrive"
],
"DiskDriveUse": "Raw",
"EncryptedDrive": false,
"FirmwareVersion": {
"Current": {
"VersionString": "HPDC"
}
},
"Id": "3",
"InterfaceSpeedMbps": 6000,
"InterfaceType": "SAS",
"LegacyBootPriority": "Primary",
"Location": "1I:0:1",
"LocationFormat": "ControllerPort:Box:Bay",
"MaximumTemperatureCelsius": 40,
"MediaType": "SSD",
"Model": "EG0600FBVFX",
"Name": "HpeSmartStorageDiskDrive",
"PowerOnHours": null,
"SSDEnduranceUtilizationPercentage": null,
"SerialNumber": "KWGER73R",
"Status": {
"Health": "Warning",
"State": "Enabled"
}
}
}

View File

@ -7,8 +7,11 @@
"Members": [
{
"@odata.id": "/redfish/v1/Systems/1/SmartStorage/ArrayControllers/0/DiskDrives/3/"
},
{
"@odata.id": "/redfish/v1/Systems/1/SmartStorage/ArrayControllers/0/DiskDrives/4/"
}
],
"Members@odata.count": 1,
"Members@odata.count": 2,
"Name": "HpeSmartStorageDiskDrives"
}

View File

@ -50,8 +50,8 @@
},
"CapacityBytes": 899527000000,
"FailurePredicted": false,
"Protocol": "SAS",
"MediaType": "HDD",
"Protocol": "NVMe",
"MediaType": "SSD",
"Manufacturer": "Contoso",
"SerialNumber": "1234567",
"PartNumber": "C123-1111",
@ -62,7 +62,6 @@
"HotspareType": "None",
"EncryptionAbility": "SelfEncryptingDrive",
"EncryptionStatus": "Unlocked",
"RotationSpeedRPM": 15000,
"BlockSizeBytes": 512,
"CapableSpeedGbs": 12,
"NegotiatedSpeedGbs": 12,

View File

@ -153,8 +153,31 @@ class HPEArrayControllerCollectionTestCase(testtools.TestCase):
path = ('proliantutils/tests/redfish/json_samples/'
'disk_drive.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
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 = 572325
actual = self.sys_stor_col.physical_drives_maximum_size_mib
self.assertEqual(expected, actual)
def test_has_ssd(self):
self.assertIsNone(self.sys_stor_col._has_ssd)
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
self.assertTrue(self.sys_stor_col.has_ssd)

View File

@ -29,6 +29,13 @@ class CommonMethodsTestCase(testtools.TestCase):
super(CommonMethodsTestCase, self).setUp()
self.system_obj = mock.MagicMock()
def _mock_property(self, value):
if value is sushy.exceptions.SushyError:
mock_value = mock.PropertyMock(side_effect=value)
else:
mock_value = mock.PropertyMock(return_value=value)
return mock_value
@ddt.data((953837, 60000, 60000, 60000, 60000, 930),
(sushy.exceptions.SushyError, 1000169537536, 60000, 60000,
60000, 930),
@ -49,23 +56,17 @@ class CommonMethodsTestCase(testtools.TestCase):
def test_get_local_gb(self, logical_max, volume_max, physical_max,
drive_max, simple_max, expected):
def _mock_property(value):
if value is sushy.exceptions.SushyError:
mock_value = mock.PropertyMock(side_effect=value)
else:
mock_value = mock.PropertyMock(return_value=value)
return mock_value
system_obj = self.system_obj
type(system_obj.smart_storage).logical_drives_maximum_size_mib = (
_mock_property(logical_max))
self._mock_property(logical_max))
type(system_obj.storages).volumes_maximum_size_bytes = (
_mock_property(volume_max))
self._mock_property(volume_max))
type(system_obj.smart_storage).physical_drives_maximum_size_mib = (
_mock_property(physical_max))
self._mock_property(physical_max))
type(system_obj.storages).drives_maximum_size_bytes = (
_mock_property(drive_max))
self._mock_property(drive_max))
type(system_obj.simple_storages).maximum_size_bytes = (
_mock_property(simple_max))
self._mock_property(simple_max))
actual = common.get_local_gb(system_obj)
self.assertEqual(expected, actual)
@ -94,3 +95,17 @@ class CommonMethodsTestCase(testtools.TestCase):
actual = common._get_attribute_value_of(system_obj.simple_storages,
'maximum_size_bytes')
self.assertIsNone(actual)
@ddt.data((True, False, True),
(True, True, True),
(False, True, True),
(False, False, False))
@ddt.unpack
def test_has_ssd(self, smart_value, storage_value, expected):
system_obj = self.system_obj
type(system_obj.smart_storage).has_ssd = (
self._mock_property(smart_value))
type(system_obj.storages).has_ssd = (
self._mock_property(storage_value))
actual = common.has_ssd(system_obj)
self.assertEqual(expected, actual)

View File

@ -28,7 +28,8 @@ class HPEPhysicalDriveTestCase(testtools.TestCase):
logical_file = ('proliantutils/tests/redfish/json_samples/'
'disk_drive.json')
with open(logical_file, 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
dr_json = json.loads(f.read())
self.conn.get.return_value.json.return_value = dr_json['drive1']
path = ("/redfish/v1/Systems/1/SmartStorage/"
"ArrayControllers/0/DiskDrives")
@ -59,7 +60,9 @@ class HPEPhysicalDriveCollectionTestCase(testtools.TestCase):
self.assertEqual('HpeSmartStorageDiskDrives',
self.sys_stor_col.name)
path = ('/redfish/v1/Systems/1/SmartStorage/'
'ArrayControllers/0/DiskDrives/3',)
'ArrayControllers/0/DiskDrives/3',
'/redfish/v1/Systems/1/SmartStorage/'
'ArrayControllers/0/DiskDrives/4',)
self.assertEqual(path, self.sys_stor_col.members_identities)
@mock.patch.object(physical_drive, 'HPEPhysicalDrive', autospec=True)
@ -78,13 +81,17 @@ class HPEPhysicalDriveCollectionTestCase(testtools.TestCase):
members = self.sys_stor_col.get_members()
path = ("/redfish/v1/Systems/1/SmartStorage/ArrayControllers/"
"0/DiskDrives/3")
path2 = ("/redfish/v1/Systems/1/SmartStorage/ArrayControllers/"
"0/DiskDrives/4")
calls = [
mock.call(self.sys_stor_col._conn, path,
redfish_version=self.sys_stor_col.redfish_version),
mock.call(self.sys_stor_col._conn, path2,
redfish_version=self.sys_stor_col.redfish_version),
]
mock_eth.assert_has_calls(calls)
self.assertIsInstance(members, list)
self.assertEqual(1, len(members))
self.assertEqual(2, len(members))
def test_maximum_size_mib(self):
self.assertIsNone(self.sys_stor_col._maximum_size_mib)
@ -92,7 +99,21 @@ class HPEPhysicalDriveCollectionTestCase(testtools.TestCase):
path = ('proliantutils/tests/redfish/json_samples/'
'disk_drive.json')
with open(path, 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
dr_json = json.loads(f.read())
val = [dr_json['drive1'], dr_json['drive2']]
self.conn.get.return_value.json.side_effect = val
expected = 572325
actual = self.sys_stor_col.maximum_size_mib
self.assertEqual(expected, actual)
def test_has_ssd(self):
self.assertIsNone(self.sys_stor_col._has_ssd)
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
actual = self.sys_stor_col.has_ssd
self.assertTrue(actual)

View File

@ -100,8 +100,35 @@ class HPESmartStorageTestCase(testtools.TestCase):
path = ('proliantutils/tests/redfish/json_samples/'
'disk_drive.json')
with open(path, 'r') as f:
val.append(json.loads(f.read()))
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 = 572325
actual = self.sys_stor.physical_drives_maximum_size_mib
self.assertEqual(expected, actual)
def test_has_ssd(self):
self.assertIsNone(self.sys_stor._has_ssd)
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
self.assertTrue(self.sys_stor.has_ssd)

View File

@ -87,6 +87,19 @@ class StorageTestCase(testtools.TestCase):
actual = self.sys_stor.drives_maximum_size_bytes
self.assertEqual(expected, actual)
def test_has_ssd_true(self):
self.assertIsNone(self.sys_stor._has_ssd)
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'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor.has_ssd)
class StorageCollectionTestCase(testtools.TestCase):
@ -168,3 +181,20 @@ class StorageCollectionTestCase(testtools.TestCase):
expected = 899527000000
actual = self.sys_stor_col.drives_maximum_size_bytes
self.assertEqual(expected, actual)
def test_has_ssd_true(self):
self.assertIsNone(self.sys_stor_col._has_ssd)
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'])
self.conn.get.return_value.json.side_effect = val
self.assertTrue(self.sys_stor_col.has_ssd)

View File

@ -684,9 +684,11 @@ 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, 'has_ssd')
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_system')
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
def test_get_server_capabilities(self, get_manager_mock, get_system_mock):
def test_get_server_capabilities(self, get_manager_mock, get_system_mock,
ssd_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 = (
@ -723,6 +725,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
memory_mock = mock.MagicMock(spec=memory.MemoryCollection)
memory_mock.details = mock.MagicMock(return_value=mem)
get_system_mock.return_value.memory = memory_mock
ssd_mock.return_value = True
actual = self.rf_client.get_server_capabilities()
expected = {'pci_gpu_devices': 1, 'sriov_enabled': 'true',
'secure_boot': 'true', 'cpu_vt': 'true',
@ -736,13 +739,15 @@ class RedfishOperationsTestCase(testtools.TestCase):
'raid_support': 'true',
'persistent_memory': 'true',
'nvdimm_n': 'true',
'logical_nvdimm_n': 'false'}
'logical_nvdimm_n': 'false',
'has_ssd': 'true'}
self.assertEqual(expected, actual)
@mock.patch.object(common_storage, 'has_ssd')
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_system')
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
def test_get_server_capabilities_optional_capabilities_absent(
self, get_manager_mock, get_system_mock):
self, get_manager_mock, get_system_mock, ssd_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 = (
@ -780,6 +785,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
memory_mock = mock.MagicMock(spec=memory.MemoryCollection)
get_system_mock.return_value.memory = memory_mock
memory_mock.details = mock.MagicMock(return_value=mem)
ssd_mock.return_value = False
actual = self.rf_client.get_server_capabilities()
expected = {'pci_gpu_devices': 1,
'rom_firmware_version': 'U31 v1.00 (03/11/2017)',