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 _to_remote_error(self, error): '''Converts the given exception to 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, ["senlin.common.exception"]) return remote_error
def test_should_not_ignore_parent_classes_even_for_remote_ones(self): # We want tracebacks cfg.CONF.set_override('debug', True) error = ClusterNotFoundChild(cluster='a') exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["senlin.tests.unit.middleware.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': { 'code': 404, 'message': expected_message, 'traceback': expected_traceback, 'type': 'ClusterNotFoundChild' }, '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) print msg errmsg = { 'code': 500, 'error': {'message': msg['response']['error']['message'], 'traceback': None, 'type': 'RemoteError'}, 'explanation': msg['response']['explanation'], 'title': 'Internal Server Error'} expected = { 'success': False, 'response': errmsg, 'install': { 'success': False, 'response': '' }, 'test': { 'success': False, 'response': '' }, 'deploy': { 'success': False, 'response': '' } } self.assertEqual(expected, msg)
def test_remote_exception(self): # We want tracebacks cfg.CONF.set_override('debug', True) error = validator_exc.InvalidContentType(content_type='a') exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["validator.common.exception"]) wrapper = fault.FaultWrapper(None) msg = wrapper._error(remote_error) expected_message, expected_traceback = six.text_type( remote_error).split('\n', 1) error = {u'code': 500, u'error': {u'message': u'Invalid content type %(content_type)s', u'traceback': u'InvalidContentType: Invalid content type a\n', u'type': 'InvalidContentType'}, u'explanation': 'The server has either erred or is incapable of performing the requested operation.', u'title': 'Internal Server Error'} expected = { 'success': False, 'response': error, 'install': { 'success': False, 'response': '' }, 'test': { 'success': False, 'response': '' }, 'deploy': { 'success': False, 'response': '' } } self.assertEqual(expected, msg)
def test_should_not_ignore_parent_classes_even_for_remote_ones(self): # We want tracebacks cfg.CONF.set_override('debug', True) error = ClusterNotFoundChild(cluster='a') exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["senlin.tests.middleware.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': { 'code': 404, 'message': expected_message, 'traceback': expected_traceback, 'type': 'ClusterNotFoundChild' }, 'explanation': 'The resource could not be found.', 'title': 'Not Found' } self.assertEqual(expected, msg)
def to_remote_error(error): '''Prepend the given exception 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, ["senlin.common.exception"]) return remote_error
def unmarshal_response(message, allowed): # TODO(kgiusti) This may fail to unpack and raise an exception. Need to # communicate this to the caller! data = jsonutils.loads(message.body) failure = data.get('failure') if failure is not None: raise common.deserialize_remote_exception(failure, allowed) return data.get("response")
def _process_reply(self, data): self.msg_id_cache.check_duplicate_message(data) if data["failure"]: failure = data["failure"] result = rpc_common.deserialize_remote_exception(failure, self.allowed_remote_exmods) else: result = data.get("result", None) ending = data.get("ending", False) return result, ending
def _process_reply(self, data): self.msg_id_cache.check_duplicate_message(data) if data['failure']: failure = data['failure'] result = rpc_common.deserialize_remote_exception( failure, self.allowed_remote_exmods) else: result = data.get('result', None) ending = data.get('ending', False) return result, ending
def _process_reply(self, data): result = None ending = False self.msg_id_cache.check_duplicate_message(data) if data['failure']: failure = data['failure'] result = rpc_common.deserialize_remote_exception( failure, self.allowed_remote_exmods) elif data.get('ending', False): ending = True else: result = data['result'] return result, ending
def send_request(self, request): reply_future = self.sender.send_request(request) try: reply = reply_future.result(timeout=request.timeout) except futures.TimeoutError: raise oslo_messaging.MessagingTimeout("Timeout %s seconds was reached" % request.timeout) finally: self.reply_waiter.untrack_id(request.message_id) LOG.debug("Received reply %s", reply) if reply[zmq_names.FIELD_FAILURE]: raise rpc_common.deserialize_remote_exception(reply[zmq_names.FIELD_FAILURE], request.allowed_remote_exmods) else: return reply[zmq_names.FIELD_REPLY]
def remote_exception_helper(self, name, error): error.args = () 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': {'traceback': None, 'type': 'RemoteError'}, 'explanation': msg['explanation'], 'title': 'Internal Server Error'} self.assertEqual(expected, msg)
def send_request(self, request): reply_future = self.sender.send_request(request) try: reply = reply_future.result(timeout=request.timeout) except futures.TimeoutError: raise oslo_messaging.MessagingTimeout( "Timeout %s seconds was reached" % request.timeout) finally: self.reply_waiter.untrack_id(request.message_id) LOG.debug("Received reply %s", reply) if reply[zmq_names.FIELD_FAILURE]: raise rpc_common.deserialize_remote_exception( reply[zmq_names.FIELD_FAILURE], request.allowed_remote_exmods) else: return reply[zmq_names.FIELD_REPLY]
def remote_exception_helper(self, name, error): if six.PY3: error.args = () 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': {'traceback': None, 'type': 'RemoteError'}, 'explanation': msg['explanation'], 'title': 'Internal Server Error'} self.assertEqual(expected, msg)
def remote_exception_helper(self, name, error): if six.PY3: error.args = () 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 _receive_reply(socket, request): def _receive_method(socket): return socket.recv_pyobj() # NOTE(ozamiatin): Check for retry here (no retries now) with contextlib.closing(zmq_async.get_reply_poller()) as poller: poller.register(socket, recv_method=_receive_method) reply, socket = poller.poll(timeout=request.timeout) if reply is None: raise oslo_messaging.MessagingTimeout( "Timeout %s seconds was reached" % request.timeout) if reply[zmq_names.FIELD_FAILURE]: raise rpc_common.deserialize_remote_exception( reply[zmq_names.FIELD_FAILURE], request.allowed_remote_exmods) else: return reply[zmq_names.FIELD_REPLY]
def test_remote_exception(self): # We want tracebacks cfg.CONF.set_override("debug", True) error = heat_exc.EntityNotFound(entity="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": "EntityNotFound"}, "explanation": "The resource could not be found.", "title": "Not Found", } self.assertEqual(expected, msg)
def test_remote_exception(self): # We want tracebacks cfg.CONF.set_override('debug', True) error = heat_exc.EntityNotFound(entity='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 = str( remote_error).split('\n', 1) expected = {'code': 404, 'error': {'message': expected_message, 'traceback': expected_traceback, 'type': 'EntityNotFound'}, 'explanation': 'The resource could not be found.', 'title': 'Not Found'} self.assertEqual(expected, msg)
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, ["validator.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) error = {u'code': 500, u'error': { u'message': u"Remote error: StackNotFoundChild " u"The %(entity)s (%(name)s) could not be " u"found.\n[u'StackNotFoundChild: " u"The %(entity)s (%(name)s) " u"could not be found.\\n'].", u'traceback': 'None\n', u'type': 'RemoteError'}, u'explanation': 'The server has either erred or is incapable ' 'of performing the requested operation.', u'title': 'Internal Server Error'} expected = { 'success': False, 'response': error, 'install': { 'success': False, 'response': '' }, 'test': { 'success': False, 'response': '' }, 'deploy': { 'success': False, 'response': '' } } self.assertEqual(expected, msg)
def test_remote_exception(self): # We want tracebacks cfg.CONF.set_override('debug', True) error = heat_exc.EntityNotFound(entity='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': 'EntityNotFound'}, 'explanation': 'The resource could not be found.', 'title': 'Not Found'} self.assertEqual(expected, msg)
def _recv_reply(self, request): reply_future, = self.receiver.track_request(request) try: _, reply = reply_future.result(timeout=request.timeout) except AssertionError: LOG.error(_LE("Message format error in reply for %s"), request.message_id) return None except futures.TimeoutError: self._raise_timeout(request) finally: self.receiver.untrack_request(request) if reply.failure: raise rpc_common.deserialize_remote_exception( reply.failure, request.allowed_remote_exmods) else: return reply.reply_body
def send_request(self, request): reply_future = self.sender.send_request(request) try: reply = reply_future.result(timeout=request.timeout) LOG.debug("Received reply %s", request.message_id) except AssertionError: LOG.error(_LE("Message format error in reply %s"), request.message_id) return None except futures.TimeoutError: raise oslo_messaging.MessagingTimeout( "Timeout %(tout)s seconds was reached for message %(id)s" % {"tout": request.timeout, "id": request.message_id} ) finally: self.reply_waiter.untrack_id(request.message_id) if reply.failure: raise rpc_common.deserialize_remote_exception(reply.failure, request.allowed_remote_exmods) else: return reply.reply_body
def receive_reply(self, socket, request): self.receiver.register_socket(socket) _, reply_future = self.receiver.track_request(request) try: reply = reply_future.result(timeout=request.timeout) self._check_reply(reply, request) except AssertionError: LOG.error(_LE("Message format error in reply for %s"), request.message_id) return None except futures.TimeoutError: self._raise_timeout(request) finally: self._finally_unregister(socket, request) if reply.failure: raise rpc_common.deserialize_remote_exception( reply.failure, request.allowed_remote_exmods) else: return reply.reply_body
def test_remote_exception(self): cfg.CONF.set_override('debug', True, enforce_type=True) error = senlin_exc.ClusterNotFound(cluster='a') exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["senlin.common.exception"]) wrapper = fault.FaultWrapper(None) msg = wrapper._error(remote_error) expected_message = six.text_type(remote_error).split('\n', 1)[0] expected = { 'code': 404, 'error': { 'code': 404, 'message': expected_message, 'type': 'ClusterNotFound' }, 'explanation': 'The resource could not be found.', 'title': 'Not Found' } self.assertEqual(expected, msg)
def test_remote_exception(self): cfg.CONF.set_override('debug', True) error = senlin_exc.ResourceNotFound(type='cluster', id='a') exc_info = (type(error), error, None) serialized = rpc_common.serialize_remote_exception(exc_info) remote_error = rpc_common.deserialize_remote_exception( serialized, ["senlin.common.exception"]) wrapper = fault.FaultWrapper(None) msg = wrapper._error(remote_error) expected_message = six.text_type(remote_error).split('\n', 1)[0] expected = { 'code': 404, 'error': { 'code': 404, 'message': expected_message, 'type': 'ResourceNotFound' }, 'explanation': 'The resource could not be found.', 'title': 'Not Found' } self.assertEqual(expected, msg)
def test_deserialize_remote_exception(self): failure = { 'class': self.clsname, 'module': self.modname, 'message': 'test', 'tb': ['traceback\ntraceback\n'], 'args': self.args, 'kwargs': self.kwargs, } serialized = jsonutils.dumps(failure) ex = exceptions.deserialize_remote_exception(serialized, self.allowed) self.assertIsInstance(ex, self.cls) self.assertEqual(self.remote_name, ex.__class__.__name__) self.assertEqual(self.str, str(ex)) if hasattr(self, 'msg'): self.assertEqual(self.msg, str(ex)) self.assertEqual((self.msg, ) + self.remote_args, ex.args) else: self.assertEqual(self.remote_args, ex.args)
def receive_reply(self, socket, request): self.receiver.register_socket(socket) reply_future = \ self.receiver.track_request(request)[zmq_names.REPLY_TYPE] try: reply_id, reply = reply_future.result(timeout=request.timeout) self._check_received_data(reply_id, reply, request) except AssertionError: LOG.error(_LE("Message format error in reply for %s"), request.message_id) return None except futures.TimeoutError: self._raise_timeout(request) finally: self._finally_unregister(socket, request) if reply.failure: raise rpc_common.deserialize_remote_exception( reply.failure, request.allowed_remote_exmods) else: return reply.reply_body
def test_deserialize_remote_exception(self): failure = { 'class': self.clsname, 'module': self.modname, 'message': 'test', 'tb': ['traceback\ntraceback\n'], 'args': self.args, 'kwargs': self.kwargs, } serialized = jsonutils.dumps(failure) ex = exceptions.deserialize_remote_exception(serialized, self.allowed) self.assertIsInstance(ex, self.cls) self.assertEqual(self.remote_name, ex.__class__.__name__) self.assertEqual(self.str, six.text_type(ex)) if hasattr(self, 'msg'): self.assertEqual(self.msg, six.text_type(ex)) self.assertEqual((self.msg,) + self.remote_args, ex.args) else: self.assertEqual(self.remote_args, ex.args)
def send_request(self, request): reply_future = self.sender.send_request(request) try: reply = reply_future.result(timeout=request.timeout) LOG.debug("Received reply %s", request.message_id) except AssertionError: LOG.error(_LE("Message format error in reply %s"), request.message_id) return None except futures.TimeoutError: raise oslo_messaging.MessagingTimeout( "Timeout %(tout)s seconds was reached for message %(id)s" % { "tout": request.timeout, "id": request.message_id }) finally: self.reply_waiter.untrack_id(request.message_id) if reply.failure: raise rpc_common.deserialize_remote_exception( reply.failure, request.allowed_remote_exmods) else: return reply.reply_body
def _call(addr, context, topic, msg, timeout=None, envelope=False, allowed_remote_exmods=None): allowed_remote_exmods = allowed_remote_exmods or [] # timeout_response is how long we wait for a response timeout = timeout or CONF.rpc_response_timeout # The msg_id is used to track replies. msg_id = uuid.uuid4().hex # Replies always come into the reply service. reply_topic = "zmq_replies.%s" % CONF.rpc_zmq_host LOG.debug("Creating payload") # Curry the original request into a reply method. mcontext = RpcContext.marshal(context) payload = { 'method': '-reply', 'args': { 'msg_id': msg_id, 'topic': reply_topic, # TODO(ewindisch): safe to remove mcontext in I. 'msg': [mcontext, msg] } } LOG.debug("Creating queue socket for reply waiter") # Messages arriving async. # TODO(ewindisch): have reply consumer with dynamic subscription mgmt with Timeout(timeout, exception=rpc_common.Timeout): try: msg_waiter = ZmqSocket("ipc://%s/zmq_topic_zmq_replies.%s" % (CONF.rpc_zmq_ipc_dir, CONF.rpc_zmq_host), zmq.SUB, subscribe=msg_id, bind=False) LOG.debug("Sending cast: %s", topic) _cast(addr, context, topic, payload, envelope=envelope) LOG.debug("Cast sent; Waiting reply") # Blocks until receives reply msg = msg_waiter.recv() if msg is None: raise rpc_common.Timeout() LOG.debug("Received message: %s", msg) LOG.debug("Unpacking response") if msg[2] == 'cast': # Legacy version raw_msg = _deserialize(msg[-1])[-1] elif msg[2] == 'impl_zmq_v2': rpc_envelope = unflatten_envelope(msg[4:]) raw_msg = rpc_common.deserialize_msg(rpc_envelope) else: raise rpc_common.UnsupportedRpcEnvelopeVersion( _("Unsupported or unknown ZMQ envelope returned.")) responses = raw_msg['args']['response'] # ZMQError trumps the Timeout error. except zmq.ZMQError: raise RPCException("ZMQ Socket Error") except (IndexError, KeyError): raise RPCException(_("RPC Message Invalid.")) finally: if 'msg_waiter' in vars(): msg_waiter.close() # It seems we don't need to do all of the following, # but perhaps it would be useful for multicall? # One effect of this is that we're checking all # responses for Exceptions. for resp in responses: if isinstance(resp, types.DictType) and 'exc' in resp: raise rpc_common.deserialize_remote_exception( resp['exc'], allowed_remote_exmods) return responses[-1]
def _call(addr, context, topic, msg, timeout=None, envelope=False, allowed_remote_exmods=None): allowed_remote_exmods = allowed_remote_exmods or [] # timeout_response is how long we wait for a response timeout = timeout or CONF.rpc_response_timeout # The msg_id is used to track replies. msg_id = uuid.uuid4().hex # Replies always come into the reply service. reply_topic = "zmq_replies.%s" % CONF.rpc_zmq_host LOG.debug("Creating payload") # Curry the original request into a reply method. mcontext = RpcContext.marshal(context) payload = { 'method': '-reply', 'args': { 'msg_id': msg_id, 'topic': reply_topic, # TODO(ewindisch): safe to remove mcontext in I. 'msg': [mcontext, msg] } } LOG.debug("Creating queue socket for reply waiter") # Messages arriving async. # TODO(ewindisch): have reply consumer with dynamic subscription mgmt with Timeout(timeout, exception=rpc_common.Timeout): try: msg_waiter = ZmqSocket( "ipc://%s/zmq_topic_zmq_replies.%s" % (CONF.rpc_zmq_ipc_dir, CONF.rpc_zmq_host), zmq.SUB, subscribe=msg_id, bind=False ) LOG.debug("Sending cast: %s", topic) _cast(addr, context, topic, payload, envelope=envelope) LOG.debug("Cast sent; Waiting reply") # Blocks until receives reply msg = msg_waiter.recv() if msg is None: raise rpc_common.Timeout() LOG.debug("Received message: %s", msg) LOG.debug("Unpacking response") if msg[2] == 'cast': # Legacy version raw_msg = _deserialize(msg[-1])[-1] elif msg[2] == 'impl_zmq_v2': rpc_envelope = unflatten_envelope(msg[4:]) raw_msg = rpc_common.deserialize_msg(rpc_envelope) else: raise rpc_common.UnsupportedRpcEnvelopeVersion( _("Unsupported or unknown ZMQ envelope returned.")) responses = raw_msg['args']['response'] # ZMQError trumps the Timeout error. except zmq.ZMQError: raise RPCException("ZMQ Socket Error") except (IndexError, KeyError): raise RPCException(_("RPC Message Invalid.")) finally: if 'msg_waiter' in vars(): msg_waiter.close() # It seems we don't need to do all of the following, # but perhaps it would be useful for multicall? # One effect of this is that we're checking all # responses for Exceptions. for resp in responses: if isinstance(resp, types.DictType) and 'exc' in resp: raise rpc_common.deserialize_remote_exception( resp['exc'], allowed_remote_exmods) return responses[-1]
def call(self, ctxt, method, args): """Synchronous Call""" # # check if the call has a message saved in cache # # key: string concatenation of ctxt + method + args # # value: rpc response object # key = "" # for k, v in ctxt.items(): # key += str(k) # key += '#' + str(v) + '#' # key += '|' + str(method) + '|' # for k, v in args.items(): # key += str(k) # key += '#' + str(v) + '#' # # # check if the method has been called before # # and cached # if key in self.message_cache: # LOG.debug("Retrieved method {} with args " # "{} from cache".format(method, args)) # return self.message_cache[key] rpc_start_time = time.time() rpc = self.RPC(action=self.RPC.CALL, ctxt=ctxt, method=method, args=args) # TODO(jdandrea): Do something if the assert fails. assert (rpc.enqueued) rpc_id = rpc.id topic = self.target.topic LOG.info(_LI("Message {} on topic {} enqueued.").format(rpc_id, topic)) if self.conf.messaging_server.debug: LOG.debug("Calling method {} with args {}".format(method, args)) # Check message status within a thread executor = futurist.ThreadPoolExecutor() started_at = time.time() while (time.time() - started_at) <= self.conf.messaging_server.response_timeout: fut = executor.submit(self.__check_rpc_status, rpc_id, method) rpc = fut.result() if rpc and rpc.finished: if self.conf.messaging_server.debug: LOG.debug("Message {} method {} response received".format( rpc_id, method)) break executor.shutdown() # Get response, delete message, and return response if not rpc or not rpc.finished: LOG.error( _LE("Message {} on topic {} timed out at {} seconds").format( rpc_id, topic, self.conf.messaging_server.response_timeout)) elif not rpc.ok: LOG.error( _LE("Message {} on topic {} returned an error").format( rpc_id, topic)) response = rpc.response failure = rpc.failure rpc.delete() # TODO(jdandrea): Put a TTL on the msg instead? # self.message_cache[key] = response LOG.debug("Elapsed time: {0:.3f} sec".format(time.time() - rpc_start_time)) # If there's a failure, raise it as an exception allowed = [] if failure is not None and failure != '': # TODO(jdandrea): Do we need to populate allowed(_remote_exmods)? raise rpc_common.deserialize_remote_exception(failure, allowed) return response