EventService support
This commit adds support for the EventService in Redfish Story: 2008366 Task: 42486 Change-Id: I8991bed87cea60e2834b05b1af879a146b12e04c
This commit is contained in:
6
releasenotes/notes/event-service-d6607420effc3df8.yaml
Normal file
6
releasenotes/notes/event-service-d6607420effc3df8.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for the Redfish EventService resource.
|
||||
`EventService` is responsible for managing event subscriptions and
|
||||
generates the events sent to subscribers.
|
||||
@@ -19,6 +19,7 @@ import pbr.version
|
||||
from sushy.main import Sushy
|
||||
from sushy.resources.chassis.constants import * # noqa
|
||||
from sushy.resources.constants import * # noqa
|
||||
from sushy.resources.eventservice.constants import * # noqa
|
||||
from sushy.resources.fabric.constants import * # noqa
|
||||
from sushy.resources.manager.constants import * # noqa
|
||||
from sushy.resources.system.constants import * # noqa
|
||||
|
||||
@@ -24,6 +24,7 @@ from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources.chassis import chassis
|
||||
from sushy.resources.compositionservice import compositionservice
|
||||
from sushy.resources.eventservice import eventservice
|
||||
from sushy.resources.fabric import fabric
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.registry import message_registry
|
||||
@@ -145,6 +146,9 @@ class Sushy(base.ResourceBase):
|
||||
_update_service_path = base.Field(['UpdateService', '@odata.id'])
|
||||
"""UpdateService path"""
|
||||
|
||||
_event_service_path = base.Field(['EventService', '@odata.id'])
|
||||
"""EventService path"""
|
||||
|
||||
def __init__(self, base_url, username=None, password=None,
|
||||
root_prefix='/redfish/v1/', verify=True,
|
||||
auth=None, connector=None,
|
||||
@@ -444,6 +448,21 @@ class Sushy(base.ResourceBase):
|
||||
redfish_version=self.redfish_version,
|
||||
registries=self.lazy_registries)
|
||||
|
||||
def get_event_service(self):
|
||||
"""Get the EventService object
|
||||
|
||||
:raises: MissingAttributeError, if the EventService is not found
|
||||
:returns: The EventService object
|
||||
"""
|
||||
if not self._event_service_path:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='EventService/@odata.id',
|
||||
resource=self._path)
|
||||
return eventservice.EventService(
|
||||
self._conn, self._event_service_path,
|
||||
redfish_version=self.redfish_version,
|
||||
registries=self.lazy_registries)
|
||||
|
||||
def _get_standard_message_registry_collection(self):
|
||||
"""Load packaged standard message registries
|
||||
|
||||
|
||||
0
sushy/resources/eventservice/__init__.py
Normal file
0
sushy/resources/eventservice/__init__.py
Normal file
38
sushy/resources/eventservice/constants.py
Normal file
38
sushy/resources/eventservice/constants.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# 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.
|
||||
|
||||
# EventType constants
|
||||
# http://redfish.dmtf.org/schemas/v1/Event.json#/definitions/EventType
|
||||
# https://redfish.dmtf.org/schemas/v1/EventService.v1_0_6.json
|
||||
|
||||
EVENT_TYPE_STATUS_CHANGE = "Status Change"
|
||||
"""The status of a resource has changed"""
|
||||
|
||||
EVENT_TYPE_RESOURCE_ADDED = "Resource Added"
|
||||
"""A resource has been added."""
|
||||
|
||||
EVENT_TYPE_RESOURCE_REMOVED = "Resource Removed"
|
||||
"""A resource has been removed"""
|
||||
|
||||
EVENT_TYPE_RESOURCE_UPDATED = "Resource Updated"
|
||||
"""A resource has been updated"""
|
||||
|
||||
EVENT_TYPE_ALERT = "Alert"
|
||||
"""A condition requires attention"""
|
||||
|
||||
EVENT_TYPE_METRIC_REPORT = "Metric Report"
|
||||
"""The telemetry service is sending a metric report"""
|
||||
|
||||
EVENT_TYPE_OTHER = "Other"
|
||||
"""Because EventType is deprecated as of Redfish Specification v1.6,
|
||||
the event is based on a registry or resource but not an EventType."""
|
||||
123
sushy/resources/eventservice/eventdestination.py
Normal file
123
sushy/resources/eventservice/eventdestination.py
Normal file
@@ -0,0 +1,123 @@
|
||||
# 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.
|
||||
|
||||
|
||||
# Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/v1/EventDestination.v1_0_0.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EventDestination(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The EventDestination resource identity"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The EventDestination resource name"""
|
||||
|
||||
context = base.Field('Context', required=True)
|
||||
"""A client-supplied string that is stored with the event destination
|
||||
subscription"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The description of the EventDestination resource"""
|
||||
|
||||
destination = base.Field('Destination')
|
||||
"""The URI of the destination Event Service"""
|
||||
|
||||
event_types = base.Field('EventTypes', adapter=list)
|
||||
"""The types of events that shall be sent to the destination"""
|
||||
|
||||
protocol = base.Field('Protocol')
|
||||
"""Contain the protocol type that the event will use for sending
|
||||
the event to the destination. A value of Redfish shall be used
|
||||
to indicate that the event type shall adhere to that defined in
|
||||
the Redfish specification"""
|
||||
|
||||
http_headers = base.Field('HttpHeaders', adapter=list)
|
||||
"""This is for setting HTTP headers, such as authorization information.
|
||||
This object will be null on a GET."""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None,
|
||||
registries=None):
|
||||
"""A class representing an EventDestination
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the EventDestination resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
:param registries: Dict of registries to be used in any resource
|
||||
that needs registries to parse messages.
|
||||
"""
|
||||
super(EventDestination, self).__init__(
|
||||
connector, identity, redfish_version, registries)
|
||||
|
||||
def delete(self):
|
||||
"""Delete an EventDestination
|
||||
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
"""
|
||||
self._conn.delete(self._path)
|
||||
|
||||
|
||||
class EventDestinationCollection(base.ResourceCollectionBase):
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The EventDestination collection name"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The EventDestination collection description"""
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return EventDestination
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None,
|
||||
registries=None):
|
||||
"""A class representing a EventDestinationCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the EventDestination resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
:param registries: Dict of registries to be used in any resource
|
||||
that needs registries to parse messages.
|
||||
"""
|
||||
super(EventDestinationCollection, self).__init__(
|
||||
connector, identity, redfish_version, registries)
|
||||
|
||||
def _create(self, payload):
|
||||
r = self._conn.post(self._path, data=payload)
|
||||
location = r.headers.get('Location')
|
||||
return r, location
|
||||
|
||||
def create(self, payload):
|
||||
"""Create a Subscription
|
||||
|
||||
:param payload: The payload representing the subscription.
|
||||
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
:returns: The new subscription
|
||||
"""
|
||||
r, location = self._create(payload)
|
||||
if r.status_code == 201:
|
||||
if location:
|
||||
self.refresh()
|
||||
return self.get_member(location)
|
||||
150
sushy/resources/eventservice/eventservice.py
Normal file
150
sushy/resources/eventservice/eventservice.py
Normal file
@@ -0,0 +1,150 @@
|
||||
# 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.
|
||||
|
||||
|
||||
# Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/v1/EventService.v1_0_8.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
from sushy.resources.eventservice import eventdestination
|
||||
from sushy.resources.eventservice import mappings as evs_maps
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActionsField(base.CompositeField):
|
||||
|
||||
submit_test_event = common.ActionField(
|
||||
'#EventService.SubmitTestEvent')
|
||||
|
||||
|
||||
class EventService(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The EventService resource identity"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The EventService resource name"""
|
||||
|
||||
delivery_retry_attempts = base.Field('DeliveryRetryAttempts')
|
||||
"""Number of attempts an event posting is retried before the subscription
|
||||
is terminated. This retry is at the service level, meaning the HTTP POST
|
||||
to the Event Destination was returned by the HTTP operation as unsuccessful
|
||||
(4xx or 5xx return code) or an HTTP timeout occurred this many times before
|
||||
the Event Destination subscription is terminated
|
||||
"""
|
||||
|
||||
delivery_retry_interval = base.Field('DeliveryRetryIntervalSeconds')
|
||||
"""Number of seconds between retry attempts for sending any given Event"""
|
||||
|
||||
event_types_for_subscription = base.Field('EventTypesForSubscription',
|
||||
adapter=list)
|
||||
"""Types of Events that can be subscribed to"""
|
||||
|
||||
service_enabled = base.Field('ServiceEnabled', adapter=bool)
|
||||
"""Indicates whether the EventService is enabled"""
|
||||
|
||||
status = common.StatusField('Status')
|
||||
"""The status of the EventService"""
|
||||
|
||||
_actions = ActionsField('Actions', required=True)
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None,
|
||||
registries=None):
|
||||
"""A class representing a EventService
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the EventService resource
|
||||
:param redfish_version: The version of Redfish. Used to construct
|
||||
the object according to schema of given version
|
||||
:param registries: Dict of registries to be used in any resource
|
||||
that needs registries to parse messages.
|
||||
"""
|
||||
super(EventService, self).__init__(
|
||||
connector, identity, redfish_version, registries)
|
||||
|
||||
def _get_submit_test_event(self):
|
||||
submit_test_event_action = self._actions.submit_test_event
|
||||
if not submit_test_event_action:
|
||||
raise exceptions.MissingActionError(
|
||||
action='#EventService.SubmitTestEvent',
|
||||
resource=self._path)
|
||||
return submit_test_event_action
|
||||
|
||||
def submit_test_event(self, event_id, event_timestamp, event_type,
|
||||
message, message_args, message_id, origin,
|
||||
severity):
|
||||
"""Submit Test Event is used to to send a test event to the BMC
|
||||
|
||||
:param event_id: ID of event to be added.
|
||||
:param event_timestamp: time stamp of event to be added.
|
||||
:param event_type: type of event to be added.
|
||||
:param message: human readable message of event to be added.
|
||||
:param message_args: array of message arguments of the event to
|
||||
be added.
|
||||
:param message_id: message ID of event to be added.
|
||||
:param origin: string of the URL within the OriginOfCondition
|
||||
property of the event to be added
|
||||
:param severity: the Severity of event to be added.
|
||||
:param target: The link to invoke action.
|
||||
:raises: MissingActionError if the EvenService does not have the
|
||||
action.
|
||||
"""
|
||||
|
||||
target_uri = self._get_submit_test_event().target_uri
|
||||
|
||||
data = {
|
||||
'EventId': event_id,
|
||||
'EventTimestamp': event_timestamp,
|
||||
'EventType': event_type,
|
||||
'Message': message,
|
||||
'MessageArgs': message_args,
|
||||
'MessageId': message_id,
|
||||
'OriginOfCondition': origin,
|
||||
'Severity': severity
|
||||
}
|
||||
|
||||
self._conn.post(target_uri, data=data)
|
||||
|
||||
def get_event_types_for_subscription(self):
|
||||
"""Get the Types of Events that can be subscribed to
|
||||
|
||||
:returns: A set with the types of Events that can be subscribed to.
|
||||
"""
|
||||
if not self.event_types_for_subscription:
|
||||
LOG.warning('Could not figure out the Event types supported by '
|
||||
'the EventService %s', self.identity)
|
||||
return set(evs_maps.EVENT_TYPE_VALUE_MAP.values())
|
||||
|
||||
return set([evs_maps.EVENT_TYPE_VALUE_MAP[v] for v in
|
||||
set(evs_maps.EVENT_TYPE_VALUE_MAP).
|
||||
intersection(self.event_types_for_subscription)])
|
||||
|
||||
def _get_subscriptions_collection_path(self):
|
||||
"""Helper function to find the EventDestinationCollections path"""
|
||||
subscriptions = self.json.get('Subscriptions')
|
||||
if not subscriptions:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='Subscriptions', resource=self._path)
|
||||
return subscriptions.get('@odata.id')
|
||||
|
||||
@property
|
||||
def subscriptions(self):
|
||||
"""Reference to a collection of Event Destination resources"""
|
||||
return eventdestination.EventDestinationCollection(
|
||||
self._conn, self._get_subscriptions_collection_path(),
|
||||
self.redfish_version, self.registries)
|
||||
24
sushy/resources/eventservice/mappings.py
Normal file
24
sushy/resources/eventservice/mappings.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# 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.eventservice import constants as evt_cons
|
||||
|
||||
|
||||
EVENT_TYPE_VALUE_MAP = {
|
||||
'StatusChange': evt_cons.EVENT_TYPE_STATUS_CHANGE,
|
||||
'ResourceAdded': evt_cons.EVENT_TYPE_RESOURCE_ADDED,
|
||||
'ResourceRemoved': evt_cons.EVENT_TYPE_RESOURCE_REMOVED,
|
||||
'ResourceUpdated': evt_cons.EVENT_TYPE_RESOURCE_UPDATED,
|
||||
'Alert': evt_cons.EVENT_TYPE_ALERT,
|
||||
'MetricReport': evt_cons.EVENT_TYPE_METRIC_REPORT,
|
||||
'Other': evt_cons.EVENT_TYPE_OTHER
|
||||
}
|
||||
16
sushy/tests/unit/json_samples/eventdestination1.json
Normal file
16
sushy/tests/unit/json_samples/eventdestination1.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#EventDestination.EventDestination",
|
||||
"@odata.id": "/redfish/v1/EventService/Subscriptions/1",
|
||||
"@odata.type": "#EventDestination.v1_0_0.EventDestination",
|
||||
"Id": "1",
|
||||
"Context": "SomeContext",
|
||||
"Description": "Event Subscription",
|
||||
"Destination": "https://localhost/RedfishEvents/EventReceiver.php",
|
||||
"EventTypes": [
|
||||
"Alert",
|
||||
"StatusChange"
|
||||
],
|
||||
"HttpHeaders": [],
|
||||
"Name": "Event Subscription",
|
||||
"Protocol": "Redfish"
|
||||
}
|
||||
15
sushy/tests/unit/json_samples/eventdestination2.json
Normal file
15
sushy/tests/unit/json_samples/eventdestination2.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#EventDestination.EventDestination",
|
||||
"@odata.id": "/redfish/v1/EventService/Subscriptions/2",
|
||||
"@odata.type": "#EventDestination.v1_0_0.EventDestination",
|
||||
"Id": "2",
|
||||
"Context": "IronicContext",
|
||||
"Description": "Event Subscription",
|
||||
"Destination": "https://localhost/RedfishEvents/EventReceiver.php",
|
||||
"EventTypes": [
|
||||
"Alert"
|
||||
],
|
||||
"HttpHeaders": [],
|
||||
"Name": "Event Subscription",
|
||||
"Protocol": "Redfish"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#EventDestinationCollection.EventDestinationCollection",
|
||||
"@odata.id": "/redfish/v1/EventService/Subscriptions",
|
||||
"@odata.type": "#EventDestinationCollection.EventDestinationCollection",
|
||||
"Description": "User Event Subscriptions",
|
||||
"Name": "EventSubscriptions",
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/EventService/Subscriptions/1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/EventService/Subscriptions/2"
|
||||
}
|
||||
],
|
||||
"Members@odata.count": 2
|
||||
}
|
||||
33
sushy/tests/unit/json_samples/eventservice.json
Normal file
33
sushy/tests/unit/json_samples/eventservice.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"@odata.context": "/redfish/v1/$metadata#EventService.EventService",
|
||||
"@odata.id": "/redfish/v1/EventService/",
|
||||
"@odata.type": "#EventService.v1_0_8.EventService",
|
||||
"Id": "EventService",
|
||||
"Actions": {
|
||||
"#EventService.SubmitTestEvent": {
|
||||
"target": "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/"
|
||||
}
|
||||
},
|
||||
"DeliveryRetryAttempts": 3,
|
||||
"DeliveryRetryIntervalSeconds": 30,
|
||||
"Description": "Event Subscription service",
|
||||
"EventTypesForSubscription": [
|
||||
"StatusChange",
|
||||
"ResourceUpdated",
|
||||
"ResourceAdded",
|
||||
"ResourceRemoved",
|
||||
"Alert"
|
||||
],
|
||||
"Name": "Event Service",
|
||||
"Oem": {
|
||||
},
|
||||
"ServiceEnabled": true,
|
||||
"Status": {
|
||||
"Health": "OK",
|
||||
"HealthRollup": "OK",
|
||||
"State": "Enabled"
|
||||
},
|
||||
"Subscriptions": {
|
||||
"@odata.id": "/redfish/v1/EventService/Subscriptions/"
|
||||
}
|
||||
}
|
||||
0
sushy/tests/unit/resources/eventservice/__init__.py
Normal file
0
sushy/tests/unit/resources/eventservice/__init__.py
Normal file
125
sushy/tests/unit/resources/eventservice/test_evendestination.py
Normal file
125
sushy/tests/unit/resources/eventservice/test_evendestination.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# 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
|
||||
from unittest import mock
|
||||
|
||||
from sushy.resources.eventservice import eventdestination
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class EventDestinationTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(EventDestinationTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/eventdestination1.json') as f:
|
||||
self.json_doc = json.load(f)
|
||||
|
||||
self.conn.get.return_value.json.return_value = self.json_doc
|
||||
|
||||
self.subscription = eventdestination.EventDestination(
|
||||
self.conn, '/redfish/v1/EventService',
|
||||
redfish_version='1.0.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.subscription._parse_attributes(self.json_doc)
|
||||
|
||||
self.assertEqual(self.subscription.identity, '1')
|
||||
self.assertEqual(self.subscription.name, 'Event Subscription')
|
||||
self.assertEqual(self.subscription.context, 'SomeContext')
|
||||
self.assertEqual(self.subscription.destination,
|
||||
'https://localhost/RedfishEvents/EventReceiver.php')
|
||||
self.assertEqual(self.subscription.protocol, 'Redfish')
|
||||
self.assertEqual(set(self.subscription.event_types),
|
||||
set(["Alert", "StatusChange"]))
|
||||
self.assertEqual(self.subscription.http_headers, [])
|
||||
|
||||
def test__delete(self):
|
||||
self.subscription.delete()
|
||||
self.subscription._conn.delete.assert_called_once_with(
|
||||
self.subscription._path)
|
||||
|
||||
|
||||
class EventDestinationCollectionTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(EventDestinationCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'eventdestination_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.eventdestination = eventdestination.EventDestinationCollection(
|
||||
self.conn, '/redfish/v1/EventService/Subscriptions',
|
||||
redfish_version='1.0.0')
|
||||
|
||||
@mock.patch.object(eventdestination, 'EventDestination', autospec=True)
|
||||
def test_get_member(self, subscription_mock):
|
||||
self.eventdestination.get_member(
|
||||
'/redfish/v1/EventService/Subscriptions/1')
|
||||
subscription_mock.assert_called_once_with(
|
||||
self.eventdestination._conn,
|
||||
'/redfish/v1/EventService/Subscriptions/1',
|
||||
self.eventdestination.redfish_version, None)
|
||||
|
||||
@mock.patch.object(eventdestination, 'EventDestination', autospec=True)
|
||||
def test_get_members(self, subscription_mock):
|
||||
members = self.eventdestination.get_members()
|
||||
calls = [
|
||||
mock.call(self.eventdestination._conn,
|
||||
'/redfish/v1/EventService/Subscriptions/%s' % member,
|
||||
self.eventdestination.redfish_version, None)
|
||||
for member in ('1', '2')
|
||||
]
|
||||
subscription_mock.assert_has_calls(calls)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(2, len(members))
|
||||
|
||||
def test__create_subscription_with_required_parameters(self):
|
||||
payload = {
|
||||
'Protocol': 'Redfish',
|
||||
'Destination': 'https://localhost/RedfishEvents/EventReceiver.php',
|
||||
'Context': 'IronicContext',
|
||||
'EventTypes': ["Alert"]
|
||||
}
|
||||
with open('sushy/tests/unit/json_samples/eventdestination2.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
self.conn.post.return_value.status_code = 201
|
||||
self.conn.post.return_value.headers.return_value = {
|
||||
'Location': '/redfish/v1/EventService/Subscriptions/2'
|
||||
}
|
||||
new_subscription = self.eventdestination.create(payload)
|
||||
self.eventdestination._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/EventService/Subscriptions',
|
||||
data=payload,
|
||||
)
|
||||
self.assertIsNotNone(new_subscription)
|
||||
self.assertEqual(new_subscription.identity, '2')
|
||||
self.assertEqual(new_subscription.context, 'IronicContext')
|
||||
self.assertEqual(new_subscription.destination,
|
||||
'https://localhost/RedfishEvents/EventReceiver.php')
|
||||
self.assertIn("Alert", new_subscription.event_types)
|
||||
|
||||
def test__create_subscription_with_invalid_event_type(self):
|
||||
payload = {
|
||||
'Protocol': 'Redfish',
|
||||
'Destination': 'https://localhost/RedfishEvents/EventReceiver.php',
|
||||
'Context': 'IronicContext',
|
||||
'EventTypes': ["Other"]
|
||||
}
|
||||
self.conn.post.return_value.status_code = 400
|
||||
new_subscription = self.eventdestination.create(payload)
|
||||
self.eventdestination._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/EventService/Subscriptions',
|
||||
data=payload,
|
||||
)
|
||||
self.assertIsNone(new_subscription)
|
||||
109
sushy/tests/unit/resources/eventservice/test_eventservice.py
Normal file
109
sushy/tests/unit/resources/eventservice/test_eventservice.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# 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
|
||||
from unittest import mock
|
||||
|
||||
import sushy
|
||||
from sushy import exceptions
|
||||
from sushy.resources.eventservice import eventservice
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class EventServiceTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(EventServiceTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/eventservice.json') as f:
|
||||
self.json_doc = json.load(f)
|
||||
|
||||
self.conn.get.return_value.json.return_value = self.json_doc
|
||||
|
||||
self.eventservice = eventservice.EventService(
|
||||
self.conn, '/redfish/v1/EventService',
|
||||
redfish_version='1.0.8')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.eventservice._parse_attributes(self.json_doc)
|
||||
|
||||
self.assertEqual(self.eventservice.identity, 'EventService')
|
||||
self.assertEqual(self.eventservice.name, 'Event Service')
|
||||
self.assertEqual(self.eventservice.delivery_retry_attempts, 3)
|
||||
self.assertEqual(self.eventservice.delivery_retry_interval, 30)
|
||||
self.assertEqual(self.eventservice.service_enabled, True)
|
||||
self.assertEqual(self.eventservice.status.health, 'ok')
|
||||
self.assertEqual(self.eventservice.status.health_rollup, 'ok')
|
||||
self.assertEqual(self.eventservice.status.state, 'enabled')
|
||||
self.assertEqual(self.eventservice.subscriptions._path,
|
||||
'/redfish/v1/EventService/Subscriptions/')
|
||||
|
||||
def test__get_event_types_for_subscription(self):
|
||||
expected = set([sushy.EVENT_TYPE_STATUS_CHANGE,
|
||||
sushy.EVENT_TYPE_RESOURCE_ADDED,
|
||||
sushy.EVENT_TYPE_RESOURCE_REMOVED,
|
||||
sushy.EVENT_TYPE_RESOURCE_UPDATED,
|
||||
sushy.EVENT_TYPE_ALERT])
|
||||
|
||||
values = self.eventservice.get_event_types_for_subscription()
|
||||
self.assertEqual(expected, values)
|
||||
self.assertIsInstance(values, set)
|
||||
|
||||
def test__no_event_types_for_subscription(self):
|
||||
expected = set([sushy.EVENT_TYPE_STATUS_CHANGE,
|
||||
sushy.EVENT_TYPE_RESOURCE_ADDED,
|
||||
sushy.EVENT_TYPE_RESOURCE_REMOVED,
|
||||
sushy.EVENT_TYPE_RESOURCE_UPDATED,
|
||||
sushy.EVENT_TYPE_ALERT,
|
||||
sushy.EVENT_TYPE_METRIC_REPORT,
|
||||
sushy.EVENT_TYPE_OTHER])
|
||||
self.eventservice.event_types_for_subscription = []
|
||||
|
||||
values = self.eventservice.get_event_types_for_subscription()
|
||||
self.assertEqual(expected, values)
|
||||
self.assertIsInstance(values, set)
|
||||
|
||||
def test__eventservice_missing_action(self):
|
||||
self.eventservice._actions.submit_test_event = None
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingActionError, '#EventService.SubmitTestEvent',
|
||||
self.eventservice.submit_test_event, mock.ANY, mock.ANY, mock.ANY,
|
||||
mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY)
|
||||
|
||||
def test__missing_submit_test_event_target(self):
|
||||
evt_json = self.eventservice.json
|
||||
evt_json['Actions']['#EventService.SubmitTestEvent'].pop('target')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
'attribute Actions/#EventService.SubmitTestEvent/target',
|
||||
self.eventservice._parse_attributes, self.json_doc)
|
||||
|
||||
def test__submit_test_event(self):
|
||||
self.assertIsNotNone(self.eventservice._actions.submit_test_event)
|
||||
payload = {
|
||||
"EventId": "myEventId",
|
||||
"EventTimestamp": "2016-10-11T09:42:59Z",
|
||||
"EventType": "StatusChange",
|
||||
"Message": "This is a test message",
|
||||
"MessageArgs": ["arg0", "arg1"],
|
||||
"MessageId": "iLOEvents.0.9.ResourceStatusChanged",
|
||||
"OriginOfCondition": "/rest/v1/Chassis/1/FooBar",
|
||||
"Severity": "OK"
|
||||
}
|
||||
self.eventservice.submit_test_event(
|
||||
payload["EventId"], payload["EventTimestamp"],
|
||||
payload["EventType"], payload["Message"],
|
||||
payload["MessageArgs"], payload["MessageId"],
|
||||
payload["OriginOfCondition"], payload["Severity"])
|
||||
self.eventservice._conn.post.assert_called_once_with(
|
||||
'/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/',
|
||||
data=payload)
|
||||
@@ -22,6 +22,7 @@ from sushy import exceptions
|
||||
from sushy import main
|
||||
from sushy.resources.chassis import chassis
|
||||
from sushy.resources.compositionservice import compositionservice
|
||||
from sushy.resources.eventservice import eventservice
|
||||
from sushy.resources.fabric import fabric
|
||||
from sushy.resources.manager import manager
|
||||
from sushy.resources.registry import message_registry_file
|
||||
@@ -72,6 +73,8 @@ class MainTestCase(base.TestCase):
|
||||
self.assertEqual('/redfish/v1/Managers', self.root._managers_path)
|
||||
self.assertEqual('/redfish/v1/Chassis', self.root._chassis_path)
|
||||
self.assertEqual('/redfish/v1/Fabrics', self.root._fabrics_path)
|
||||
self.assertEqual('/redfish/v1/EventService',
|
||||
self.root._event_service_path)
|
||||
self.assertEqual('/redfish/v1/SessionService',
|
||||
self.root._session_service_path)
|
||||
self.assertEqual('/redfish/v1/CompositionService',
|
||||
@@ -306,6 +309,13 @@ class MainTestCase(base.TestCase):
|
||||
self.root._conn, '/redfish/v1/CompositionService',
|
||||
self.root.redfish_version, self.root.lazy_registries)
|
||||
|
||||
@mock.patch.object(eventservice, 'EventService', autospec=True)
|
||||
def test_get_event_service(self, mock_event_service):
|
||||
self.root.get_event_service()
|
||||
mock_event_service.assert_called_once_with(
|
||||
self.root._conn, '/redfish/v1/EventService',
|
||||
self.root.redfish_version, self.root.lazy_registries)
|
||||
|
||||
def test__get_standard_message_registry_collection(self):
|
||||
registries = self.root._get_standard_message_registry_collection()
|
||||
|
||||
@@ -460,3 +470,9 @@ class BareMinimumMainTestCase(base.TestCase):
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
'Links/Sessions/@data.id', self.root.get_sessions_path)
|
||||
|
||||
def test_get_event_service_when_eventservice_attr_absent(self):
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
'EventService/@odata.id', self.root.get_event_service
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user