Add new get_resource method for rsd-lib 2.1
Add a get_resource method to return a resource instance from a uri, currently there is no way for users to get rsd resource from a uri. This is helpful for cases where users get the path from links and want to access the resource using given path. Change-Id: I51d4ead04d829631d37cb3bad8dd8bcf1194db3f
This commit is contained in:
parent
e05a709a70
commit
642827b727
30
rsd_lib/exceptions.py
Normal file
30
rsd_lib/exceptions.py
Normal file
@ -0,0 +1,30 @@
|
||||
# Copyright 2019 Intel, 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.
|
||||
|
||||
|
||||
class RsdlibError(Exception):
|
||||
"""Basic exception for errors raised by rsd-lib"""
|
||||
|
||||
message = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
if self.message and kwargs:
|
||||
self.message = self.message % kwargs
|
||||
|
||||
super(RsdlibError, self).__init__(self.message)
|
||||
|
||||
|
||||
class NoMatchingResourceError(RsdlibError):
|
||||
message = "No matching resource for the uri %(uri)s"
|
@ -13,8 +13,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
|
||||
from rsd_lib import exceptions as rsd_lib_exceptions
|
||||
from rsd_lib.resources.v2_1.chassis import chassis
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import ethernet_switch
|
||||
from rsd_lib.resources.v2_1.event_service import event_service
|
||||
@ -25,6 +27,7 @@ from rsd_lib.resources.v2_1.registries import message_registry_file
|
||||
from rsd_lib.resources.v2_1.storage_service import storage_service
|
||||
from rsd_lib.resources.v2_1.system import system
|
||||
from rsd_lib.resources.v2_1.task import task_service
|
||||
from rsd_lib.resources.v2_1 import types
|
||||
|
||||
|
||||
class RSDLibV2_1(base.ResourceBase):
|
||||
@ -279,3 +282,34 @@ class RSDLibV2_1(base.ResourceBase):
|
||||
self._event_service_path,
|
||||
redfish_version=self.redfish_version,
|
||||
)
|
||||
|
||||
def _get_resource_class_from_path(self, path):
|
||||
"""Get resource class from a given path
|
||||
|
||||
:param path: Path of any rsd resource
|
||||
:returns: Corresponding resource class
|
||||
"""
|
||||
body = self._conn.get(path=path).json()
|
||||
if not body.get("@odata.type"):
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute="@odata.type", resource=path
|
||||
)
|
||||
|
||||
# Normally the format of resource_type is '#{namespace}.{entity_type}'
|
||||
# Here we use entity_type to find the corresponding resource class
|
||||
entity_type = body["@odata.type"].split(".")[-1]
|
||||
|
||||
return types.RESOURCE_CLASS.get(entity_type)
|
||||
|
||||
def get_resource(self, path):
|
||||
"""Return corresponding resource object from path
|
||||
|
||||
:param path: The path of a resource or resource collection
|
||||
:returns: corresponding resource or resource collection object
|
||||
"""
|
||||
resource_class = self._get_resource_class_from_path(path)
|
||||
if not resource_class:
|
||||
raise rsd_lib_exceptions.NoMatchingResourceError(uri=path)
|
||||
return resource_class(
|
||||
self._conn, path, redfish_version=self.redfish_version
|
||||
)
|
||||
|
163
rsd_lib/resources/v2_1/types.py
Normal file
163
rsd_lib/resources/v2_1/types.py
Normal file
@ -0,0 +1,163 @@
|
||||
# Copyright 2019 Intel, 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 rsd_lib.resources.v2_1.chassis import chassis
|
||||
from rsd_lib.resources.v2_1.chassis import log_entry
|
||||
from rsd_lib.resources.v2_1.chassis import log_service
|
||||
from rsd_lib.resources.v2_1.chassis import power
|
||||
from rsd_lib.resources.v2_1.chassis import power_zone
|
||||
from rsd_lib.resources.v2_1.chassis import thermal
|
||||
from rsd_lib.resources.v2_1.chassis import thermal_zone
|
||||
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import ethernet_switch
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import ethernet_switch_acl
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import ethernet_switch_acl_rule
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import ethernet_switch_port
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import ethernet_switch_static_mac
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import vlan_network_interface
|
||||
|
||||
from rsd_lib.resources.v2_1.event_service import event_destination
|
||||
from rsd_lib.resources.v2_1.event_service import event_service
|
||||
|
||||
from rsd_lib.resources.v2_1.fabric import endpoint
|
||||
from rsd_lib.resources.v2_1.fabric import fabric
|
||||
from rsd_lib.resources.v2_1.fabric import port
|
||||
from rsd_lib.resources.v2_1.fabric import switch
|
||||
from rsd_lib.resources.v2_1.fabric import zone
|
||||
|
||||
from rsd_lib.resources.v2_1.manager import manager
|
||||
from rsd_lib.resources.v2_1.manager import manager_network_protocol
|
||||
from rsd_lib.resources.v2_1.manager import serial_interface
|
||||
from rsd_lib.resources.v2_1.manager import virtual_media
|
||||
|
||||
from rsd_lib.resources.v2_1.node import node
|
||||
|
||||
from rsd_lib.resources.v2_1.registries import message_registry_file
|
||||
|
||||
from rsd_lib.resources.v2_1.storage_service import logical_drive
|
||||
from rsd_lib.resources.v2_1.storage_service import physical_drive
|
||||
from rsd_lib.resources.v2_1.storage_service import remote_target
|
||||
from rsd_lib.resources.v2_1.storage_service import storage_service
|
||||
|
||||
from rsd_lib.resources.v2_1.system import drive
|
||||
from rsd_lib.resources.v2_1.system import ethernet_interface
|
||||
from rsd_lib.resources.v2_1.system import memory
|
||||
from rsd_lib.resources.v2_1.system import network_device_function
|
||||
from rsd_lib.resources.v2_1.system import network_interface
|
||||
from rsd_lib.resources.v2_1.system import pcie_device
|
||||
from rsd_lib.resources.v2_1.system import pcie_function
|
||||
from rsd_lib.resources.v2_1.system import processor
|
||||
from rsd_lib.resources.v2_1.system import simple_storage
|
||||
from rsd_lib.resources.v2_1.system import storage
|
||||
from rsd_lib.resources.v2_1.system import system
|
||||
from rsd_lib.resources.v2_1.system import volume
|
||||
|
||||
from rsd_lib.resources.v2_1.task import task
|
||||
from rsd_lib.resources.v2_1.task import task_service
|
||||
|
||||
RESOURCE_CLASS = {
|
||||
'Chassis': chassis.Chassis,
|
||||
'ChassisCollection': chassis.ChassisCollection,
|
||||
'.ComposedNode': node.Node,
|
||||
'ComposedNodeCollection': node.NodeCollection,
|
||||
'ComputerSystem': system.System,
|
||||
'ComputerSystemCollection': system.SystemCollection,
|
||||
'Drive': drive.Drive,
|
||||
'Endpoint': endpoint.Endpoint,
|
||||
'EndpointCollection': endpoint.EndpointCollection,
|
||||
'EthernetInterface': ethernet_interface.EthernetInterface,
|
||||
'EthernetInterfaceCollection':
|
||||
ethernet_interface.EthernetInterfaceCollection,
|
||||
'EthernetSwitch': ethernet_switch.EthernetSwitch,
|
||||
'EthernetSwitchACL': ethernet_switch_acl.EthernetSwitchACL,
|
||||
'EthernetSwitchACLCollection':
|
||||
ethernet_switch_acl.EthernetSwitchACLCollection,
|
||||
'EthernetSwitchACLRule': ethernet_switch_acl_rule.EthernetSwitchACLRule,
|
||||
'EthernetSwitchACLRuleCollection':
|
||||
ethernet_switch_acl_rule.EthernetSwitchACLRuleCollection,
|
||||
'EthernetSwitchCollection': ethernet_switch.EthernetSwitchCollection,
|
||||
'EthernetSwitchPort': ethernet_switch_port.EthernetSwitchPort,
|
||||
'EthernetSwitchPortCollection':
|
||||
ethernet_switch_port.EthernetSwitchPortCollection,
|
||||
'EthernetSwitchStaticMAC':
|
||||
ethernet_switch_static_mac.EthernetSwitchStaticMAC,
|
||||
'EthernetSwitchStaticMACCollection':
|
||||
ethernet_switch_static_mac.EthernetSwitchStaticMACCollection,
|
||||
'EventDestination': event_destination.EventDestination,
|
||||
'EventDestinationCollection': event_destination.EventDestinationCollection,
|
||||
'EventService': event_service.EventService,
|
||||
'Fabric': fabric.Fabric,
|
||||
'FabricCollection': fabric.FabricCollection,
|
||||
'LogEntry': log_entry.LogEntry,
|
||||
'LogEntryCollection': log_entry.LogEntryCollection,
|
||||
'LogService': log_service.LogService,
|
||||
'LogServiceCollection': log_service.LogServiceCollection,
|
||||
'LogicalDrive': logical_drive.LogicalDrive,
|
||||
'LogicalDriveCollection': logical_drive.LogicalDriveCollection,
|
||||
'Manager': manager.Manager,
|
||||
'ManagerCollection': manager.ManagerCollection,
|
||||
'ManagerNetworkProtocol': manager_network_protocol.ManagerNetworkProtocol,
|
||||
'Memory': memory.Memory,
|
||||
'MemoryCollection': memory.MemoryCollection,
|
||||
'MessageRegistryFile': message_registry_file.MessageRegistryFile,
|
||||
'MessageRegistryFileCollection':
|
||||
message_registry_file.MessageRegistryFileCollection,
|
||||
'NetworkDeviceFunction': network_device_function.NetworkDeviceFunction,
|
||||
'NetworkDeviceFunctionCollection':
|
||||
network_device_function.NetworkDeviceFunctionCollection,
|
||||
'NetworkInterface': network_interface.NetworkInterface,
|
||||
'NetworkInterfaceCollection': network_interface.NetworkInterfaceCollection,
|
||||
'PCIeDevice': pcie_device.PCIeDevice,
|
||||
'PCIeFunction': pcie_function.PCIeFunction,
|
||||
'PhysicalDrive': physical_drive.PhysicalDrive,
|
||||
'PhysicalDriveCollection': physical_drive.PhysicalDriveCollection,
|
||||
'Port': port.Port,
|
||||
'PortCollection': port.PortCollection,
|
||||
'Power': power.Power,
|
||||
'PowerZone': power_zone.PowerZone,
|
||||
'PowerZoneCollection': power_zone.PowerZoneCollection,
|
||||
'Processor': processor.Processor,
|
||||
'ProcessorCollection': processor.ProcessorCollection,
|
||||
'RemoteTarget': remote_target.RemoteTarget,
|
||||
'RemoteTargetCollection':
|
||||
remote_target.RemoteTargetCollection,
|
||||
'SerialInterface': serial_interface.SerialInterface,
|
||||
'SerialInterfaceCollection': serial_interface.SerialInterfaceCollection,
|
||||
'SimpleStorage': simple_storage.SimpleStorage,
|
||||
'SimpleStorageCollection': simple_storage.SimpleStorageCollection,
|
||||
'Storage': storage.Storage,
|
||||
'StorageCollection': storage.StorageCollection,
|
||||
'StorageService': storage_service.StorageService,
|
||||
'StorageServiceCollection': storage_service.StorageServiceCollection,
|
||||
'Switch': switch.Switch,
|
||||
'SwitchCollection': switch.SwitchCollection,
|
||||
'Task': task.Task,
|
||||
'TaskCollection': task.TaskCollection,
|
||||
'TaskService': task_service.TaskService,
|
||||
'Thermal': thermal.Thermal,
|
||||
'ThermalZone': thermal_zone.ThermalZone,
|
||||
'ThermalZoneCollection':
|
||||
thermal_zone.ThermalZoneCollection,
|
||||
'VLanNetworkInterface':
|
||||
vlan_network_interface.VLanNetworkInterface,
|
||||
'VLanNetworkInterfaceCollection':
|
||||
vlan_network_interface.VLanNetworkInterfaceCollection,
|
||||
'VirtualMedia': virtual_media.VirtualMedia,
|
||||
'VirtualMediaCollection': virtual_media.VirtualMediaCollection,
|
||||
'Volume': volume.Volume,
|
||||
'VolumeCollection': volume.VolumeCollection,
|
||||
'Zone': zone.Zone,
|
||||
'ZoneCollection': zone.ZoneCollection
|
||||
}
|
@ -15,8 +15,10 @@
|
||||
|
||||
import json
|
||||
import mock
|
||||
from sushy import exceptions
|
||||
import testtools
|
||||
|
||||
from rsd_lib.exceptions import NoMatchingResourceError
|
||||
from rsd_lib.resources import v2_1
|
||||
from rsd_lib.resources.v2_1.chassis import chassis
|
||||
from rsd_lib.resources.v2_1.ethernet_switch import ethernet_switch
|
||||
@ -234,3 +236,59 @@ class RSDLibV2_1TestCase(testtools.TestCase):
|
||||
"/redfish/v1/EventService",
|
||||
redfish_version=self.rsd.redfish_version,
|
||||
)
|
||||
|
||||
def test_get_resource_class_with_connection_error(self):
|
||||
self.conn.get.side_effect = exceptions.ConnectionError()
|
||||
self.assertRaises(
|
||||
exceptions.ConnectionError,
|
||||
self.rsd._get_resource_class_from_path,
|
||||
"/redfish/v1/Chassis/1",
|
||||
)
|
||||
self.conn.reset()
|
||||
|
||||
def test_get_resource_class_from_path_with_invalid_response(self):
|
||||
self.conn.get.return_value.json.return_value = {}
|
||||
self.assertRaisesRegexp(
|
||||
exceptions.MissingAttributeError,
|
||||
"The attribute @odata.type is missing from the resource "
|
||||
"/redfish/v1/Chassis/1",
|
||||
self.rsd._get_resource_class_from_path,
|
||||
"/redfish/v1/Chassis/1",
|
||||
)
|
||||
self.conn.reset()
|
||||
|
||||
def test_get_resource_class_from_path(self):
|
||||
self.conn.get.return_value.json.return_value = {
|
||||
"@odata.type": "#Chassis.v1_3_0.Chassis"
|
||||
}
|
||||
self.assertEqual(
|
||||
chassis.Chassis,
|
||||
self.rsd._get_resource_class_from_path("/redfish/v1/Chassis/1"),
|
||||
)
|
||||
self.conn.reset()
|
||||
|
||||
def test_get_resource(self):
|
||||
with mock.patch.object(
|
||||
self.rsd,
|
||||
"_get_resource_class_from_path",
|
||||
return_value=chassis.Chassis,
|
||||
):
|
||||
with open(
|
||||
"rsd_lib/tests/unit/json_samples/v2_1/chassis.json", "r"
|
||||
) as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(
|
||||
f.read()
|
||||
)
|
||||
self.assertIsInstance(
|
||||
self.rsd.get_resource("/redfish/v1/Chassis/1"), chassis.Chassis
|
||||
)
|
||||
|
||||
def test_get_resource_with_no_class_match(self):
|
||||
with mock.patch.object(
|
||||
self.rsd, "_get_resource_class_from_path", return_value=None
|
||||
):
|
||||
self.assertRaises(
|
||||
NoMatchingResourceError,
|
||||
self.rsd.get_resource,
|
||||
"/redfish/v1/chassis/1",
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user