Add memory info for RSD v2.1

Change-Id: Ib06e72eebaf8a30251a71a3038c7fe32b6a3eea4
This commit is contained in:
Lin Yang 2018-02-13 18:32:51 -08:00
parent e3044f81d2
commit cb473aeb6d
13 changed files with 553 additions and 4 deletions

View File

@ -14,12 +14,12 @@
# under the License.
from sushy.resources import base
from sushy.resources.system import system
from rsd_lib.resources.v2_1.chassis import chassis
from rsd_lib.resources.v2_1.fabric import fabric
from rsd_lib.resources.v2_1.node import node
from rsd_lib.resources.v2_1.storage_service import storage_service
from rsd_lib.resources.v2_1.system import system
class RSDLibV2_1(base.ResourceBase):

View File

@ -0,0 +1,135 @@
# 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.resources import base
class MemoryLocationField(base.CompositeField):
socket = base.Field('Socket', required=int)
memory_controller = base.Field('MemoryController', required=int)
channel = base.Field('Channel', required=int)
slot = base.Field('Slot', required=int)
class StatusField(base.CompositeField):
state = base.Field('State')
health = base.Field('Health')
health_rollup = base.Field('HealthRollup')
class Memory(base.ResourceBase):
name = base.Field('Name')
"""The memory name"""
identity = base.Field('Id', required=True)
"""The processor identity string"""
memory_type = base.Field('MemoryType')
"""The type of memory"""
memory_device_type = base.Field('MemoryDeviceType')
"""The type of memory device"""
base_module_type = base.Field('BaseModuleType')
"""The type of base module"""
memory_media = base.Field('MemoryMedia', adapter=list)
"""The memory media"""
capacity_mib = base.Field('CapacityMiB', adapter=int)
"""The capacity of this memory in MiB"""
data_width_bits = base.Field('DataWidthBits', adapter=int)
"""The data width bits of this memory."""
bus_width_bits = base.Field('BusWidthBits', adapter=int)
"""The bus width bits of this memory."""
manufacturer = base.Field('Manufacturer')
"""The manufacturer of this memory"""
serial_number = base.Field('SerialNumber')
"""The serial number of this memory"""
part_number = base.Field('PartNumber')
"""The part number of this memory"""
allowed_speeds_mhz = base.Field('AllowedSpeedsMHz', adapter=list)
"""The allowed speeds of this memory in MHz"""
firmware_revision = base.Field('FirmwareRevision')
"""The revision of this memory firmware"""
frirmware_api_version = base.Field('FirmwareApiVersion')
"""The API revision of this memory firmware"""
function_classes = base.Field('FunctionClasses', adapter=list)
"""The function_classes of the memory"""
vendor_id = base.Field('VendorID')
"""The vendor identity"""
device_id = base.Field('DeviceID')
"""The device identity"""
rank_count = base.Field('RankCount', adapter=int)
"""The rank count of this memory"""
device_locator = base.Field('DeviceLocator')
"""The device locator"""
error_correction = base.Field('ErrorCorrection')
"""The error correction"""
operating_speed_mhz = base.Field('OperatingSpeedMhz', adapter=int)
"""The operating speed of this memory in MHz"""
operating_memory_modes = base.Field('OperatingMemoryModes', adapter=list)
"""The operating memory modes"""
memory_location = MemoryLocationField('MemoryLocation')
"""The location information of this memory"""
status = StatusField('Status')
"""The memory status"""
def __init__(self, connector, identity, redfish_version=None):
"""A class representing a Processor
:param connector: A Connector instance
:param identity: The identity of the processor
:param redfish_version: The version of RedFish. Used to construct
the object according to schema of the given version.
"""
super(Memory, self).__init__(connector, identity, redfish_version)
class MemoryCollection(base.ResourceCollectionBase):
@property
def _resource_type(self):
return Memory
def __init__(self, connector, path, redfish_version=None):
"""A class representing a ProcessorCollection
:param connector: A Connector instance
:param path: The canonical path to the Processor collection resource
:param redfish_version: The version of RedFish. Used to construct
the object according to schema of the given version.
"""
super(MemoryCollection, self).__init__(connector, path,
redfish_version)

View File

