Redfish: Add the get_server_capabilities() and pci_gpu_device attribute
This patch adds the routine get_server_capabilities() and one of the capability 'pci_gpu_devices' which gives the count of gpu devices. Change-Id: Iff38aa201b7a1658723d926292707e163c22c34d
This commit is contained in:
parent
d85ef6498c
commit
ca5a0c973e
|
@ -593,3 +593,21 @@ class RedfishOperations(operations.IloOperations):
|
|||
{'username': self._username, 'error': str(e)})
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
||||
def get_server_capabilities(self):
|
||||
"""Returns the server capabilities
|
||||
|
||||
:raises: IloError if any Sushy error is encountered.
|
||||
"""
|
||||
capabilities = {}
|
||||
sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID)
|
||||
try:
|
||||
count = len(sushy_system.pci_devices.gpu_devices)
|
||||
capabilities.update({'pci_gpu_devices': count})
|
||||
except sushy.exceptions.SushyError as e:
|
||||
msg = (self._("The Redfish controller is unable to get "
|
||||
"resource or its members. Error"
|
||||
"%(error)s)") % {'error': str(e)})
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
return capabilities
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# 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 logging
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
CLASSCODE_FOR_GPU_DEVICES = [3]
|
||||
SUBCLASSCODE_FOR_GPU_DEVICES = [0, 1, 2, 128]
|
||||
|
||||
|
||||
class PCIDevice(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
|
||||
name = base.Field('Name')
|
||||
|
||||
class_code = base.Field('ClassCode')
|
||||
|
||||
sub_class_code = base.Field('SubclassCode')
|
||||
|
||||
|
||||
class PCIDeviceCollection(base.ResourceCollectionBase):
|
||||
|
||||
_gpu_devices = None
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return PCIDevice
|
||||
|
||||
@property
|
||||
def gpu_devices(self):
|
||||
if self._gpu_devices is None:
|
||||
self._gpu_devices = []
|
||||
for member in self.get_members():
|
||||
if member.class_code in CLASSCODE_FOR_GPU_DEVICES:
|
||||
if member.sub_class_code in SUBCLASSCODE_FOR_GPU_DEVICES:
|
||||
self._gpu_devices.append(member)
|
||||
return self._gpu_devices
|
||||
|
||||
def refresh(self):
|
||||
super(PCIDeviceCollection, self).refresh()
|
||||
self._gpu_devices = None
|
|
@ -22,6 +22,7 @@ from proliantutils import exception
|
|||
from proliantutils import log
|
||||
from proliantutils.redfish.resources.system import bios
|
||||
from proliantutils.redfish.resources.system import mappings
|
||||
from proliantutils.redfish.resources.system import pci_device
|
||||
from proliantutils.redfish import utils
|
||||
|
||||
LOG = log.get_logger(__name__)
|
||||
|
@ -59,6 +60,8 @@ class HPESystem(system.System):
|
|||
|
||||
_bios_settings = None
|
||||
|
||||
_pci_devices = None
|
||||
|
||||
def _get_hpe_push_power_button_action_element(self):
|
||||
push_action = self._hpe_actions.computer_system_ext_powerbutton
|
||||
if not push_action:
|
||||
|
@ -141,3 +144,20 @@ class HPESystem(system.System):
|
|||
tenure = (sushy.BOOT_SOURCE_ENABLED_CONTINUOUS
|
||||
if persistent else sushy.BOOT_SOURCE_ENABLED_ONCE)
|
||||
self.set_system_boot_source(device, enabled=tenure)
|
||||
|
||||
@property
|
||||
def pci_devices(self):
|
||||
"""Provides the collection of PCI devices
|
||||
|
||||
It is calculated once when the first time it is queried. On refresh,
|
||||
this property gets reset.
|
||||
"""
|
||||
if self._pci_devices is None:
|
||||
self._pci_devices = pci_device.PCIDeviceCollection(
|
||||
self._conn, utils.get_subresource_path_by(
|
||||
self, ['Oem', 'Hpe', 'Links', 'PCIDevices']))
|
||||
return self._pci_devices
|
||||
|
||||
def refresh(self):
|
||||
super(HPESystem, self).refresh()
|
||||
self._pci_devices = None
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/PCIDevices/Members/$entity",
|
||||
"@odata.etag": "W/\"33150E20\"",
|
||||
"@odata.id": "/redfish/v1/Systems/1/PCIDevices/1/",
|
||||
"@odata.type": "#HpeServerPciDevice.v2_0_0.HpeServerPciDevice",
|
||||
"BusNumber": 2,
|
||||
"ClassCode": 2,
|
||||
"DeviceID": 5719,
|
||||
"DeviceInstance": 1,
|
||||
"DeviceLocation": "Embedded",
|
||||
"DeviceNumber": 0,
|
||||
"DeviceSubInstance": 1,
|
||||
"DeviceType": "Embedded LOM",
|
||||
"FunctionNumber": 0,
|
||||
"Id": "1",
|
||||
"LocationString": "Embedded LOM 1",
|
||||
"Name": "Network Controller",
|
||||
"SegmentNumber": 0,
|
||||
"StructuredName": "NIC.LOM.1.1",
|
||||
"SubclassCode": 0,
|
||||
"SubsystemDeviceID": 8894,
|
||||
"SubsystemVendorID": 4156,
|
||||
"UEFIDevicePath": "PciRoot(0x0)/Pci(0x1C,0x0)/Pci(0x0,0x0)",
|
||||
"VendorID": 5348
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/PCIDevices/Members/$entity",
|
||||
"@odata.etag": "W/\"5ABCB1B9\"",
|
||||
"@odata.id": "/redfish/v1/Systems/1/PCIDevices/6/",
|
||||
"@odata.type": "#HpeServerPciDevice.v2_0_0.HpeServerPciDevice",
|
||||
"BusNumber": 1,
|
||||
"ClassCode": 3,
|
||||
"DeviceID": 1336,
|
||||
"DeviceInstance": 1,
|
||||
"DeviceLocation": "Embedded",
|
||||
"DeviceNumber": 0,
|
||||
"DeviceSubInstance": 1,
|
||||
"DeviceType": "Video",
|
||||
"FunctionNumber": 1,
|
||||
"Id": "6",
|
||||
"LocationString": "Embedded Video Controller",
|
||||
"Name": "Embedded Video Controller",
|
||||
"SegmentNumber": 0,
|
||||
"StructuredName": "PCI.Emb.1.1",
|
||||
"SubclassCode": 0,
|
||||
"SubsystemDeviceID": 228,
|
||||
"SubsystemVendorID": 5520,
|
||||
"UEFIDevicePath": "PciRoot(0x0)/Pci(0x1C,0x4)/Pci(0x0,0x1)",
|
||||
"VendorID": 4139
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/PCIDevices",
|
||||
"@odata.etag": "W/\"9975C252\"",
|
||||
"@odata.id": "/redfish/v1/Systems/1/PCIDevices/",
|
||||
"@odata.type": "#HpeServerPciDeviceCollection.HpeServerPciDeviceCollection",
|
||||
"Description": " PciDevices view",
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/1/PCIDevices/1/"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/1/PCIDevices/6/"
|
||||
}
|
||||
],
|
||||
"Members@odata.count": 2,
|
||||
"Name": "PciDevices"
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
# Copyright 2017 Hewlett Packard Enterprise Development LP
|
||||
# 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 proliantutils.redfish.resources.system import pci_device
|
||||
|
||||
|
||||
class PCIDeviceTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(PCIDeviceTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
pci_file = 'proliantutils/tests/redfish/json_samples/pci_device.json'
|
||||
with open(pci_file, 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = (
|
||||
json.loads(f.read()))
|
||||
|
||||
pci_path = "/redfish/v1/Systems/1/PCIDevices/1"
|
||||
self.sys_pci = pci_device.PCIDevice(
|
||||
self.conn, pci_path, redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.sys_pci._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.sys_pci.redfish_version)
|
||||
self.assertEqual('1', self.sys_pci.identity)
|
||||
|
||||
|
||||
class PCIDeviceCollectionTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(PCIDeviceCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('proliantutils/tests/redfish/json_samples/'
|
||||
'pci_device_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.sys_pci_col = pci_device.PCIDeviceCollection(
|
||||
self.conn, '/redfish/v1/Systems/1/PCIDevices',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.sys_pci_col._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.sys_pci_col.redfish_version)
|
||||
self.assertEqual('PciDevices', self.sys_pci_col.name)
|
||||
pci_path = ('/redfish/v1/Systems/1/PCIDevices/1',
|
||||
'/redfish/v1/Systems/1/PCIDevices/6')
|
||||
self.assertEqual(pci_path, self.sys_pci_col.members_identities)
|
||||
|
||||
@mock.patch.object(pci_device, 'PCIDevice', autospec=True)
|
||||
def test_get_member(self, mock_pci):
|
||||
self.sys_pci_col.get_member(
|
||||
'/redfish/v1/Systems/1/PCIDevices/1')
|
||||
mock_pci.assert_called_once_with(
|
||||
self.sys_pci_col._conn,
|
||||
('/redfish/v1/Systems/1/PCIDevices/1'),
|
||||
redfish_version=self.sys_pci_col.redfish_version)
|
||||
|
||||
@mock.patch.object(pci_device, 'PCIDevice', autospec=True)
|
||||
def test_get_members(self, mock_pci):
|
||||
members = self.sys_pci_col.get_members()
|
||||
path_list = ["/redfish/v1/Systems/1/PCIDevices/1",
|
||||
"/redfish/v1/Systems/1/PCIDevices/6"]
|
||||
calls = [
|
||||
mock.call(self.sys_pci_col._conn, path_list[0],
|
||||
redfish_version=self.sys_pci_col.redfish_version),
|
||||
mock.call(self.sys_pci_col._conn, path_list[1],
|
||||
redfish_version=self.sys_pci_col.redfish_version)
|
||||
]
|
||||
mock_pci.assert_has_calls(calls)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(2, len(members))
|
||||
|
||||
def test_gpu_devices(self):
|
||||
self.assertIsNone(self.sys_pci_col._gpu_devices)
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
val = []
|
||||
path = ('proliantutils/tests/redfish/json_samples/'
|
||||
'pci_device.json')
|
||||
with open(path, 'r') as f:
|
||||
val.append(json.loads(f.read()))
|
||||
path = ('proliantutils/tests/redfish/json_samples/'
|
||||
'pci_device1.json')
|
||||
with open(path, 'r') as f:
|
||||
val.append(json.loads(f.read()))
|
||||
self.conn.get.return_value.json.side_effect = val
|
||||
self.sys_pci_col.gpu_devices
|
||||
self.assertEqual(1, len(self.sys_pci_col._gpu_devices))
|
|
@ -145,3 +145,27 @@ class HPESystemTestCase(testtools.TestCase):
|
|||
exception.IloError,
|
||||
'The BIOS Boot Settings was not found.',
|
||||
self.sys_inst.update_persistent_boot, ['ISCSI'], True, '12345678')
|
||||
|
||||
def test_pci_devices(self):
|
||||
pci_dev_return_value = None
|
||||
pci_dev1_return_value = None
|
||||
pci_coll_return_value = None
|
||||
self.assertIsNone(self.sys_inst._pci_devices)
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/pci_device_collection.json') as f:
|
||||
pci_coll_return_value = json.loads(f.read())
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/pci_device.json') as f:
|
||||
pci_dev_return_value = json.loads(f.read())
|
||||
with open('proliantutils/tests/redfish/'
|
||||
'json_samples/pci_device1.json') as f:
|
||||
pci_dev1_return_value = json.loads(f.read())
|
||||
self.conn.get.return_value.json.side_effect = (
|
||||
[pci_coll_return_value, pci_dev_return_value,
|
||||
pci_dev1_return_value])
|
||||
actual_pci = self.sys_inst.pci_devices
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
self.assertIs(actual_pci,
|
||||
self.sys_inst.pci_devices)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
|
|
@ -645,3 +645,25 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
|||
exception.IloError,
|
||||
'No account found with username: foo',
|
||||
self.rf_client.reset_ilo_credential, 'fake-password')
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_system')
|
||||
def test_get_server_capabilities(self, get_system_mock):
|
||||
val = []
|
||||
path = ('proliantutils/tests/redfish/json_samples/'
|
||||
'pci_device.json')
|
||||
with open(path, 'r') as f:
|
||||
val.append(json.loads(f.read()))
|
||||
gpu_mock = mock.PropertyMock(return_value=val)
|
||||
type(get_system_mock.return_value.pci_devices).gpu_devices = (
|
||||
gpu_mock)
|
||||
actual = self.rf_client.get_server_capabilities()
|
||||
expected = {'pci_gpu_devices': 1}
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_system')
|
||||
def test_get_server_capabilities_gpu_fail(self, get_system_mock):
|
||||
gpu_mock = mock.PropertyMock(side_effect=sushy.exceptions.SushyError)
|
||||
type(get_system_mock.return_value.pci_devices).gpu_devices = (
|
||||
gpu_mock)
|
||||
self.assertRaises(exception.IloError,
|
||||
self.rf_client.get_server_capabilities)
|
||||
|
|
Loading…
Reference in New Issue