Add metrics info for memory in RSD v2.2

Change-Id: Ifc00d06dfda7fa87b467e49b1b8894116e4d2130
This commit is contained in:
Lin Yang 2018-02-13 22:15:34 -08:00
parent ec6c7ea66d
commit 5a990b7e8c
10 changed files with 488 additions and 8 deletions

View File

@ -0,0 +1,61 @@
# 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 import base
from rsd_lib.resources.v2_1.system import memory
from rsd_lib.resources.v2_2.system import memory_metrics
from rsd_lib import utils
class Memory(memory.Memory):
max_tdp_milliwatts = base.Field('MaxTDPMilliWatts', adapter=list)
_metrics = None # ref to System instance
def _get_metrics_path(self):
"""Helper function to find the System path"""
metrics = self.json.get('Metrics')
if not metrics:
raise exceptions.MissingAttributeError(
attribute='Memory Metrics', resource=self._path)
return utils.get_resource_identity(metrics)
@property
def metrics(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._metrics is None:
self._metrics = memory_metrics.MemoryMetrics(
self._conn, self._get_metrics_path(),
redfish_version=self.redfish_version)
return self._metrics
def refresh(self):
super(Memory, self).refresh()
self._metrics = None
class MemoryCollection(memory.MemoryCollection):
@property
def _resource_type(self):
return Memory

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 sushy.resources import base
class MemoryMetrics(base.ResourceBase):
name = base.Field('Name')
"""The metrics name"""
description = base.Field('Description')
"""The metrics description"""
identity = base.Field('Id')
"""The metrics identity"""
temperature_celsius = base.Field(
['Oem', 'Intel_RackScale', 'TemperatureCelsius'], adapter=int)
"""The memory temperature celsius"""
health = base.Field(['Oem', 'Intel_RackScale', 'Health'], adapter=list)
"""The detail health information"""

View File

@ -35,12 +35,12 @@ class Processor(processor.Processor):
_metrics = None # ref to System instance _metrics = None # ref to System instance
def _get_metrics_path(self): def _get_metrics_path(self):
"""Helper function to find the System path""" """Helper function to find the System process metrics path"""
system_col = self.json.get('Oem').get('Intel_RackScale').get('Metrics') metrics = self.json.get('Oem').get('Intel_RackScale').get('Metrics')
if not system_col: if not metrics:
raise exceptions.MissingAttributeError( raise exceptions.MissingAttributeError(
attribute='Processor Metrics', resource=self._path) attribute='Processor Metrics', resource=self._path)
return utils.get_resource_identity(system_col) return utils.get_resource_identity(metrics)
@property @property
def metrics(self): def metrics(self):

View File

@ -16,6 +16,7 @@
from sushy import exceptions from sushy import exceptions
from rsd_lib.resources.v2_1.system import system from rsd_lib.resources.v2_1.system import system
from rsd_lib.resources.v2_2.system import memory
from rsd_lib.resources.v2_2.system import metrics 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 processor
from rsd_lib import utils from rsd_lib import utils
@ -25,14 +26,15 @@ class System(system.System):
_metrics = None # ref to System metrics instance _metrics = None # ref to System metrics instance
_processors = None # ref to ProcessorCollection instance _processors = None # ref to ProcessorCollection instance
_memory = None # ref to ProcessorCollection instance
def _get_metrics_path(self): def _get_metrics_path(self):
"""Helper function to find the System path""" """Helper function to find the System metrics path"""
system_col = self.json.get('Oem').get('Intel_RackScale').get('Metrics') metrics = self.json.get('Oem').get('Intel_RackScale').get('Metrics')
if not system_col: if not metrics:
raise exceptions.MissingAttributeError(attribute='Metrics', raise exceptions.MissingAttributeError(attribute='Metrics',
resource=self._path) resource=self._path)
return utils.get_resource_identity(system_col) return utils.get_resource_identity(metrics)
@property @property
def metrics(self): def metrics(self):
@ -62,10 +64,25 @@ class System(system.System):
return self._processors return self._processors
@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): def refresh(self):
super(System, self).refresh() super(System, self).refresh()
self._metrics = None self._metrics = None
self._processors = None self._processors = None
self._memory = None
class SystemCollection(system.SystemCollection): class SystemCollection(system.SystemCollection):

View File

