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 69a9a41802)
This commit is contained in:
Mark Goddard 2020-07-31 12:26:16 +01:00
parent df08881742
commit fc3cdd7520
1 changed files with 16 additions and 6 deletions

View File

@ -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),