@ -0,0 +1,58 @@
# 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 sushy.resources.system import system
from rsd_lib.resources.v2_1.system import memory
from rsd_lib import utils
class System(system.System):
_memory = None # ref to System memory collection instance
def _get_memory_collection_path(self):
"""Helper function to find the System path"""
system_col = self.json.get('Memory')
if not system_col:
raise exceptions.MissingAttributeError(attribute='Memory',
resource=self._path)
return utils.get_resource_identity(system_col)
@property
def memory(self):
"""Property to provide reference to `Metrics` instance
It is calculated once the first time it is queried. On refresh,
this property is reset.
"""
if self._memory is None:
self._memory = memory.MemoryCollection(
self._conn, self._get_memory_collection_path(),
redfish_version=self.redfish_version)
return self._memory
def refresh(self):
super(System, self).refresh()
self._memory = None
class SystemCollection(system.SystemCollection):
@property
def _resource_type(self):
return System

View File

@ -14,8 +14,8 @@
# under the License.
from sushy import exceptions
from sushy.resources.system import system
from rsd_lib.resources.v2_1.system import system
from rsd_lib.resources.v2_2.system import metrics
from rsd_lib.resources.v2_2.system import processor
from rsd_lib import utils

View File

@ -0,0 +1,63 @@
{
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/Memory/$entity",
"@odata.id": "/redfish/v1/Systems/System1/Memory/Dimm1",
"@odata.type": "#Memory.v1_1_0.Memory",
"Name": "DIMM",
"Id": "Dimm1",
"MemoryType": "DRAM",
"MemoryDeviceType": "DDR4",
"BaseModuleType": "LRDIMM",
"MemoryMedia": [
"DRAM"
],
"CapacityMiB": 16384,
"DataWidthBits": 64,
"BusWidthBits": 72,
"Manufacturer": "Contoso",
"SerialNumber": "1A2B3B",
"PartNumber": "1A2B3D",
"AllowedSpeedsMHz": [
2133,
2400,
2667
],
"FirmwareRevision": "RevAbc",
"FirmwareApiVersion": "ApiAbc",
"FunctionClasses": [
"Volatile"
],
"VendorID": "vendorX",
"DeviceID": "deviceX",
"RankCount": 1,
"DeviceLocator": "PROC 1 DIMM 1",
"MemoryLocation": {
"Socket": 1,
"MemoryController": 1,
"Channel": 1,
"Slot": 1
},
"ErrorCorrection": "MultiBitECC",
"Status": {
"State": "Enabled",
"Health": "OK",
"HealthRollup": "OK"
},
"OperatingSpeedMhz": 2400,
"Regions": [
{
"RegionId": "1",
"MemoryClassification": "Volatile",
"OffsetMiB": 0,
"SizeMiB": 16384
}
],
"OperatingMemoryModes": [
"Volatile"
],
"Oem": {
"Intel_RackScale": {
"@odata.type": "#Intel.Oem.DimmConfig",
"VoltageVolt": 1.35
}
}
}

View File

@ -0,0 +1,15 @@
{
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/Memory/$entity",
"@odata.type": "#MemoryCollection.MemoryCollection",
"@odata.id": "/redfish/v1/Systems/System1/Memory",
"Name": "Memory Collection",
"Members@odata.count": 2,
"Members": [
{
"@odata.id": "/redfish/v1/Systems/System1/Memory/Dimm1"
},
{
"@odata.id": "/redfish/v1/Systems/System1/Memory/Dimm2"
}
]
}

View File

@ -0,0 +1,15 @@
{
"@odata.context": "/redfish/v1/$metadata#ComputerSystemCollection.ComputerSystemCollection",
"@odata.id": "/redfish/v1/Systems",
"@odata.type": "#ComputerSystemCollection.ComputerSystemCollection",
"Name": "Computer System Collection",
"Members@odata.count": 2,
"Members": [
{
"@odata.id": "/redfish/v1/Systems/System1"
},
{
"@odata.id": "/redfish/v1/Systems/System2"
}
]
}

View File

