Add another protocol "NVMeOverFabrics" of remote drive

It support another protocol "NVMeOverFabrics" of remote storage drive
beside "iSCSI" when attach it to composed node in RSD 2.3.

Change-Id: I7089e98469352d30d7ab459741e465b354d2040f
This commit is contained in:
Lin Yang 2018-04-09 14:13:40 -07:00
parent 11b975dd44
commit e2ff3b548e
9 changed files with 421 additions and 0 deletions

View File

@ -0,0 +1,35 @@
# Copyright 2018 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 import v2_2
from rsd_lib.resources.v2_3.node import node
class RSDLibV2_3(v2_2.RSDLibV2_2):
# Override these two variables inherited from v2.2. The corresponding
# services don't exist in RSD v2.3
_storage_service_path = None
_telemetry_service_path = None
def get_node(self, identity):
"""Given the identity return a Node object
:param identity: The identity of the Node resource
:returns: The Node object
"""
return node.Node(self._conn, identity,
redfish_version=self.redfish_version)

View File

View File

@ -0,0 +1,45 @@
# Copyright 2018 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 sushy import exceptions
from rsd_lib.resources.v2_1.node import node as v2_1_node
class Node(v2_1_node.Node):
def attach_endpoint(self, endpoint, protocol=None):
"""Attach endpoint from available pool to composed node
:param endpoint: Link to endpoint to attach.
:param protocol: Protocol of the remote drive.
:raises: InvalidParameterValueError
"""
attach_action = self._get_attach_endpoint_action_element()
valid_endpoints = attach_action.allowed_values
target_uri = attach_action.target_uri
if endpoint and endpoint not in valid_endpoints:
raise exceptions.InvalidParameterValueError(
parameter='endpoint', value=endpoint,
valid_values=valid_endpoints)
data = {}
if endpoint is not None:
data['Resource'] = {'@odata.id': endpoint}
if protocol is not None:
data['Protocol'] = protocol
self._conn.post(target_uri, data=data)

View File

@ -0,0 +1,117 @@
{
"@odata.context": "/redfish/v1/$metadata#Nodes/Members/$entity",
"@odata.id": "/redfish/v1/Nodes/Node1",
"@odata.type": "#ComposedNode.1.1.0.ComposedNode",
"Id": "Node1",
"Name": "Composed Node",
"Description": "Node #1",
"UUID": "fa39d108-7d70-400a-9db2-6940375c31c2",
"PowerState": "On",
"Status": {
"State": "Enabled",
"Health": "OK",
"HealthRollup": "OK"
},
"Processors": {
"Count": 2,
"Model": "Multi-Core Intel(R) Xeon(R) processor 7xxx Series",
"Status": {
"State": "Enabled",
"Health": "OK",
"HealthRollup" : "OK"
}
},
"Memory": {
"TotalSystemMemoryGiB": 32,
"Status": {
"State": "Enabled",
"Health": "OK",
"HealthRollup" : "OK"
}
},
"ComposedNodeState": "Allocated",
"Boot": {
"BootSourceOverrideEnabled": "Disabled",
"BootSourceOverrideTarget": "None",
"BootSourceOverrideTarget@Redfish.AllowableValues": [
"None",
"Pxe",
"Hdd",
"RemoteDrive"
],
"BootSourceOverrideMode": "Legacy",
"BootSourceOverrideMode@Redfish.AllowableValues": ["Legacy",
"UEFI"]
},
"Oem": {},
"Links": {
"ComputerSystem": {
"@odata.id": "/redfish/v1/Systems/System1"
},
"Processors": [
{
"@odata.id": "/redfish/v1/Systems/System1/Processors/CPU1"
}
],
"Memory": [
{
"@odata.id": "/redfish/v1/Systems/System1/Memory/Dimm1"
}
],
"EthernetInterfaces": [
{
"@odata.id":
"/redfish/v1/Systems/System1/EthernetInterfaces/LAN1"
}
],
"LocalDrives": [
{
"@odata.id": "/redfish/v1/Chassis/Blade1/Drives/1"
}
],
"RemoteDrives": [
{
"@odata.id": "/redfish/v1/Services/RSS1/Targets/target1"
}
],
"ManagedBy": [
{
"@odata.id": "/redfish/v1/Managers/PODM"
}
],
"Oem": {}
},
"Actions": {
"#ComposedNode.Reset": {
"target": "/redfish/v1/Nodes/Node1/Actions/ComposedNode.Reset",
"ResetType@Redfish.AllowableValues": [
"On",
"ForceOff",
"GracefulRestart",
"ForceRestart",
"Nmi",
"ForceOn",
"PushPowerButton",
"GracefulShutdown"
]
},
"#ComposedNode.Assemble": {
"target": "/redfish/v1/Nodes/Node1/Actions/ComposedNode.Assemble"
},
"#ComposedNode.AttachEndpoint": {
"target":
"/redfish/v1/Nodes/Node1/Actions/ComposedNode.AttachEndpoint",
"Resource@Redfish.AllowableValues": [
{"@odata.id":"/redfish/v1/Chassis/PCIeSwitchChassis/Drives/Disk.Bay.1"},
{"@odata.id":"/redfish/v1/StorageServices/NVMeoE1/Volumes/1"}
]
},
"#ComposedNode.DetachEndpoint": {
"target":
"/redfish/v1/Nodes/Node1/Actions/ComposedNode.DetachEndpoint",
"Resource@Redfish.AllowableValues": [
{"@odata.id":"/redfish/v1/Chassis/PCIeSwitchChassis/Drives/Disk.Bay.3"}
]
}
}
}

