-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add unit tests Move emit notification to objects layer
- Loading branch information
Showing
20 changed files
with
1,327 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# 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 contextlib | ||
|
||
from oslo_config import cfg | ||
from oslo_log import log | ||
from oslo_messaging import exceptions as oslo_msg_exc | ||
from oslo_utils import excutils | ||
from oslo_versionedobjects import exception as oslo_vo_exc | ||
|
||
from esi_leap.common import exception | ||
from esi_leap.common.i18n import _ | ||
from esi_leap.objects import fields | ||
from esi_leap.objects import notification | ||
|
||
LOG = log.getLogger(__name__) | ||
CONF = cfg.CONF | ||
|
||
|
||
def _emit_api_notification(context, obj, action, level, status, | ||
crud_notify_obj, **kwargs): | ||
"""Helper for emitting API notifications. | ||
:param context: request context. | ||
:param obj: resource rpc object. | ||
:param action: Action string to go in the EventType. | ||
:param level: Notification level. One of | ||
`esi_leap.objects.fields.NotificationLevel.ALL` | ||
:param status: Status to go in the EventType. One of | ||
`esi_leap.objects.fields.NotificationStatus.ALL` | ||
:param kwargs: kwargs to use when creating the notification payload. | ||
""" | ||
resource = obj.__class__.__name__.lower() | ||
extra_args = kwargs | ||
try: | ||
try: | ||
if resource not in crud_notify_obj: | ||
notification_name = payload_name = _("is not defined") | ||
raise KeyError(_("Unsupported resource: %s") % resource) | ||
else: | ||
notification_method, payload_method = crud_notify_obj[resource] | ||
|
||
notification_name = notification_method.__name__ | ||
payload_name = payload_method.__name__ | ||
finally: | ||
# Prepare our exception message just in case | ||
exception_values = {"resource": resource, | ||
"uuid": obj.uuid, | ||
"action": action, | ||
"status": status, | ||
"level": level, | ||
"notification_method": notification_name, | ||
"payload_method": payload_name} | ||
exception_message = (_("Failed to send esi_leap.%(resource)s." | ||
"%(action)s.%(status)s notification for " | ||
"%(resource)s %(uuid)s with level " | ||
"%(level)s, notification method " | ||
"%(notification_method)s, payload method " | ||
"%(payload_method)s, error %(error)s")) | ||
payload = payload_method(obj, **extra_args) | ||
notification_method( | ||
publisher=notification.NotificationPublisher( | ||
service='esi-leap-manager', host=CONF.host), | ||
event_type=notification.EventType( | ||
object=resource, action=action, status=status), | ||
level=level, | ||
payload=payload).emit(context) | ||
LOG.info("Emit esi_leap notification: host is %s " | ||
"event is esi_leap.%s.%s.%s ," | ||
"level is %s ," | ||
"notification method is %s", | ||
CONF.host, resource, action, status, | ||
level, notification_method) | ||
except (exception.NotificationSchemaObjectError, | ||
exception.NotificationSchemaKeyError, | ||
exception.NotificationPayloadError, | ||
oslo_msg_exc.MessageDeliveryFailure, | ||
oslo_vo_exc.VersionedObjectsException) as e: | ||
exception_values['error'] = e | ||
LOG.warning(exception_message, exception_values) | ||
LOG.exception(e.msg_fmt) | ||
|
||
except Exception as e: | ||
exception_values['error'] = e | ||
LOG.exception(exception_message, exception_values) | ||
|
||
|
||
def emit_start_notification(context, obj, action, crud_notify_obj, **kwargs): | ||
"""Helper for emitting API 'start' notifications. | ||
:param context: request context. | ||
:param obj: resource rpc object. | ||
:param action: Action string to go in the EventType. | ||
:param kwargs: kwargs to use when creating the notification payload. | ||
""" | ||
_emit_api_notification(context, obj, action, | ||
fields.NotificationLevel.INFO, | ||
fields.NotificationStatus.START, | ||
crud_notify_obj, | ||
**kwargs) | ||
|
||
|
||
@contextlib.contextmanager | ||
def handle_error_notification(context, obj, action, crud_notify_obj, **kwargs): | ||
"""Context manager to handle any error notifications. | ||
:param context: request context. | ||
:param obj: resource rpc object. | ||
:param action: Action string to go in the EventType. | ||
:param kwargs: kwargs to use when creating the notification payload. | ||
""" | ||
try: | ||
yield | ||
except Exception: | ||
with excutils.save_and_reraise_exception(): | ||
_emit_api_notification(context, obj, action, | ||
fields.NotificationLevel.ERROR, | ||
fields.NotificationStatus.ERROR, | ||
crud_notify_obj, | ||
**kwargs) | ||
|
||
|
||
def emit_end_notification(context, obj, action, crud_notify_obj, **kwargs): | ||
"""Helper for emitting API 'end' notifications. | ||
:param context: request context. | ||
:param obj: resource rpc object. | ||
:param action: Action string to go in the EventType. | ||
:param kwargs: kwargs to use when creating the notification payload. | ||
""" | ||
_emit_api_notification(context, obj, action, | ||
fields.NotificationLevel.INFO, | ||
fields.NotificationStatus.END, | ||
crud_notify_obj, | ||
**kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# 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.fic language governing permissions and limitations | ||
# under the License. | ||
|
||
from esi_leap.common import exception | ||
from oslo_context import context as ctx | ||
import oslo_messaging as messaging | ||
from osprofiler import profiler | ||
|
||
NOTIFICATION_TRANSPORT = None | ||
VERSIONED_NOTIFIER = None | ||
|
||
ALLOWED_EXMODS = [ | ||
exception.__name__, | ||
] | ||
EXTRA_EXMODS = [] | ||
TOPICS = ['esi_leap_versioned_notifications'] | ||
|
||
|
||
def init(conf): | ||
global NOTIFICATION_TRANSPORT | ||
global VERSIONED_NOTIFIER | ||
exmods = get_allowed_exmods() | ||
NOTIFICATION_TRANSPORT = messaging.get_notification_transport( | ||
conf, | ||
allowed_remote_exmods=exmods) | ||
|
||
serializer = RequestContextSerializer(messaging.JsonPayloadSerializer()) | ||
|
||
if conf.notification.notification_level is None: | ||
|
||
VERSIONED_NOTIFIER = messaging.Notifier(NOTIFICATION_TRANSPORT, | ||
serializer=serializer, | ||
driver='noop') | ||
else: | ||
VERSIONED_NOTIFIER = messaging.Notifier( | ||
NOTIFICATION_TRANSPORT, | ||
serializer=serializer, | ||
topics=TOPICS) | ||
|
||
|
||
def cleanup(): | ||
global NOTIFICATION_TRANSPORT | ||
global VERSIONED_NOTIFIER | ||
assert NOTIFICATION_TRANSPORT is not None | ||
assert VERSIONED_NOTIFIER is not None | ||
NOTIFICATION_TRANSPORT.cleanup() | ||
NOTIFICATION_TRANSPORT = None | ||
VERSIONED_NOTIFIER = None | ||
|
||
|
||
def get_allowed_exmods(): | ||
return ALLOWED_EXMODS + EXTRA_EXMODS | ||
|
||
|
||
# RequestContextSerializer borrowed from Ironic | ||
class RequestContextSerializer(messaging.Serializer): | ||
|
||
def __init__(self, base): | ||
self._base = base | ||
|
||
def serialize_entity(self, context, entity): | ||
if not self._base: | ||
return entity | ||
return self._base.serialize_entity(context, entity) | ||
|
||
def deserialize_entity(self, context, entity): | ||
if not self._base: | ||
return entity | ||
return self._base.deserialize_entity(context, entity) | ||
|
||
def serialize_context(self, context): | ||
_context = context.to_dict() | ||
prof = profiler.get() | ||
if prof: | ||
trace_info = { | ||
"hmac_key": prof.hmac_key, | ||
"base_id": prof.get_base_id(), | ||
"parent_id": prof.get_id() | ||
} | ||
_context.update({"trace_info": trace_info}) | ||
return _context | ||
|
||
def deserialize_context(self, context): | ||
trace_info = context.pop("trace_info", None) | ||
if trace_info: | ||
profiler.init(**trace_info) | ||
return ctx.RequestContext.from_dict(context) | ||
|
||
|
||
def get_versioned_notifier(publisher_id=None): | ||
assert VERSIONED_NOTIFIER is not None | ||
assert publisher_id is not None | ||
return VERSIONED_NOTIFIER.prepare(publisher_id=publisher_id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# 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 esi_leap.common.i18n import _ | ||
from oslo_config import cfg | ||
|
||
# borrowed from Ironic | ||
opts = [ | ||
cfg.StrOpt('notification_level', | ||
choices=[('debug', _('"debug" level')), | ||
('info', _('"info" level')), | ||
('warning', _('"warning" level')), | ||
('error', _('"error" level')), | ||
('critical', _('"critical" level'))], | ||
help=_('Specifies the minimum level for which to send ' | ||
'notifications. If not set, no notifications will ' | ||
'be sent.')), | ||
] | ||
|
||
|
||
notification_group = cfg.OptGroup('notification', title='Notification Options') | ||
|
||
|
||
def register_opts(conf): | ||
conf.register_opts(opts, group=notification_group) | ||
conf.set_default('notification_level', 'info', group=notification_group) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.