Add metric report definition resource for RSD2.2
Change-Id: I009e7c04f14a13394b5d89f0677b4d4793345933
This commit is contained in:
parent
bedc76e7ed
commit
7372e555bd
119
rsd_lib/resources/v2_2/telemetry/metric.py
Normal file
119
rsd_lib/resources/v2_2/telemetry/metric.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# 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 sushy.resources import base
|
||||||
|
|
||||||
|
from rsd_lib import utils as rsd_lib_utils
|
||||||
|
|
||||||
|
|
||||||
|
class DiscreteTriggerConditionField(base.ListField):
|
||||||
|
name = base.Field("Name")
|
||||||
|
"""This property shall contain a name for the trigger"""
|
||||||
|
|
||||||
|
trigger_value = base.Field("TriggerValue")
|
||||||
|
"""This property contains the value that sets a trigger"""
|
||||||
|
|
||||||
|
previous_value = base.Field("PreviousValue")
|
||||||
|
"""If present, this property shall contain a previous value that shall be
|
||||||
|
used in evaluating the behavior of setting the trigger.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class NumericTriggerConditionField(base.ListField):
|
||||||
|
name = base.Field("Name")
|
||||||
|
"""This property shall contain a name for the trigger"""
|
||||||
|
|
||||||
|
value = base.Field("Value", adapter=rsd_lib_utils.num_or_none)
|
||||||
|
"""This property shall contain the value of the trigger"""
|
||||||
|
|
||||||
|
direction_of_crossing = base.Field("DirectionOfCrossing")
|
||||||
|
"""If present, this property shall contain the direction of crossing. If
|
||||||
|
not present, the direction is not relevant
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TriggerConditionField(base.CompositeField):
|
||||||
|
dwell_interval = base.Field("DwellInterval")
|
||||||
|
"""The value shall be an ISO 8601 conformant interval during which the
|
||||||
|
triggering state shall persist before the trigger is invoked.
|
||||||
|
"""
|
||||||
|
|
||||||
|
trigger_type = base.Field("TriggerType")
|
||||||
|
"""The value of this property shall specific the type of trigger"""
|
||||||
|
|
||||||
|
discrete_trigger_conditions = DiscreteTriggerConditionField(
|
||||||
|
"DiscreteTriggerConditions")
|
||||||
|
"""A Trigger condition based on TriggerDiscreteCondition"""
|
||||||
|
|
||||||
|
filter_trigger_condition = base.Field("FilterTriggerCondition")
|
||||||
|
"""A Trigger condition based on FilterTriggerCondition"""
|
||||||
|
|
||||||
|
numeric_trigger_conditions = NumericTriggerConditionField(
|
||||||
|
"NumericTriggerConditions")
|
||||||
|
"""A Trigger condition based on NumericTriggerConditions"""
|
||||||
|
|
||||||
|
|
||||||
|
class StatusField(base.CompositeField):
|
||||||
|
state = base.Field("State")
|
||||||
|
"""The status state"""
|
||||||
|
|
||||||
|
health = base.Field("Health")
|
||||||
|
"""The status health"""
|
||||||
|
|
||||||
|
|
||||||
|
class Metric(base.ResourceBase):
|
||||||
|
identity = base.Field("Id")
|
||||||
|
"""The metric identity"""
|
||||||
|
|
||||||
|
name = base.Field('Name')
|
||||||
|
"""The metric name"""
|
||||||
|
|
||||||
|
description = base.Field('Description')
|
||||||
|
"""The metric description"""
|
||||||
|
|
||||||
|
metric_properties = base.Field("MetricProperties")
|
||||||
|
"""The report definition metric properties"""
|
||||||
|
|
||||||
|
collection_function = base.Field('CollectionFunction')
|
||||||
|
"""If present, the value shall define the function to apply over the
|
||||||
|
collection duration
|
||||||
|
"""
|
||||||
|
|
||||||
|
collection_duration = base.Field('CollectionDuration')
|
||||||
|
"""This property shall not be present if MetricDefinition.Timescope=Point
|
||||||
|
or if MetricDefintion.Duration is present. If present, the value shall
|
||||||
|
be an ISO 8601 duration of the interval over which this metric value
|
||||||
|
shall be computed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
trigger_condition = TriggerConditionField("TriggerCondition")
|
||||||
|
"""If present the values define conditions that shall be met before the
|
||||||
|
event is triggered. This trigger applies to all properties defined by
|
||||||
|
the value of the MetricPropertyDeclaration property in the associated
|
||||||
|
MetricDefinition and as constrained by the MetricScope property.
|
||||||
|
"""
|
||||||
|
|
||||||
|
status = StatusField("Status")
|
||||||
|
"""The report definition status"""
|
||||||
|
|
||||||
|
def __init__(self, connector, identity, redfish_version=None):
|
||||||
|
"""A class representing a Metric
|
||||||
|
|
||||||
|
:param connector: A Connector instance
|
||||||
|
:param identity: The identity of the Metric resource
|
||||||
|
:param redfish_version: The version of RedFish. Used to construct
|
||||||
|
the object according to schema of the given version.
|
||||||
|
"""
|
||||||
|
super(Metric, self).__init__(connector, identity, redfish_version)
|
@ -24,6 +24,9 @@ class MetricDefinition(base.ResourceBase):
|
|||||||
identity = base.Field('Id', required=True)
|
identity = base.Field('Id', required=True)
|
||||||
"""The CPUHealth metric definition identity string"""
|
"""The CPUHealth metric definition identity string"""
|
||||||
|
|
||||||
|
description = base.Field('Description')
|
||||||
|
"""The metric definition description"""
|
||||||
|
|
||||||
sensor_type = base.Field('SensorType')
|
sensor_type = base.Field('SensorType')
|
||||||
"""The type of sensor"""
|
"""The type of sensor"""
|
||||||
|
|
||||||
|
177
rsd_lib/resources/v2_2/telemetry/metric_report_definition.py
Normal file
177
rsd_lib/resources/v2_2/telemetry/metric_report_definition.py
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
# 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 import exceptions
|
||||||
|
from sushy.resources import base
|
||||||
|
from sushy import utils
|
||||||
|
|
||||||
|
from rsd_lib.resources.v2_2.telemetry import metric
|
||||||
|
from rsd_lib.resources.v2_2.telemetry import metric_report_definition_schemas
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ScheduleField(base.CompositeField):
|
||||||
|
recurrence_interval = base.Field("RecurrenceInterval")
|
||||||
|
"""The schedule recurrence interval"""
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
||||||
|
"""The status state"""
|
||||||
|
|
||||||
|
health = base.Field("Health")
|
||||||
|
"""The status health"""
|
||||||
|
|
||||||
|
health_rollup = base.Field('HealthRollup')
|
||||||
|
"""The status health_rollup"""
|
||||||
|
|
||||||
|
|
||||||
|
class MetricReportDefinition(base.ResourceBase):
|
||||||
|
identity = base.Field("Id")
|
||||||
|
"""The metric report definition identity"""
|
||||||
|
|
||||||
|
name = base.Field('Name')
|
||||||
|
"""The metric report definition name"""
|
||||||
|
|
||||||
|
description = base.Field('Description')
|
||||||
|
"""The metric report definition description"""
|
||||||
|
|
||||||
|
schedule = ScheduleField("Schedule")
|
||||||
|
"""If present, A metric values collected starting at each scheduled
|
||||||
|
interval and for the time specified by Duration. No more than
|
||||||
|
Schedule.MaxOccurrences values shall be collected for this metric. If
|
||||||
|
not present, the corresponding metric values shall be collected when the
|
||||||
|
related metric report is retrieved.
|
||||||
|
"""
|
||||||
|
|
||||||
|
metric_report_type = base.Field("MetricReportType")
|
||||||
|
"""The value shall specify the collection type for the corresponding
|
||||||
|
metric values
|
||||||
|
"""
|
||||||
|
|
||||||
|
collection_time_scope = base.Field("CollectionTimeScope")
|
||||||
|
"""The value shall specify the time scope for collecting the corresponding
|
||||||
|
metric values
|
||||||
|
"""
|
||||||
|
|
||||||
|
report_actions = base.Field("ReportActions")
|
||||||
|
"""The value of this property shall specify the action to perform when the
|
||||||
|
metric report is generated. When a metric report is generated, place the
|
||||||
|
metric information in the resource specified by the MetricReport
|
||||||
|
property. The Volatile property will specify the behavior if
|
||||||
|
MetricReport resource already exists.
|
||||||
|
"""
|
||||||
|
|
||||||
|
volatile = base.Field("Volatile")
|
||||||
|
"""Entries in the resulting metric value properties are reused on each
|
||||||
|
scheduled interval
|
||||||
|
"""
|
||||||
|
|
||||||
|
wildcards = WildcardsField("Wildcards")
|
||||||
|
"""The property shall contain an array of wildcards and their replacements
|
||||||
|
strings, which are to appliced to the MetricProperties array property
|
||||||
|
"""
|
||||||
|
|
||||||
|
status = StatusField("Status")
|
||||||
|
"""The report definition status"""
|
||||||
|
|
||||||
|
metric_properties = base.Field("MetricProperties")
|
||||||
|
"""The report definition metric properties"""
|
||||||
|
|
||||||
|
def __init__(self, connector, identity, redfish_version=None):
|
||||||
|
"""A class representing a MetricReportDefinition
|
||||||
|
|
||||||
|
:param connector: A Connector instance
|
||||||
|
:param identity: The identity of the MetricReportDefinition resource
|
||||||
|
:param redfish_version: The version of RedFish. Used to construct
|
||||||
|
the object according to schema of the given version.
|
||||||
|
"""
|
||||||
|
super(MetricReportDefinition, self).__init__(
|
||||||
|
connector, identity, redfish_version)
|
||||||
|
|
||||||
|
def _get_metrics_path(self):
|
||||||
|
"""Helper function to find the metrics path"""
|
||||||
|
if 'Metrics' not in self.json:
|
||||||
|
raise exceptions.MissingAttributeError(
|
||||||
|
attribute='Metrics', resource=self.path)
|
||||||
|
|
||||||
|
return utils.get_members_identities(self.json.get('Metrics'))
|
||||||
|
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def metrics(self):
|
||||||
|
"""Property to provide collection to `Metric`
|
||||||
|
|
||||||
|
It is calculated once the first time it is queried. On refresh,
|
||||||
|
this property is reset.
|
||||||
|
"""
|
||||||
|
return [metric.Metric(
|
||||||
|
self._conn, path, redfish_version=self.redfish_version)
|
||||||
|
for path in self._get_metrics_path()]
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
"""Delete report definition"""
|
||||||
|
self._conn.delete(self.path)
|
||||||
|
|
||||||
|
|
||||||
|
class MetricReportDefinitionCollection(base.ResourceCollectionBase):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _resource_type(self):
|
||||||
|
return MetricReportDefinition
|
||||||
|
|
||||||
|
def __init__(self, connector, path, redfish_version=None):
|
||||||
|
"""A class representing a ReportDefinitionCollection
|
||||||
|
|
||||||
|
:param connector: A Connector instance
|
||||||
|
:param path: The canonical path to the ReportDefinition collection
|
||||||
|
resource
|
||||||
|
:param redfish_version: The version of RedFish. Used to construct
|
||||||
|
the object according to schema of the given version.
|
||||||
|
"""
|
||||||
|
super(MetricReportDefinitionCollection, self).__init__(
|
||||||
|
connector, path, redfish_version)
|
||||||
|
|
||||||
|
def create_metric_report_definition(self, metric_report_definition_req):
|
||||||
|
"""Create a new report definition
|
||||||
|
|
||||||
|
:param metric_report_definition_req: JSON for event subscription
|
||||||
|
:returns: The uri of the new event report definition
|
||||||
|
"""
|
||||||
|
target_uri = self._path
|
||||||
|
validate(metric_report_definition_req,
|
||||||
|
metric_report_definition_schemas.report_definition_req_schema)
|
||||||
|
|
||||||
|
resp = self._conn.post(target_uri, data=metric_report_definition_req)
|
||||||
|
|
||||||
|
report_definition_url = resp.headers['Location']
|
||||||
|
LOG.info("report definition created at %s", report_definition_url)
|
||||||
|
return report_definition_url[report_definition_url.find(self._path):]
|
@ -0,0 +1,60 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
report_definition_req_schema = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'Name': {'type': 'string'},
|
||||||
|
'Schedule': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'RecurrenceInterval': {'type': 'string'},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'MetricReportType': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['OnChange', 'Periodic', 'OnRequests']
|
||||||
|
},
|
||||||
|
'CollectionTimeScope': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['Point', 'Interval', 'StartupInterval']
|
||||||
|
},
|
||||||
|
'ReportActions': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['Transmit', 'Log']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'MetricReport': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'@odata.id': {'type': 'string'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Status': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'State': {'type': 'string'},
|
||||||
|
'Health': {'type': 'string'},
|
||||||
|
'HealthRollup': {'type': 'string'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'MetricProperties': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {'type': 'string'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
@ -17,6 +17,7 @@ from sushy.resources import base
|
|||||||
from sushy import utils
|
from sushy import utils
|
||||||
|
|
||||||
from rsd_lib.resources.v2_2.telemetry import metric_definitions
|
from rsd_lib.resources.v2_2.telemetry import metric_definitions
|
||||||
|
from rsd_lib.resources.v2_2.telemetry import metric_report_definition
|
||||||
from rsd_lib import utils as rsd_lib_utils
|
from rsd_lib import utils as rsd_lib_utils
|
||||||
|
|
||||||
|
|
||||||
@ -61,3 +62,19 @@ class Telemetry(base.ResourceBase):
|
|||||||
return metric_definitions.MetricDefinitionsCollection(
|
return metric_definitions.MetricDefinitionsCollection(
|
||||||
self._conn, self._get_metric_definitions_path(),
|
self._conn, self._get_metric_definitions_path(),
|
||||||
redfish_version=self.redfish_version)
|
redfish_version=self.redfish_version)
|
||||||
|
|
||||||
|
def _get_metric_report_definitions_path(self):
|
||||||
|
"""Helper function to find the metric report definitions path"""
|
||||||
|
return utils.get_sub_resource_path_by(self, 'MetricReportDefinitions')
|
||||||
|
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def metric_report_definitions(self):
|
||||||
|
"""Property to provide reference to `MetricReportDefinitionCollection`
|
||||||
|
|
||||||
|
It is calculated once the first time it is queried. On refresh,
|
||||||
|
this property is reset.
|
||||||
|
"""
|
||||||
|
return metric_report_definition.MetricReportDefinitionCollection(
|
||||||
|
self._conn, self._get_metric_definitions_path(),
|
||||||
|
redfish_version=self.redfish_version)
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"@odata.context":"/redfish/v1/$metadata#MetricReportDefinition",
|
||||||
|
"@odata.type":"#MetricReportDefinition.1.0.0.MetricReportDefinition",
|
||||||
|
"@odata.id":"/redfish/v1/TelemetryService/MetricReportDefinitions/CPU1Metrics",
|
||||||
|
"Id":"CPUEventPublish",
|
||||||
|
"Name":"CPU1 Metric Publisher",
|
||||||
|
"Schedule":{
|
||||||
|
"RecurrenceInterval":"PT1M"
|
||||||
|
},
|
||||||
|
"MetricReportType":"Periodic",
|
||||||
|
"CollectionTimeScope":"Interval",
|
||||||
|
"ReportActions":[
|
||||||
|
"Transmit",
|
||||||
|
"Log"
|
||||||
|
],
|
||||||
|
"MetricReport":{
|
||||||
|
"@odata.id":"/redfish/v1/TelemetryService/MetricReports/TransmitCPU1Metrics"
|
||||||
|
},
|
||||||
|
"Metrics":[
|
||||||
|
{
|
||||||
|
"@odata.id":"/redfish/v1/TelemetryService/FakeMetric"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Status":{
|
||||||
|
"State":"Enabled",
|
||||||
|
"Health":"OK"
|
||||||
|
},
|
||||||
|
"MetricProperties":[
|
||||||
|
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/BandwidthPercent",
|
||||||
|
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/CPUHealth",
|
||||||
|
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/TemperatureCelsius"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"@odata.context":"/redfish/v1/$metadata#TelemetryService/MetricReportDefinitions/$entity",
|
||||||
|
"@odata.id":"/redfish/v1/TelemetryService/MetricReportDefinitions",
|
||||||
|
"@odata.type":"#MetricReportDefinitionCollection.MetricReportDefinitionCollection",
|
||||||
|
"Name":"MetricReportDefinition Collection",
|
||||||
|
"Members@odata.count":1,
|
||||||
|
"Members":[
|
||||||
|
{
|
||||||
|
"@odata.id":"/redfish/v1/TelemetryService/MetricReportDefinitions/CPU1Metrics"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -38,10 +38,10 @@ class MetricDefinitionTestCase(testtools.TestCase):
|
|||||||
self.metric_definition_inst._parse_attributes()
|
self.metric_definition_inst._parse_attributes()
|
||||||
self.assertEqual('1.1.0',
|
self.assertEqual('1.1.0',
|
||||||
self.metric_definition_inst.redfish_version)
|
self.metric_definition_inst.redfish_version)
|
||||||
self.assertEqual('memoryTemperature',
|
self.assertEqual('memoryTemperature', self.metric_definition_inst.name)
|
||||||
self.metric_definition_inst.name)
|
self.assertEqual('1-md-6', self.metric_definition_inst.identity)
|
||||||
self.assertEqual('1-md-6',
|
self.assertEqual('Metric Definition description',
|
||||||
self.metric_definition_inst.identity)
|
self.metric_definition_inst.description)
|
||||||
self.assertEqual('Numeric',
|
self.assertEqual('Numeric',
|
||||||
self.metric_definition_inst.metric_type)
|
self.metric_definition_inst.metric_type)
|
||||||
self.assertEqual('Temperature',
|
self.assertEqual('Temperature',
|
||||||
|
@ -0,0 +1,276 @@
|
|||||||
|
# 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 jsonschema
|
||||||
|
import mock
|
||||||
|
import testtools
|
||||||
|
|
||||||
|
from sushy import exceptions
|
||||||
|
|
||||||
|
from rsd_lib.resources.v2_2.telemetry import metric
|
||||||
|
from rsd_lib.resources.v2_2.telemetry import metric_report_definition
|
||||||
|
from rsd_lib.tests.unit.fakes import request_fakes
|
||||||
|
|
||||||
|
|
||||||
|
class ReportDefinitionTestCase(testtools.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ReportDefinitionTestCase, self).setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
with open(
|
||||||
|
'rsd_lib/tests/unit/json_samples/v2_2/'
|
||||||
|
'metric_report_definition.json', 'r') as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.metric_report_definition_inst = metric_report_definition.\
|
||||||
|
MetricReportDefinition(
|
||||||
|
self.conn,
|
||||||
|
'/redfish/v1/TelemetryService/MetricReportDefinitions/'
|
||||||
|
'CPU1Metrics',
|
||||||
|
redfish_version='1.1.0')
|
||||||
|
|
||||||
|
def test__parse_attributes(self):
|
||||||
|
self.metric_report_definition_inst._parse_attributes()
|
||||||
|
self.assertEqual("CPUEventPublish",
|
||||||
|
self.metric_report_definition_inst.identity)
|
||||||
|
self.assertEqual("CPU1 Metric Publisher",
|
||||||
|
self.metric_report_definition_inst.name)
|
||||||
|
self.assertEqual(None,
|
||||||
|
self.metric_report_definition_inst.description)
|
||||||
|
self.assertEqual(
|
||||||
|
"PT1M",
|
||||||
|
self.metric_report_definition_inst.schedule.recurrence_interval)
|
||||||
|
self.assertEqual("Periodic",
|
||||||
|
self.metric_report_definition_inst.metric_report_type)
|
||||||
|
self.assertEqual(
|
||||||
|
"Interval",
|
||||||
|
self.metric_report_definition_inst.collection_time_scope)
|
||||||
|
self.assertEqual(['Transmit', 'Log'],
|
||||||
|
self.metric_report_definition_inst.report_actions)
|
||||||
|
self.assertEqual(
|
||||||
|
"Enabled", self.metric_report_definition_inst.status.state)
|
||||||
|
self.assertEqual(
|
||||||
|
"OK", self.metric_report_definition_inst.status.health)
|
||||||
|
self.assertEqual(
|
||||||
|
None, self.metric_report_definition_inst.status.health_rollup)
|
||||||
|
self.assertEqual(None, self.metric_report_definition_inst.volatile)
|
||||||
|
self.assertEqual(None, self.metric_report_definition_inst.wildcards)
|
||||||
|
self.assertEqual(
|
||||||
|
[
|
||||||
|
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#"
|
||||||
|
"/BandwidthPercent",
|
||||||
|
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#"
|
||||||
|
"/CPUHealth",
|
||||||
|
"/redfish/v1/Systems/System1/Processors/CPU1/Metrics#"
|
||||||
|
"/TemperatureCelsius"
|
||||||
|
],
|
||||||
|
self.metric_report_definition_inst.metric_properties)
|
||||||
|
|
||||||
|
def test__get_metrics_path(self):
|
||||||
|
self.assertEqual(
|
||||||
|
("/redfish/v1/TelemetryService/FakeMetric",),
|
||||||
|
self.metric_report_definition_inst._get_metrics_path())
|
||||||
|
|
||||||
|
def test__get_metrics_path_missing_systems_attr(self):
|
||||||
|
self.metric_report_definition_inst._json.pop('Metrics')
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
exceptions.MissingAttributeError, 'attribute Metrics'):
|
||||||
|
self.metric_report_definition_inst._get_metrics_path()
|
||||||
|
|
||||||
|
def test_metrics(self):
|
||||||
|
# | 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.metric_report_definition_inst.metrics
|
||||||
|
# | THEN |
|
||||||
|
self.assertIsInstance(actual_metrics, list)
|
||||||
|
self.assertIsInstance(actual_metrics[0], metric.Metric)
|
||||||
|
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.metric_report_definition_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.metric_report_definition_inst.metrics, list)
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.metric_report_definition_inst.metrics[0], metric.Metric)
|
||||||
|
|
||||||
|
# On refreshing the telemetry service instance...
|
||||||
|
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||||
|
'metric_report_definition.json', 'r') as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
|
||||||
|
self.metric_report_definition_inst.invalidate()
|
||||||
|
self.metric_report_definition_inst.refresh(force=False)
|
||||||
|
|
||||||
|
# | 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.metric_report_definition_inst.metrics, list)
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.metric_report_definition_inst.metrics[0], metric.Metric)
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
self.metric_report_definition_inst.delete()
|
||||||
|
self.metric_report_definition_inst._conn.delete.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
class ReportDefinitionCollectionTestCase(testtools.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ReportDefinitionCollectionTestCase, self).setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
|
||||||
|
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||||
|
'metric_report_definition_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/MetricReportDefinitions/1"})
|
||||||
|
|
||||||
|
self.report_definition_col = metric_report_definition.\
|
||||||
|
MetricReportDefinitionCollection(
|
||||||
|
self.conn,
|
||||||
|
'/redfish/v1/TelemetryService/MetricReportDefinitions',
|
||||||
|
redfish_version='1.1.0')
|
||||||
|
|
||||||
|
def test_parse_attributes(self):
|
||||||
|
self.report_definition_col._parse_attributes()
|
||||||
|
self.assertEqual("MetricReportDefinition Collection", self.
|
||||||
|
report_definition_col.name)
|
||||||
|
|
||||||
|
@mock.patch.object(
|
||||||
|
metric_report_definition, 'MetricReportDefinition', autospec=True)
|
||||||
|
def test_get_member(self, mock_metric_report_definition):
|
||||||
|
self.report_definition_col.get_member(
|
||||||
|
'/redfish/v1/TelemetryService/MetricReportDefinitions/CPU1Metrics')
|
||||||
|
|
||||||
|
mock_metric_report_definition.assert_called_once_with(
|
||||||
|
self.report_definition_col._conn,
|
||||||
|
'/redfish/v1/TelemetryService/MetricReportDefinitions/CPU1Metrics',
|
||||||
|
redfish_version=self.report_definition_col.redfish_version
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(
|
||||||
|
metric_report_definition, 'MetricReportDefinition', autospec=True)
|
||||||
|
def test_get_members(self, mock_metric_report_definition):
|
||||||
|
members = self.report_definition_col.get_members()
|
||||||
|
self.assertEqual(mock_metric_report_definition.call_count, 1)
|
||||||
|
self.assertIsInstance(members, list)
|
||||||
|
self.assertEqual(1, len(members))
|
||||||
|
|
||||||
|
def test_create_report_definition_reqs(self):
|
||||||
|
reqs = {
|
||||||
|
'Name': 'CPU1 Metric Publisher',
|
||||||
|
'Schedule': {
|
||||||
|
'RecurrenceInterval': 'PT1M'
|
||||||
|
},
|
||||||
|
'MetricReportType': 'Periodic',
|
||||||
|
'CollectionTimeScope': 'Interval',
|
||||||
|
'ReportActions': [
|
||||||
|
'Transmit',
|
||||||
|
'Log'
|
||||||
|
],
|
||||||
|
'MetricReport': {
|
||||||
|
'@odata.id': '/redfish/v1/TelemetryService'
|
||||||
|
'/MetricReports/TransmitCPU1Metrics'
|
||||||
|
},
|
||||||
|
'Status': {
|
||||||
|
'State': 'Enabled',
|
||||||
|
'Health': 'OK'
|
||||||
|
},
|
||||||
|
'MetricProperties': [
|
||||||
|
'/redfish/v1/Systems/System1/Processors/CPU1/Metrics'
|
||||||
|
'#/BandwidthPercent',
|
||||||
|
'/redfish/v1/Systems/System1/Processors/CPU1/Metrics'
|
||||||
|
'#/CPUHealth',
|
||||||
|
'/redfish/v1/Systems/System1/Processors/CPU1/Metrics'
|
||||||
|
'#/TemperatureCelsius'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = self.report_definition_col.create_metric_report_definition(
|
||||||
|
reqs)
|
||||||
|
self.report_definition_col._conn.post.assert_called_once_with(
|
||||||
|
'/redfish/v1/TelemetryService/MetricReportDefinitions',
|
||||||
|
data=reqs)
|
||||||
|
self.assertEqual(
|
||||||
|
result, '/redfish/v1/TelemetryService/MetricReportDefinitions/1')
|
||||||
|
|
||||||
|
def test_create_report_definition_invalid_reqs(self):
|
||||||
|
reqs = {
|
||||||
|
'Name': 'CPU1 Metric Publisher',
|
||||||
|
'Schedule': {
|
||||||
|
'RecurrenceInterval': 'PT1M'
|
||||||
|
},
|
||||||
|
'MetricReportType': 'Periodic',
|
||||||
|
'CollectionTimeScope': 'Interval',
|
||||||
|
'ReportActions': [
|
||||||
|
'Transmit',
|
||||||
|
'Log'
|
||||||
|
],
|
||||||
|
'MetricReport': {
|
||||||
|
'@odata.id': '/redfish/v1/TelemetryService/MetricReports'
|
||||||
|
'/TransmitCPU1Metrics'
|
||||||
|
},
|
||||||
|
'Status': {
|
||||||
|
'State': 'Enabled',
|
||||||
|
'Health': 'OK'
|
||||||
|
},
|
||||||
|
'MetricProperties': [
|
||||||
|
'/redfish/v1/Systems/System1/Processors/CPU1/Metrics'
|
||||||
|
'#/BandwidthPercent',
|
||||||
|
'/redfish/v1/Systems/System1/Processors/CPU1/Metrics'
|
||||||
|
'#/CPUHealth',
|
||||||
|
'/redfish/v1/Systems/System1/Processors/CPU1/Metrics'
|
||||||
|
'#/TemperatureCelsius'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wrong format
|
||||||
|
report_definition_req = reqs.copy()
|
||||||
|
report_definition_req.update({'ReportActions': True})
|
||||||
|
self.assertRaises(
|
||||||
|
jsonschema.exceptions.ValidationError,
|
||||||
|
self.report_definition_col.create_metric_report_definition,
|
||||||
|
report_definition_req)
|
||||||
|
|
||||||
|
# Wrong additional fields
|
||||||
|
report_definition_req = reqs.copy()
|
||||||
|
report_definition_req['Additional'] = 'AdditionalField'
|
||||||
|
self.assertRaises(
|
||||||
|
jsonschema.exceptions.ValidationError,
|
||||||
|
self.report_definition_col.create_metric_report_definition,
|
||||||
|
report_definition_req)
|
@ -20,6 +20,7 @@ import testtools
|
|||||||
from sushy import exceptions
|
from sushy import exceptions
|
||||||
|
|
||||||
from rsd_lib.resources.v2_2.telemetry import metric_definitions
|
from rsd_lib.resources.v2_2.telemetry import metric_definitions
|
||||||
|
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 telemetry
|
||||||
|
|
||||||
|
|
||||||
@ -78,7 +79,7 @@ class TelemetryTestCase(testtools.TestCase):
|
|||||||
self.telemetry_inst.metric_definitions)
|
self.telemetry_inst.metric_definitions)
|
||||||
self.conn.get.return_value.json.assert_not_called()
|
self.conn.get.return_value.json.assert_not_called()
|
||||||
|
|
||||||
def test_metrics_on_refresh(self):
|
def test_metrics_definitions_on_refresh(self):
|
||||||
# | GIVEN |
|
# | GIVEN |
|
||||||
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||||
'metric_definitions.json', 'r') as f:
|
'metric_definitions.json', 'r') as f:
|
||||||
@ -102,3 +103,65 @@ class TelemetryTestCase(testtools.TestCase):
|
|||||||
# | WHEN & THEN |
|
# | WHEN & THEN |
|
||||||
self.assertIsInstance(self.telemetry_inst.metric_definitions,
|
self.assertIsInstance(self.telemetry_inst.metric_definitions,
|
||||||
metric_definitions.MetricDefinitionsCollection)
|
metric_definitions.MetricDefinitionsCollection)
|
||||||
|
|
||||||
|
def test__get_metric_report_definitions_path_path(self):
|
||||||
|
self.assertEqual(
|
||||||
|
'/redfish/v1/TelemetryService/MetricReportDefinitions',
|
||||||
|
self.telemetry_inst._get_metric_report_definitions_path())
|
||||||
|
|
||||||
|
def test__get_metric_report_definitions_path_missing_systems_attr(self):
|
||||||
|
self.telemetry_inst._json.pop('MetricReportDefinitions')
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
exceptions.MissingAttributeError,
|
||||||
|
'attribute MetricReportDefinitions'):
|
||||||
|
self.telemetry_inst._get_metric_report_definitions_path()
|
||||||
|
|
||||||
|
def test_metric_report_definitions(self):
|
||||||
|
# | GIVEN |
|
||||||
|
self.conn.get.return_value.json.reset_mock()
|
||||||
|
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||||
|
'metric_report_definition_collection.json', 'r') as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN |
|
||||||
|
actual_report_definitions = \
|
||||||
|
self.telemetry_inst.metric_report_definitions
|
||||||
|
# | THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
actual_report_definitions,
|
||||||
|
metric_report_definition.MetricReportDefinitionCollection)
|
||||||
|
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_report_definitions,
|
||||||
|
self.telemetry_inst.metric_report_definitions)
|
||||||
|
self.conn.get.return_value.json.assert_not_called()
|
||||||
|
|
||||||
|
def test_metrics_report_definitions_on_refresh(self):
|
||||||
|
# | GIVEN |
|
||||||
|
with open('rsd_lib/tests/unit/json_samples/v2_2/'
|
||||||
|
'metric_report_definition_collection.json', 'r') as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.telemetry_inst.metric_report_definitions,
|
||||||
|
metric_report_definition.MetricReportDefinitionCollection)
|
||||||
|
|
||||||
|
# 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/'
|
||||||
|
'metric_report_definition_collection.json', 'r') as f:
|
||||||
|
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||||
|
# | WHEN & THEN |
|
||||||
|
self.assertIsInstance(
|
||||||
|
self.telemetry_inst.metric_report_definitions,
|
||||||
|
metric_report_definition.MetricReportDefinitionCollection)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user