Merge "Use 'Exception.__traceback__' for versioned notifications"
This commit is contained in:
+15
-29
@@ -2339,20 +2339,18 @@ class ComputeManager(manager.Manager):
|
||||
with excutils.save_and_reraise_exception():
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
except exception.ComputeResourcesUnavailable as e:
|
||||
LOG.debug(e.format_message(), instance=instance)
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
raise exception.RescheduledException(
|
||||
instance_uuid=instance.uuid, reason=e.format_message())
|
||||
except exception.BuildAbortException as e:
|
||||
@@ -2360,21 +2358,19 @@ class ComputeManager(manager.Manager):
|
||||
LOG.debug(e.format_message(), instance=instance)
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
except exception.NoMoreFixedIps as e:
|
||||
LOG.warning('No more fixed IP to be allocated',
|
||||
instance=instance)
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
msg = _('Failed to allocate the network(s) with error %s, '
|
||||
'not rescheduling.') % e.format_message()
|
||||
raise exception.BuildAbortException(instance_uuid=instance.uuid,
|
||||
@@ -2389,11 +2385,10 @@ class ComputeManager(manager.Manager):
|
||||
instance=instance)
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
msg = _('Failed to allocate the network(s), not rescheduling.')
|
||||
raise exception.BuildAbortException(instance_uuid=instance.uuid,
|
||||
reason=msg)
|
||||
@@ -2412,11 +2407,10 @@ class ComputeManager(manager.Manager):
|
||||
exception.RequestedVRamTooHigh) as e:
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
raise exception.BuildAbortException(instance_uuid=instance.uuid,
|
||||
reason=e.format_message())
|
||||
except Exception as e:
|
||||
@@ -2424,11 +2418,10 @@ class ComputeManager(manager.Manager):
|
||||
instance=instance)
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
raise exception.RescheduledException(
|
||||
instance_uuid=instance.uuid, reason=six.text_type(e))
|
||||
|
||||
@@ -2460,11 +2453,10 @@ class ComputeManager(manager.Manager):
|
||||
with excutils.save_and_reraise_exception():
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'create.error', fault=e)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_create(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=e,
|
||||
bdms=block_device_mapping, tb=tb)
|
||||
bdms=block_device_mapping)
|
||||
|
||||
self._update_scheduler_instance_info(context, instance)
|
||||
self._notify_about_instance_usage(context, instance, 'create.end',
|
||||
@@ -3235,13 +3227,11 @@ class ComputeManager(manager.Manager):
|
||||
block_device_info=new_block_device_info)
|
||||
|
||||
def _notify_instance_rebuild_error(self, context, instance, error, bdms):
|
||||
tb = traceback.format_exc()
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'rebuild.error', fault=error)
|
||||
compute_utils.notify_about_instance_rebuild(
|
||||
context, instance, self.host,
|
||||
phase=fields.NotificationPhase.ERROR, exception=error, bdms=bdms,
|
||||
tb=tb)
|
||||
phase=fields.NotificationPhase.ERROR, exception=error, bdms=bdms)
|
||||
|
||||
@messaging.expected_exceptions(exception.PreserveEphemeralNotSupported)
|
||||
@wrap_exception()
|
||||
@@ -3748,12 +3738,11 @@ class ComputeManager(manager.Manager):
|
||||
instance, error, exc_info)
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
'reboot.error', fault=error)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_action(
|
||||
context, instance, self.host,
|
||||
action=fields.NotificationAction.REBOOT,
|
||||
phase=fields.NotificationPhase.ERROR,
|
||||
exception=error, bdms=bdms, tb=tb
|
||||
exception=error, bdms=bdms
|
||||
)
|
||||
ctxt.reraise = False
|
||||
else:
|
||||
@@ -5263,7 +5252,7 @@ class ComputeManager(manager.Manager):
|
||||
action=fields.NotificationAction.RESIZE,
|
||||
phase=fields.NotificationPhase.ERROR,
|
||||
exception=error,
|
||||
tb=','.join(traceback.format_exception(*exc_info)))
|
||||
)
|
||||
|
||||
if rescheduled:
|
||||
self._log_original_error(exc_info, instance_uuid)
|
||||
@@ -5276,7 +5265,7 @@ class ComputeManager(manager.Manager):
|
||||
action=fields.NotificationAction.RESIZE,
|
||||
phase=fields.NotificationPhase.ERROR,
|
||||
exception=exc_info[1],
|
||||
tb=','.join(traceback.format_exception(*exc_info)))
|
||||
)
|
||||
else:
|
||||
# not re-scheduling
|
||||
six.reraise(*exc_info)
|
||||
@@ -6977,13 +6966,12 @@ class ComputeManager(manager.Manager):
|
||||
exc, instance=instance)
|
||||
else:
|
||||
self.volume_api.unreserve_volume(context, bdm.volume_id)
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_volume_attach_detach(
|
||||
context, instance, self.host,
|
||||
action=fields.NotificationAction.VOLUME_ATTACH,
|
||||
phase=fields.NotificationPhase.ERROR,
|
||||
exception=e,
|
||||
volume_id=bdm.volume_id, tb=tb)
|
||||
volume_id=bdm.volume_id)
|
||||
|
||||
info = {'volume_id': bdm.volume_id}
|
||||
self._notify_about_instance_usage(
|
||||
@@ -7184,11 +7172,10 @@ class ComputeManager(manager.Manager):
|
||||
except Exception as ex:
|
||||
failed = True
|
||||
with excutils.save_and_reraise_exception():
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_volume_swap(
|
||||
context, instance, self.host,
|
||||
fields.NotificationPhase.ERROR,
|
||||
old_volume_id, new_volume_id, ex, tb)
|
||||
old_volume_id, new_volume_id, ex)
|
||||
if new_cinfo:
|
||||
msg = ("Failed to swap volume %(old_volume_id)s "
|
||||
"for %(new_volume_id)s")
|
||||
@@ -7497,12 +7484,11 @@ class ComputeManager(manager.Manager):
|
||||
instance=instance)
|
||||
self._deallocate_port_for_instance(context, instance, port_id)
|
||||
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_instance_action(
|
||||
context, instance, self.host,
|
||||
action=fields.NotificationAction.INTERFACE_ATTACH,
|
||||
phase=fields.NotificationPhase.ERROR,
|
||||
exception=ex, tb=tb)
|
||||
exception=ex)
|
||||
|
||||
raise exception.InterfaceAttachFailed(
|
||||
instance_uuid=instance.uuid)
|
||||
|
||||
+23
-30
@@ -452,14 +452,15 @@ def notify_about_instance_usage(notifier, context, instance, event_suffix,
|
||||
method(context, 'compute.instance.%s' % event_suffix, usage_info)
|
||||
|
||||
|
||||
def _get_fault_and_priority_from_exc_and_tb(exception, tb):
|
||||
def _get_fault_and_priority_from_exception(exception: Exception):
|
||||
fault = None
|
||||
priority = fields.NotificationPriority.INFO
|
||||
|
||||
if exception:
|
||||
priority = fields.NotificationPriority.ERROR
|
||||
fault = notification_exception.ExceptionPayload.from_exc_and_traceback(
|
||||
exception, tb)
|
||||
if not exception:
|
||||
return fault, priority
|
||||
|
||||
fault = notification_exception.ExceptionPayload.from_exception(exception)
|
||||
priority = fields.NotificationPriority.ERROR
|
||||
|
||||
return fault, priority
|
||||
|
||||
@@ -467,7 +468,7 @@ def _get_fault_and_priority_from_exc_and_tb(exception, tb):
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_instance_action(context, instance, host, action, phase=None,
|
||||
source=fields.NotificationSource.COMPUTE,
|
||||
exception=None, bdms=None, tb=None):
|
||||
exception=None, bdms=None):
|
||||
"""Send versioned notification about the action made on the instance
|
||||
:param instance: the instance which the action performed on
|
||||
:param host: the host emitting the notification
|
||||
@@ -476,10 +477,9 @@ def notify_about_instance_action(context, instance, host, action, phase=None,
|
||||
:param source: the source of the notification
|
||||
:param exception: the thrown exception (used in error notifications)
|
||||
:param bdms: BlockDeviceMappingList object for the instance. If it is not
|
||||
provided then we will load it from the db if so configured
|
||||
:param tb: the traceback (used in error notifications)
|
||||
provided then we will load it from the db if so configured
|
||||
"""
|
||||
fault, priority = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, priority = _get_fault_and_priority_from_exception(exception)
|
||||
payload = instance_notification.InstanceActionPayload(
|
||||
context=context,
|
||||
instance=instance,
|
||||
@@ -500,7 +500,7 @@ def notify_about_instance_action(context, instance, host, action, phase=None,
|
||||
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_instance_create(context, instance, host, phase=None,
|
||||
exception=None, bdms=None, tb=None):
|
||||
exception=None, bdms=None):
|
||||
"""Send versioned notification about instance creation
|
||||
|
||||
:param context: the request context
|
||||
@@ -510,9 +510,8 @@ def notify_about_instance_create(context, instance, host, phase=None,
|
||||
:param exception: the thrown exception (used in error notifications)
|
||||
:param bdms: BlockDeviceMappingList object for the instance. If it is not
|
||||
provided then we will load it from the db if so configured
|
||||
:param tb: the traceback (used in error notifications)
|
||||
"""
|
||||
fault, priority = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, priority = _get_fault_and_priority_from_exception(exception)
|
||||
payload = instance_notification.InstanceCreatePayload(
|
||||
context=context,
|
||||
instance=instance,
|
||||
@@ -558,7 +557,7 @@ def notify_about_scheduler_action(context, request_spec, action, phase=None,
|
||||
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_volume_attach_detach(context, instance, host, action, phase,
|
||||
volume_id=None, exception=None, tb=None):
|
||||
volume_id=None, exception=None):
|
||||
"""Send versioned notification about the action made on the instance
|
||||
:param instance: the instance which the action performed on
|
||||
:param host: the host emitting the notification
|
||||
@@ -566,9 +565,8 @@ def notify_about_volume_attach_detach(context, instance, host, action, phase,
|
||||
:param phase: the phase of the action
|
||||
:param volume_id: id of the volume will be attached
|
||||
:param exception: the thrown exception (used in error notifications)
|
||||
:param tb: the traceback (used in error notifications)
|
||||
"""
|
||||
fault, priority = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, priority = _get_fault_and_priority_from_exception(exception)
|
||||
payload = instance_notification.InstanceActionVolumePayload(
|
||||
context=context,
|
||||
instance=instance,
|
||||
@@ -590,7 +588,7 @@ def notify_about_volume_attach_detach(context, instance, host, action, phase,
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_instance_rescue_action(context, instance, host,
|
||||
rescue_image_ref, phase=None,
|
||||
exception=None, tb=None):
|
||||
exception=None):
|
||||
"""Send versioned notification about the action made on the instance
|
||||
|
||||
:param instance: the instance which the action performed on
|
||||
@@ -598,9 +596,8 @@ def notify_about_instance_rescue_action(context, instance, host,
|
||||
:param rescue_image_ref: the rescue image ref
|
||||
:param phase: the phase of the action
|
||||
:param exception: the thrown exception (used in error notifications)
|
||||
:param tb: the traceback (used in error notifications)
|
||||
"""
|
||||
fault, priority = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, priority = _get_fault_and_priority_from_exception(exception)
|
||||
payload = instance_notification.InstanceActionRescuePayload(
|
||||
context=context,
|
||||
instance=instance,
|
||||
@@ -644,8 +641,7 @@ def notify_about_keypair_action(context, keypair, action, phase):
|
||||
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_volume_swap(context, instance, host, phase,
|
||||
old_volume_id, new_volume_id, exception=None,
|
||||
tb=None):
|
||||
old_volume_id, new_volume_id, exception=None):
|
||||
"""Send versioned notification about the volume swap action
|
||||
on the instance
|
||||
|
||||
@@ -656,9 +652,8 @@ def notify_about_volume_swap(context, instance, host, phase,
|
||||
:param old_volume_id: the ID of the volume that is copied from and detached
|
||||
:param new_volume_id: the ID of the volume that is copied to and attached
|
||||
:param exception: an exception
|
||||
:param tb: the traceback (used in error notifications)
|
||||
"""
|
||||
fault, priority = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, priority = _get_fault_and_priority_from_exception(exception)
|
||||
payload = instance_notification.InstanceActionVolumeSwapPayload(
|
||||
context=context,
|
||||
instance=instance,
|
||||
@@ -877,7 +872,7 @@ def notify_about_instance_rebuild(context, instance, host,
|
||||
action=fields.NotificationAction.REBUILD,
|
||||
phase=None,
|
||||
source=fields.NotificationSource.COMPUTE,
|
||||
exception=None, bdms=None, tb=None):
|
||||
exception=None, bdms=None):
|
||||
"""Send versioned notification about instance rebuild
|
||||
|
||||
:param instance: the instance which the action performed on
|
||||
@@ -888,9 +883,8 @@ def notify_about_instance_rebuild(context, instance, host,
|
||||
:param exception: the thrown exception (used in error notifications)
|
||||
:param bdms: BlockDeviceMappingList object for the instance. If it is not
|
||||
provided then we will load it from the db if so configured
|
||||
:param tb: the traceback (used in error notifications)
|
||||
"""
|
||||
fault, priority = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, priority = _get_fault_and_priority_from_exception(exception)
|
||||
payload = instance_notification.InstanceActionRebuildPayload(
|
||||
context=context,
|
||||
instance=instance,
|
||||
@@ -938,15 +932,14 @@ def notify_about_metrics_update(context, host, host_ip, nodename,
|
||||
|
||||
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_libvirt_connect_error(context, ip, exception, tb):
|
||||
def notify_about_libvirt_connect_error(context, ip, exception):
|
||||
"""Send a versioned notification about libvirt connect error.
|
||||
|
||||
:param context: the request context
|
||||
:param ip: the IP address of the host
|
||||
:param exception: the thrown exception
|
||||
:param tb: the traceback
|
||||
"""
|
||||
fault, _ = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, _ = _get_fault_and_priority_from_exception(exception)
|
||||
payload = libvirt_notification.LibvirtErrorPayload(ip=ip, reason=fault)
|
||||
notification = libvirt_notification.LibvirtErrorNotification(
|
||||
priority=fields.NotificationPriority.ERROR,
|
||||
@@ -984,7 +977,7 @@ def notify_about_volume_usage(context, vol_usage, host):
|
||||
|
||||
@rpc.if_notifications_enabled
|
||||
def notify_about_compute_task_error(context, action, instance_uuid,
|
||||
request_spec, state, exception, tb):
|
||||
request_spec, state, exception):
|
||||
"""Send a versioned notification about compute task error.
|
||||
|
||||
:param context: the request context
|
||||
@@ -1001,7 +994,7 @@ def notify_about_compute_task_error(context, action, instance_uuid,
|
||||
request_spec = objects.RequestSpec.from_primitives(
|
||||
context, request_spec, {})
|
||||
|
||||
fault, _ = _get_fault_and_priority_from_exc_and_tb(exception, tb)
|
||||
fault, _ = _get_fault_and_priority_from_exception(exception)
|
||||
payload = task_notification.ComputeTaskPayload(
|
||||
instance_uuid=instance_uuid, request_spec=request_spec, state=state,
|
||||
reason=fault)
|
||||
|
||||
+18
-19
@@ -12,14 +12,12 @@
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import traceback
|
||||
|
||||
from oslo_utils import excutils
|
||||
|
||||
|
||||
import nova.conf
|
||||
from nova.notifications.objects import base
|
||||
from nova.notifications.objects import exception
|
||||
from nova.notifications.objects import exception as exception_obj
|
||||
from nova.objects import fields
|
||||
from nova import rpc
|
||||
from nova import safe_utils
|
||||
@@ -27,26 +25,28 @@ from nova import safe_utils
|
||||
CONF = nova.conf.CONF
|
||||
|
||||
|
||||
def _emit_exception_notification(notifier, context, ex, function_name, args,
|
||||
source, trace_back):
|
||||
_emit_legacy_exception_notification(notifier, context, ex, function_name,
|
||||
args)
|
||||
_emit_versioned_exception_notification(context, ex, source, trace_back)
|
||||
def _emit_exception_notification(
|
||||
notifier, context, exception, function_name, args, source,
|
||||
):
|
||||
_emit_legacy_exception_notification(
|
||||
notifier, context, exception, function_name, args)
|
||||
_emit_versioned_exception_notification(context, exception, source)
|
||||
|
||||
|
||||
@rpc.if_notifications_enabled
|
||||
def _emit_versioned_exception_notification(context, ex, source, trace_back):
|
||||
versioned_exception_payload = \
|
||||
exception.ExceptionPayload.from_exc_and_traceback(ex, trace_back)
|
||||
def _emit_versioned_exception_notification(context, exception, source):
|
||||
payload = exception_obj.ExceptionPayload.from_exception(exception)
|
||||
publisher = base.NotificationPublisher(host=CONF.host, source=source)
|
||||
event_type = base.EventType(
|
||||
object='compute',
|
||||
action=fields.NotificationAction.EXCEPTION)
|
||||
notification = exception.ExceptionNotification(
|
||||
object='compute',
|
||||
action=fields.NotificationAction.EXCEPTION,
|
||||
)
|
||||
notification = exception_obj.ExceptionNotification(
|
||||
publisher=publisher,
|
||||
event_type=event_type,
|
||||
priority=fields.NotificationPriority.ERROR,
|
||||
payload=versioned_exception_payload)
|
||||
payload=payload,
|
||||
)
|
||||
notification.emit(context)
|
||||
|
||||
|
||||
@@ -67,16 +67,15 @@ def wrap_exception(notifier=None, get_notifier=None, binary=None):
|
||||
# contain confidential information.
|
||||
try:
|
||||
return f(self, context, *args, **kw)
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
except Exception as exc:
|
||||
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, tb)
|
||||
notifier or get_notifier(), context, exc,
|
||||
function_name, call_dict, binary)
|
||||
|
||||
return functools.wraps(f)(wrapped)
|
||||
return inner
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
# 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 inspect
|
||||
|
||||
import six
|
||||
import inspect
|
||||
import traceback as tb
|
||||
|
||||
from nova.notifications.objects import base
|
||||
from nova.objects import base as nova_base
|
||||
@@ -41,19 +41,38 @@ class ExceptionPayload(base.NotificationPayloadBase):
|
||||
self.traceback = traceback
|
||||
|
||||
@classmethod
|
||||
def from_exc_and_traceback(cls, fault, traceback):
|
||||
trace = inspect.trace()[-1]
|
||||
def from_exception(cls, fault: Exception):
|
||||
traceback = fault.__traceback__
|
||||
|
||||
# NOTE(stephenfin): inspect.trace() will only return something if we're
|
||||
# inside the scope of an exception handler. If we are not, we fallback
|
||||
# to extracting information from the traceback. This is lossy, since
|
||||
# the stack stops at the exception handler, not the exception raise.
|
||||
# Check the inspect docs for more information.
|
||||
#
|
||||
# https://docs.python.org/3/library/inspect.html#types-and-members
|
||||
trace = inspect.trace()
|
||||
if trace:
|
||||
module = inspect.getmodule(trace[-1][0])
|
||||
function_name = trace[-1][3]
|
||||
else:
|
||||
module = inspect.getmodule(traceback)
|
||||
function_name = traceback.tb_frame.f_code.co_name
|
||||
|
||||
module_name = module.__name__ if module else 'unknown'
|
||||
|
||||
# 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])
|
||||
module_name = module.__name__ if module else 'unknown'
|
||||
return cls(
|
||||
function_name=trace[3],
|
||||
module_name=module_name,
|
||||
exception=fault.__class__.__name__,
|
||||
exception_message=six.text_type(fault),
|
||||
traceback=traceback)
|
||||
function_name=function_name,
|
||||
module_name=module_name,
|
||||
exception=fault.__class__.__name__,
|
||||
exception_message=str(fault),
|
||||
# NOTE(stephenfin): the first argument to format_exception is
|
||||
# ignored since Python 3.5
|
||||
traceback=','.join(tb.format_exception(None, fault, traceback)),
|
||||
)
|
||||
|
||||
|
||||
@base.notification_sample('compute-exception.json')
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import collections
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import os_resource_classes as orc
|
||||
import os_traits
|
||||
@@ -840,8 +839,7 @@ def set_vm_state_and_notify(context, instance_uuid, service, method, updates,
|
||||
event_type = '%s.%s' % (service, method)
|
||||
notifier.error(context, event_type, payload)
|
||||
compute_utils.notify_about_compute_task_error(
|
||||
context, method, instance_uuid, request_spec, vm_state, ex,
|
||||
traceback.format_exc())
|
||||
context, method, instance_uuid, request_spec, vm_state, ex)
|
||||
|
||||
|
||||
def build_filter_properties(scheduler_hints, forced_host,
|
||||
|
||||
@@ -424,8 +424,7 @@ class ComputeVolumeTestCase(BaseTestCase):
|
||||
mock.call(self.context, instance, 'fake-mini',
|
||||
action='volume_attach', phase='error',
|
||||
volume_id=uuids.volume_id,
|
||||
exception=expected_exception,
|
||||
tb=mock.ANY),
|
||||
exception=expected_exception),
|
||||
])
|
||||
mock_event.assert_called_once_with(
|
||||
self.context, 'compute_attach_volume', CONF.host,
|
||||
@@ -465,8 +464,7 @@ class ComputeVolumeTestCase(BaseTestCase):
|
||||
mock.call(self.context, instance, 'fake-mini',
|
||||
action='volume_attach', phase='error',
|
||||
volume_id=uuids.volume_id,
|
||||
exception=expected_exception,
|
||||
tb=mock.ANY),
|
||||
exception=expected_exception),
|
||||
])
|
||||
|
||||
@mock.patch.object(compute_manager.LOG, 'debug')
|
||||
@@ -514,8 +512,7 @@ class ComputeVolumeTestCase(BaseTestCase):
|
||||
mock.call(self.context, instance, 'fake-mini',
|
||||
action='volume_attach', phase='error',
|
||||
volume_id=uuids.volume_id,
|
||||
exception=expected_exception,
|
||||
tb=mock.ANY),
|
||||
exception=expected_exception),
|
||||
])
|
||||
mock_event.assert_called_once_with(
|
||||
self.context, 'compute_attach_volume', CONF.host,
|
||||
@@ -3111,7 +3108,7 @@ class ComputeTestCase(BaseTestCase,
|
||||
notify_action_call_list.append(
|
||||
mock.call(econtext, instance, 'fake-mini',
|
||||
action='reboot', phase='error', exception=fault,
|
||||
bdms=bdms, tb=mock.ANY))
|
||||
bdms=bdms))
|
||||
notify_call_list.append(mock.call(econtext, instance,
|
||||
'reboot.end'))
|
||||
notify_action_call_list.append(
|
||||
@@ -10408,7 +10405,7 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
mock.call(self.context, instance, self.compute.host,
|
||||
action='interface_attach',
|
||||
exception=mock_attach.side_effect,
|
||||
phase='error', tb=mock.ANY)])
|
||||
phase='error')])
|
||||
|
||||
@mock.patch.object(compute_utils, 'notify_about_instance_action')
|
||||
def test_detach_interface(self, mock_notify):
|
||||
@@ -12541,11 +12538,12 @@ class ComputeRescheduleResizeOrReraiseTestCase(BaseTestCase):
|
||||
raise test.TestingException("Original")
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
# because we're not retrying, we should re-raise the exception
|
||||
self.assertRaises(test.TestingException,
|
||||
self.compute._reschedule_resize_or_reraise, self.context,
|
||||
self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
|
||||
# because we're not retrying, we should re-raise the exception
|
||||
self.assertRaises(test.TestingException,
|
||||
self.compute._reschedule_resize_or_reraise, self.context,
|
||||
self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
|
||||
def test_reschedule_resize_or_reraise_no_retry_info(self):
|
||||
"""Test behavior when ``filter_properties`` doesn't contain 'retry'.
|
||||
@@ -12559,11 +12557,12 @@ class ComputeRescheduleResizeOrReraiseTestCase(BaseTestCase):
|
||||
raise test.TestingException("Original")
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
# because we're not retrying, we should re-raise the exception
|
||||
self.assertRaises(test.TestingException,
|
||||
self.compute._reschedule_resize_or_reraise, self.context,
|
||||
self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
|
||||
# because we're not retrying, we should re-raise the exception
|
||||
self.assertRaises(test.TestingException,
|
||||
self.compute._reschedule_resize_or_reraise, self.context,
|
||||
self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
|
||||
@mock.patch.object(compute_manager.ComputeManager, '_instance_update')
|
||||
@mock.patch('nova.conductor.api.ComputeTaskAPI.resize_instance',
|
||||
@@ -12581,23 +12580,24 @@ class ComputeRescheduleResizeOrReraiseTestCase(BaseTestCase):
|
||||
raise test.TestingException('Original')
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
self.assertRaises(test.TestingException,
|
||||
self.compute._reschedule_resize_or_reraise, self.context,
|
||||
self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
|
||||
mock_update.assert_called_once_with(
|
||||
self.context, mock.ANY, task_state=task_states.RESIZE_PREP)
|
||||
mock_resize.assert_called_once_with(
|
||||
self.context, mock.ANY,
|
||||
{'filter_properties': filter_properties}, self.instance_type,
|
||||
request_spec=self.request_spec, host_list=None)
|
||||
mock_notify.assert_called_once_with(
|
||||
self.context, self.instance, 'fake-mini', action='resize',
|
||||
phase='error', exception=mock_resize.side_effect, tb=mock.ANY)
|
||||
# If not rescheduled, the original resize exception should not be
|
||||
# logged.
|
||||
mock_log.assert_not_called()
|
||||
self.assertRaises(test.TestingException,
|
||||
self.compute._reschedule_resize_or_reraise, self.context,
|
||||
self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
|
||||
mock_update.assert_called_once_with(
|
||||
self.context, mock.ANY, task_state=task_states.RESIZE_PREP)
|
||||
mock_resize.assert_called_once_with(
|
||||
self.context, mock.ANY,
|
||||
{'filter_properties': filter_properties}, self.instance_type,
|
||||
request_spec=self.request_spec, host_list=None)
|
||||
mock_notify.assert_called_once_with(
|
||||
self.context, self.instance, 'fake-mini', action='resize',
|
||||
phase='error', exception=mock_resize.side_effect)
|
||||
# If not rescheduled, the original resize exception should not be
|
||||
# logged.
|
||||
mock_log.assert_not_called()
|
||||
|
||||
@mock.patch.object(compute_manager.ComputeManager, '_instance_update')
|
||||
@mock.patch('nova.conductor.api.ComputeTaskAPI.resize_instance')
|
||||
@@ -12612,21 +12612,21 @@ class ComputeRescheduleResizeOrReraiseTestCase(BaseTestCase):
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
|
||||
self.compute._reschedule_resize_or_reraise(
|
||||
self.context, self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
self.compute._reschedule_resize_or_reraise(
|
||||
self.context, self.instance, exc_info, self.instance_type,
|
||||
self.request_spec, filter_properties, None)
|
||||
|
||||
mock_update.assert_called_once_with(
|
||||
self.context, mock.ANY, task_state=task_states.RESIZE_PREP)
|
||||
mock_resize.assert_called_once_with(
|
||||
self.context, mock.ANY,
|
||||
{'filter_properties': filter_properties}, self.instance_type,
|
||||
request_spec=self.request_spec, host_list=None)
|
||||
mock_notify.assert_called_once_with(
|
||||
self.context, self.instance, 'fake-mini', action='resize',
|
||||
phase='error', exception=exc_info[1], tb=mock.ANY)
|
||||
# If rescheduled, the original resize exception should be logged.
|
||||
mock_log.assert_called_once_with(exc_info, self.instance.uuid)
|
||||
mock_update.assert_called_once_with(
|
||||
self.context, mock.ANY, task_state=task_states.RESIZE_PREP)
|
||||
mock_resize.assert_called_once_with(
|
||||
self.context, mock.ANY,
|
||||
{'filter_properties': filter_properties}, self.instance_type,
|
||||
request_spec=self.request_spec, host_list=None)
|
||||
mock_notify.assert_called_once_with(
|
||||
self.context, self.instance, 'fake-mini', action='resize',
|
||||
phase='error', exception=exc_info[1])
|
||||
# If rescheduled, the original resize exception should be logged.
|
||||
mock_log.assert_called_once_with(exc_info, self.instance.uuid)
|
||||
|
||||
|
||||
class ComputeInactiveImageTestCase(BaseTestCase):
|
||||
|
||||
@@ -2595,7 +2595,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
|
||||
self.compute.host,
|
||||
fields.NotificationPhase.ERROR,
|
||||
uuids.old_volume, uuids.new_volume,
|
||||
test.MatchType(expected_exception), mock.ANY)
|
||||
test.MatchType(expected_exception))
|
||||
else:
|
||||
self.compute.swap_volume(self.context, uuids.old_volume,
|
||||
uuids.new_volume, instance1, None)
|
||||
@@ -5017,7 +5017,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
|
||||
)
|
||||
mock_notify.assert_called_once_with(
|
||||
mock.ANY, instance, 'fake-mini', phase='error', exception=exc,
|
||||
bdms=None, tb=mock.ANY)
|
||||
bdms=None)
|
||||
|
||||
def test_rebuild_deleting(self):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
@@ -5168,7 +5168,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase,
|
||||
elevated_context, instance, 'fake-node', node_type='destination')
|
||||
mock_notify.assert_called_once_with(
|
||||
elevated_context, instance, 'fake-mini', bdms=None, exception=exc,
|
||||
phase='error', tb=mock.ANY)
|
||||
phase='error')
|
||||
# Make sure the instance vm_state did not change.
|
||||
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
|
||||
|
||||
@@ -7152,7 +7152,7 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
|
||||
mock.call(self.context, self.instance, 'fake-mini',
|
||||
phase='start', bdms=[]),
|
||||
mock.call(self.context, self.instance, 'fake-mini',
|
||||
phase='error', exception=exc, bdms=[], tb=mock.ANY)])
|
||||
phase='error', exception=exc, bdms=[])])
|
||||
|
||||
save.assert_has_calls([
|
||||
mock.call(),
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
import copy
|
||||
import datetime
|
||||
import string
|
||||
import traceback
|
||||
|
||||
import mock
|
||||
from oslo_serialization import jsonutils
|
||||
@@ -733,11 +732,10 @@ class UsageInfoTestCase(test.TestCase):
|
||||
# To get exception trace, raise and catch an exception
|
||||
raise test.TestingException('Volume swap error.')
|
||||
except Exception as ex:
|
||||
tb = traceback.format_exc()
|
||||
compute_utils.notify_about_volume_swap(
|
||||
self.context, instance, 'fake-compute',
|
||||
fields.NotificationPhase.ERROR,
|
||||
uuids.old_volume_id, uuids.new_volume_id, ex, tb)
|
||||
uuids.old_volume_id, uuids.new_volume_id, ex)
|
||||
|
||||
self.assertEqual(len(fake_notifier.VERSIONED_NOTIFICATIONS), 1)
|
||||
notification = fake_notifier.VERSIONED_NOTIFICATIONS[0]
|
||||
|
||||
@@ -826,7 +826,7 @@ class _BaseTaskTestCase(object):
|
||||
mock_notify.assert_called_once_with(
|
||||
self.context, 'build_instances',
|
||||
instance.uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(exc.MaxRetriesExceeded), test.MatchType(str))
|
||||
test.MatchType(exc.MaxRetriesExceeded))
|
||||
|
||||
@mock.patch.object(conductor_manager.ComputeTaskManager,
|
||||
'_destroy_build_request')
|
||||
@@ -2228,13 +2228,11 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
||||
mock_notify.assert_called_once_with(
|
||||
test.MatchType(context.RequestContext), 'build_instances',
|
||||
instance.uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(Exception), test.MatchType(str))
|
||||
test.MatchType(Exception))
|
||||
request_spec_dict = mock_notify.call_args_list[0][0][3]
|
||||
for key in ('instance_type', 'num_instances', 'instance_properties',
|
||||
'image'):
|
||||
self.assertIn(key, request_spec_dict)
|
||||
tb = mock_notify.call_args_list[0][0][6]
|
||||
self.assertIn('Traceback (most recent call last):', tb)
|
||||
|
||||
@mock.patch('nova.objects.TagList.destroy')
|
||||
@mock.patch('nova.objects.TagList.create')
|
||||
@@ -2465,13 +2463,11 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
||||
mock_notify.assert_called_once_with(
|
||||
test.MatchType(context.RequestContext), 'build_instances',
|
||||
instance.uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(exc.TooManyInstances), test.MatchType(str))
|
||||
test.MatchType(exc.TooManyInstances))
|
||||
request_spec_dict = mock_notify.call_args_list[0][0][3]
|
||||
for key in ('instance_type', 'num_instances', 'instance_properties',
|
||||
'image'):
|
||||
self.assertIn(key, request_spec_dict)
|
||||
tb = mock_notify.call_args_list[0][0][6]
|
||||
self.assertIn('Traceback (most recent call last):', tb)
|
||||
|
||||
@mock.patch('nova.compute.rpcapi.ComputeAPI.build_and_run_instance')
|
||||
@mock.patch('nova.objects.quotas.Quotas.check_deltas')
|
||||
@@ -2712,19 +2708,19 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
||||
mock.call(
|
||||
test.MatchType(context.RequestContext), 'build_instances',
|
||||
bare_br.instance_uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(Exception), test.MatchType(str)),
|
||||
test.MatchType(Exception)),
|
||||
mock.call(
|
||||
test.MatchType(context.RequestContext), 'build_instances',
|
||||
inst_br.instance_uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(Exception), test.MatchType(str)),
|
||||
test.MatchType(Exception)),
|
||||
mock.call(
|
||||
test.MatchType(context.RequestContext), 'build_instances',
|
||||
deleted_br.instance_uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(Exception), test.MatchType(str)),
|
||||
test.MatchType(Exception)),
|
||||
mock.call(
|
||||
test.MatchType(context.RequestContext), 'build_instances',
|
||||
fast_deleted_br.instance_uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(Exception), test.MatchType(str))],
|
||||
test.MatchType(Exception))],
|
||||
any_order=True)
|
||||
|
||||
for i in range(0, 3):
|
||||
@@ -2760,7 +2756,7 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
||||
mock_notify.assert_called_once_with(
|
||||
test.MatchType(context.RequestContext), 'build_instances',
|
||||
inst.uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(Exception), test.MatchType(str))
|
||||
test.MatchType(Exception))
|
||||
# traceback.format_exc() returns 'NoneType'
|
||||
# because an exception is not raised in this test.
|
||||
# So the argument for traceback is not checked.
|
||||
@@ -3480,13 +3476,11 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
||||
mock_notify.assert_called_once_with(
|
||||
self.context, 'build_instances',
|
||||
instance.uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(exc.MaxRetriesExceeded), test.MatchType(str))
|
||||
test.MatchType(exc.MaxRetriesExceeded))
|
||||
request_spec_dict = mock_notify.call_args_list[0][0][3]
|
||||
for key in ('instance_type', 'num_instances', 'instance_properties',
|
||||
'image'):
|
||||
self.assertIn(key, request_spec_dict)
|
||||
tb = mock_notify.call_args_list[0][0][6]
|
||||
self.assertIn('Traceback (most recent call last):', tb)
|
||||
|
||||
@mock.patch('nova.compute.utils.notify_about_compute_task_error')
|
||||
@mock.patch('nova.objects.Instance.save')
|
||||
@@ -3518,13 +3512,11 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase):
|
||||
mock_notify.assert_called_once_with(
|
||||
self.context, 'build_instances',
|
||||
instance.uuid, test.MatchType(dict), 'error',
|
||||
test.MatchType(exc.NoValidHost), test.MatchType(str))
|
||||
test.MatchType(exc.NoValidHost))
|
||||
request_spec_dict = mock_notify.call_args_list[0][0][3]
|
||||
for key in ('instance_type', 'num_instances', 'instance_properties',
|
||||
'image'):
|
||||
self.assertIn(key, request_spec_dict)
|
||||
tb = mock_notify.call_args_list[0][0][6]
|
||||
self.assertIn('Traceback (most recent call last):', tb)
|
||||
|
||||
@mock.patch('nova.scheduler.utils.claim_resources', return_value=True)
|
||||
@mock.patch('nova.scheduler.utils.fill_provider_mapping')
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
# under the License.
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
import unittest
|
||||
|
||||
from nova.notifications.objects import exception
|
||||
from nova import test
|
||||
@@ -22,40 +20,34 @@ from nova import test
|
||||
|
||||
class TestExceptionPayload(test.NoDBTestCase):
|
||||
|
||||
# Failing due to bug #1881455
|
||||
@unittest.expectedFailure
|
||||
def test_from_exc_and_traceback(self):
|
||||
def test_from_exception(self):
|
||||
try:
|
||||
raise Exception('foo')
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
tb = traceback.format_exc()
|
||||
|
||||
payload = exception.ExceptionPayload.from_exc_and_traceback(
|
||||
exc_info[1], tb)
|
||||
payload = exception.ExceptionPayload.from_exception(exc_info[1])
|
||||
|
||||
self.assertEqual(
|
||||
'nova.tests.unit.notifications.objects.test_exception',
|
||||
payload.module_name,
|
||||
)
|
||||
self.assertEqual(
|
||||
'test_from_exc_and_traceback', payload.function_name)
|
||||
'test_from_exception', payload.function_name)
|
||||
self.assertEqual('foo', payload.exception_message)
|
||||
|
||||
def test_from_exc_and_traceback_nested(self):
|
||||
def test_from_exception_nested(self):
|
||||
try:
|
||||
raise Exception('foo')
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
tb = traceback.format_exc()
|
||||
|
||||
payload = exception.ExceptionPayload.from_exc_and_traceback(
|
||||
exc_info[1], tb)
|
||||
payload = exception.ExceptionPayload.from_exception(exc_info[1])
|
||||
|
||||
self.assertEqual(
|
||||
'nova.tests.unit.notifications.objects.test_exception',
|
||||
payload.module_name,
|
||||
)
|
||||
self.assertEqual(
|
||||
'test_from_exc_and_traceback_nested', payload.function_name)
|
||||
'test_from_exception_nested', payload.function_name)
|
||||
self.assertEqual('foo', payload.exception_message)
|
||||
|
||||
@@ -99,7 +99,7 @@ class SchedulerUtilsTestCase(test.NoDBTestCase):
|
||||
mock_notify_task.assert_called_once_with(
|
||||
self.context, method, expected_uuid,
|
||||
payload_request_spec, updates['vm_state'],
|
||||
exc_info, test.MatchType(str))
|
||||
exc_info)
|
||||
|
||||
def test_set_vm_state_and_notify_request_spec_dict(self):
|
||||
"""Tests passing a legacy dict format request spec to
|
||||
|
||||
@@ -2009,9 +2009,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
drvr._host.get_connection)
|
||||
mock_get.assert_called_once_with()
|
||||
mock_notify.assert_called_once_with(self.context, ip=CONF.my_ip,
|
||||
exception=fake_error, tb=mock.ANY)
|
||||
_, kwargs = mock_notify.call_args
|
||||
self.assertIn('Traceback (most recent call last):', kwargs['tb'])
|
||||
exception=fake_error)
|
||||
|
||||
@mock.patch.object(fakelibvirt.virConnect, "nodeDeviceLookupByName")
|
||||
@mock.patch.object(fakelibvirt.virNodeDevice, "dettach")
|
||||
|
||||
@@ -34,7 +34,6 @@ import os
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
from eventlet import greenio
|
||||
from eventlet import greenthread
|
||||
@@ -510,7 +509,7 @@ class Host(object):
|
||||
'compute.libvirt.error',
|
||||
payload)
|
||||
compute_utils.notify_about_libvirt_connect_error(
|
||||
ctxt, ip=CONF.my_ip, exception=ex, tb=traceback.format_exc())
|
||||
ctxt, ip=CONF.my_ip, exception=ex)
|
||||
raise exception.HypervisorUnavailable(host=CONF.host)
|
||||
|
||||
return conn
|
||||
|
||||
Reference in New Issue
Block a user