summaryrefslogtreecommitdiff
path: root/nova/exception_wrapper.py
diff options
context:
space:
mode:
authorLaszlo Hegedus <laszlo.hegedus@ericsson.com>2016-05-23 09:20:04 +0200
committerBalazs Gibizer <balazs.gibizer@ericsson.com>2016-06-21 09:39:47 +0200
commit6329d721ef326488d5d660e4f68febf563ed93ab (patch)
treef58c81d0177f00b85c306a2c01b927b6a712797b /nova/exception_wrapper.py
parent5cb46edbf089b477a57bf48a13956e4be493d1db (diff)
downloadnova-6329d721ef326488d5d660e4f68febf563ed93ab.tar.gz
Transform wrap_exception notification to versioned format
A new versioned notification is emitted from the wrap_exception decorator. Change-Id: I8fcbce111537dae6ad3ba0961fb761540ae800ed Partially-Implements: bp versioned-notification-transformation-newton
Diffstat (limited to 'nova/exception_wrapper.py')
-rw-r--r--nova/exception_wrapper.py94
1 files changed, 94 insertions, 0 deletions
diff --git a/nova/exception_wrapper.py b/nova/exception_wrapper.py
new file mode 100644
index 0000000000..5b74c3b72f
--- /dev/null
+++ b/nova/exception_wrapper.py
@@ -0,0 +1,94 @@
+# 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 functools
+import inspect
+
+from oslo_utils import excutils
+import six
+
+import nova.conf
+from nova.notifications.objects import base
+from nova.notifications.objects import exception
+from nova.objects import fields
+from nova import safe_utils
+
+CONF = nova.conf.CONF
+
+
+def _emit_exception_notification(notifier, context, ex, function_name, args,
+ binary):
+ _emit_legacy_exception_notification(notifier, context, ex, function_name,
+ args)
+ _emit_versioned_exception_notification(context, ex, binary)
+
+
+def _emit_versioned_exception_notification(context, ex, binary):
+ versioned_exception_payload = exception.ExceptionPayload.from_exception(ex)
+ publisher = base.NotificationPublisher(context=context, host=CONF.host,
+ binary=binary)
+ event_type = base.EventType(
+ object='compute',
+ action=fields.NotificationAction.EXCEPTION)
+ notification = exception.ExceptionNotification(
+ publisher=publisher,
+ event_type=event_type,
+ priority=fields.NotificationPriority.ERROR,
+ payload=versioned_exception_payload)
+ notification.emit(context)
+
+
+def _emit_legacy_exception_notification(notifier, context, ex, function_name,
+ args):
+ payload = dict(exception=ex, args=args)
+ notifier.error(context, function_name, payload)
+
+
+def wrap_exception(notifier=None, get_notifier=None, binary=None):
+ """This decorator wraps a method to catch any exceptions that may
+ get thrown. It also optionally sends the exception to the notification
+ system.
+ """
+ def inner(f):
+ def wrapped(self, context, *args, **kw):
+ # Don't store self or context in the payload, it now seems to
+ # contain confidential information.
+ try:
+ return f(self, context, *args, **kw)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ if notifier or get_notifier:
+ call_dict = _get_call_dict(
+ f, self, context, *args, **kw)
+ function_name = f.__name__
+ _emit_exception_notification(
+ notifier or get_notifier(), context, e,
+ function_name, call_dict, binary)
+
+ return functools.wraps(f)(wrapped)
+ return inner
+
+
+def _get_call_dict(function, self, context, *args, **kw):
+ wrapped_func = safe_utils.get_wrapped_function(function)
+
+ call_dict = inspect.getcallargs(wrapped_func, self,
+ context, *args, **kw)
+ # self can't be serialized and shouldn't be in the
+ # payload
+ call_dict.pop('self', None)
+ return _cleanse_dict(call_dict)
+
+
+def _cleanse_dict(original):
+ """Strip all admin_password, new_pass, rescue_pass keys from a dict."""
+ return {k: v for k, v in six.iteritems(original) if "_pass" not in k}