Merge "Use 'Exception.__traceback__' for versioned notifications"

This commit is contained in:
Zuul
2020-06-10 17:17:12 +00:00
committed by Gerrit Code Review
13 changed files with 159 additions and 185 deletions
+15 -29
View File
@@ -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
View File
@@ -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
View File
@@ -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
+30 -11
View File
@@ -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')
+1 -3
View File
@@ -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,
+48 -48
View File
@@ -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):
+4 -4
View File
@@ -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]
+10 -18
View File
@@ -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
+1 -3
View File
@@ -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")
+1 -2
View File
@@ -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