@ -0,0 +1,113 @@
# 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.system import memory
class MemoryTestCase(testtools.TestCase):
def setUp(self):
super(MemoryTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_1/memory.json',
'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.memory_inst = memory.Memory(
self.conn, '/redfish/v1/Systems/System1/Memory/Dimm1',
redfish_version='1.1.0')
def test__parse_attributes(self):
self.memory_inst._parse_attributes()
self.assertEqual('1.1.0', self.memory_inst.redfish_version)
self.assertEqual('DIMM', self.memory_inst.name)
self.assertEqual('Dimm1', self.memory_inst.identity)
self.assertEqual('DRAM', self.memory_inst.memory_type)
self.assertEqual('DDR4', self.memory_inst.memory_device_type)
self.assertEqual('LRDIMM', self.memory_inst.base_module_type)
self.assertEqual(['DRAM'], self.memory_inst.memory_media)
self.assertEqual(16384, self.memory_inst.capacity_mib)
self.assertEqual(64, self.memory_inst.data_width_bits)
self.assertEqual(72, self.memory_inst.bus_width_bits)
self.assertEqual('Contoso', self.memory_inst.manufacturer)
self.assertEqual('1A2B3B', self.memory_inst.serial_number)
self.assertEqual('1A2B3D', self.memory_inst.part_number)
self.assertEqual([2133, 2400, 2667],
self.memory_inst.allowed_speeds_mhz)
self.assertEqual('RevAbc', self.memory_inst.firmware_revision)
self.assertEqual('ApiAbc', self.memory_inst.frirmware_api_version)
self.assertEqual(['Volatile'], self.memory_inst.function_classes)
self.assertEqual('vendorX', self.memory_inst.vendor_id)
self.assertEqual('deviceX', self.memory_inst.device_id)
self.assertEqual(1, self.memory_inst.rank_count)
self.assertEqual('PROC 1 DIMM 1', self.memory_inst.device_locator)
self.assertEqual('MultiBitECC', self.memory_inst.error_correction)
self.assertEqual(2400, self.memory_inst.operating_speed_mhz)
self.assertEqual(['Volatile'], self.memory_inst.operating_memory_modes)
self.assertEqual(1, self.memory_inst.memory_location.socket)
self.assertEqual(1, self.memory_inst.memory_location.memory_controller)
self.assertEqual(1, self.memory_inst.memory_location.channel)
self.assertEqual(1, self.memory_inst.memory_location.slot)
self.assertEqual('Enabled', self.memory_inst.status.state)
self.assertEqual('OK', self.memory_inst.status.health)
self.assertEqual('OK', self.memory_inst.status.health_rollup)
class MemoryCollectionTestCase(testtools.TestCase):
def setUp(self):
super(MemoryCollectionTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_1/'
'memory_collection.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.sys_memory_col = memory.MemoryCollection(
self.conn, '/redfish/v1/Systems/System1/Memory',
redfish_version='1.1.0')
def test__parse_attributes(self):
self.sys_memory_col._parse_attributes()
self.assertEqual('1.1.0', self.sys_memory_col.redfish_version)
self.assertEqual(('/redfish/v1/Systems/System1/Memory/Dimm1',
'/redfish/v1/Systems/System1/Memory/Dimm2'),
self.sys_memory_col.members_identities)
@mock.patch.object(memory, 'Memory', autospec=True)
def test_get_member(self, mock_memory):
self.sys_memory_col.get_member(
'/redfish/v1/Systems/System1/Memory/Dimm1')
mock_memory.assert_called_once_with(
self.sys_memory_col._conn,
'/redfish/v1/Systems/System1/Memory/Dimm1',
redfish_version=self.sys_memory_col.redfish_version)
@mock.patch.object(memory, 'Memory', autospec=True)
def test_get_members(self, mock_memory):
members = self.sys_memory_col.get_members()
calls = [
mock.call(self.sys_memory_col._conn,
'/redfish/v1/Systems/System1/Memory/Dimm1',
redfish_version=self.sys_memory_col.redfish_version),
mock.call(self.sys_memory_col._conn,
'/redfish/v1/Systems/System1/Memory/Dimm2',
redfish_version=self.sys_memory_col.redfish_version)
]
mock_memory.assert_has_calls(calls)
self.assertIsInstance(members, list)
self.assertEqual(2, len(members))

View File

