From e13da0e76388944c1462240524e32dc6f233c41d Mon Sep 17 00:00:00 2001 From: Lin Yang Date: Wed, 13 Sep 2017 14:46:12 -0700 Subject: [PATCH] Add new command to show fabric details New command 'openstack rsd fabric show ' to allow user to show the details of fabric resource. Change-Id: Ie51478e3c66bb8bce57b133fbab2d70f2ba7dc79 --- rsdclient/common/utils.py | 2 + rsdclient/osc/v1/fabric.py | 21 +++++ rsdclient/tests/common/fakes.py | 95 ++++++++++++++++++++++ rsdclient/tests/v1/test_fabric.py | 58 +++++++++++++ rsdclient/tests/v1/test_storage_service.py | 4 +- rsdclient/v1/fabric.py | 19 +++++ setup.cfg | 1 + 7 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 rsdclient/tests/v1/test_fabric.py diff --git a/rsdclient/common/utils.py b/rsdclient/common/utils.py index 873fdfc..d8e0e21 100644 --- a/rsdclient/common/utils.py +++ b/rsdclient/common/utils.py @@ -28,6 +28,8 @@ def extract_attr(redfish_obj): return redfish_obj if isinstance(redfish_obj, list): return [extract_attr(i) for i in redfish_obj] + if isinstance(redfish_obj, tuple): + return tuple(extract_attr(i) for i in redfish_obj) if isinstance(redfish_obj, dict): return {i: extract_attr(redfish_obj[i]) for i in redfish_obj} diff --git a/rsdclient/osc/v1/fabric.py b/rsdclient/osc/v1/fabric.py index 4683f16..71f786a 100644 --- a/rsdclient/osc/v1/fabric.py +++ b/rsdclient/osc/v1/fabric.py @@ -13,6 +13,8 @@ # under the License. # +import json + from rsdclient.common import command @@ -24,3 +26,22 @@ class ListFabric(command.Command): rsd_client = self.app.client_manager.rsd fabric_list = rsd_client.fabric.list() print(fabric_list) + + +class ShowFabric(command.Command): + _description = "Display fabric details" + + def get_parser(self, prog_name): + parser = super(ShowFabric, self).get_parser(prog_name) + parser.add_argument( + 'fabric', + metavar='', + help='ID of the fabric.') + + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + rsd_client = self.app.client_manager.rsd + fabric_detail = rsd_client.fabric.show(parsed_args.fabric) + print("{0}".format(json.dumps(fabric_detail, indent=2))) diff --git a/rsdclient/tests/common/fakes.py b/rsdclient/tests/common/fakes.py index 75a20b7..9de7af0 100644 --- a/rsdclient/tests/common/fakes.py +++ b/rsdclient/tests/common/fakes.py @@ -190,3 +190,98 @@ class FakeStorageSerice(object): self.physical_drives.get_members.return_value = [FakePhysicalDrive()] self.logical_drives = mock.Mock() self.logical_drives.get_members.return_value = [FakeLogicalDrive()] + + +FAKE_FABRIC_PYTHON_DICT = { + 'description': 'PCIe Fabric', + 'fabric_type': 'PCIe', + 'identity': 'PCIe', + 'max_zones': 5, + 'name': 'PCIe Fabric', + 'zones': [{ + 'description': 'PCIe Zone 1', + 'identity': '1', + 'links': { + 'endpoint_identities': ( + '/redfish/v1/Fabrics/PCIe/Endpoints/HostRootComplex1', + '/redfish/v1/Fabrics/PCIe/Endpoints/NVMeDrivePF2' + ) + }, + 'name': 'PCIe Zone 1' + }], + 'endpoints': [{ + 'connected_entities': [{ + 'entity_link': '/redfish/v1/Chassis/PCIeSwitch1/Drives/Disk.Bay.0', + 'entity_role': 'Target', + 'entity_type': 'Drive', + 'identifiers': [{ + 'name': '00000000-0000-0000-0000-000000000000', + 'name_format': 'UUID' + }] + }], + 'description': 'The PCIe Physical function of an 850GB NVMe drive', + 'host_reservation_memory': 1000, + 'identifiers': [{ + 'name': '00000000-0000-0000-0000-000000000000', + 'name_format': 'UUID' + }], + 'identity': 'NVMeDrivePF1', + 'name': 'NVMe Drive', + 'protocol': 'PCIe', + 'redfish_version': '1.0.2', + 'redundancy': [] + }] +} + + +class FakeEndpoint(object): + + def __init__(self): + self.connected_entities = [{ + 'entity_link': '/redfish/v1/Chassis/PCIeSwitch1/Drives/Disk.Bay.0', + 'entity_role': 'Target', + 'entity_type': 'Drive', + 'identifiers': [{ + 'name': '00000000-0000-0000-0000-000000000000', + 'name_format': 'UUID' + }] + }] + self.description = 'The PCIe Physical function of an 850GB NVMe drive' + self.host_reservation_memory = 1000 + self.identifiers = [{ + 'name': '00000000-0000-0000-0000-000000000000', + 'name_format': 'UUID' + }] + self.identity = 'NVMeDrivePF1' + self.name = 'NVMe Drive' + self.protocol = 'PCIe' + self.redfish_version = '1.0.2' + self.redundancy = [] + + +class FakeZone(object): + + def __init__(self): + self.description = 'PCIe Zone 1' + self.identity = '1' + self.name = 'PCIe Zone 1' + self.links = { + 'endpoint_identities': ( + '/redfish/v1/Fabrics/PCIe/Endpoints/HostRootComplex1', + '/redfish/v1/Fabrics/PCIe/Endpoints/NVMeDrivePF2' + ) + } + + +class FakeFabric(object): + + def __init__(self): + self.description = 'PCIe Fabric' + self.fabric_type = 'PCIe' + self.identity = 'PCIe' + self.max_zones = 5 + self.name = 'PCIe Fabric' + self.endpoints = mock.Mock() + self.endpoints.get_members.return_value = [FakeEndpoint()] + self.zones = mock.Mock() + self.zones.get_members.return_value = [FakeZone()] diff --git a/rsdclient/tests/v1/test_fabric.py b/rsdclient/tests/v1/test_fabric.py new file mode 100644 index 0000000..28e1a66 --- /dev/null +++ b/rsdclient/tests/v1/test_fabric.py @@ -0,0 +1,58 @@ +# Copyright 2017 Intel, Inc. +# +# 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 mock +import testtools + +from rsdclient.tests.common import fakes +from rsdclient.v1 import fabric + + +class FabricTest(testtools.TestCase): + + def setUp(self): + super(FabricTest, self).setUp() + self.client = mock.Mock() + self.client._fabrics_path = '/redfish/v1/Fabrics' + self.mgr = fabric.FabricManager(self.client) + + def test_list_fabric(self): + mock_fabric_collection = mock.Mock() + mock_fabric_collection.members_identities = \ + ('/redfish/v1/Fabrics/PCIe',) + self.mgr.client.get_fabric_collection.return_value = \ + mock_fabric_collection + self.mgr.client.get_fabric.return_value = fakes.FakeFabric() + + expected = ( + '+----------+-------------+-------------+-------------+\n' + '| Identity | Name | Fabric_Type | Description |\n' + '+----------+-------------+-------------+-------------+\n' + '| PCIe | PCIe Fabric | PCIe | PCIe Fabric |\n' + '+----------+-------------+-------------+-------------+') + + result = self.mgr.list() + self.mgr.client.get_fabric_collection.assert_called_once() + self.mgr.client.get_fabric.assert_called_once_with( + '/redfish/v1/Fabrics/PCIe') + self.assertEqual(str(result), expected) + + def test_show_fabric(self): + self.client.get_fabric.return_value = fakes.FakeFabric() + result = self.mgr.show('PCIe') + expected = fakes.FAKE_FABRIC_PYTHON_DICT + self.mgr.client.get_fabric.assert_called_once_with( + '/redfish/v1/Fabrics/PCIe') + self.assertEqual(result, expected) diff --git a/rsdclient/tests/v1/test_storage_service.py b/rsdclient/tests/v1/test_storage_service.py index 1c1ff51..a992b59 100644 --- a/rsdclient/tests/v1/test_storage_service.py +++ b/rsdclient/tests/v1/test_storage_service.py @@ -20,10 +20,10 @@ from rsdclient.tests.common import fakes from rsdclient.v1 import storage_service -class NodeTest(testtools.TestCase): +class StorageServiceTest(testtools.TestCase): def setUp(self): - super(NodeTest, self).setUp() + super(StorageServiceTest, self).setUp() self.client = mock.Mock() self.client._storage_service_path = '/redfish/v1/Services' self.mgr = storage_service.StorageServiceManager(self.client) diff --git a/rsdclient/v1/fabric.py b/rsdclient/v1/fabric.py index fd6f278..6a16d46 100644 --- a/rsdclient/v1/fabric.py +++ b/rsdclient/v1/fabric.py @@ -13,6 +13,8 @@ # under the License. # +import os + from rsdclient.common import base from rsdclient.common import utils @@ -24,6 +26,9 @@ class FabricManager(base.Manager): super(FabricManager, self).__init__(*args, **kwargs) self.fabrics_path = self.client._fabrics_path + def _get_fabric_uri(self, fabric_id): + return os.path.join(self.fabrics_path, fabric_id) + def list(self): fabric_collection = self.client.get_fabric_collection() fabrics = [utils.extract_attr(self.client.get_fabric(fabric_uri)) @@ -31,3 +36,17 @@ class FabricManager(base.Manager): fabric_info_table = utils.print_dict( fabrics, ["Identity", "Name", "Fabric_Type", "Description"]) return fabric_info_table + + def show(self, fabric_id): + fabric = self.client.get_fabric(self._get_fabric_uri(fabric_id)) + fabric_dict = utils.extract_attr(fabric) + + # Append sub-items attributions + fabric_dict['endpoints'] = [ + utils.extract_attr(item) + for item in fabric.endpoints.get_members()] + fabric_dict['zones'] = [ + utils.extract_attr(item) + for item in fabric.zones.get_members()] + + return fabric_dict diff --git a/setup.cfg b/setup.cfg index ce9274a..b2db077 100644 --- a/setup.cfg +++ b/setup.cfg @@ -39,6 +39,7 @@ openstack.rsd.v1 = rsd_storage_show = rsdclient.osc.v1.storage_service:ShowStorageServices rsd_fabric_list = rsdclient.osc.v1.fabric:ListFabric + rsd_fabric_show = rsdclient.osc.v1.fabric:ShowFabric [build_sphinx] all-files = 1