Add Chassis<->ComputerSystem/Manager linkage

Redfish data model rests on three interlinked
entities - ComputerSystem(s), Manager(s) and Chassis. As of this
moment, sushy does not support traversal via Chassis despite the
availability of such linkage in the JSON documents sushy feeds on.

This change establishes Chassis<->ComputerSystem/Managers links.

Change-Id: If26f95b3ef6d70419b3c37b3e9eabe41be258c8d
Story: 2004512
Task: 28308
This commit is contained in:
Ilya Etingof 2018-12-05 17:55:04 +01:00
parent 815da08998
commit bbbadbd0b5
7 changed files with 136 additions and 4 deletions

View File

@ -0,0 +1,7 @@
---
features:
- |
Establishes linkage between Chassis and ComputerSystem/Managers
resources as references at sushy data abstraction level. That
makes it possible to look up Chassis by Manager/ComputerSystem or
any other way around.

View File

@ -17,7 +17,9 @@ from sushy import exceptions
from sushy.resources import base
from sushy.resources.chassis import mappings as cha_maps
from sushy.resources import common
from sushy.resources.manager import manager
from sushy.resources import mappings as res_maps
from sushy import utils
import logging
@ -194,6 +196,43 @@ class Chassis(base.ResourceBase):
self._conn.post(target_uri, data={'ResetType': value})
LOG.info('The Chassis %s is being reset', self.identity)
@property
@utils.cache_it
def managers(self):
"""A list of managers for this chassis.
Returns a list of `Manager` objects representing the managers
that manage this chassis.
: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]
@property
@utils.cache_it
def systems(self):
"""A list of systems residing in this chassis.
Returns a list of `System` objects representing systems being
mounted in this chassis/cabinet.
:raises: MissingAttributeError if '@odata.id' field is missing.
:returns: A list of `System` instances
"""
paths = utils.get_sub_resource_path_by(
self, ["Links", "ComputerSystems"], 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 ChassisCollection(base.ResourceCollectionBase):

View File

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

View File

@ -20,6 +20,7 @@ import logging
from sushy import exceptions
from sushy.resources import base
from sushy.resources.chassis import chassis
from sushy.resources import common
from sushy.resources.manager import manager
from sushy.resources import mappings as res_maps
@ -245,10 +246,6 @@ class System(base.ResourceBase):
# Probably we should call refresh() as well.
self._conn.patch(self.path, data=data)
# TODO(lucasagomes): All system have a Manager and Chassis object,
# include a get_manager() and get_chassis() once we have an abstraction
# for those resources.
def _get_processor_collection_path(self):
"""Helper function to find the ProcessorCollection path"""
return utils.get_sub_resource_path_by(self, 'Processors')
@ -355,6 +352,24 @@ class System(base.ResourceBase):
redfish_version=self.redfish_version)
for path in paths]
@property
@utils.cache_it
def chassis(self):
"""A list of chassis where this system resides.
Returns a list of `Chassis` objects representing the chassis
or cabinets where this system is mounted.
:raises: MissingAttributeError if '@odata.id' field is missing.
:returns: A list of `Chassis` instances
"""
paths = utils.get_sub_resource_path_by(
self, ["Links", "Chassis"], is_collection=True)
return [chassis.Chassis(self._conn, path,
redfish_version=self.redfish_version)
for path in paths]
class SystemCollection(base.ResourceCollectionBase):

View File

@ -19,6 +19,8 @@ import mock
import sushy
from sushy import exceptions
from sushy.resources.chassis import chassis
from sushy.resources.manager import manager
from sushy.resources.system import system
from sushy.tests.unit import base
@ -118,6 +120,30 @@ class ChassisTestCase(base.TestCase):
self.assertRaises(exceptions.InvalidParameterValueError,
self.chassis.reset_chassis, 'invalid-value')
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.chassis.managers
self.assertIsInstance(actual_managers[0], manager.Manager)
self.assertEqual(
'/redfish/v1/Managers/Blade1BMC', actual_managers[0].path)
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.chassis.systems
self.assertIsInstance(actual_systems[0], system.System)
self.assertEqual(
'/redfish/v1/Systems/529QB9450R6', actual_systems[0].path)
class ChassisCollectionTestCase(base.TestCase):

View File

@ -16,6 +16,7 @@ import mock
import sushy
from sushy import exceptions
from sushy.resources.chassis import chassis
from sushy.resources.manager import manager
from sushy.resources.manager import virtual_media
from sushy.resources.system import system
@ -279,6 +280,18 @@ class ManagerTestCase(base.TestCase):
self.assertEqual(
'/redfish/v1/Systems/437XR1138R2', actual_systems[0].path)
def test_chassis(self):
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'chassis.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
actual_chassis = self.manager.chassis
self.assertIsInstance(actual_chassis[0], chassis.Chassis)
self.assertEqual(
'/redfish/v1/Chassis/1U', actual_chassis[0].path)
class ManagerCollectionTestCase(base.TestCase):

View File

@ -19,6 +19,7 @@ import mock
import sushy
from sushy import exceptions
from sushy.resources.chassis import chassis
from sushy.resources import constants as res_cons
from sushy.resources.manager import manager
from sushy.resources.system import bios
@ -491,6 +492,18 @@ class SystemTestCase(base.TestCase):
self.assertEqual(
'/redfish/v1/Managers/BMC', actual_managers[0].path)
def test_chassis(self):
# | GIVEN |
with open('sushy/tests/unit/json_samples/'
'chassis.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
# | WHEN & THEN |
actual_chassis = self.sys_inst.chassis
self.assertIsInstance(actual_chassis[0], chassis.Chassis)
self.assertEqual(
'/redfish/v1/Chassis/1U', actual_chassis[0].path)
class SystemCollectionTestCase(base.TestCase):