From 196108acc1fe9bf17bbdd05157b1df0a39e3e893 Mon Sep 17 00:00:00 2001 From: Nisha Agarwal Date: Tue, 25 Jul 2017 19:32:22 +0000 Subject: [PATCH] Redfish: Add the Storage and its related URIs for local_gb discovery Change-Id: Ie963c439cdb40681f819c418a529b3a1d785a67b --- .../redfish/resources/system/storage/drive.py | 35 ++++ .../resources/system/storage/storage.py | 123 +++++++++++++ .../resources/system/storage/volume.py | 52 ++++++ .../redfish/resources/system/system.py | 17 +- .../tests/redfish/json_samples/drive.json | 82 +++++++++ .../tests/redfish/json_samples/storage.json | 55 ++++++ .../json_samples/storage_collection.json | 10 + .../tests/redfish/json_samples/volume.json | 37 ++++ .../json_samples/volume_collection.json | 12 ++ .../resources/system/storage/test_drive.py | 40 ++++ .../resources/system/storage/test_storage.py | 172 ++++++++++++++++++ .../resources/system/storage/test_volume.py | 94 ++++++++++ .../redfish/resources/system/test_system.py | 18 ++ 13 files changed, 746 insertions(+), 1 deletion(-) create mode 100644 proliantutils/redfish/resources/system/storage/drive.py create mode 100644 proliantutils/redfish/resources/system/storage/storage.py create mode 100644 proliantutils/redfish/resources/system/storage/volume.py create mode 100644 proliantutils/tests/redfish/json_samples/drive.json create mode 100644 proliantutils/tests/redfish/json_samples/storage.json create mode 100644 proliantutils/tests/redfish/json_samples/storage_collection.json create mode 100644 proliantutils/tests/redfish/json_samples/volume.json create mode 100644 proliantutils/tests/redfish/json_samples/volume_collection.json create mode 100644 proliantutils/tests/redfish/resources/system/storage/test_drive.py create mode 100644 proliantutils/tests/redfish/resources/system/storage/test_storage.py create mode 100644 proliantutils/tests/redfish/resources/system/storage/test_volume.py diff --git a/proliantutils/redfish/resources/system/storage/drive.py b/proliantutils/redfish/resources/system/storage/drive.py new file mode 100644 index 00000000..36733a1a --- /dev/null +++ b/proliantutils/redfish/resources/system/storage/drive.py @@ -0,0 +1,35 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# There is no explicit collection for Drives. That said, a URI link as +# "/redfish/v1/Systems/1/Storage/1/Drives" will be an invalid URI. + + +from sushy.resources import base + + +class Drive(base.ResourceBase): + + capacity_bytes = base.Field('CapacityBytes', adapter=int) + """The size in bytes of this Drive""" + + media_type = base.Field('MediaType') + """The type of media contained in this drive""" + + protocol = base.Field('Protocol') + """The protocol this drive is using to communicate to the storage + controller.""" + + rotation_speed_rpm = base.Field('RotationSpeedRPM', adapter=int) + """The rotation speed of this Drive in Revolutions per Minute (RPM).""" diff --git a/proliantutils/redfish/resources/system/storage/storage.py b/proliantutils/redfish/resources/system/storage/storage.py new file mode 100644 index 00000000..38721d5f --- /dev/null +++ b/proliantutils/redfish/resources/system/storage/storage.py @@ -0,0 +1,123 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging + +from proliantutils.redfish.resources.system.storage import drive as sys_drives +from proliantutils.redfish.resources.system.storage \ + import volume as sys_volumes +from proliantutils.redfish import utils +from sushy.resources import base + +LOG = logging.getLogger(__name__) + + +class Storage(base.ResourceBase): + + identity = base.Field('Id', required=True) + """The Storage identity string""" + + name = base.Field('Name') + """The name of the resource or array element""" + + description = base.Field('Description') + """Description""" + + storage_controllers = base.Field('StorageControllers') + """The set of storage controllers""" + + drives = base.Field('Drives') + """The set of drives attached to the storage controllers""" + + _volumes = None + _drives_maximum_size_bytes = None + + @property + def volumes(self): + """This property prepares the list of volumes + + :return a list of volumes. + """ + if self._volumes is None: + self._volumes = sys_volumes.VolumeCollection( + self._conn, utils.get_subresource_path_by(self, 'Volumes'), + redfish_version=self.redfish_version) + return self._volumes + + def _drives_list(self): + """This property prepares the list of drives + + :return a list of drives. + """ + drives_list = [] + for member in self.drives: + drives_list.append(sys_drives.Drive( + self._conn, member.get('@odata.id'), self.redfish_version)) + return drives_list + + @property + def drives_maximum_size_bytes(self): + """Gets the biggest disk + + :returns the size in MiB. + """ + if self._drives_maximum_size_bytes is None: + self._drives_maximum_size_bytes = ( + max([member.capacity_bytes + for member in self._drives_list()])) + return self._drives_maximum_size_bytes + + def refresh(self): + super(Storage, self).refresh() + self._drives_maximum_size_bytes = None + self._volumes = None + + +class StorageCollection(base.ResourceCollectionBase): + + _volumes_maximum_size_bytes = None + _drives_maximum_size_bytes = None + + @property + def _resource_type(self): + return Storage + + @property + def volumes_maximum_size_bytes(self): + """Gets the biggest logical drive + + :returns the size in MiB. + """ + if self._volumes_maximum_size_bytes is None: + self._volumes_maximum_size_bytes = ( + max([member.volumes.maximum_size_bytes + for member in self.get_members()])) + return self._volumes_maximum_size_bytes + + @property + def drives_maximum_size_bytes(self): + """Gets the biggest disk + + :returns the size in MiB. + """ + if self._drives_maximum_size_bytes is None: + self._drives_maximum_size_bytes = ( + max([member.drives_maximum_size_bytes + for member in self.get_members()])) + return self._drives_maximum_size_bytes + + def refresh(self): + super(StorageCollection, self).refresh() + self._volumes_maximum_size_bytes = None + self._drives_maximum_size_bytes = None diff --git a/proliantutils/redfish/resources/system/storage/volume.py b/proliantutils/redfish/resources/system/storage/volume.py new file mode 100644 index 00000000..43869660 --- /dev/null +++ b/proliantutils/redfish/resources/system/storage/volume.py @@ -0,0 +1,52 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +from sushy.resources import base + + +class Volume(base.ResourceBase): + + identity = base.Field('Id', required=True) + """The processor identity string""" + + capacity_bytes = base.Field('CapacityBytes', adapter=int) + """The size in bytes of this Volume""" + + volume_type = base.Field('VolumeType') + """The type of this volume.""" + + +class VolumeCollection(base.ResourceCollectionBase): + + _maximum_size_bytes = None + + @property + def _resource_type(self): + return Volume + + @property + def maximum_size_bytes(self): + """Gets the biggest volume + + :returns size in bytes. + """ + if self._maximum_size_bytes is None: + self._maximum_size_bytes = ( + max([member.capacity_bytes for member in self.get_members()])) + return self._maximum_size_bytes + + def refresh(self): + super(VolumeCollection, self).refresh() + self._maximum_size_bytes = None diff --git a/proliantutils/redfish/resources/system/system.py b/proliantutils/redfish/resources/system/system.py index 44102c7c..d96a9a84 100644 --- a/proliantutils/redfish/resources/system/system.py +++ b/proliantutils/redfish/resources/system/system.py @@ -28,6 +28,7 @@ from proliantutils.redfish.resources.system import pci_device from proliantutils.redfish.resources.system import secure_boot from proliantutils.redfish.resources.system.storage import \ smart_storage as hpe_smart_storage +from proliantutils.redfish.resources.system.storage import storage from proliantutils.redfish import utils @@ -76,7 +77,7 @@ class HPESystem(system.System): _secure_boot = None # ref to SecureBoot instance _smart_storage = None - + _storages = None _pci_devices = None _ethernet_interfaces = None @@ -197,6 +198,7 @@ class HPESystem(system.System): self._secure_boot = None self._ethernet_interfaces = None self._smart_storage = None + self._storages = None def _get_hpe_sub_resource_collection_path(self, sub_res): path = None @@ -234,3 +236,16 @@ class HPESystem(system.System): self, ['Oem', 'Hpe', 'Links', 'SmartStorage']), redfish_version=self.redfish_version) return self._smart_storage + + @property + def storages(self): + """This property gets the list of instances for Storages + + This property gets the list of instances for Storages + :returns: a list of instances of Storages + """ + if self._storages is None: + self._storages = storage.StorageCollection( + self._conn, utils.get_subresource_path_by(self, 'Storage'), + redfish_version=self.redfish_version) + return self._storages diff --git a/proliantutils/tests/redfish/json_samples/drive.json b/proliantutils/tests/redfish/json_samples/drive.json new file mode 100644 index 00000000..24996754 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/drive.json @@ -0,0 +1,82 @@ +{ + "drive1":{ + "@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": 15000, + "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" + }, + "drive2": { + "@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": "3F5A8C54207B7233" + }], + "HotspareType": "None", + "EncryptionAbility": "SelfEncryptingDrive", + "EncryptionStatus": "Unlocked", + "RotationSpeedRPM": 15000, + "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/3F5A8C54207B7233/Actions/Drive.SecureErase" + } + }, + "@odata.context": "/redfish/v1/$metadata#Drive.Drive", + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/3F5A8C54207B7233" + } +} diff --git a/proliantutils/tests/redfish/json_samples/storage.json b/proliantutils/tests/redfish/json_samples/storage.json new file mode 100644 index 00000000..6fb28236 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/storage.json @@ -0,0 +1,55 @@ +{ + "@odata.type": "#Storage.v1_1_0.Storage", + "Id": "1", + "Name": "Local Storage Controller", + "Description": "Integrated RAID Controller", + "Status": { + "State": "Enabled", + "Health": "OK", + "HealthRollup": "OK" + }, + "StorageControllers": [{ + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1#/StorageControllers/0", + "@odata.type": "#Storage.v1_0_0.StorageController", + "Id": "0", + "Name": "Contoso Integrated RAID", + "Description": "Contoso Integrated RAID", + "Status": { + "State": "Enabled", + "Health": "OK" + }, + "Identifiers": [{ + "DurableNameFormat": "NAA", + "DurableName": "345C59DBD970859C" + }], + "Manufacturer": "Contoso", + "Model": "12Gbs Integrated RAID", + "SerialNumber": "2M220100SL", + "PartNumber": "CT18754", + "SpeedGbps": 12, + "FirmwareVersion": "1.0.0.7", + "SupportedControllerProtocols": [ + "PCIe" + ], + "SupportedDeviceProtocols": [ + "SAS", + "SATA" + ] + }], + "Drives": [{ + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/35D38F11ACEF7BD3" + }, { + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/3F5A8C54207B7233" + }], + "Volumes": { + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes" + }, + "Links": {}, + "Actions": { + "#Storage.SetEncryptionKey": { + "Target": "/redfish/v1/Systems/437XR1138R2/Storage/1/Actions/Storage.SetEncryptionKey" + } + }, + "@odata.context": "/redfish/v1/$metadata#Storage.Storage", + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1" +} diff --git a/proliantutils/tests/redfish/json_samples/storage_collection.json b/proliantutils/tests/redfish/json_samples/storage_collection.json new file mode 100644 index 00000000..e22f3c20 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/storage_collection.json @@ -0,0 +1,10 @@ +{ + "@odata.type": "#StorageCollection.StorageCollection", + "Name": "Storage Collection", + "Members@odata.count": 1, + "Members": [{ + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1" + }], + "@odata.context": "/redfish/v1/$metadata#StorageCollection.StorageCollection", + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage" +} diff --git a/proliantutils/tests/redfish/json_samples/volume.json b/proliantutils/tests/redfish/json_samples/volume.json new file mode 100644 index 00000000..55984214 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/volume.json @@ -0,0 +1,37 @@ +{ + "@odata.type": "#Volume.v1_0_0.Volume", + "Id": "1", + "Name": "Virtual Disk 1", + "Status": { + "State": "Enabled", + "Health": "OK" + }, + "Encrypted": false, + "VolumeType": "Mirrored", + "CapacityBytes": 899527000000, + "Identifiers": [{ + "DurableNameFormat": "VPD83type3", + "DurableName": "690b11c02547001d96f0fbe6c1cb31" + }, { + "DurableNameFormat": "UUID", + "DurableName": "38f1818b-111e-463a-aa19-fa54f792e468" + }], + "Links": { + "Drives": [{ + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/3F5A8C54207B7233" + }, { + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Drives/35D38F11ACEF7BD3" + }] + }, + "Actions": { + "#Volume.Initialize": { + "Target": "/redfish/v1/Systems/3/Storage/RAIDIntegrated/Volumes/1/Actions/Volume.Initialize", + "InitializeType@Redfish.AllowableValues": [ + "Fast", + "Slow" + ] + } + }, + "@odata.context": "/redfish/v1/$metadata#Volume.Volume", + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1" +} diff --git a/proliantutils/tests/redfish/json_samples/volume_collection.json b/proliantutils/tests/redfish/json_samples/volume_collection.json new file mode 100644 index 00000000..8a8fb32f --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/volume_collection.json @@ -0,0 +1,12 @@ +{ + "@odata.context": "/redfish/v1/$metadata#VolumeCollection.VolumeCollection", + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes", + "@odata.type": "#VolumeCollection.VolumeCollection", + "Name": "Storage Volume Collection", + "Description": "Storage Volume Collection", + "Members@odata.count": 1, + "Members": [{ + "@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1" + }], + "Oem": {} +} diff --git a/proliantutils/tests/redfish/resources/system/storage/test_drive.py b/proliantutils/tests/redfish/resources/system/storage/test_drive.py new file mode 100644 index 00000000..32f0dfc3 --- /dev/null +++ b/proliantutils/tests/redfish/resources/system/storage/test_drive.py @@ -0,0 +1,40 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json + +import mock +import testtools + +from proliantutils.redfish.resources.system.storage import drive + + +class DriveTestCase(testtools.TestCase): + + def setUp(self): + super(DriveTestCase, self).setUp() + self.conn = mock.Mock() + drive_file = 'proliantutils/tests/redfish/json_samples/drive.json' + with open(drive_file, 'r') as f: + dr_json = json.loads(f.read()) + self.conn.get.return_value.json.return_value = dr_json['drive1'] + + drive_path = ("/redfish/v1/Systems/437XR1138R2/Storage/1/" + "Drives/35D38F11ACEF7BD3") + self.sys_drive = drive.Drive( + self.conn, drive_path, redfish_version='1.0.2') + + def test__parse_attributes(self): + self.sys_drive._parse_attributes() + self.assertEqual('1.0.2', self.sys_drive.redfish_version) diff --git a/proliantutils/tests/redfish/resources/system/storage/test_storage.py b/proliantutils/tests/redfish/resources/system/storage/test_storage.py new file mode 100644 index 00000000..f5cbb5c0 --- /dev/null +++ b/proliantutils/tests/redfish/resources/system/storage/test_storage.py @@ -0,0 +1,172 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json + +import mock +import testtools + +from proliantutils.redfish.resources.system.storage import storage + + +class StorageTestCase(testtools.TestCase): + + def setUp(self): + super(StorageTestCase, self).setUp() + self.conn = mock.Mock() + storage_file = 'proliantutils/tests/redfish/json_samples/storage.json' + with open(storage_file, 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + self.stor_json = self.conn.get.return_value.json.return_value + + path = ("/redfish/v1/Systems/437XR1138R2/Storage/1") + self.sys_stor = storage.Storage( + self.conn, path, redfish_version='1.0.2') + + def test__parse_attributes(self): + self.sys_stor._parse_attributes() + self.assertEqual('1.0.2', self.sys_stor.redfish_version) + self.assertEqual('1', self.sys_stor.identity) + self.assertEqual('Local Storage Controller', self.sys_stor.name) + self.assertEqual('Integrated RAID Controller', + self.sys_stor.description) + self.assertEqual(self.stor_json.get('StorageControllers'), + self.sys_stor.storage_controllers) + self.assertEqual(self.stor_json.get('Drives'), + self.sys_stor.drives) + + def test_volumes(self): + log_coll = None + log_dr = None + self.assertIsNone(self.sys_stor._volumes) + self.conn.get.return_value.json.reset_mock() + with open('proliantutils/tests/redfish/' + 'json_samples/volume_collection.json') as f: + log_coll = json.loads(f.read()) + with open('proliantutils/tests/redfish/' + 'json_samples/volume.json') as f: + log_dr = json.loads(f.read()) + self.conn.get.return_value.json.side_effect = [log_coll, log_dr] + actual_log_dr = self.sys_stor.volumes + self.assertIs(actual_log_dr, + self.sys_stor.volumes) + self.sys_stor.refresh() + self.assertIsNone(self.sys_stor._volumes) + + def test_drives_list(self): + self.conn.get.return_value.json.reset_mock() + with open('proliantutils/tests/redfish/' + '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']] + actual_dr = self.sys_stor._drives_list() + self.assertIsInstance(actual_dr, list) + + def test_drives_maximum_size_bytes(self): + self.assertIsNone(self.sys_stor._drives_maximum_size_bytes) + 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 + expected = 899527000000 + actual = self.sys_stor.drives_maximum_size_bytes + self.assertEqual(expected, actual) + + +class StorageCollectionTestCase(testtools.TestCase): + + def setUp(self): + super(StorageCollectionTestCase, self).setUp() + self.conn = mock.Mock() + with open('proliantutils/tests/redfish/json_samples/' + 'storage_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + self.sys_stor_col = storage.StorageCollection( + self.conn, '/redfish/v1/Systems/437XR1138R2/Storage', + redfish_version='1.0.2') + + def test__parse_attributes(self): + self.sys_stor_col._parse_attributes() + self.assertEqual('1.0.2', self.sys_stor_col.redfish_version) + self.assertEqual('Storage Collection', + self.sys_stor_col.name) + path = ('/redfish/v1/Systems/437XR1138R2/Storage/1',) + self.assertEqual(path, self.sys_stor_col.members_identities) + + @mock.patch.object(storage, 'Storage', autospec=True) + def test_get_member(self, mock_eth): + self.sys_stor_col.get_member( + '/redfish/v1/Systems/437XR1138R2/Storage/1') + mock_eth.assert_called_once_with( + self.sys_stor_col._conn, + ('/redfish/v1/Systems/437XR1138R2/Storage/1'), + redfish_version=self.sys_stor_col.redfish_version) + + @mock.patch.object(storage, 'Storage', autospec=True) + def test_get_members(self, mock_eth): + members = self.sys_stor_col.get_members() + path = ("/redfish/v1/Systems/437XR1138R2/Storage/1") + calls = [ + mock.call(self.sys_stor_col._conn, path, + redfish_version=self.sys_stor_col.redfish_version), + ] + mock_eth.assert_has_calls(calls) + self.assertIsInstance(members, list) + self.assertEqual(1, len(members)) + + def test_volumes_maximum_size_bytes(self): + self.assertIsNone(self.sys_stor_col._volumes_maximum_size_bytes) + 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/' + 'volume_collection.json') + with open(path, 'r') as f: + val.append(json.loads(f.read())) + path = ('proliantutils/tests/redfish/json_samples/' + 'volume.json') + with open(path, 'r') as f: + val.append(json.loads(f.read())) + self.conn.get.return_value.json.side_effect = val + expected = 899527000000 + actual = self.sys_stor_col.volumes_maximum_size_bytes + self.assertEqual(expected, actual) + + def test_drives_maximum_size_bytes(self): + self.assertIsNone(self.sys_stor_col._drives_maximum_size_bytes) + 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 + expected = 899527000000 + actual = self.sys_stor_col.drives_maximum_size_bytes + self.assertEqual(expected, actual) diff --git a/proliantutils/tests/redfish/resources/system/storage/test_volume.py b/proliantutils/tests/redfish/resources/system/storage/test_volume.py new file mode 100644 index 00000000..13d4e2c1 --- /dev/null +++ b/proliantutils/tests/redfish/resources/system/storage/test_volume.py @@ -0,0 +1,94 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json + +import mock +import testtools + +from proliantutils.redfish.resources.system.storage import volume + + +class VolumeTestCase(testtools.TestCase): + + def setUp(self): + super(VolumeTestCase, self).setUp() + self.conn = mock.Mock() + vol_file = 'proliantutils/tests/redfish/json_samples/volume.json' + with open(vol_file, 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + + vol_path = ("/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1") + self.sys_vol = volume.Volume( + self.conn, vol_path, redfish_version='1.0.2') + + def test__parse_attributes(self): + self.sys_vol._parse_attributes() + self.assertEqual('1.0.2', self.sys_vol.redfish_version) + self.assertEqual('1', self.sys_vol.identity) + self.assertEqual('Mirrored', self.sys_vol.volume_type) + self.assertEqual(899527000000, self.sys_vol.capacity_bytes) + + +class VolumeCollectionTestCase(testtools.TestCase): + + def setUp(self): + super(VolumeCollectionTestCase, self).setUp() + self.conn = mock.Mock() + with open('proliantutils/tests/redfish/json_samples/' + 'volume_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + self.sys_vol_col = volume.VolumeCollection( + self.conn, '/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes', + redfish_version='1.0.2') + + def test__parse_attributes(self): + self.sys_vol_col._parse_attributes() + self.assertEqual('1.0.2', self.sys_vol_col.redfish_version) + self.assertEqual('Storage Volume Collection', + self.sys_vol_col.name) + vol_path = ('/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1',) + self.assertEqual(vol_path, self.sys_vol_col.members_identities) + + @mock.patch.object(volume, 'Volume', autospec=True) + def test_get_member(self, mock_vol): + self.sys_vol_col.get_member( + '/redfish/v1/Systems/437XR1138R2/Volumes/1') + mock_vol.assert_called_once_with( + self.sys_vol_col._conn, + ('/redfish/v1/Systems/437XR1138R2/Volumes/1'), + redfish_version=self.sys_vol_col.redfish_version) + + @mock.patch.object(volume, 'Volume', autospec=True) + def test_get_members(self, mock_vol): + members = self.sys_vol_col.get_members() + vol_path = ("/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1") + calls = [ + mock.call(self.sys_vol_col._conn, vol_path, + redfish_version=self.sys_vol_col.redfish_version), + ] + mock_vol.assert_has_calls(calls) + self.assertIsInstance(members, list) + self.assertEqual(1, len(members)) + + def test_maximum_size_bytes(self): + self.assertIsNone(self.sys_vol_col._maximum_size_bytes) + self.conn.get.return_value.json.reset_mock() + path = ('proliantutils/tests/redfish/json_samples/' + 'volume.json') + with open(path, 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + expected = 899527000000 + actual = self.sys_vol_col.maximum_size_bytes + self.assertEqual(expected, actual) diff --git a/proliantutils/tests/redfish/resources/system/test_system.py b/proliantutils/tests/redfish/resources/system/test_system.py index ac49787e..24532d0b 100644 --- a/proliantutils/tests/redfish/resources/system/test_system.py +++ b/proliantutils/tests/redfish/resources/system/test_system.py @@ -25,6 +25,7 @@ from proliantutils.redfish.resources.system import constants as sys_cons from proliantutils.redfish.resources.system import ethernet_interface from proliantutils.redfish.resources.system import secure_boot from proliantutils.redfish.resources.system.storage import smart_storage +from proliantutils.redfish.resources.system.storage import storage from proliantutils.redfish.resources.system import system from proliantutils.redfish import utils from sushy.resources.system import system as sushy_system @@ -358,3 +359,20 @@ class HPESystemTestCase(testtools.TestCase): self.sys_inst.smart_storage self.assertIsInstance(self.sys_inst._smart_storage, smart_storage.HPESmartStorage) + + def test_storages(self): + self.conn.get.return_value.json.reset_mock() + coll = None + value = None + path = ('proliantutils/tests/redfish/json_samples/' + 'storage_collection.json') + with open(path, 'r') as f: + coll = json.loads(f.read()) + with open('proliantutils/tests/redfish/json_samples/' + 'storage.json', 'r') as f: + value = (json.loads(f.read())) + self.conn.get.return_value.json.side_effect = [coll, value] + self.assertIsNone(self.sys_inst._storages) + self.sys_inst.storages + self.assertIsInstance(self.sys_inst._storages, + storage.StorageCollection)