Add storage and simple_storage attr to system
Adds the support to get SimpleStorage and Storage collection from System resource via `simple_storage` and `storage` properties respectively. Story: 1668487 Task: 23042 Change-Id: I3a79f2afe6c838636df554ee468f8f2e0cf0859e
This commit is contained in:
parent
b36e7c07f5
commit
fdc3e99169
@ -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.
|
@ -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):
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user