Merge "Add storage and simple_storage attr to system"

This commit is contained in:
Zuul 2018-09-15 02:12:02 +00:00 committed by Gerrit Code Review
commit f3b3ea6892
5 changed files with 199 additions and 3 deletions

View File

@ -0,0 +1,12 @@
---
features:
- |
Exposes the ``simple_storage`` and ``storage`` properties from system
resource in sushy.
* ``simple_storage`` property indicates a collection of storage
controllers and their directly-attached devices associated with the
system.
* ``storage`` property refers to a collection of storage subsystem
associated with system. Resources such as drives and volumes can be
accessed from that subsystem.

View File

@ -23,6 +23,8 @@ from sushy.resources.system import constants as sys_cons
from sushy.resources.system import ethernet_interface
from sushy.resources.system import mappings as sys_maps
from sushy.resources.system import processor
from sushy.resources.system import simple_storage as sys_simple_storage
from sushy.resources.system.storage import storage as sys_storage
from sushy import utils
@ -119,14 +121,23 @@ class System(base.ResourceBase):
memory_summary = MemorySummaryField('MemorySummary')
"""The summary info of memory of the system in general detail"""
_processors = None # ref to ProcessorCollection instance
_actions = ActionsField('Actions', required=True)
# reference to ProcessorCollection instance
_processors = None
# reference to EthernetInterfaceCollection instance
_ethernet_interfaces = None
# reference to BIOS instance
_bios = None
# reference to SimpleStorageCollection instance
_simple_storage = None
# reference to StorageCollection instance
_storage = None
def __init__(self, connector, identity, redfish_version=None):
"""A class representing a ComputerSystem
@ -303,6 +314,56 @@ class System(base.ResourceBase):
self._bios.refresh(force=False)
return self._bios
@property
def simple_storage(self):
"""A collection of simple storage associated with system.
This returns a reference to `SimpleStorageCollection` instance.
SimpleStorage represents the properties of a storage controller and its
directly-attached devices.
It is set once when the first time it is queried. On refresh,
this property is marked as stale (greedy-refresh not done).
Here the actual refresh of the sub-resource happens, if stale.
:raises: MissingAttributeError if 'SimpleStorage/@odata.id' field
is missing.
:returns: `SimpleStorageCollection` instance
"""
if self._simple_storage is None:
self._simple_storage = sys_simple_storage.SimpleStorageCollection(
self._conn,
utils.get_sub_resource_path_by(self, "SimpleStorage"),
redfish_version=self.redfish_version)
self._simple_storage.refresh(force=False)
return self._simple_storage
@property
def storage(self):
"""A collection of storage subsystems associated with system.
This returns a reference to `StorageCollection` instance.
A storage subsystem represents a set of storage controllers (physical
or virtual) and the resources such as drives and volumes that can be
accessed from that subsystem.
It is set once when the first time it is queried. On refresh,
this property is marked as stale (greedy-refresh not done).
Here the actual refresh of the sub-resource happens, if stale.
:raises: MissingAttributeError if 'Storage/@odata.id' field
is missing.
:returns: `StorageCollection` instance
"""
if self._storage is None:
self._storage = sys_storage.StorageCollection(
self._conn, utils.get_sub_resource_path_by(self, "Storage"),
redfish_version=self.redfish_version)
self._storage.refresh(force=False)
return self._storage
def _do_refresh(self, force=False):
"""Do custom resource specific refresh activities
@ -316,6 +377,10 @@ class System(base.ResourceBase):
self._ethernet_interfaces.invalidate(force)
if self._bios is not None:
self._bios.invalidate(force)
if self._simple_storage is not None:
self._simple_storage.invalidate(force)
if self._storage is not None:
self._storage.invalidate(force)
class SystemCollection(base.ResourceCollectionBase):

View File

@ -93,6 +93,9 @@
"SimpleStorage": {
"@odata.id": "/redfish/v1/Systems/437XR1138R2/SimpleStorage"
},
"Storage": {
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage"
},
"LogServices": {
"@odata.id": "/redfish/v1/Systems/437XR1138R2/LogServices"
},

View File