View File

@ -0,0 +1,41 @@
{
"@odata.context": "/redfish/v1/$metadata#ServiceRoot.ServiceRoot",
"@odata.id": "/redfish/v1/",
"@odata.type": "#ServiceRoot.v1_1_1.ServiceRoot",
"Id": "RootService",
"Name": "Root Service",
"Description": "description-as-string",
"RedfishVersion": "1.1.0",
"UUID": "92384634-2938-2342-8820-489239905423",
"Systems": {
"@odata.id": "/redfish/v1/Systems"
},
"Chassis": {
"@odata.id": "/redfish/v1/Chassis"
},
"Managers": {
"@odata.id": "/redfish/v1/Managers"
},
"EventService": {
"@odata.id": "/redfish/v1/EventService"
},
"Fabrics": {
"@odata.id": "/redfish/v1/Fabrics"
},
"StorageServices": {
"@odata.id": "/redfish/v1/StorageSerices"
},
"Oem": {
"Intel_RackScale": {
"@odata.type": "#Intel.Oem.ServiceRoot",
"ApiVersion": "2.3.0",
"Nodes": {
"@odata.id": "/redfish/v1/Nodes"
},
"EthernetSwitches": {
"@odata.id": "/redfish/v1/EthernetSwitches"
}
}
},
"Links": {}
}

View File

