From 087f2658915fdbe46b5124d681ae18000fb90015 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Fri, 31 Jul 2020 12:26:16 +0100 Subject: [PATCH] Fix exception notification with no trace The Exception notification code calls inspect.trace(), which returns an empty list if called outside of an except clause. The returned list is then indexed, causing an IndexError. In fact, every use of this exception in the engine is from outside of an except clause. This can affect notification processing, causing notifications to get stuck in a running state, requiring manual DB deletion. This change addresses the issue by checking whether the list returned by inspect.trace() is empty. A more complete solution would involve checking every call path to the exception notification, and ensuring that it is made from an except clause. Change-Id: I01af664d53db20041ac7306d2bca63254ffc9ede Partial-Bug: #1889765 (cherry picked from commit 69a9a41802edf21c8e4784835654697e13db9ca2) --- masakari/notifications/objects/exception.py | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/masakari/notifications/objects/exception.py b/masakari/notifications/objects/exception.py index 1f3448b1..86d754a5 100644 --- a/masakari/notifications/objects/exception.py +++ b/masakari/notifications/objects/exception.py @@ -36,14 +36,24 @@ class ExceptionPayload(base.NotificationPayloadBase): @classmethod def from_exc_and_traceback(cls, fault, traceback): - trace = inspect.trace()[-1] - # TODO(gibi): apply strutils.mask_password on exception_message and - # consider emitting the exception_message only if the safe flag is - # true in the exception like in the REST API - module = inspect.getmodule(trace[0]) + trace = inspect.trace() + # FIXME(mgoddard): In some code paths we reach this point without being + # inside an exception handler. This results in inspect.trace() + # returning an empty list. Ideally we should only end up here from an + # exception handler. + if trace: + trace = trace[-1] + # TODO(gibi): apply strutils.mask_password on exception_message and + # consider emitting the exception_message only if the safe flag is + # true in the exception like in the REST API + module = inspect.getmodule(trace[0]) + function_name = trace[3] + else: + module = None + function_name = 'unknown' module_name = module.__name__ if module else 'unknown' return cls( - function_name=trace[3], + function_name=function_name, module_name=module_name, exception=fault.__class__.__name__, exception_message=six.text_type(fault),