def _get_response(self, ctx, proxy, topic, data): """Process a curried message and cast the result to topic.""" LOG.debug("Running func with context: %s", ctx.to_dict()) data.setdefault('version', None) data.setdefault('args', {}) try: result = proxy.dispatch(ctx, data['version'], data['method'], data.get('namespace'), **data['args']) return ConsumerBase.normalize_reply(result, ctx.replies) except greenlet.GreenletExit: # ignore these since they are just from shutdowns pass except rpc_common.ClientException as e: LOG.debug("Expected exception during message handling (%s)", e._exc_info[1]) return { 'exc': rpc_common.serialize_remote_exception(e._exc_info, log_failure=False) } except Exception: LOG.error(_("Exception during message handling")) return { 'exc': rpc_common.serialize_remote_exception(sys.exc_info()) }
def test_should_not_ignore_parent_classes_even_for_remote_ones(self): # We want tracebacks cfg.CONF.set_override('debug', True) error = StackNotFoundChild(stack_name='a') exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["heat.tests.test_fault_middleware"]) wrapper = fault.FaultWrapper(None) msg = wrapper._error(remote_error) expected_message, expected_traceback = six.text_type( remote_error).split('\n', 1) expected = { 'code': 404, 'error': { 'message': expected_message, 'traceback': expected_traceback, 'type': 'StackNotFoundChild' }, 'explanation': 'The resource could not be found.', 'title': 'Not Found' } self.assertEqual(expected, msg)
def _to_remote_error(self, error): """Converts the given exception to the one with the _Remote suffix. """ exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["heat.common.exception"]) return remote_error
def marshal_response(reply=None, failure=None): # TODO(grs): do replies have a context? msg = proton.Message() if failure: failure = common.serialize_remote_exception(failure) data = {"failure": failure} else: data = {"response": reply} msg.body = jsonutils.dumps(data) return msg
def reply(self, reply=None, failure=None, log_failure=True): marconi = _marconi_client_with_conf() if failure: failure = rpc_common.serialize_remote_exception(failure, log_failure) envelope = { 'in_reply_to': self.msg_id, 'body': reply, 'failure': failure, 'reply_q': self.reply_q, } _post_envelope(marconi, envelope, self.reply_q)
def _get_response(self, ctx, proxy, topic, data): """Process a curried message and cast the result to topic.""" LOG.debug("Running func with context: %s", ctx.to_dict()) data.setdefault('version', None) data.setdefault('args', {}) try: result = proxy.dispatch( ctx, data['version'], data['method'], data.get('namespace'), **data['args']) return ConsumerBase.normalize_reply(result, ctx.replies) except greenlet.GreenletExit: # ignore these since they are just from shutdowns pass except rpc_common.ClientException as e: LOG.debug("Expected exception during message handling (%s)", e._exc_info[1]) return {'exc': rpc_common.serialize_remote_exception(e._exc_info, log_failure=False)} except Exception: LOG.error(_("Exception during message handling")) return {'exc': rpc_common.serialize_remote_exception(sys.exc_info())}
def remote_exception_helper(self, name, error): exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, name) wrapper = fault.FaultWrapper(None) msg = wrapper._error(remote_error) expected = {'code': 500, 'error': {'message': msg['error']['message'], 'traceback': None, 'type': 'RemoteError'}, 'explanation': msg['explanation'], 'title': 'Internal Server Error'} self.assertEqual(expected, msg)
def test_remote_exception(self): # We want tracebacks cfg.CONF.set_override('debug', True) error = heat_exc.StackNotFound(stack_name='a') exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["heat.common.exception"]) wrapper = fault.FaultWrapper(None) msg = wrapper._error(remote_error) expected_message, expected_traceback = six.text_type(remote_error).\ split('\n', 1) expected = {'code': 404, 'error': {'message': expected_message, 'traceback': expected_traceback, 'type': 'StackNotFound'}, 'explanation': 'The resource could not be found.', 'title': 'Not Found'} self.assertEqual(expected, msg)
def remote_exception_helper(self, name, error): exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, name) wrapper = fault.FaultWrapper(None) msg = wrapper._error(remote_error) expected = { 'code': 500, 'error': { 'message': msg['error']['message'], 'traceback': None, 'type': 'RemoteError' }, 'explanation': msg['explanation'], 'title': 'Internal Server Error' } self.assertEqual(expected, msg)
def _send_reply(self, conn, reply=None, failure=None, ending=False, log_failure=True): if failure: failure = rpc_common.serialize_remote_exception(failure, log_failure) msg = {'result': reply, 'failure': failure} if ending: msg['ending'] = True rpc_amqp._add_unique_id(msg) # If a reply_q exists, add the msg_id to the reply and pass the # reply_q to direct_send() to use it as the response queue. # Otherwise use the msg_id for backward compatibility. if self.reply_q: msg['_msg_id'] = self.msg_id conn.direct_send(self.reply_q, rpc_common.serialize_msg(msg)) else: conn.direct_send(self.msg_id, rpc_common.serialize_msg(msg))
def test_serialize_remote_exception(self): errors = [] def stub_error(msg, *a, **kw): if (a and len(a) == 1 and isinstance(a[0], dict) and a[0]): a = a[0] errors.append(str(msg) % a) self.stubs.Set(exceptions.LOG, 'error', stub_error) try: try: raise self.cls(*self.args, **self.kwargs) except Exception as ex: cls_error = ex if self.add_remote: ex = add_remote_postfix(ex) raise ex except Exception: exc_info = sys.exc_info() serialized = exceptions.serialize_remote_exception( exc_info, log_failure=self.log_failure) failure = jsonutils.loads(serialized) self.assertEqual(self.clsname, failure['class'], failure) self.assertEqual(self.modname, failure['module']) self.assertEqual(self.msg, failure['message']) self.assertEqual([self.msg], failure['args']) self.assertEqual(self.kwargs, failure['kwargs']) # Note: _Remote prefix not stripped from tracebacks tb = cls_error.__class__.__name__ + ': ' + self.msg self.assertIn(tb, ''.join(failure['tb'])) if self.log_failure: self.assertTrue(len(errors) > 0, errors) else: self.assertEqual(0, len(errors), errors)
def msg_reply(conf, msg_id, reply_q, connection_pool, reply=None, failure=None, ending=False, log_failure=True): """Sends a reply or an error on the channel signified by msg_id. Failure should be a sys.exc_info() tuple. """ with ConnectionContext(conf, connection_pool) as conn: if failure: failure = rpc_common.serialize_remote_exception(failure, log_failure) msg = {'result': reply, 'failure': failure} if ending: msg['ending'] = True _add_unique_id(msg) # If a reply_q exists, add the msg_id to the reply and pass the # reply_q to direct_send() to use it as the response queue. # Otherwise use the msg_id for backward compatibility. if reply_q: msg['_msg_id'] = msg_id conn.direct_send(reply_q, rpc_common.serialize_msg(msg)) else: conn.direct_send(msg_id, rpc_common.serialize_msg(msg))
def msg_reply(conf, msg_id, reply_q, connection_pool, reply=None, failure=None, ending=False, log_failure=True): """Sends a reply or an error on the channel signified by msg_id. Failure should be a sys.exc_info() tuple. """ with ConnectionContext(conf, connection_pool) as conn: if failure: failure = rpc_common.serialize_remote_exception(failure, log_failure) msg = {'result': reply, 'failure': failure} if ending: msg['ending'] = True _add_unique_id(msg) # If a reply_q exists, add the msg_id to the reply and pass the # reply_q to direct_send() to use it as the response queue. # Otherwise use the msg_id for backward compatibilty. if reply_q: msg['_msg_id'] = msg_id conn.direct_send(reply_q, rpc_common.serialize_msg(msg)) else: conn.direct_send(msg_id, rpc_common.serialize_msg(msg))