Merge "Add `FabricCollection` and `Fabric` classes"

This commit is contained in:
Zuul 2019-04-17 21:49:18 +00:00 committed by Gerrit Code Review
commit f10322a67c
13 changed files with 347 additions and 0 deletions

View File

@ -0,0 +1,5 @@
---
features:
- |
Adds support for the Fabric resource to the library.

View File

@ -21,6 +21,7 @@ from sushy.resources.constants import * # noqa
from sushy.resources.system.constants import * # noqa from sushy.resources.system.constants import * # noqa
from sushy.resources.manager.constants import * # noqa from sushy.resources.manager.constants import * # noqa
from sushy.resources.chassis.constants import * # noqa from sushy.resources.chassis.constants import * # noqa
from sushy.resources.fabric.constants import * # noqa
__all__ = ('Sushy',) __all__ = ('Sushy',)
__version__ = pbr.version.VersionInfo( __version__ = pbr.version.VersionInfo(

View File

@ -21,6 +21,7 @@ from sushy import exceptions
from sushy.resources import base from sushy.resources import base
from sushy.resources.chassis import chassis from sushy.resources.chassis import chassis
from sushy.resources.compositionservice import compositionservice from sushy.resources.compositionservice import compositionservice
from sushy.resources.fabric import fabric
from sushy.resources.manager import manager from sushy.resources.manager import manager
from sushy.resources.registry import message_registry from sushy.resources.registry import message_registry
from sushy.resources.registry import message_registry_file from sushy.resources.registry import message_registry_file
@ -83,6 +84,9 @@ class Sushy(base.ResourceBase):
_chassis_path = base.Field(['Chassis', '@odata.id']) _chassis_path = base.Field(['Chassis', '@odata.id'])
"""ChassisCollection path""" """ChassisCollection path"""
_fabrics_path = base.Field(['Fabrics', '@odata.id'])
"""FabricCollection path"""
_session_service_path = base.Field(['SessionService', '@odata.id']) _session_service_path = base.Field(['SessionService', '@odata.id'])
"""SessionService path""" """SessionService path"""
@ -192,6 +196,29 @@ class Sushy(base.ResourceBase):
return chassis.Chassis(self._conn, identity, return chassis.Chassis(self._conn, identity,
redfish_version=self.redfish_version) redfish_version=self.redfish_version)
def get_fabric_collection(self):
"""Get the FabricCollection object
:raises: MissingAttributeError, if the collection attribute is
not found
:returns: a FabricCollection object
"""
if not self._fabrics_path:
raise exceptions.MissingAttributeError(
attribute='Fabrics/@odata.id', resource=self._path)
return fabric.FabricCollection(self._conn, self._fabrics_path,
redfish_version=self.redfish_version)
def get_fabric(self, identity):
"""Given the identity return a Fabric object
:param identity: The identity of the Fabric resource
:returns: The Fabric object
"""
return fabric.Fabric(self._conn, identity,
redfish_version=self.redfish_version)
def get_manager_collection(self): def get_manager_collection(self):
"""Get the ManagerCollection object """Get the ManagerCollection object

View File

View File

@ -0,0 +1,42 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Values come from the Redfish Fabric json-schema 1.0.4:
# http://redfish.dmtf.org/schemas/v1/Fabric.v1_0_4.json#/definitions/Fabric
# Fabric Types constants
FABRIC_TYPE_AHCI = 'Advanced Host Controller Interface'
FABRIC_TYPE_FC = 'Fibre Channel'
FABRIC_TYPE_FCP = 'Fibre Channel Protocol for SCSI'
FABRIC_TYPE_FCoE = 'Fibre Channel over Ethernet'
FABRIC_TYPE_FICON = 'FIbre CONnection (FICON)'
FABRIC_TYPE_FTP = 'File Transfer Protocol'
FABRIC_TYPE_HTTP = 'Hypertext Transport Protocol'
FABRIC_TYPE_HTTPS = 'Secure Hypertext Transport Protocol'
FABRIC_TYPE_I2C = 'Inter-Integrated Circuit Bus'
FABRIC_TYPE_NFSv3 = 'Network File System version 3'
FABRIC_TYPE_NFSv4 = 'Network File System version 4'
FABRIC_TYPE_NVMe = 'Non-Volatile Memory Express'
FABRIC_TYPE_NVMeOverFabrics = 'NVMe over Fabrics'
FABRIC_TYPE_OEM = 'OEM specific'
FABRIC_TYPE_PCIe = 'PCI Express'
FABRIC_TYPE_RoCE = 'RDMA over Converged Ethernet Protocol'
FABRIC_TYPE_RoCEv2 = 'RDMA over Converged Ethernet Protocol Version 2'
FABRIC_TYPE_SAS = 'Serial Attached SCSI'
FABRIC_TYPE_SATA = 'Serial AT Attachment'
FABRIC_TYPE_SFTP = 'Secure File Transfer Protocol'
FABRIC_TYPE_SMB = 'Server Message Block (aka CIFS Common Internet File System)'
FABRIC_TYPE_UHCI = 'Universal Host Controller Interface'
FABRIC_TYPE_USB = 'Universal Serial Bus'
FABRIC_TYPE_iSCSI = 'Internet SCSI'
FABRIC_TYPE_iWARP = 'Internet Wide Area Remote Direct Memory Access Protocol'

View File

@ -0,0 +1,77 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# This is referred from Redfish standard schema.
# http://redfish.dmtf.org/schemas/v1/Fabric.v1_0_4.json
from sushy.resources import base
from sushy.resources import common
from sushy.resources.fabric import mappings as fab_maps
import logging
LOG = logging.getLogger(__name__)
class Fabric(base.ResourceBase):
"""Fabric resource
The Fabric represents a simple fabric consisting of one or more
switches, zero or more endpoints, and zero or more zones.
"""
identity = base.Field('Id', required=True)
"""Identifier for the fabric"""
name = base.Field('Name', required=True)
"""The fabric name"""
description = base.Field('Description')
"""The fabric description"""
max_zones = base.Field('MaxZones')
"""The maximum number of zones the switch can currently configure"""
status = common.StatusField('Status')
"""The fabric status"""
fabric_type = base.MappedField('FabricType',
fab_maps.FABRIC_TYPE_VALUE_MAP)
"""The protocol being sent over this fabric"""
def __init__(self, connector, identity, redfish_version=None):
"""A class representing a Fabric
:param connector: A Connector instance
:param identity: The identity of the Fabric resource
:param redfish_version: The version of RedFish. Used to construct
the object according to schema of the given version.
"""
super(Fabric, self).__init__(connector, identity, redfish_version)
class FabricCollection(base.ResourceCollectionBase):
@property
def _resource_type(self):
return Fabric
def __init__(self, connector, path, redfish_version=None):
"""A class representing a FabricCollection
:param connector: A Connector instance
:param path: The canonical path to the Fabric collection resource
:param redfish_version: The version of RedFish. Used to construct
the object according to schema of the given version.
"""
super(FabricCollection, self).__init__(connector, path,
redfish_version)

View File

@ -0,0 +1,47 @@
# Copyright 2017 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sushy.resources.fabric import constants as fab_cons
from sushy import utils
FABRIC_TYPE_VALUE_MAP = {
'AHCI': fab_cons.FABRIC_TYPE_AHCI,
'FC': fab_cons.FABRIC_TYPE_FC,
'FCP': fab_cons.FABRIC_TYPE_FCP,
'FCoE': fab_cons.FABRIC_TYPE_FCoE,
'FICON': fab_cons.FABRIC_TYPE_FICON,
'FTP': fab_cons.FABRIC_TYPE_FTP,
'HTTP': fab_cons.FABRIC_TYPE_HTTP,
'HTTPS': fab_cons.FABRIC_TYPE_HTTPS,
'I2C': fab_cons.FABRIC_TYPE_I2C,
'NFSv3': fab_cons.FABRIC_TYPE_NFSv3,
'NFSv4': fab_cons.FABRIC_TYPE_NFSv4,
'NVMe': fab_cons.FABRIC_TYPE_NVMe,
'NVMeOverFabrics': fab_cons.FABRIC_TYPE_NVMeOverFabrics,
'OEM': fab_cons.FABRIC_TYPE_OEM,
'PCIe': fab_cons.FABRIC_TYPE_PCIe,
'RoCE': fab_cons.FABRIC_TYPE_RoCE,
'RoCEv2': fab_cons.FABRIC_TYPE_RoCEv2,
'SAS': fab_cons.FABRIC_TYPE_SAS,
'SATA': fab_cons.FABRIC_TYPE_SATA,
'SFTP': fab_cons.FABRIC_TYPE_SFTP,
'SMB': fab_cons.FABRIC_TYPE_SMB,
'UHCI': fab_cons.FABRIC_TYPE_UHCI,
'USB': fab_cons.FABRIC_TYPE_USB,
'iSCSI': fab_cons.FABRIC_TYPE_iSCSI,
'iWARP': fab_cons.FABRIC_TYPE_iWARP,
}
FABRIC_TYPE_VALUE_MAP_REV = utils.revert_dictionary(FABRIC_TYPE_VALUE_MAP)

View File

@ -0,0 +1,29 @@
{
"@odata.type": "#Fabric.v1_0_3.Fabric",
"Id": "SAS",
"Name": "SAS Fabric",
"FabricType": "SAS",
"Description": "A SAS Fabric with redundant switches.",
"Status": {
"State": "Enabled",
"Health": "OK"
},
"Zones": {
"@odata.id": "/redfish/v1/Fabrics/SAS/Zones"
},
"Endpoints": {
"@odata.id": "/redfish/v1/Fabrics/SAS/Endpoints"
},
"Switches": {
"@odata.id": "/redfish/v1/Fabrics/SAS/Switches"
},
"Links": {
"Oem": {}
},
"Actions": {
"Oem": {}
},
"Oem": {},
"@odata.context": "/redfish/v1/$metadata#Fabric.Fabric",
"@odata.id": "/redfish/v1/Fabrics/SAS"
}

View File

@ -0,0 +1,16 @@
{
"@odata.type": "#FabricCollection.FabricCollection",
"Name": "Fabric Collection",
"Members@odata.count": 2,
"Members": [
{
"@odata.id": "/redfish/v1/Fabrics/SAS1"
},
{
"@odata.id": "/redfish/v1/Fabrics/SAS2"
}
],
"@odata.context": "/redfish/v1/$metadata#FabricCollection.FabricCollection",
"@odata.id": "/redfish/v1/Fabrics",
"@Redfish.Copyright": "Copyright 2014-2017 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
}

View File

@ -21,6 +21,9 @@
"Managers": { "Managers": {
"@odata.id": "/redfish/v1/Managers" "@odata.id": "/redfish/v1/Managers"
}, },
"Fabrics": {
"@odata.id": "/redfish/v1/Fabrics"
},
"Tasks": { "Tasks": {
"@odata.id": "/redfish/v1/TaskService" "@odata.id": "/redfish/v1/TaskService"
}, },

View File

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import mock
import sushy
from sushy.resources.fabric import fabric
from sushy.tests.unit import base
class FabricTestCase(base.TestCase):
def setUp(self):
super(FabricTestCase, self).setUp()
self.conn = mock.Mock()
with open('sushy/tests/unit/json_samples/fabric.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
self.fabric = fabric.Fabric(self.conn, '/redfish/v1/Fabrics/SAS',
redfish_version='1.0.3')
def test__parse_attributes(self):
# | WHEN |
self.fabric._parse_attributes()
# | THEN |
self.assertEqual('1.0.3', self.fabric.redfish_version)
self.assertEqual('SAS', self.fabric.identity)
self.assertEqual('SAS Fabric', self.fabric.name)
self.assertEqual('A SAS Fabric with redundant switches.',
self.fabric.description)
self.assertEqual(sushy.FABRIC_TYPE_SAS,
self.fabric.fabric_type)
self.assertEqual(sushy.STATE_ENABLED, self.fabric.status.state)
self.assertEqual(sushy.HEALTH_OK, self.fabric.status.health)
class FabricCollectionTestCase(base.TestCase):
def setUp(self):
super(FabricCollectionTestCase, self).setUp()
self.conn = mock.Mock()
with open('sushy/tests/unit/json_samples/'
'fabric_collection.json') as f:
self.conn.get.return_value.json.return_value = json.load(f)
self.fabric = fabric.FabricCollection(
self.conn, '/redfish/v1/Fabrics', redfish_version='1.0.3')
@mock.patch.object(fabric, 'Fabric', autospec=True)
def test_get_member(self, fabric_mock):
self.fabric.get_member('/redfish/v1/Fabrics/SAS1')
fabric_mock.assert_called_once_with(
self.fabric._conn, '/redfish/v1/Fabrics/SAS1',
redfish_version=self.fabric.redfish_version)
@mock.patch.object(fabric, 'Fabric', autospec=True)
def test_get_members(self, fabric_mock):
members = self.fabric.get_members()
calls = [
mock.call(self.fabric._conn, '/redfish/v1/Fabrics/SAS1',
redfish_version=self.fabric.redfish_version),
mock.call(self.fabric._conn, '/redfish/v1/Fabrics/SAS2',
redfish_version=self.fabric.redfish_version)
]
fabric_mock.assert_has_calls(calls)
self.assertIsInstance(members, list)
self.assertEqual(2, len(members))

View File

@ -22,6 +22,7 @@ from sushy import exceptions
from sushy import main from sushy import main
from sushy.resources.chassis import chassis from sushy.resources.chassis import chassis
from sushy.resources.compositionservice import compositionservice from sushy.resources.compositionservice import compositionservice
from sushy.resources.fabric import fabric
from sushy.resources.manager import manager from sushy.resources.manager import manager
from sushy.resources.registry import message_registry_file from sushy.resources.registry import message_registry_file
from sushy.resources.sessionservice import session from sushy.resources.sessionservice import session
@ -67,6 +68,7 @@ class MainTestCase(base.TestCase):
self.assertEqual('/redfish/v1/Systems', self.root._systems_path) self.assertEqual('/redfish/v1/Systems', self.root._systems_path)
self.assertEqual('/redfish/v1/Managers', self.root._managers_path) self.assertEqual('/redfish/v1/Managers', self.root._managers_path)
self.assertEqual('/redfish/v1/Chassis', self.root._chassis_path) self.assertEqual('/redfish/v1/Chassis', self.root._chassis_path)
self.assertEqual('/redfish/v1/Fabrics', self.root._fabrics_path)
self.assertEqual('/redfish/v1/SessionService', self.assertEqual('/redfish/v1/SessionService',
self.root._session_service_path) self.root._session_service_path)
self.assertEqual('/redfish/v1/CompositionService', self.assertEqual('/redfish/v1/CompositionService',
@ -118,6 +120,20 @@ class MainTestCase(base.TestCase):
self.root._conn, '/redfish/v1/Chassis', self.root._conn, '/redfish/v1/Chassis',
redfish_version=self.root.redfish_version) redfish_version=self.root.redfish_version)
@mock.patch.object(fabric, 'Fabric', autospec=True)
def test_get_fabric(self, mock_fabric):
self.root.get_fabric('fake-fabric-id')
mock_fabric.assert_called_once_with(
self.root._conn, 'fake-fabric-id',
redfish_version=self.root.redfish_version)
@mock.patch.object(fabric, 'FabricCollection', autospec=True)
def test_get_fabric_collection(self, fabric_collection_mock):
self.root.get_fabric_collection()
fabric_collection_mock.assert_called_once_with(
self.root._conn, '/redfish/v1/Fabrics',
redfish_version=self.root.redfish_version)
@mock.patch.object(manager, 'ManagerCollection', autospec=True) @mock.patch.object(manager, 'ManagerCollection', autospec=True)
def test_get_manager_collection(self, ManagerCollection_mock): def test_get_manager_collection(self, ManagerCollection_mock):
self.root.get_manager_collection() self.root.get_manager_collection()
@ -205,6 +221,11 @@ class BareMinimumMainTestCase(base.TestCase):
exceptions.MissingAttributeError, exceptions.MissingAttributeError,
'Chassis/@odata.id', self.root.get_chassis_collection) 'Chassis/@odata.id', self.root.get_chassis_collection)
def test_get_fabric_collection_when_fabrics_attr_absent(self):
self.assertRaisesRegex(
exceptions.MissingAttributeError,
'Fabrics/@odata.id', self.root.get_fabric_collection)
def test_get_session_service_when_sessionservice_attr_absent(self): def test_get_session_service_when_sessionservice_attr_absent(self):
self.assertRaisesRegex( self.assertRaisesRegex(
exceptions.MissingAttributeError, exceptions.MissingAttributeError,