422 is a RecoverableError, no need too detail info. class BatchAction(Action): def handle(self, table, request, obj_ids): action_success = [] action_failure = [] action_not_allowed = [] for datum_id in obj_ids: datum = table.get_object_by_id(datum_id) datum_display = table.get_object_display(datum) or _("N/A") if not table._filter_action(self, request, datum): action_not_allowed.append(datum_display) LOG.info('Permission denied to %s: "%s"' % (self._get_action_name(past=True).lower(), datum_display)) continue try: self.action(request, datum_id) # Call update to invoke changes if needed self.update(request, datum) action_success.append(datum_display) self.success_ids.append(datum_id) LOG.info('%s: "%s"' % (self._get_action_name(past=True), datum_display)) except Exception as ex: # Handle the exception but silence it since we'll display # an aggregate error message later. Otherwise we'd get # multiple error messages displayed to the user. if getattr(ex, "_safe_message", None): ignore = False else: ignore = True action_failure.append(datum_display) exceptions.handle(request, ignore=ignore)
# Begin with success message class, downgrade to info if problems. success_message_level = messages.success if action_not_allowed: msg = _('You are not allowed to %(action)s: %(objs)s') params = {"action": self._get_action_name(action_not_allowed).lower(), "objs": functions.lazy_join(", ", action_not_allowed)} messages.error(request, msg % params) success_message_level = messages.info if action_failure: msg = _('Unable to %(action)s: %(objs)s') params = {"action": self._get_action_name(action_failure).lower(), "objs": functions.lazy_join(", ", action_failure)} messages.error(request, msg % params) success_message_level = messages.info if action_success: msg = _('%(action)s: %(objs)s') params = {"action": self._get_action_name(action_success, past=True), "objs": functions.lazy_join(", ", action_success)} success_message_level(request, msg % params) return shortcuts.redirect(self.get_success_url(request)) def handle_recoverable(request, message, redirect, ignore, escalate, handled, force_silence, force_log, log_method, log_entry, log_level): if not force_silence and not handled and (not ignore or force_log): # Default recoverable error to WARN log level log_method = getattr(LOG, log_level or "warning") log_method(error_color("Recoverable error: %s" % log_entry)) if not ignore and not handled: messages.error(request, message or log_entry) if redirect: raise Http302(redirect) HANDLE_EXC_METHODS = [ {'exc': UNAUTHORIZED, 'handler': handle_unauthorized, 'set_wrap': False}, {'exc': NOT_FOUND, 'handler': handle_notfound, 'set_wrap': True}, {'exc': RECOVERABLE, 'handler': handle_recoverable, 'set_wrap': True}, ] def handle(request, message=None, redirect=None, ignore=False, escalate=False, log_level=None, force_log=None): """Centralized error handling for Horizon. Because Horizon consumes so many different APIs with completely different ``Exception`` types, it's necessary to have a centralized place for handling exceptions which may be raised. Exceptions are roughly divided into 3 types: #. ``UNAUTHORIZED``: Errors resulting from authentication or authorization problems. These result in being logged out and sent to the login screen. #. ``NOT_FOUND``: Errors resulting from objects which could not be located via the API. These generally result in a user-facing error message, but are otherwise returned to the normal code flow. Optionally a redirect value may be passed to the error handler so users are returned to a different view than the one requested in addition to the error message. #. RECOVERABLE: Generic API errors which generate a user-facing message but drop directly back to the regular code flow. All other exceptions bubble the stack as normal unless the ``ignore`` argument is passed in as ``True``, in which case only unrecognized errors are bubbled. If the exception is not re-raised, an appropriate wrapper exception class indicating the type of exception that was encountered will be returned. """ if not escalate: return RecoverableError # return to normal code flow ** Changed in: horizon Status: New => Invalid -- You received this bug notification because you are a member of Yahoo! Engineering Team, which is subscribed to OpenStack Dashboard (Horizon). https://bugs.launchpad.net/bugs/1417539 Title: When trying to delete Trove instance that is in BUILD state, Horizon shows an error, which is ok, but the error message doesn't show real reason of why instance can't be deleted Status in OpenStack Dashboard (Horizon): Invalid Bug description: When trying to delete Trove instance that is in BUILD state, Horizon shows an error, which is ok, but the error message doesn't show real reason of why instance can't be delete. Here's what Trove says when user tries to delete instance in BUILD state: ubuntu@ubuntu:~/trove-integration/scripts$ trove delete 4ff27e9b-236d-403c-8127-884f781cfd3d ERROR: Instance 4ff27e9b-236d-403c-8127-884f781cfd3d is not ready. (HTTP 422) Attachment contains screenshot of what Horizon displays to user. This should be fixed. And fix should provide error handing improvement that explicitly shows actual reason instaed of what Horizon have right now. To manage notifications about this bug go to: https://bugs.launchpad.net/horizon/+bug/1417539/+subscriptions -- Mailing list: https://launchpad.net/~yahoo-eng-team Post to : yahoo-eng-team@lists.launchpad.net Unsubscribe : https://launchpad.net/~yahoo-eng-team More help : https://help.launchpad.net/ListHelp