Add Telemetry Trigger in RSD 2.2
Change-Id: I5c8713e4c8f6cb26430c45551d77b16d51710ec4
This commit is contained in:
parent
ae9d5d78d1
commit
ec67bbbd59
@ -19,6 +19,7 @@ from sushy import utils
|
||||
from rsd_lib.resources.v2_2.telemetry import metric_definition
|
||||
from rsd_lib.resources.v2_2.telemetry import metric_report
|
||||
from rsd_lib.resources.v2_2.telemetry import metric_report_definition
|
||||
from rsd_lib.resources.v2_2.telemetry import trigger
|
||||
from rsd_lib import utils as rsd_lib_utils
|
||||
|
||||
|
||||
@ -95,3 +96,19 @@ class Telemetry(base.ResourceBase):
|
||||
return metric_report.MetricReportCollection(
|
||||
self._conn, self._get_metric_reports_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def _get_triggers_path(self):
|
||||
"""Helper function to find the triggers path"""
|
||||
return utils.get_sub_resource_path_by(self, 'Triggers')
|
||||
|
||||
@property
|
||||
@utils.cache_it
|
||||
def triggers(self):
|
||||
"""Property to provide reference to `TriggerCollection`
|
||||
|
||||
It is calculated once the first time it is queried. On refresh,
|
||||
this property is reset.
|
||||
"""
|
||||
return trigger.TriggerCollection(
|
||||
self._conn, self._get_triggers_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
215
rsd_lib/resources/v2_2/telemetry/trigger.py
Normal file
215
rsd_lib/resources/v2_2/telemetry/trigger.py
Normal file
@ -0,0 +1,215 @@
|
||||
# Copyright 2019 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 jsonschema import validate
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
from rsd_lib.resources.v2_2.telemetry import trigger_schemas
|
||||
from rsd_lib import utils as rsd_lib_utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NumericTriggersField(base.ListField):
|
||||
name = base.Field('Name')
|
||||
"""The name of trigger"""
|
||||
|
||||
value = base.Field('Value', adapter=rsd_lib_utils.num_or_none)
|
||||
"""This property contains the value of the trigger"""
|
||||
|
||||
direction_of_crossing = base.Field('DirectionOfCrossing')
|
||||
"""This property contains the value of the trigger"""
|
||||
|
||||
dwell_tim_msec = base.Field(
|
||||
'DwellTimMsec', adapter=rsd_lib_utils.num_or_none)
|
||||
"""This time the excursion persists before a trigger is determined"""
|
||||
|
||||
severity = base.Field('Severity')
|
||||
"""This property contains the value of the Severity property in the Event
|
||||
message
|
||||
"""
|
||||
|
||||
|
||||
class DiscreteTriggersField(base.ListField):
|
||||
name = base.Field('Name')
|
||||
"""The name of trigger"""
|
||||
|
||||
value = base.Field('Value')
|
||||
"""This property contains the value of the trigger"""
|
||||
|
||||
dwell_tim_msec = base.Field(
|
||||
'DwellTimMsec', adapter=rsd_lib_utils.num_or_none)
|
||||
"""This time the excursion persists before a trigger is determined"""
|
||||
|
||||
severity = base.Field('Severity')
|
||||
"""This property contains the value of the Severity property in the Event
|
||||
message
|
||||
"""
|
||||
|
||||
|
||||
class WildcardsField(base.ListField):
|
||||
name = base.Field("Name")
|
||||
"""This property shall contain a name for a Wildcard for a key"""
|
||||
|
||||
keys = base.Field("Keys")
|
||||
"""If the value is an empty string, then the server shall substitute every
|
||||
current key. Each not empty key value shall be substituted for the
|
||||
wildcard
|
||||
"""
|
||||
|
||||
|
||||
class StatusField(base.CompositeField):
|
||||
state = base.Field('State')
|
||||
health = base.Field('Health')
|
||||
health_rollup = base.Field('HealthRollup')
|
||||
|
||||
|
||||
class Trigger(base.ResourceBase):
|
||||
identity = base.Field("Id")
|
||||
"""The trigger identity"""
|
||||
|
||||
name = base.Field("Name")
|
||||
"""The trigger name"""
|
||||
|
||||
description = base.Field("Description")
|
||||
"""The trigger description"""
|
||||
|
||||
metric_type = base.Field("MetricType")
|
||||
"""The type of trigger"""
|
||||
|
||||
trigger_actions = base.Field("TriggerActions")
|
||||
"""The metric report description"""
|
||||
|
||||
numeric_triggers = NumericTriggersField("NumericTriggers")
|
||||
"""List of numeric triggers"""
|
||||
|
||||
discrete_trigger_condition = base.Field("DiscreteTriggerCondition")
|
||||
"""The value shall indicate how the corresponding metric"""
|
||||
|
||||
discrete_triggers = DiscreteTriggersField("DiscreteTriggers")
|
||||
"""List of discrete triggers"""
|
||||
|
||||
status = StatusField('Status')
|
||||
"""The trigger status"""
|
||||
|
||||
wildcards = WildcardsField("Wildcards")
|
||||
"""The property shall contain an array of wildcards and their replacements
|
||||
strings, which are to appliced to the MetricProperties array property
|
||||
"""
|
||||
|
||||
metric_properties = base.Field("MetricProperties")
|
||||
"""The report definition metric properties"""
|
||||
|
||||
def delete(self):
|
||||
"""Delete trigger"""
|
||||
self._conn.delete(self.path)
|
||||
|
||||
|
||||
class TriggerCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return Trigger
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing a TriggerCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the Trigger collection
|
||||
resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(TriggerCollection, self).__init__(
|
||||
connector, path, redfish_version)
|
||||
|
||||
def create_trigger(self, name=None, description=None, metric_type=None,
|
||||
trigger_actions=None, numeric_triggers=None,
|
||||
discrete_trigger_condition=None, discrete_triggers=None,
|
||||
status=None, wildcards=None, metric_properties=None):
|
||||
"""Create a new trigger
|
||||
|
||||
:param name: The trigger name
|
||||
:param description: The trigger description
|
||||
:param metric_type: The type of trigger
|
||||
:param trigger_actions: The metric report description
|
||||
:param numeric_triggers: List of numeric triggers
|
||||
:param discrete_trigger_condition: The value shall indicate how the
|
||||
corresponding metric
|
||||
:param discrete_triggers: List of discrete triggers
|
||||
:param status: The trigger status
|
||||
:param wildcards: Wildcards used to replace values in MetricProperties
|
||||
array property
|
||||
:param metric_properties: The report definition metric properties
|
||||
:returns: The uri of the new trigger
|
||||
"""
|
||||
target_uri = self._path
|
||||
|
||||
# prepare the request data of creating new trigger
|
||||
data = {}
|
||||
if name is not None:
|
||||
data['Name'] = name
|
||||
if description is not None:
|
||||
data['Description'] = description
|
||||
|
||||
if metric_type is not None:
|
||||
validate(metric_type,
|
||||
trigger_schemas.metric_type_schema)
|
||||
data['MetricType'] = metric_type
|
||||
|
||||
if trigger_actions is not None:
|
||||
validate(trigger_actions,
|
||||
trigger_schemas.trigger_actions_schema)
|
||||
data['TriggerActions'] = trigger_actions
|
||||
|
||||
if numeric_triggers is not None:
|
||||
validate(numeric_triggers,
|
||||
trigger_schemas.numeric_triggers_schema)
|
||||
data['NumericTriggers'] = numeric_triggers
|
||||
|
||||
if discrete_trigger_condition is not None:
|
||||
validate(discrete_trigger_condition,
|
||||
trigger_schemas.discrete_trigger_condition_schema)
|
||||
data['DiscreteTriggerCondition'] = discrete_trigger_condition
|
||||
|
||||
if discrete_triggers is not None:
|
||||
validate(discrete_triggers,
|
||||
trigger_schemas.discrete_triggers_schema)
|
||||
data['DiscreteTriggers'] = discrete_triggers
|
||||
|
||||
if status is not None:
|
||||
validate(status,
|
||||
trigger_schemas.status_schema)
|
||||
data['Status'] = status
|
||||
|
||||
if wildcards is not None:
|
||||
validate(wildcards,
|
||||
trigger_schemas.wildcards_schema)
|
||||
data['Wildcards'] = wildcards
|
||||
|
||||
if metric_properties is not None:
|
||||
validate(metric_properties,
|
||||
trigger_schemas.metric_properties_schema)
|
||||
data['MetricProperties'] = metric_properties
|
||||
|
||||
# Issue POST request to create new trigger
|
||||
resp = self._conn.post(target_uri, data=data)
|
||||
LOG.info("Node created at %s", resp.headers['Location'])
|
||||
node_url = resp.headers['Location']
|
||||
|
||||
return node_url[node_url.find(self._path):]
|
92
rsd_lib/resources/v2_2/telemetry/trigger_schemas.py
Normal file
92
rsd_lib/resources/v2_2/telemetry/trigger_schemas.py
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright (c) 2019 Intel, Corp.
|
||||
#
|
||||
# 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.
|
||||
|
||||
metric_type_schema = {
|
||||
'type': 'string',
|
||||
'enum': ['Numeric', 'Discrete']
|
||||
}
|
||||
|
||||
trigger_actions_schema = {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'string',
|
||||
'enum': ['Transmit', 'Log']
|
||||
}
|
||||
}
|
||||
|
||||
numeric_triggers_schema = {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'Name': {'type': 'string'},
|
||||
'Value': {'type': 'number'},
|
||||
'DirectionOfCrossing': {
|
||||
'type': 'string',
|
||||
'enum': ['Increasing', 'Decreasing']
|
||||
},
|
||||
'DwellTimMsec': {'type': 'number'},
|
||||
'Severity': {'type': 'string'}
|
||||
},
|
||||
'additionalProperties': False
|
||||
}
|
||||
}
|
||||
|
||||
discrete_trigger_condition_schema = {
|
||||
'type': 'string',
|
||||
'enum': ['Specified', 'Changed']
|
||||
}
|
||||
|
||||
discrete_triggers_schema = {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'Name': {'type': 'string'},
|
||||
'Value': {'type': 'string'},
|
||||
'DwellTimMsec': {'type': 'number'},
|
||||
'Severity': {'type': 'string'}
|
||||
},
|
||||
'additionalProperties': False
|
||||
}
|
||||
}
|
||||
|
||||
status_schema = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'State': {'type': 'string'},
|
||||
'Health': {'type': 'string'},
|
||||
'HealthRollup': {'type': 'string'}
|
||||
},
|
||||
'additionalProperties': False
|
||||
}
|
||||
|
||||
wildcards_schema = {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'Name': {'type': 'string'},
|
||||
'Keys': {'type': 'string'}
|
||||
},
|
||||
'additionalProperties': False
|
||||
}
|
||||
}
|
||||
|
||||
metric_properties_schema = {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'string'
|
||||
}
|
||||
}
|
28
rsd_lib/tests/unit/json_samples/v2_2/discrete_trigger.json
Normal file
28
rsd_lib/tests/unit/json_samples/v2_2/discrete_trigger.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#TelemetryService/Triggers/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorMachineCheckError",
|
||||
"@odata.type": "#Trigger.v1_0_0.Trigger",
|
||||
"Id": "ProcessorMachineCheckError",
|
||||
"Name": "Trigger for Processor Machine Check Error",
|
||||
"Description": "Triggers for System1 Processor Machine Check Error",
|
||||
"MetricType": "Discrete",
|
||||
"TriggerActions": [
|
||||
"Transmit"
|
||||
],
|
||||
"DiscreteTriggerCondition": "Specified",
|
||||
"DiscreteTriggers": [
|
||||
{
|
||||
"Value": "Machine Check Exception",
|
||||
"DwellTimMsec": "1",
|
||||
"Severity": "Critical"
|
||||
}
|
||||
],
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"MetricProperties": [
|
||||
"/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/CPUHealth",
|
||||
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/CPUHealth"
|
||||
]
|
||||
}
|
35
rsd_lib/tests/unit/json_samples/v2_2/numeric_trigger.json
Normal file
35
rsd_lib/tests/unit/json_samples/v2_2/numeric_trigger.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#TelemetryService/Triggers/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorTemperature",
|
||||
"@odata.type": "#Trigger.v1_0_0.Trigger",
|
||||
"Id": "ProcessorTemperature",
|
||||
"Name": "Triggers for Processor Temperature Malfunction",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"MetricType": "Numeric",
|
||||
"TriggerActions": [
|
||||
"Transmit"
|
||||
],
|
||||
"NumericTriggers": [
|
||||
{
|
||||
"Name": "UpperThresholdCritical",
|
||||
"Value": "90",
|
||||
"DirectionOfCrossing": "Increasing",
|
||||
"DwellTimMsec": "1",
|
||||
"Severity": "Critical"
|
||||
},
|
||||
{
|
||||
"Name": "UpperThresholdNonCritical",
|
||||
"Value": "75",
|
||||
"DirectionOfCrossing": "Increasing",
|
||||
"DwellTimMsec": "4",
|
||||
"Severity": "Warning"
|
||||
}
|
||||
],
|
||||
"MetricProperties": [
|
||||
"/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/TemperatureCelsius",
|
||||
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/TemperatureCelsius"
|
||||
]
|
||||
}
|
27
rsd_lib/tests/unit/json_samples/v2_2/trigger_collection.json
Normal file
27
rsd_lib/tests/unit/json_samples/v2_2/trigger_collection.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#TelemetryService/Triggers/$entity",
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers",
|
||||
"@odata.type": "#TriggersCollection.TriggersCollection",
|
||||
"Name": "Triggers Collection",
|
||||
"Members@odata.count": 6,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorCatastrophicError"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorInitializationError"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorMachineCheckError"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorPOSTFailure"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorTemperature"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/TelemetryService/Triggers/ProcessorThermalTrip"
|
||||
}
|
||||
]
|
||||
}
|
@ -48,7 +48,7 @@ class SystemTestCase(testtools.TestCase):
|
||||
self.assertEqual('/redfish/v1/Systems/437XR1138R2/Memory',
|
||||
self.system_inst._get_memory_collection_path())
|
||||
|
||||
def test__get_memory_collection_path_missing_systems_attr(self):
|
||||
def test__get_memory_collection_path_missing_attr(self):
|
||||
self.system_inst._json.pop('Memory')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Memory'):
|
||||
@ -105,7 +105,7 @@ class SystemTestCase(testtools.TestCase):
|
||||
'/redfish/v1/Systems/437XR1138R2/Storage',
|
||||
self.system_inst._get_storage_subsystem_collection_path())
|
||||
|
||||
def test__get_storage_collection_path_missing_systems_attr(self):
|
||||
def test__get_storage_collection_path_missing_attr(self):
|
||||
self.system_inst._json.pop('Storage')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Storage'):
|
||||
|
@ -76,7 +76,7 @@ class MemoryTestCase(testtools.TestCase):
|
||||
self.assertEqual('/redfish/v1/Systems/System1/Memory/Dimm1/Metrics',
|
||||
self.memory_inst._get_metrics_path())
|
||||
|
||||
def test__get_metrics_path_missing_systems_attr(self):
|
||||
def test__get_metrics_path_missing_attr(self):
|
||||
self.memory_inst._json.pop('Metrics')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Metrics'):
|
||||
|
@ -60,7 +60,7 @@ class ProcessorTestCase(testtools.TestCase):
|
||||
self.assertEqual('/redfish/v1/Systems/System1/Processors/CPU1/Metrics',
|
||||
self.processor_inst._get_metrics_path())
|
||||
|
||||
def test__get_metrics_path_missing_systems_attr(self):
|
||||
def test__get_metrics_path_missing_attr(self):
|
||||
self.processor_inst._json.get('Oem').get('Intel_RackScale')\
|
||||
.pop('Metrics')
|
||||
with self.assertRaisesRegex(exceptions.MissingAttributeError,
|
||||
|
@ -49,7 +49,7 @@ class SystemTestCase(testtools.TestCase):
|
||||
self.assertEqual('/redfish/v1/Systems/System2/Metrics',
|
||||
self.system_inst._get_metrics_path())
|
||||
|
||||
def test__get_metrics_path_missing_systems_attr(self):
|
||||
def test__get_metrics_path_missing_attr(self):
|
||||
self.system_inst._json.get('Oem').get('Intel_RackScale').pop('Metrics')
|
||||
with self.assertRaisesRegex(exceptions.MissingAttributeError,
|
||||
'attribute Oem/Intel_RackScale/Metrics'):
|
||||
|
@ -96,7 +96,7 @@ class MetricReportTestCase(testtools.TestCase):
|
||||
'/redfish/v1/TelemetryService/MetricReportDefinitions/CPU1Metrics',
|
||||
self.metric_report_inst._get_metric_report_definition_path())
|
||||
|
||||
def test__get_metric_report_definition_path_missing_systems_attr(self):
|
||||
def test__get_metric_report_definition_path_missing_attr(self):
|
||||
self.metric_report_inst._json.pop('MetricReportDefinition')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
@ -164,7 +164,7 @@ class MetricReportCollectionTestCase(testtools.TestCase):
|
||||
'metric_report_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.metric_report_col = metric_report. MetricReportCollection(
|
||||
self.metric_report_col = metric_report.MetricReportCollection(
|
||||
self.conn, '/redfish/v1/TelemetryService/MetricReports',
|
||||
redfish_version='1.1.0')
|
||||
|
||||
|
@ -85,7 +85,7 @@ class ReportDefinitionTestCase(testtools.TestCase):
|
||||
("/redfish/v1/TelemetryService/FakeMetric",),
|
||||
self.metric_report_definition_inst._get_metrics_path())
|
||||
|
||||
def test__get_metrics_path_missing_systems_attr(self):
|
||||
def test__get_metrics_path_missing_attr(self):
|
||||
self.metric_report_definition_inst._json.pop('Metrics')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Metrics'):
|
||||
@ -146,7 +146,7 @@ class ReportDefinitionTestCase(testtools.TestCase):
|
||||
'/redfish/v1/TelemetryService/MetricReports/TransmitCPU1Metrics',
|
||||
self.metric_report_definition_inst._get_metric_report_path())
|
||||
|
||||
def test__get_metric_report_path_missing_systems_attr(self):
|
||||
def test__get_metric_report_path_missing_attr(self):
|
||||
self.metric_report_definition_inst._json.pop('MetricReport')
|
||||
with self.assertRaisesRegex(exceptions.MissingAttributeError,
|
||||
'attribute MetricReport'):
|
||||
|
@ -23,6 +23,7 @@ from rsd_lib.resources.v2_2.telemetry import metric_definition
|
||||
from rsd_lib.resources.v2_2.telemetry import metric_report
|
||||
from rsd_lib.resources.v2_2.telemetry import metric_report_definition
|
||||
from rsd_lib.resources.v2_2.telemetry import telemetry
|
||||
from rsd_lib.resources.v2_2.telemetry import trigger
|
||||
|
||||
|
||||
class TelemetryTestCase(testtools.TestCase):
|
||||
@ -53,7 +54,7 @@ class TelemetryTestCase(testtools.TestCase):
|
||||
self.assertEqual('/redfish/v1/TelemetryService/MetricDefinitions',
|
||||
self.telemetry_inst._get_metric_definitions_path())
|
||||
|
||||
def test__get_metric_definitions_path_missing_systems_attr(self):
|
||||
def test__get_metric_definitions_path_missing_attr(self):
|
||||
self.telemetry_inst._json.pop('MetricDefinitions')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute MetricDefinitions'):
|
||||
@ -110,7 +111,7 @@ class TelemetryTestCase(testtools.TestCase):
|
||||
'/redfish/v1/TelemetryService/MetricReportDefinitions',
|
||||
self.telemetry_inst._get_metric_report_definitions_path())
|
||||
|
||||
def test__get_metric_report_definitions_path_missing_systems_attr(self):
|
||||
def test__get_metric_report_definitions_path_missing_attr(self):
|
||||
self.telemetry_inst._json.pop('MetricReportDefinitions')
|
||||
with self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
@ -172,7 +173,7 @@ class TelemetryTestCase(testtools.TestCase):
|
||||
'/redfish/v1/TelemetryService/MetricReports',
|
||||
self.telemetry_inst._get_metric_reports_path())
|
||||
|
||||
def test__get_metric_reports_path_missing_systems_attr(self):
|
||||
def test__get_metric_reports_path_missing_attr(self):
|
||||
self.telemetry_inst._json.pop('MetricReports')
|
||||
with self.assertRaisesRegex(exceptions.MissingAttributeError,
|
||||
'attribute MetricReports'):
|
||||
@ -225,3 +226,60 @@ class TelemetryTestCase(testtools.TestCase):
|
||||
self.assertIsInstance(
|
||||
self.telemetry_inst.metric_reports,
|
||||
metric_report.MetricReportCollection)
|
||||
|
||||
def test__get_triggers_path_path(self):
|
||||
self.assertEqual(
|
||||
'/redfish/v1/TelemetryService/Triggers',
|
||||
self.telemetry_inst._get_triggers_path())
|
||||
|
||||
def test__get_triggers_path_missing_attr(self):
|
||||
self.telemetry_inst._json.pop('Triggers')
|
||||
with self.assertRaisesRegex(exceptions.MissingAttributeError,
|
||||
'attribute Triggers'):
|
||||
self.telemetry_inst._get_triggers_path()
|
||||
|
||||
def test_triggers(self):
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'trigger_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_triggers = self.telemetry_inst.triggers
|
||||
# | THEN |
|
||||
self.assertIsInstance(
|
||||
actual_triggers, trigger.TriggerCollection)
|
||||
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_triggers,
|
||||
self.telemetry_inst.triggers)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_triggers_on_refresh(self):
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'trigger_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(
|
||||
self.telemetry_inst.triggers, trigger.TriggerCollection)
|
||||
|
||||
# On refreshing the telemetry service instance...
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'telemetry_service.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.telemetry_inst.invalidate()
|
||||
self.telemetry_inst.refresh(force=False)
|
||||
|
||||
# | GIVEN |
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'trigger_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(
|
||||
self.telemetry_inst.triggers, trigger.TriggerCollection)
|
||||
|
247
rsd_lib/tests/unit/resources/v2_2/telemetry/test_trigger.py
Normal file
247
rsd_lib/tests/unit/resources/v2_2/telemetry/test_trigger.py
Normal file
@ -0,0 +1,247 @@
|
||||
# Copyright 2019 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.telemetry import trigger
|
||||
from rsd_lib.tests.unit.fakes import request_fakes
|
||||
|
||||
|
||||
class TriggerTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TriggerTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/numeric_trigger.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.trigger_inst = trigger.Trigger(
|
||||
self.conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/ProcessorTemperature',
|
||||
redfish_version='1.1.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.trigger_inst._parse_attributes()
|
||||
self.assertEqual("ProcessorTemperature", self.trigger_inst.identity)
|
||||
self.assertEqual("Triggers for Processor Temperature Malfunction",
|
||||
self.trigger_inst.name)
|
||||
self.assertEqual(None, self.trigger_inst.description)
|
||||
|
||||
self.assertEqual('Enabled', self.trigger_inst.status.state)
|
||||
self.assertEqual('OK', self.trigger_inst.status.health)
|
||||
self.assertEqual(None, self.trigger_inst.status.health_rollup)
|
||||
|
||||
self.assertEqual('Numeric', self.trigger_inst.metric_type)
|
||||
self.assertEqual(["Transmit"], self.trigger_inst.trigger_actions)
|
||||
self.assertEqual(None, self.trigger_inst.discrete_trigger_condition)
|
||||
self.assertEqual(None, self.trigger_inst.discrete_triggers)
|
||||
self.assertEqual(None, self.trigger_inst.wildcards)
|
||||
self.assertEqual(
|
||||
[
|
||||
"/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/"
|
||||
"TemperatureCelsius",
|
||||
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/"
|
||||
"TemperatureCelsius"
|
||||
],
|
||||
self.trigger_inst.metric_properties)
|
||||
|
||||
self.assertEqual(
|
||||
'UpperThresholdCritical',
|
||||
self.trigger_inst.numeric_triggers[0].name)
|
||||
self.assertEqual(90, self.trigger_inst.numeric_triggers[0].value)
|
||||
self.assertEqual(
|
||||
'Increasing',
|
||||
self.trigger_inst.numeric_triggers[0].direction_of_crossing)
|
||||
self.assertEqual(
|
||||
1, self.trigger_inst.numeric_triggers[0].dwell_tim_msec)
|
||||
self.assertEqual(
|
||||
'Critical', self.trigger_inst.numeric_triggers[0].severity)
|
||||
|
||||
self.assertEqual(
|
||||
'UpperThresholdNonCritical',
|
||||
self.trigger_inst.numeric_triggers[1].name)
|
||||
self.assertEqual(75, self.trigger_inst.numeric_triggers[1].value)
|
||||
self.assertEqual(
|
||||
'Increasing',
|
||||
self.trigger_inst.numeric_triggers[1].direction_of_crossing)
|
||||
self.assertEqual(
|
||||
4, self.trigger_inst.numeric_triggers[1].dwell_tim_msec)
|
||||
self.assertEqual(
|
||||
'Warning', self.trigger_inst.numeric_triggers[1].severity)
|
||||
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'discrete_trigger.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.trigger_inst.refresh()
|
||||
|
||||
self.assertEqual(
|
||||
"ProcessorMachineCheckError", self.trigger_inst.identity)
|
||||
self.assertEqual("Trigger for Processor Machine Check Error",
|
||||
self.trigger_inst.name)
|
||||
self.assertEqual(
|
||||
"Triggers for System1 Processor Machine Check Error",
|
||||
self.trigger_inst.description)
|
||||
|
||||
self.assertEqual('Enabled', self.trigger_inst.status.state)
|
||||
self.assertEqual('OK', self.trigger_inst.status.health)
|
||||
self.assertEqual(None, self.trigger_inst.status.health_rollup)
|
||||
|
||||
self.assertEqual('Discrete', self.trigger_inst.metric_type)
|
||||
self.assertEqual(["Transmit"], self.trigger_inst.trigger_actions)
|
||||
self.assertEqual(
|
||||
'Specified', self.trigger_inst.discrete_trigger_condition)
|
||||
self.assertEqual(
|
||||
None, self.trigger_inst.numeric_triggers)
|
||||
self.assertEqual(None, self.trigger_inst.wildcards)
|
||||
self.assertEqual(
|
||||
[
|
||||
"/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/"
|
||||
"CPUHealth",
|
||||
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/"
|
||||
"CPUHealth"
|
||||
],
|
||||
self.trigger_inst.metric_properties)
|
||||
|
||||
self.assertEqual(None, self.trigger_inst.discrete_triggers[0].name)
|
||||
self.assertEqual(
|
||||
"Machine Check Exception",
|
||||
self.trigger_inst.discrete_triggers[0].value)
|
||||
self.assertEqual(
|
||||
1, self.trigger_inst.discrete_triggers[0].dwell_tim_msec)
|
||||
self.assertEqual(
|
||||
'Critical', self.trigger_inst.discrete_triggers[0].severity)
|
||||
|
||||
def test_delete(self):
|
||||
self.trigger_inst.delete()
|
||||
self.trigger_inst._conn.delete.assert_called_once()
|
||||
|
||||
|
||||
class TriggerCollectionTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TriggerCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
|
||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||
'trigger_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.conn.post.return_value = request_fakes.fake_request_post(
|
||||
None, headers={
|
||||
"Location": "https://localhost:8443/redfish/v1/"
|
||||
"TelemetryService/Triggers/2"})
|
||||
|
||||
self.trigger_col = trigger.TriggerCollection(
|
||||
self.conn, '/redfish/v1/TelemetryService/Triggers',
|
||||
redfish_version='1.1.0')
|
||||
|
||||
def test_parse_attributes(self):
|
||||
self.trigger_col._parse_attributes()
|
||||
self.assertEqual("Triggers Collection", self.trigger_col.name)
|
||||
|
||||
@mock.patch.object(trigger, 'Trigger', autospec=True)
|
||||
def test_get_member(self, mock_trigger):
|
||||
self.trigger_col.get_member(
|
||||
'/redfish/v1/TelemetryService/Triggers/ProcessorCatastrophicError')
|
||||
|
||||
mock_trigger.assert_called_once_with(
|
||||
self.trigger_col._conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/ProcessorCatastrophicError',
|
||||
redfish_version=self.trigger_col.redfish_version
|
||||
)
|
||||
|
||||
@mock.patch.object(trigger, 'Trigger', autospec=True)
|
||||
def test_get_members(self, mock_trigger):
|
||||
members = self.trigger_col.get_members()
|
||||
|
||||
calls = [
|
||||
mock.call(
|
||||
self.trigger_col._conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/'
|
||||
'ProcessorCatastrophicError',
|
||||
redfish_version=self.trigger_col.redfish_version),
|
||||
mock.call(
|
||||
self.trigger_col._conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/'
|
||||
'ProcessorInitializationError',
|
||||
redfish_version=self.trigger_col.redfish_version),
|
||||
mock.call(
|
||||
self.trigger_col._conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/'
|
||||
'ProcessorMachineCheckError',
|
||||
redfish_version=self.trigger_col.redfish_version),
|
||||
mock.call(
|
||||
self.trigger_col._conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/ProcessorPOSTFailure',
|
||||
redfish_version=self.trigger_col.redfish_version),
|
||||
mock.call(
|
||||
self.trigger_col._conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/ProcessorTemperature',
|
||||
redfish_version=self.trigger_col.redfish_version),
|
||||
mock.call(
|
||||
self.trigger_col._conn,
|
||||
'/redfish/v1/TelemetryService/Triggers/ProcessorThermalTrip',
|
||||
redfish_version=self.trigger_col.redfish_version)
|
||||
]
|
||||
mock_trigger.assert_has_calls(calls)
|
||||
self.assertEqual(mock_trigger.call_count, 6)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(6, len(members))
|
||||
|
||||
def test_create_trigger(self):
|
||||
reqs = {
|
||||
"Name": "Trigger for Processor Machine Check Error",
|
||||
"Description": "Triggers for System1 Processor Machine Check "
|
||||
"Error",
|
||||
"MetricType": "Discrete",
|
||||
"TriggerActions": [
|
||||
"Transmit"
|
||||
],
|
||||
"DiscreteTriggerCondition": "Specified",
|
||||
"DiscreteTriggers": [
|
||||
{
|
||||
"Value": "Machine Check Exception",
|
||||
"DwellTimMsec": 1,
|
||||
"Severity": "Critical"
|
||||
}
|
||||
],
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"MetricProperties": [
|
||||
"/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/"
|
||||
"CPUHealth",
|
||||
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/"
|
||||
"CPUHealth"
|
||||
]
|
||||
}
|
||||
|
||||
result = self.trigger_col.create_trigger(
|
||||
name=reqs['Name'], description=reqs['Description'],
|
||||
metric_type=reqs['MetricType'],
|
||||
trigger_actions=reqs['TriggerActions'],
|
||||
discrete_trigger_condition=reqs['DiscreteTriggerCondition'],
|
||||
discrete_triggers=reqs['DiscreteTriggers'], status=reqs['Status'],
|
||||
metric_properties=reqs['MetricProperties'],)
|
||||
self.trigger_col._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/TelemetryService/Triggers',
|
||||
data=reqs)
|
||||
self.assertEqual(
|
||||
result, '/redfish/v1/TelemetryService/Triggers/2')
|
Loading…
x
Reference in New Issue
Block a user