Merge "Add System<->Manager linkage"

This commit is contained in:
Zuul 2019-01-08 14:20:14 +00:00 committed by Gerrit Code Review
commit 815da08998
7 changed files with 100 additions and 6 deletions

View File

@ -0,0 +1,6 @@
---
features:
- |
Establishes ComputerSystem->Managers and Manager->ComputerSystems
references at sushy data abstraction level what make it possible to
look up Manager(s) responsible for a ComputerSystem and vice versa.

View File

@ -195,6 +195,25 @@ class Manager(base.ResourceBase):
self._conn, utils.get_sub_resource_path_by(self, 'VirtualMedia'),
redfish_version=self.redfish_version)
@property
@utils.cache_it
def systems(self):
"""A list of systems managed by this manager.
Returns a list of `System` objects representing systems being
managed by this manager.
:raises: MissingAttributeError if '@odata.id' field is missing.
:returns: A list of `System` instances
"""
paths = utils.get_sub_resource_path_by(
self, ["Links", "ManagerForServers"], is_collection=True)
from sushy.resources.system import system
return [system.System(self._conn, path,
redfish_version=self.redfish_version)
for path in paths]
class ManagerCollection(base.ResourceCollectionBase):

View File

@ -21,6 +21,7 @@ import logging
from sushy import exceptions
from sushy.resources import base
from sushy.resources import common
from sushy.resources.manager import manager
from sushy.resources import mappings as res_maps
from sushy.resources.system import bios
from sushy.resources.system import constants as sys_cons
@ -336,6 +337,24 @@ class System(base.ResourceBase):
self._conn, utils.get_sub_resource_path_by(self, "Storage"),
redfish_version=self.redfish_version)
@property
@utils.cache_it
def managers(self):
"""A list of managers for this system.
Returns a list of `Manager` objects representing the managers
that manage this system.
:raises: MissingAttributeError if '@odata.id' field is missing.
:returns: A list of `Manager` instances
"""
paths = utils.get_sub_resource_path_by(
self, ["Links", "ManagedBy"], is_collection=True)
return [manager.Manager(self._conn, path,
redfish_version=self.redfish_version)
for path in paths]
class SystemCollection(base.ResourceCollectionBase):

View File

@ -18,6 +18,7 @@ import sushy
from sushy import exceptions
from sushy.resources.manager import manager
from sushy.resources.manager import virtual_media
from sushy.resources.system import system
from sushy.tests.unit import base
@ -266,6 +267,18 @@ class ManagerTestCase(base.TestCase):
virtual_media.VirtualMediaCollection)
self.assertFalse(vrt_media._is_stale)
def test_systems(self):
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'system.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
actual_systems = self.manager.systems
self.assertIsInstance(actual_systems[0], system.System)
self.assertEqual(
'/redfish/v1/Systems/437XR1138R2', actual_systems[0].path)
class ManagerCollectionTestCase(base.TestCase):

View File

@ -20,6 +20,7 @@ import mock
import sushy
from sushy import exceptions
from sushy.resources import constants as res_cons
from sushy.resources.manager import manager
from sushy.resources.system import bios
from sushy.resources.system import mappings as sys_map
from sushy.resources.system import processor
@ -478,6 +479,18 @@ class SystemTestCase(base.TestCase):
# | WHEN & THEN |
self.assertIsInstance(self.sys_inst.storage, storage.StorageCollection)
def test_managers(self):
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'manager.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
actual_managers = self.sys_inst.managers
self.assertIsInstance(actual_managers[0], manager.Manager)
self.assertEqual(
'/redfish/v1/Managers/BMC', actual_managers[0].path)
class SystemCollectionTestCase(base.TestCase):

View File

@ -69,6 +69,14 @@ class UtilsTestCase(base.TestCase):
subresource_path)
self.assertEqual(expected_result, value)
def test_get_sub_resource_path_by_collection(self):
subresource_path = ["Links", "ManagedBy"]
expected_result = ['/redfish/v1/Managers/BMC']
value = utils.get_sub_resource_path_by(self.sys_inst,
subresource_path,
is_collection=True)
self.assertEqual(expected_result, value)
def test_get_sub_resource_path_by_fails(self):
subresource_path = ['Links', 'Chassis']
expected_result = 'attribute Links/Chassis/@odata.id is missing'

View File

@ -66,13 +66,17 @@ def int_or_none(x):
return int(x)
def get_sub_resource_path_by(resource, subresource_name):
def get_sub_resource_path_by(resource, subresource_name, is_collection=False):
"""Helper function to find the subresource path
:param resource: ResourceBase instance on which the name
gets queried upon.
:param subresource_name: name of the resource field to
fetch the '@odata.id' from.
:param is_collection: if `True`, expect a list of resources to
fetch the '@odata.id' from.
:returns: Resource path (if `is_collection` is `False`) or
a list of resource paths (if `is_collection` is `True`).
"""
if not subresource_name:
raise ValueError('"subresource_name" cannot be empty')
@ -88,12 +92,24 @@ def get_sub_resource_path_by(resource, subresource_name):
raise exceptions.MissingAttributeError(
attribute='/'.join(subresource_name), resource=resource.path)
if '@odata.id' not in body:
raise exceptions.MissingAttributeError(
attribute='/'.join(subresource_name) + '/@odata.id',
resource=resource.path)
elements = []
return body['@odata.id']
try:
if is_collection:
for element in body:
elements.append(element['@odata.id'])
return elements
else:
return body['@odata.id']
except (TypeError, KeyError):
attribute = '/'.join(subresource_name)
if is_collection:
attribute += '[%s]' % len(elements)
attribute += '/@odata.id'
raise exceptions.MissingAttributeError(
attribute=attribute, resource=resource.path)
def max_safe(iterable, default=0):