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 ethernet_interface
|
||||||
from sushy.resources.system import mappings as sys_maps
|
from sushy.resources.system import mappings as sys_maps
|
||||||
from sushy.resources.system import processor
|
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
|
from sushy import utils
|
||||||
|
|
||||||
|
|
||||||
@ -119,14 +121,23 @@ class System(base.ResourceBase):
|
|||||||
memory_summary = MemorySummaryField('MemorySummary')
|
memory_summary = MemorySummaryField('MemorySummary')
|
||||||
"""The summary info of memory of the system in general detail"""
|
"""The summary info of memory of the system in general detail"""
|
||||||
|
|
||||||
_processors = None # ref to ProcessorCollection instance
|
|
||||||
|
|
||||||
_actions = ActionsField('Actions', required=True)
|
_actions = ActionsField('Actions', required=True)
|
||||||
|
|
||||||
|
# reference to ProcessorCollection instance
|
||||||
|
_processors = None
|
||||||
|
|
||||||
|
# reference to EthernetInterfaceCollection instance
|
||||||
_ethernet_interfaces = None
|
_ethernet_interfaces = None
|
||||||
|
|
||||||
|
# reference to BIOS instance
|
||||||
_bios = None
|
_bios = None
|
||||||
|
|
||||||
|
# reference to SimpleStorageCollection instance
|
||||||
|
_simple_storage = None
|
||||||
|
|
||||||
|
# reference to StorageCollection instance
|
||||||
|
_storage = None
|
||||||
|
|
||||||
def __init__(self, connector, identity, redfish_version=None):
|
def __init__(self, connector, identity, redfish_version=None):
|
||||||
"""A class representing a ComputerSystem
|
"""A class representing a ComputerSystem
|
||||||
|
|
||||||
@ -303,6 +314,56 @@ class System(base.ResourceBase):
|
|||||||
self._bios.refresh(force=False)
|
self._bios.refresh(force=False)
|
||||||
return self._bios
|
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):
|
def _do_refresh(self, force=False):
|
||||||
"""Do custom resource specific refresh activities
|
"""Do custom resource specific refresh activities
|
||||||
|
|
||||||
@ -316,6 +377,10 @@ class System(base.ResourceBase):
|
|||||||
self._ethernet_interfaces.invalidate(force)
|
self._ethernet_interfaces.invalidate(force)
|
||||||
if self._bios is not None:
|
if self._bios is not None:
|
||||||
self._bios.invalidate(force)
|
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):
|
class SystemCollection(base.ResourceCollectionBase):
|
||||||
|
@ -93,6 +93,9 @@
|
|||||||
"SimpleStorage": {
|
"SimpleStorage": {
|
||||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/SimpleStorage"
|
"@odata.id": "/redfish/v1/Systems/437XR1138R2/SimpleStorage"
|
||||||
},
|
},
|
||||||
|
"Storage": {
|
||||||
|
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Storage"
|
||||||
|
},
|
||||||
"LogServices": {
|
"LogServices": {
|
||||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/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 ethernet_interface
|
||||||
from sushy.resources.system import mappings as sys_map
|
from sushy.resources.system import mappings as sys_map
|
||||||
from sushy.resources.system import processor
|
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.resources.system import system
|
||||||
from sushy.tests.unit import base
|
from sushy.tests.unit import base
|
||||||
|
|
||||||
@ -392,6 +394,120 @@ class SystemTestCase(base.TestCase):
|
|||||||
self.assertEqual('BIOS Configuration Current Settings',
|
self.assertEqual('BIOS Configuration Current Settings',
|
||||||
self.sys_inst.bios.name)
|
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):
|
class SystemCollectionTestCase(base.TestCase):
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ def max_safe(iterable, default=0):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
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:
|
except ValueError:
|
||||||
# TypeError is not caught here as that should be thrown.
|
# TypeError is not caught here as that should be thrown.
|
||||||
return default
|
return default
|
||||||
|
Loading…
x
Reference in New Issue
Block a user