Add system processor metrics info
Change-Id: I5331b87f0b53293a14aea559ae6d4c4bc45202bc
This commit is contained in:
parent
d01f675d8b
commit
1bdc8e12f9
68
rsd_lib/resources/v2_2/system/processor.py
Normal file
68
rsd_lib/resources/v2_2/system/processor.py
Normal file
@ -0,0 +1,68 @@
|
||||
# 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 sushy.resources.system import processor
|
||||
|
||||
from rsd_lib.resources.v2_2.system import processor_metrics
|
||||
from rsd_lib import utils
|
||||
|
||||
|
||||
class StatusField(base.CompositeField):
|
||||
state = base.Field('State')
|
||||
health = base.Field('Health')
|
||||
health_rollup = base.Field('HealthRollup')
|
||||
|
||||
|
||||
class Processor(processor.Processor):
|
||||
|
||||
status = StatusField('Status')
|
||||
"""The processor status"""
|
||||
|
||||
_metrics = None # ref to System instance
|
||||
|
||||
def _get_metrics_path(self):
|
||||
"""Helper function to find the System path"""
|
||||
system_col = self.json.get('Oem').get('Intel_RackScale').get('Metrics')
|
||||
if not system_col:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='Processor Metrics', resource=self._path)
|
||||
return utils.get_resource_identity(system_col)
|
||||
|
||||
@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 = processor_metrics.ProcessorMetrics(
|
||||
self._conn, self._get_metrics_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._metrics
|
||||
|
||||
def refresh(self):
|
||||
super(Processor, self).refresh()
|
||||
self._metrics = None
|
||||
|
||||
|
||||
class ProcessorCollection(processor.ProcessorCollection):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return Processor
|
42
rsd_lib/resources/v2_2/system/processor_metrics.py
Normal file
42
rsd_lib/resources/v2_2/system/processor_metrics.py
Normal file
@ -0,0 +1,42 @@
|
||||
# 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 ProcessorMetrics(base.ResourceBase):
|
||||
name = base.Field('Name')
|
||||
"""The metrics name"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The metrics description"""
|
||||
|
||||
identity = base.Field('Id')
|
||||
"""The metrics identity"""
|
||||
|
||||
average_frequency_mhz = base.Field('AverageFrequencyMHz', adapter=int)
|
||||
"""The processor average frequency mhz"""
|
||||
|
||||
throttling_celsius = base.Field('ThrottlingCelsius', adapter=int)
|
||||
"""The processor throttling celsius"""
|
||||
|
||||
temperature_celsius = base.Field('TemperatureCelsius', adapter=int)
|
||||
"""The processor temperature celsius"""
|
||||
|
||||
consumed_power_watt = base.Field('ConsumedPowerWatt', adapter=int)
|
||||
"""The processor consumed power watt"""
|
||||
|
||||
health = base.Field('Health', adapter=list)
|
||||
"""The detail health information"""
|
@ -17,12 +17,14 @@ from sushy import exceptions
|
||||
from sushy.resources.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
|
||||
|
||||
|
||||
class System(system.System):
|
||||
|
||||
_metrics = None # ref to System instance
|
||||
_metrics = None # ref to System metrics instance
|
||||
_processors = None # ref to ProcessorCollection instance
|
||||
|
||||
def _get_metrics_path(self):
|
||||
"""Helper function to find the System path"""
|
||||
@ -46,6 +48,21 @@ class System(system.System):
|
||||
|
||||
return self._metrics
|
||||
|
||||
@property
|
||||
def processors(self):
|
||||
"""Property to provide reference to `ProcessorCollection` instance
|
||||
|
||||
It is calculated once when the first time it is queried. On refresh,
|
||||
this property gets reset.
|
||||
"""
|
||||
if self._processors is None:
|
||||
self._processors = processor.ProcessorCollection(
|
||||
self._conn, self._get_processor_collection_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._processors
|
||||
|
||||
def refresh(self):
|
||||
super(System, self).refresh()
|
||||
self._metrics = None
|
||||
self._processors = None
|
||||
|
74
rsd_lib/tests/unit/json_samples/v2_2/processor.json
Normal file
74
rsd_lib/tests/unit/json_samples/v2_2/processor.json
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Processor.Processor",
|
||||
"@odata.id": "/redfish/v1/Systems/System1/Processors/CPU1",
|
||||
"@odata.type": "#Processor.v1_0_0.Processor",
|
||||
"Name": "Processor",
|
||||
"Id": "CPU1",
|
||||
"Socket": "CPU 1",
|
||||
"ProcessorType": "CPU",
|
||||
"ProcessorArchitecture": "x86",
|
||||
"InstructionSet": "x86-64",
|
||||
"Manufacturer": "Intel(R) Corporation",
|
||||
"Model": "Multi-Core Intel(R) Xeon(R) processor 7xxx Series",
|
||||
"ProcessorId": {
|
||||
"VendorId": "GenuineIntel",
|
||||
"IdentificationRegisters": "0x34AC34DC8901274A",
|
||||
"EffectiveFamily": "0x42",
|
||||
"EffectiveModel": "0x61",
|
||||
"Step": "0x1",
|
||||
"MicrocodeInfo": "0x429943"
|
||||
},
|
||||
"MaxSpeedMHz": 3700,
|
||||
"TotalCores": 8,
|
||||
"TotalThreads": 16,
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK",
|
||||
"HealthRollup": "OK"
|
||||
},
|
||||
"Oem": {
|
||||
"Intel_RackScale": {
|
||||
"@odata.type": "http://rsa.intel.com/Schema#RSA.Processor",
|
||||
"Brand": "E5",
|
||||
"Capabilities": [
|
||||
"sse",
|
||||
"sse2",
|
||||
"sse3"
|
||||
],
|
||||
"OnPackageMemory": [
|
||||
{
|
||||
"Type": "L2Cache",
|
||||
"CapacityMB": 2,
|
||||
"SpeedMHz": null
|
||||
},
|
||||
{
|
||||
"Type": "L3Cache",
|
||||
"CapacityMB": 20,
|
||||
"SpeedMHz": null
|
||||
}
|
||||
],
|
||||
"ThermalDesignPowerWatt": 160,
|
||||
"Metrics": {
|
||||
"@odata.id": "/redfish/v1/Systems/System1/Processors/CPU1/Metrics"
|
||||
},
|
||||
"ExtendedIdentificationRegisters": {
|
||||
"EAX_00h": "0x0429943FFFFFFFFF",
|
||||
"EAX_01h": "0x0429943FFFFFFFFF",
|
||||
"EAX_02h": "0x0429943FFFFFFFFF",
|
||||
"EAX_03h": "0x0429943FFFFFFFFF",
|
||||
"EAX_04h": "0x0429943FFFFFFFFF",
|
||||
"EAX_05h": "0x0429943FFFFFFFFF",
|
||||
"EAX_07h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000000h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000001h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000002h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000003h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000004h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000005h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000006h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000007h": "0x0429943FFFFFFFFF",
|
||||
"EAX_80000008h": "0x0429943FFFFFFFFF"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Members/1/Processors/#entity",
|
||||
"@odata.id": "/redfish/v1/Systems/System1/Processors",
|
||||
"@odata.type": "#ProcessorCollection.ProcessorCollection",
|
||||
"Name": "Processors Collection",
|
||||
"Members@odata.count": 1,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/System1/Processors/CPU1"
|
||||
}
|
||||
]
|
||||
}
|
13
rsd_lib/tests/unit/json_samples/v2_2/processor_metrics.json
Normal file
13
rsd_lib/tests/unit/json_samples/v2_2/processor_metrics.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#ProcessorMetrics.ProcessorMetrics",
|
||||
"@odata.id": "/redfish/v1/Systems/System1/Processors/CPU1/Metrics",
|
||||
"@odata.type": "#ProcessorMetrics.v1_0_0.ProcessorMetrics",
|
||||
"Name": "ProcessorMetrics for CPU1",
|
||||
"Description": "description-as-string",
|
||||
"Id": "Metrics for CPU1",
|
||||
"AverageFrequencyMHz": 3014,
|
||||
"ThrottlingCelsius": 19,
|
||||
"TemperatureCelsius": 73,
|
||||
"ConsumedPowerWatt": 153,
|
||||
"Health": ["FRB1 BIST Failure", "Processor Throttled"]
|
||||
}
|
116
rsd_lib/tests/unit/resources/v2_2/system/test_processor.py
Normal file
116
rsd_lib/tests/unit/resources/v2_2/system/test_processor.py
Normal file
@ -0,0 +1,116 @@
|
||||
# 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 processor
|
||||
from rsd_lib.resources.v2_2.system import processor_metrics
|
||||
|
||||
|
||||
class ProcessorTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ProcessorTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/processor.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.processor_inst = processor.Processor(
|
||||
self.conn, '/redfish/v1/Systems/System1/Processors/CPU1',
|
||||
redfish_version='1.1.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.processor_inst._parse_attributes()
|
||||
self.assertEqual('1.1.0', self.processor_inst.redfish_version)
|
||||
self.assertEqual('CPU1', self.processor_inst.identity)
|
||||
self.assertEqual('CPU 1', self.processor_inst.socket)
|
||||
self.assertEqual('CPU', self.processor_inst.processor_type)
|
||||
self.assertEqual('x86 or x86-64',
|
||||
self.processor_inst.processor_architecture)
|
||||
self.assertEqual('x86-64', self.processor_inst.instruction_set)
|
||||
self.assertEqual('Intel(R) Corporation',
|
||||
self.processor_inst.manufacturer)
|
||||
self.assertEqual('Multi-Core Intel(R) Xeon(R) processor 7xxx Series',
|
||||
self.processor_inst.model)
|
||||
self.assertEqual(3700, self.processor_inst.max_speed_mhz)
|
||||
self.assertEqual(8, self.processor_inst.total_cores)
|
||||
self.assertEqual(16, self.processor_inst.total_threads)
|
||||
self.assertEqual('Enabled', self.processor_inst.status.state)
|
||||
self.assertEqual('OK', self.processor_inst.status.health)
|
||||
self.assertEqual('OK', self.processor_inst.status.health_rollup)
|
||||
|
||||
def test__get_metrics_path(self):
|
||||
self.assertEqual('/redfish/v1/Systems/System1/Processors/CPU1/Metrics',
|
||||
self.processor_inst._get_metrics_path())
|
||||
|
||||
def test__get_metrics_path_missing_systems_attr(self):
|
||||
self.processor_inst._json.get('Oem').get('Intel_RackScale')\
|
||||
.pop('Metrics')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Processor Metrics'):
|
||||
self.processor_inst._get_metrics_path()
|
||||
|
||||
def test_metrics(self):
|
||||
# check for the underneath variable value
|
||||
self.assertIsNone(self.processor_inst._metrics)
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'processor_metrics.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_metrics = self.processor_inst.metrics
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_metrics,
|
||||
processor_metrics.ProcessorMetrics)
|
||||
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.processor_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/'
|
||||
'processor_metrics.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.processor_inst.metrics,
|
||||
processor_metrics.ProcessorMetrics)
|
||||
|
||||
# On refreshing the processor instance...
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/processor.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.processor_inst.refresh()
|
||||
# | WHEN & THEN |
|
||||
self.assertIsNone(self.processor_inst._metrics)
|
||||
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'processor_metrics.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.processor_inst.metrics,
|
||||
processor_metrics.ProcessorMetrics)
|
@ -0,0 +1,52 @@
|
||||
# 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 processor_metrics
|
||||
|
||||
|
||||
class ProcessorMetricsTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ProcessorMetricsTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'processor_metrics.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.processor_metrics_inst = processor_metrics.ProcessorMetrics(
|
||||
self.conn, '/redfish/v1/Systems/System1/Metrics',
|
||||
redfish_version='1.1.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.processor_metrics_inst._parse_attributes()
|
||||
self.assertEqual('1.1.0', self.processor_metrics_inst.redfish_version)
|
||||
self.assertEqual('ProcessorMetrics for CPU1',
|
||||
self.processor_metrics_inst.name)
|
||||
self.assertEqual('description-as-string',
|
||||
self.processor_metrics_inst.description)
|
||||
self.assertEqual('Metrics for CPU1',
|
||||
self.processor_metrics_inst.identity)
|
||||
self.assertEqual(
|
||||
3014, self.processor_metrics_inst.average_frequency_mhz)
|
||||
self.assertEqual(19, self.processor_metrics_inst.throttling_celsius)
|
||||
self.assertEqual(73, self.processor_metrics_inst.temperature_celsius)
|
||||
self.assertEqual(153, self.processor_metrics_inst.consumed_power_watt)
|
||||
self.assertEqual(["FRB1 BIST Failure", "Processor Throttled"],
|
||||
self.processor_metrics_inst.health)
|
@ -20,6 +20,7 @@ import testtools
|
||||
from sushy import exceptions
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -93,3 +94,51 @@ class SystemTestCase(testtools.TestCase):
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.system_inst.metrics,
|
||||
metrics.Metrics)
|
||||
|
||||
def test_processors(self):
|
||||
# check for the underneath variable value
|
||||
self.assertIsNone(self.system_inst._processors)
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'processor_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_processors = self.system_inst.processors
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_processors,
|
||||
processor.ProcessorCollection)
|
||||
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_processors,
|
||||
self.system_inst.processors)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_processors_on_refresh(self):
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'processor_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.system_inst.processors,
|
||||
processor.ProcessorCollection)
|
||||
|
||||
# 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._processors)
|
||||
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'processor_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.system_inst.processors,
|
||||
processor.ProcessorCollection)
|
||||
|
Loading…
x
Reference in New Issue
Block a user