@ -0,0 +1,58 @@
# Copyright 2017 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.
import json
import mock
import testtools
from sushy import exceptions
from rsd_lib.resources.v2_3.node import node
class NodeTestCase(testtools.TestCase):
def setUp(self):
super(NodeTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_3/node.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.node_inst = node.Node(
self.conn, '/redfish/v1/Nodes/Node1',
redfish_version='1.0.2')
def test_attach_endpoint(self):
self.node_inst.attach_endpoint(
endpoint='/redfish/v1/StorageServices/NVMeoE1/Volumes/1',
protocol='NVMeOverFabrics')
self.node_inst._conn.post.assert_called_once_with(
'/redfish/v1/Nodes/Node1/Actions/ComposedNode.AttachEndpoint',
data={'Resource': {'@odata.id': '/redfish/v1/'
'StorageServices/NVMeoE1/Volumes/1'},
'Protocol': 'NVMeOverFabrics'})
def test_attach_endpoint_invalid_parameter(self):
self.assertRaises(exceptions.InvalidParameterValueError,
self.node_inst.attach_endpoint,
endpoint='invalid')
def test_attach_endpoint_only_with_resource_uri(self):
self.node_inst.attach_endpoint(
endpoint='/redfish/v1/StorageServices/NVMeoE1/Volumes/1')
self.node_inst._conn.post.assert_called_once_with(
'/redfish/v1/Nodes/Node1/Actions/ComposedNode.AttachEndpoint',
data={'Resource': {'@odata.id': '/redfish/v1/'
'StorageServices/NVMeoE1/Volumes/1'}})

View File

@ -0,0 +1,125 @@
# Copyright 2018 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.
import json
import mock
import testtools
from rsd_lib.resources.v2_1.chassis import chassis as v2_1_chassis
from rsd_lib.resources.v2_1.fabric import fabric as v2_1_fabric
from rsd_lib.resources.v2_1.node import node as v2_1_node
from rsd_lib.resources.v2_2.system import system as v2_2_system
from rsd_lib.resources import v2_3
from rsd_lib.resources.v2_3.node import node as v2_3_node
class RSDLibV2_3TestCase(testtools.TestCase):
def setUp(self):
super(RSDLibV2_3TestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_3/root.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.rsd = v2_3.RSDLibV2_3(self.conn)
def test__parse_attributes(self):
self.rsd._parse_attributes()
self.assertEqual("2.3.0", self.rsd._rsd_api_version)
self.assertEqual("1.1.0", self.rsd._redfish_version)
self.assertEqual("/redfish/v1/Systems", self.rsd._systems_path)
self.assertEqual("/redfish/v1/Nodes", self.rsd._nodes_path)
self.assertEqual("/redfish/v1/Chassis", self.rsd._chassis_path)
self.assertEqual("/redfish/v1/Fabrics", self.rsd._fabrics_path)
self.assertEqual(None, self.rsd._storage_service_path)
self.assertEqual(None, self.rsd._telemetry_service_path)
@mock.patch.object(v2_2_system, 'SystemCollection', autospec=True)
def test_get_system_collection(self, mock_system_collection):
self.rsd.get_system_collection()
mock_system_collection.assert_called_once_with(
self.rsd._conn, '/redfish/v1/Systems',
redfish_version=self.rsd.redfish_version)
@mock.patch.object(v2_2_system, 'System', autospec=True)
def test_get_system(self, mock_system):
self.rsd.get_system('fake-system-id')
mock_system.assert_called_once_with(
self.rsd._conn, 'fake-system-id',
redfish_version=self.rsd.redfish_version)
@mock.patch.object(v2_1_node, 'NodeCollection', autospec=True)
def test_get_node_collection(self, mock_node_collection):
self.rsd.get_node_collection()
mock_node_collection.assert_called_once_with(
self.rsd._conn, '/redfish/v1/Nodes',
redfish_version=self.rsd.redfish_version)
@mock.patch.object(v2_3_node, 'Node', autospec=True)
def test_get_node(self, mock_node):
self.rsd.get_node('fake-node-id')
mock_node.assert_called_once_with(
self.rsd._conn, 'fake-node-id',
redfish_version=self.rsd.redfish_version)
@mock.patch.object(v2_1_fabric, 'FabricCollection', autospec=True)
def test_get_fabric_collection(self, mock_fabric_collection):
self.rsd.get_fabric_collection()
mock_fabric_collection.assert_called_once_with(
self.rsd._conn, '/redfish/v1/Fabrics',
redfish_version=self.rsd.redfish_version)
@mock.patch.object(v2_1_fabric, 'Fabric', autospec=True)
def test_get_fabric(self, mock_fabric):
self.rsd.get_fabric('fake-fabric-id')
mock_fabric.assert_called_once_with(
self.rsd._conn, 'fake-fabric-id',
redfish_version=self.rsd.redfish_version)
@mock.patch.object(v2_1_chassis, 'ChassisCollection', autospec=True)
def test_get_chassis_collection(self, mock_chassis_collection):
self.rsd.get_chassis_collection()
mock_chassis_collection.assert_called_once_with(
self.rsd._conn, '/redfish/v1/Chassis',
redfish_version=self.rsd.redfish_version)
@mock.patch.object(v2_1_chassis, 'Chassis', autospec=True)
def test_get_chassis(self, mock_chassis):
self.rsd.get_chassis('fake-chassis-id')
mock_chassis.assert_called_once_with(
self.rsd._conn, 'fake-chassis-id',
redfish_version=self.rsd.redfish_version)
# @mock.patch.object(v2_1_storage_service, 'StorageServiceCollection',
# autospec=True)
# def test_get_storage_service_collection(self,
# mock_storage_service_collection):
# self.rsd.get_storage_service_collection()
# mock_storage_service_collection.assert_called_once_with(
# self.rsd._conn, '/redfish/v1/Services',
# redfish_version=self.rsd.redfish_version)
# @mock.patch.object(v2_1_storage_service, 'StorageService', autospec=True)
# def test_get_storage_service(self, mock_storage_service):
# self.rsd.get_storage_service('fake-storage-service-id')
# mock_storage_service.assert_called_once_with(
# self.rsd._conn, 'fake-storage-service-id',
# redfish_version=self.rsd.redfish_version)
# @mock.patch.object(v2_2_telemetry, 'Telemetry', autospec=True)
# def test_get_telemetry_service(self, mock_telemetry_service):
# self.rsd.get_telemetry_service()
# mock_telemetry_service.assert_called_once_with(
# self.rsd._conn, '/redfish/v1/TelemetryService',
# redfish_version=self.rsd.redfish_version)