@ -24,6 +24,8 @@ from sushy.resources.system import bios
from sushy.resources.system import ethernet_interface
from sushy.resources.system import mappings as sys_map
from sushy.resources.system import processor
from sushy.resources.system import simple_storage
from sushy.resources.system.storage import storage
from sushy.resources.system import system
from sushy.tests.unit import base
@ -392,6 +394,120 @@ class SystemTestCase(base.TestCase):
self.assertEqual('BIOS Configuration Current Settings',
self.sys_inst.bios.name)
def test_simple_storage_for_missing_attr(self):
self.sys_inst.json.pop('SimpleStorage')
with self.assertRaisesRegex(
exceptions.MissingAttributeError, 'attribute SimpleStorage'):
self.sys_inst.simple_storage
def test_simple_storage(self):
# check for the underneath variable value
self.assertIsNone(self.sys_inst._simple_storage)
# | GIVEN |
self.conn.get.return_value.json.reset_mock()
with open('sushy/tests/unit/json_samples/'
'simple_storage_collection.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN |
actual_simple_storage = self.sys_inst.simple_storage
# | THEN |
self.assertIsInstance(actual_simple_storage,
simple_storage.SimpleStorageCollection)
self.conn.get.return_value.json.assert_called_once_with()
# reset mock
self.conn.get.return_value.json.reset_mock()
# | WHEN & THEN |
# tests for same object on invoking subsequently
self.assertIs(actual_simple_storage,
self.sys_inst.simple_storage)
self.conn.get.return_value.json.assert_not_called()
def test_simple_storage_on_refresh(self):
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'simple_storage_collection.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
self.assertIsInstance(self.sys_inst.simple_storage,
simple_storage.SimpleStorageCollection)
# On refreshing the system instance...
with open('sushy/tests/unit/json_samples/system.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
self.sys_inst.invalidate()
self.sys_inst.refresh(force=False)
# | WHEN & THEN |
self.assertIsNotNone(self.sys_inst._simple_storage)
self.assertTrue(self.sys_inst._simple_storage._is_stale)
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'simple_storage_collection.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
self.assertIsInstance(self.sys_inst.simple_storage,
simple_storage.SimpleStorageCollection)
self.assertFalse(self.sys_inst._simple_storage._is_stale)
def test_storage_for_missing_attr(self):
self.sys_inst.json.pop('Storage')
with self.assertRaisesRegex(
exceptions.MissingAttributeError, 'attribute Storage'):
self.sys_inst.storage
def test_storage(self):
# check for the underneath variable value
self.assertIsNone(self.sys_inst._storage)
# | GIVEN |
self.conn.get.return_value.json.reset_mock()
with open('sushy/tests/unit/json_samples/'
'storage_collection.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN |
actual_storage = self.sys_inst.storage
# | THEN |
self.assertIsInstance(actual_storage, storage.StorageCollection)
self.conn.get.return_value.json.assert_called_once_with()
# reset mock
self.conn.get.return_value.json.reset_mock()
# | WHEN & THEN |
# tests for same object on invoking subsequently
self.assertIs(actual_storage, self.sys_inst.storage)
self.conn.get.return_value.json.assert_not_called()
def test_storage_on_refresh(self):
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'storage_collection.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
self.assertIsInstance(self.sys_inst.storage,
storage.StorageCollection)
# On refreshing the system instance...
with open('sushy/tests/unit/json_samples/system.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
self.sys_inst.invalidate()
self.sys_inst.refresh(force=False)
# | WHEN & THEN |
self.assertIsNotNone(self.sys_inst._storage)
self.assertTrue(self.sys_inst._storage._is_stale)
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'storage_collection.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
self.assertIsInstance(self.sys_inst.storage,
storage.StorageCollection)
self.assertFalse(self.sys_inst._storage._is_stale)
class SystemCollectionTestCase(base.TestCase):

View File

@ -102,7 +102,7 @@ def max_safe(iterable, default=0):
"""
try:
return max([x for x in iterable if x is not None])
return max(x for x in iterable if x is not None)
except ValueError:
# TypeError is not caught here as that should be thrown.
return default