@ -0,0 +1,144 @@
# 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 sushy import exceptions
from sushy.resources.system import system as sushy_system
from rsd_lib.resources.v2_1.system import memory
from rsd_lib.resources.v2_1.system import system
class SystemTestCase(testtools.TestCase):
def setUp(self):
super(SystemTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_1/system.json',
'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.system_inst = system.System(
self.conn, '/redfish/v1/Systems/437XR1138R2',
redfish_version='1.1.0')
def test_class_inherit(self):
self.assertIsInstance(self.system_inst, system.System)
self.assertIsInstance(self.system_inst, sushy_system.System)
def test__get_memory_collection_path(self):
self.assertEqual('/redfish/v1/Systems/437XR1138R2/Memory',
self.system_inst._get_memory_collection_path())
def test__get_memory_collection_path_missing_systems_attr(self):
self.system_inst._json.pop('Memory')
with self.assertRaisesRegex(
exceptions.MissingAttributeError, 'attribute Memory'):
self.system_inst._get_memory_collection_path()
def test_memory(self):
# check for the underneath variable value
self.assertIsNone(self.system_inst._memory)
# | GIVEN |
self.conn.get.return_value.json.reset_mock()
with open('rsd_lib/tests/unit/json_samples/v2_1/'
'memory_collection.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
# | WHEN |
actual_memory_col = self.system_inst.memory
# | THEN |
self.assertIsInstance(actual_memory_col,
memory.MemoryCollection)
self.conn.get.return_value.json.assert_called_once_with()
# reset mock
self.conn.get.return_value.json.reset_mock()
# | WHEN & THEN |
# tests for same object on invoking subsequently
self.assertIs(actual_memory_col,
self.system_inst.memory)
self.conn.get.return_value.json.assert_not_called()
def test_memory_on_refresh(self):
# | GIVEN |
with open('rsd_lib/tests/unit/json_samples/v2_1/'
'memory_collection.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
# | WHEN & THEN |
self.assertIsInstance(self.system_inst.memory,
memory.MemoryCollection)
# On refreshing the system instance...
with open('rsd_lib/tests/unit/json_samples/v2_1/system.json',
'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.system_inst.refresh()
# | WHEN & THEN |
self.assertIsNone(self.system_inst._memory)
# | GIVEN |
with open('rsd_lib/tests/unit/json_samples/v2_1/'
'memory_collection.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
# | WHEN & THEN |
self.assertIsInstance(self.system_inst.memory,
memory.MemoryCollection)
class SystemCollectionTestCase(testtools.TestCase):
def setUp(self):
super(SystemCollectionTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_1/'
'system_collection.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.system_col = system.SystemCollection(
self.conn, '/redfish/v1/Systems',
redfish_version='1.1.0')
def test__parse_attributes(self):
self.system_col._parse_attributes()
self.assertEqual('1.1.0', self.system_col.redfish_version)
self.assertEqual(('/redfish/v1/Systems/System1',
'/redfish/v1/Systems/System2'),
self.system_col.members_identities)
@mock.patch.object(system, 'System', autospec=True)
def test_get_member(self, mock_system):
self.system_col.get_member(
'/redfish/v1/Systems/System1')
mock_system.assert_called_once_with(
self.system_col._conn,
'/redfish/v1/Systems/System1',
redfish_version=self.system_col.redfish_version)
@mock.patch.object(system, 'System', autospec=True)
def test_get_members(self, mock_system):
members = self.system_col.get_members()
calls = [
mock.call(self.system_col._conn,
'/redfish/v1/Systems/System1',
redfish_version=self.system_col.redfish_version),
mock.call(self.system_col._conn,
'/redfish/v1/Systems/System2',
redfish_version=self.system_col.redfish_version)
]
mock_system.assert_has_calls(calls)
self.assertIsInstance(members, list)
self.assertEqual(2, len(members))

View File

@ -17,13 +17,12 @@ import json
import mock
import testtools
from sushy.resources.system import system
from rsd_lib.resources import v2_1
from rsd_lib.resources.v2_1.chassis import chassis
from rsd_lib.resources.v2_1.fabric import fabric
from rsd_lib.resources.v2_1.node import node
from rsd_lib.resources.v2_1.storage_service import storage_service
from rsd_lib.resources.v2_1.system import system
class RSDLibV2_1TestCase(testtools.TestCase):

View File

@ -18,7 +18,9 @@ import mock
import testtools
from sushy import exceptions
from sushy.resources.system import system as sushy_system
from rsd_lib.resources.v2_1.system import system as v2_1_system
from rsd_lib.resources.v2_2.system import metrics
from rsd_lib.resources.v2_2.system import processor
from rsd_lib.resources.v2_2.system import system
@ -37,6 +39,11 @@ class SystemTestCase(testtools.TestCase):
self.conn, '/redfish/v1/Systems/System2',
redfish_version='1.0.2')
def test_class_inherit(self):
self.assertIsInstance(self.system_inst, system.System)
self.assertIsInstance(self.system_inst, v2_1_system.System)
self.assertIsInstance(self.system_inst, sushy_system.System)
def test__get_metrics_path(self):
self.assertEqual('/redfish/v1/Systems/System2/Metrics',
self.system_inst._get_metrics_path())