@ -0,0 +1,67 @@
{
"@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"
],
"Metrics": {
"@odata.id": "/redfish/v1/Systems/System1/Memory/Dimm1/Metrics"
},
"Oem": {
"Intel_RackScale": {
"@odata.type": "#Intel.Oem.Memory",
"VoltageVolt": 1.35
}
},
"MaxTDPMilliWatts": [ 5000 ]
}

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,14 @@
{
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/Memory/Metrics/$entity",
"@odata.id": "/redfish/v1/Systems/3/Memory/Dimm1/Metrics",
"@odata.type": "#MemoryMetrics.v1_0_0.MemoryMetrics",
"Name": "Memory Metrics for DIMM1",
"Description": "description-as-string",
"Id": "Metrics for DIMM1",
"Oem": {
"Intel_RackScale": {
"TemperatureCelsius": 46,
"Health": ["OK"]
}
}
}

View File

@ -0,0 +1,175 @@
# 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 rsd_lib.resources.v2_2.system import memory
from rsd_lib.resources.v2_2.system import memory_metrics
class MemoryTestCase(testtools.TestCase):
def setUp(self):
super(MemoryTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_2/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)
self.assertEqual([5000], self.memory_inst.max_tdp_milliwatts)
def test__get_metrics_path(self):
self.assertEqual('/redfish/v1/Systems/System1/Memory/Dimm1/Metrics',
self.memory_inst._get_metrics_path())
def test__get_metrics_path_missing_systems_attr(self):
self.memory_inst._json.pop('Metrics')
with self.assertRaisesRegex(
exceptions.MissingAttributeError, 'attribute Memory Metrics'):
self.memory_inst._get_metrics_path()
def test_metrics(self):
# check for the underneath variable value
self.assertIsNone(self.memory_inst._metrics)
# | GIVEN |
self.conn.get.return_value.json.reset_mock()
with open('rsd_lib/tests/unit/json_samples/v2_2/'
'memory_metrics.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
# | WHEN |
actual_metrics = self.memory_inst.metrics
# | THEN |
self.assertIsInstance(actual_metrics,
memory_metrics.MemoryMetrics)
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_metrics,
self.memory_inst.metrics)
self.conn.get.return_value.json.assert_not_called()
def test_metrics_on_refresh(self):
# | GIVEN |
with open('rsd_lib/tests/unit/json_samples/v2_2/'
'memory_metrics.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
# | WHEN & THEN |
self.assertIsInstance(self.memory_inst.metrics,
memory_metrics.MemoryMetrics)
# On refreshing the processor instance...
with open('rsd_lib/tests/unit/json_samples/v2_2/memory.json',
'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.memory_inst.refresh()
# | WHEN & THEN |
self.assertIsNone(self.memory_inst._metrics)
# | GIVEN |
with open('rsd_lib/tests/unit/json_samples/v2_2/'
'memory_metrics.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
# | WHEN & THEN |
self.assertIsInstance(self.memory_inst.metrics,
memory_metrics.MemoryMetrics)
class MemoryCollectionTestCase(testtools.TestCase):
def setUp(self):
super(MemoryCollectionTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_2/'
'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,47 @@
# 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_2.system import memory_metrics
class MemoryMetricsTestCase(testtools.TestCase):
def setUp(self):
super(MemoryMetricsTestCase, self).setUp()
self.conn = mock.Mock()
with open('rsd_lib/tests/unit/json_samples/v2_2/'
'memory_metrics.json', 'r') as f:
self.conn.get.return_value.json.return_value = json.loads(f.read())
self.memory_metrics_inst = memory_metrics.MemoryMetrics(
self.conn, '/redfish/v1/Systems/3/Memory/Dimm1/Metrics',
redfish_version='1.1.0')
def test__parse_attributes(self):
self.memory_metrics_inst._parse_attributes()
self.assertEqual('1.1.0', self.memory_metrics_inst.redfish_version)
self.assertEqual('Memory Metrics for DIMM1',
self.memory_metrics_inst.name)
self.assertEqual('description-as-string',
self.memory_metrics_inst.description)
self.assertEqual('Metrics for DIMM1',
self.memory_metrics_inst.identity)
self.assertEqual(46, self.memory_metrics_inst.temperature_celsius)
self.assertEqual(["OK"], self.memory_metrics_inst.health)

View File

@ -21,6 +21,7 @@ from sushy import exceptions
from sushy.resources.system import system as sushy_system 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_1.system import system as v2_1_system
from rsd_lib.resources.v2_2.system import memory
from rsd_lib.resources.v2_2.system import metrics 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 processor
from rsd_lib.resources.v2_2.system import system from rsd_lib.resources.v2_2.system import system
@ -150,6 +151,54 @@ class SystemTestCase(testtools.TestCase):
self.assertIsInstance(self.system_inst.processors, self.assertIsInstance(self.system_inst.processors,
processor.ProcessorCollection) processor.ProcessorCollection)
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_2/'
'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_2/'
'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_2/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_2/'
'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): class SystemCollectionTestCase(testtools.TestCase):