From 4ee1f1936803cb6fb686c1719e95fed68cb78e15 Mon Sep 17 00:00:00 2001 From: Nisha Agarwal Date: Tue, 25 Jul 2017 20:04:12 +0000 Subject: [PATCH] Redfish: Adds SimpleStorage URI for local_gb discovery Change-Id: I51be5006c5eaec2b233568db4bd13ae8fdfe13bd --- .../system/storage/simple_storage.py | 80 +++++++++++++ .../redfish/resources/system/system.py | 16 +++ .../redfish/json_samples/simple_storage.json | 43 +++++++ .../simple_storage_collection.json | 10 ++ .../tests/redfish/json_samples/system.json | 3 + .../system/storage/test_simple_storage.py | 109 ++++++++++++++++++ .../redfish/resources/system/test_system.py | 46 ++++++++ 7 files changed, 307 insertions(+) create mode 100644 proliantutils/redfish/resources/system/storage/simple_storage.py create mode 100644 proliantutils/tests/redfish/json_samples/simple_storage.json create mode 100644 proliantutils/tests/redfish/json_samples/simple_storage_collection.json create mode 100644 proliantutils/tests/redfish/resources/system/storage/test_simple_storage.py diff --git a/proliantutils/redfish/resources/system/storage/simple_storage.py b/proliantutils/redfish/resources/system/storage/simple_storage.py new file mode 100644 index 00000000..5e27c5db --- /dev/null +++ b/proliantutils/redfish/resources/system/storage/simple_storage.py @@ -0,0 +1,80 @@ +# 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 sushy.resources import base + + +LOG = logging.getLogger(__name__) + + +class SimpleStorage(base.ResourceBase): + """This class represents the SimpleStorage resource""" + + identity = base.Field('Id', required=True) + """The SimpleStorage identity string""" + + name = base.Field('Name') + """The name of the resource or array element""" + + description = base.Field('Description') + """Description""" + + devices = base.Field('Devices') + """The storage devices associated with this resource""" + + _maximum_size_bytes = None + + @property + def maximum_size_bytes(self): + """Gets the biggest disk drive + + :returns size in bytes. + """ + if self._maximum_size_bytes is None: + self._maximum_size_bytes = ( + max([device.get('CapacityBytes') + for device in self.devices + if device.get('CapacityBytes') is not None])) + return self._maximum_size_bytes + + def refresh(self): + super(SimpleStorage, self).refresh() + self._maximum_size_bytes = None + + +class SimpleStorageCollection(base.ResourceCollectionBase): + + @property + def _resource_type(self): + return SimpleStorage + + _maximum_size_bytes = None + + @property + def maximum_size_bytes(self): + """Gets the biggest disk drive + + :returns size in bytes. + """ + if self._maximum_size_bytes is None: + self._maximum_size_bytes = ( + max([member.maximum_size_bytes + for member in self.get_members()])) + return self._maximum_size_bytes + + def refresh(self): + super(SimpleStorageCollection, self).refresh() + self._maximum_size_bytes = None diff --git a/proliantutils/redfish/resources/system/system.py b/proliantutils/redfish/resources/system/system.py index d96a9a84..3ed09a0d 100644 --- a/proliantutils/redfish/resources/system/system.py +++ b/proliantutils/redfish/resources/system/system.py @@ -26,6 +26,7 @@ from proliantutils.redfish.resources.system import ethernet_interface from proliantutils.redfish.resources.system import mappings from proliantutils.redfish.resources.system import pci_device from proliantutils.redfish.resources.system import secure_boot +from proliantutils.redfish.resources.system.storage import simple_storage from proliantutils.redfish.resources.system.storage import \ smart_storage as hpe_smart_storage from proliantutils.redfish.resources.system.storage import storage @@ -199,6 +200,7 @@ class HPESystem(system.System): self._ethernet_interfaces = None self._smart_storage = None self._storages = None + self._simple_storages = None def _get_hpe_sub_resource_collection_path(self, sub_res): path = None @@ -249,3 +251,17 @@ class HPESystem(system.System): self._conn, utils.get_subresource_path_by(self, 'Storage'), redfish_version=self.redfish_version) return self._storages + + @property + def simple_storages(self): + """This property gets the list of instances for SimpleStorages + + :returns: a list of instances of SimpleStorages + """ + + if self._simple_storages is None: + self._simple_storages = simple_storage.SimpleStorageCollection( + self._conn, utils.get_subresource_path_by( + self, 'SimpleStorage'), + redfish_version=self.redfish_version) + return self._simple_storages diff --git a/proliantutils/tests/redfish/json_samples/simple_storage.json b/proliantutils/tests/redfish/json_samples/simple_storage.json new file mode 100644 index 00000000..e8772ef6 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/simple_storage.json @@ -0,0 +1,43 @@ +{ + "@odata.type": "#SimpleStorage.v1_0_2.SimpleStorage", + "Id": "1", + "Name": "Simple Storage Controller", + "Description": "System SATA", + "UefiDevicePath": "Acpi(PNP0A03,0)/Pci(1F|1)/Ata(Primary,Master)/HD(Part3, Sig00110011)", + "Status": { + "State": "Enabled", + "Health": "OK", + "HealthRollup": "Warning" + }, + "Devices": [{ + "Name": "SATA Bay 1", + "Manufacturer": "Contoso", + "Model": "3000GT8", + "CapacityBytes": 8000000000000, + "Status": { + "State": "Enabled", + "Health": "OK" + } + }, { + "Name": "SATA Bay 2", + "Manufacturer": "Contoso", + "Model": "3000GT7", + "CapacityBytes": 4000000000000, + "Status": { + "State": "Enabled", + "Health": "Degraded" + } + }, { + "Name": "SATA Bay 3", + "Status": { + "State": "Absent" + } + }, { + "Name": "SATA Bay 4", + "Status": { + "State": "Absent" + } + }], + "@odata.context": "/redfish/v1/$metadata#SimpleStorage.SimpleStorage", + "@odata.id": "/redfish/v1/Systems/437XR1138R2/SimpleStorage/1" +} diff --git a/proliantutils/tests/redfish/json_samples/simple_storage_collection.json b/proliantutils/tests/redfish/json_samples/simple_storage_collection.json new file mode 100644 index 00000000..06b49475 --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/simple_storage_collection.json @@ -0,0 +1,10 @@ +{ + "@odata.type": "#SimpleStorageCollection.SimpleStorageCollection", + "Name": "Simple Storage Collection", + "Members@odata.count": 1, + "Members": [{ + "@odata.id": "/redfish/v1/Systems/437XR1138R2/SimpleStorage/1" + }], + "@odata.context": "/redfish/v1/$metadata#SimpleStorageCollection.SimpleStorageCollection", + "@odata.id": "/redfish/v1/Systems/437XR1138R2/SimpleStorage" +} diff --git a/proliantutils/tests/redfish/json_samples/system.json b/proliantutils/tests/redfish/json_samples/system.json index ffb1e9d7..8801c469 100644 --- a/proliantutils/tests/redfish/json_samples/system.json +++ b/proliantutils/tests/redfish/json_samples/system.json @@ -210,6 +210,9 @@ "SecureBoot": { "@odata.id": "/redfish/v1/Systems/1/SecureBoot/" }, + "SimpleStorage": { + "@odata.id": "/redfish/v1/Systems/1/SimpleStorage/" + }, "SerialNumber": " ", "Status": { "Health": "OK", diff --git a/proliantutils/tests/redfish/resources/system/storage/test_simple_storage.py b/proliantutils/tests/redfish/resources/system/storage/test_simple_storage.py new file mode 100644 index 00000000..29c62038 --- /dev/null +++ b/proliantutils/tests/redfish/resources/system/storage/test_simple_storage.py @@ -0,0 +1,109 @@ +# 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 simple_storage + + +class SimpleStorageTestCase(testtools.TestCase): + + def setUp(self): + super(SimpleStorageTestCase, self).setUp() + self.conn = mock.Mock() + simple_file = ('proliantutils/tests/redfish/json_samples/' + 'simple_storage.json') + with open(simple_file, 'r') as f: + self.simple_json = json.loads(f.read()) + self.conn.get.return_value.json.return_value = self.simple_json + + simple_path = ("/redfish/v1/Systems/437XR1138R2/SimpleStorage/1") + self.sys_simple = simple_storage.SimpleStorage( + self.conn, simple_path, redfish_version='1.0.2') + + def test__parse_attributes(self): + self.sys_simple._parse_attributes() + self.assertEqual('1.0.2', self.sys_simple.redfish_version) + self.assertEqual('1', self.sys_simple.identity) + self.assertEqual('Simple Storage Controller', self.sys_simple.name) + self.assertEqual('System SATA', self.sys_simple.description) + self.assertEqual(self.simple_json.get('Devices'), + self.sys_simple.devices) + + def test_maximum_size_bytes(self): + self.assertIsNone(self.sys_simple._maximum_size_bytes) + self.conn.get.return_value.json.reset_mock() + expected = 8000000000000 + actual = self.sys_simple.maximum_size_bytes + self.assertEqual(expected, actual) + + def test_maximum_size_bytes_on_refresh(self): + self.sys_simple.refresh() + self.assertIsNone(self.sys_simple._maximum_size_bytes) + + +class SimpleStorageCollectionTestCase(testtools.TestCase): + + def setUp(self): + super(SimpleStorageCollectionTestCase, self).setUp() + self.conn = mock.Mock() + with open('proliantutils/tests/redfish/json_samples/' + 'simple_storage_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + self.sys_simple_col = simple_storage.SimpleStorageCollection( + self.conn, '/redfish/v1/Systems/437XR1138R2/SimpleStorage', + redfish_version='1.0.2') + + def test__parse_attributes(self): + self.sys_simple_col._parse_attributes() + self.assertEqual('1.0.2', self.sys_simple_col.redfish_version) + self.assertEqual('Simple Storage Collection', + self.sys_simple_col.name) + simple_path = ('/redfish/v1/Systems/437XR1138R2/SimpleStorage/1',) + self.assertEqual(simple_path, self.sys_simple_col.members_identities) + + @mock.patch.object(simple_storage, 'SimpleStorage', autospec=True) + def test_get_member(self, mock_simple): + self.sys_simple_col.get_member( + '/redfish/v1/Systems/437XR1138R2/SimpleStorage/1') + mock_simple.assert_called_once_with( + self.sys_simple_col._conn, + '/redfish/v1/Systems/437XR1138R2/SimpleStorage/1', + redfish_version=self.sys_simple_col.redfish_version) + + @mock.patch.object(simple_storage, 'SimpleStorage', autospec=True) + def test_get_members(self, mock_simple): + members = self.sys_simple_col.get_members() + simple_path = ("/redfish/v1/Systems/437XR1138R2/SimpleStorage/1") + calls = [ + mock.call(self.sys_simple_col._conn, simple_path, + redfish_version=self.sys_simple_col.redfish_version), + ] + mock_simple.assert_has_calls(calls) + self.assertIsInstance(members, list) + self.assertEqual(1, len(members)) + + def test_maximum_size_bytes(self): + self.assertIsNone(self.sys_simple_col._maximum_size_bytes) + self.conn.get.return_value.json.reset_mock() + path = ('proliantutils/tests/redfish/json_samples/' + 'simple_storage.json') + with open(path, 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + expected = 8000000000000 + actual = self.sys_simple_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 24532d0b..134a5b57 100644 --- a/proliantutils/tests/redfish/resources/system/test_system.py +++ b/proliantutils/tests/redfish/resources/system/test_system.py @@ -24,6 +24,7 @@ from proliantutils.redfish.resources.system import bios 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 simple_storage from proliantutils.redfish.resources.system.storage import smart_storage from proliantutils.redfish.resources.system.storage import storage from proliantutils.redfish.resources.system import system @@ -376,3 +377,48 @@ class HPESystemTestCase(testtools.TestCase): self.sys_inst.storages self.assertIsInstance(self.sys_inst._storages, storage.StorageCollection) + + def test_simple_storages(self): + self.conn.get.return_value.json.reset_mock() + coll = None + value = None + path = ('proliantutils/tests/redfish/json_samples/' + 'simple_storage_collection.json') + with open(path, 'r') as f: + coll = json.loads(f.read()) + with open('proliantutils/tests/redfish/json_samples/' + 'simple_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._simple_storages) + self.sys_inst.simple_storages + self.assertIsInstance(self.sys_inst._simple_storages, + simple_storage.SimpleStorageCollection) + + def test_simple_storage_on_refresh(self): + # | GIVEN | + with open('proliantutils/tests/redfish/json_samples/' + 'simple_storage_collection.json', + 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + # | WHEN & THEN | + self.assertIsInstance(self.sys_inst.simple_storages, + simple_storage.SimpleStorageCollection) + + # On refreshing the system instance... + with open('proliantutils/tests/redfish/' + 'json_samples/system.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())['default']) + self.sys_inst.refresh() + + # | WHEN & THEN | + self.assertIsNone(self.sys_inst._simple_storages) + + # | GIVEN | + with open('proliantutils/tests/redfish/json_samples/' + 'simple_storage_collection.json', 'r') as f: + self.conn.get.return_value.json.return_value = json.loads(f.read()) + # | WHEN & THEN | + self.assertIsInstance(self.sys_inst.simple_storages, + simple_storage.SimpleStorageCollection)