Exemple #1
0
    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 _send_reply(self,
                    conn,
                    reply=None,
                    failure=None,
                    ending=False,
                    log_failure=True):
        if (self.reply_q and not self._obsolete_reply_queues.reply_q_valid(
                self.reply_q, self.msg_id)):
            return

        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
            try:
                conn.direct_send(self.reply_q, rpc_common.serialize_msg(msg))
            except rpc_amqp.AMQPDestinationNotFound:
                self._obsolete_reply_queues.add(self.reply_q, self.msg_id)
        else:
            # TODO(sileht): look at which version of oslo-incubator rpc
            # send need this, but I guess this is older than icehouse
            # if this is icehouse, we can drop this at M
            # if this is havana, we can drop this now.
            conn.direct_send(self.msg_id, rpc_common.serialize_msg(msg))
    def _send_reply(self, conn, reply=None, failure=None, ending=False, log_failure=True):
        if self.reply_q and not self._obsolete_reply_queues.reply_q_valid(self.reply_q, self.msg_id):
            return

        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)
        unique_id = msg[rpc_amqp.UNIQUE_ID]

        # 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
            try:
                if ending:
                    LOG.debug(
                        "sending reply msg_id: %(msg_id)s "
                        "reply queue: %(reply_q)s"
                        % {"msg_id": self.msg_id, "unique_id": unique_id, "reply_q": self.reply_q}
                    )
                conn.direct_send(self.reply_q, rpc_common.serialize_msg(msg))
            except rpc_amqp.AMQPDestinationNotFound:
                self._obsolete_reply_queues.add(self.reply_q, self.msg_id)
        else:
            # TODO(sileht): look at which version of oslo-incubator rpc
            # send need this, but I guess this is older than icehouse
            # if this is icehouse, we can drop this at Mitaka
            # if this is havana, we can drop this now.
            conn.direct_send(self.msg_id, rpc_common.serialize_msg(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)
Exemple #6
0
 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
Exemple #7
0
 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
Exemple #8
0
    def _send_reply(self, conn, reply=None, failure=None, ending=True):
        if not self._obsolete_reply_queues.reply_q_valid(
                self.reply_q, self.msg_id):
            return

        if failure:
            failure = rpc_common.serialize_remote_exception(failure)
        # NOTE(sileht): ending can be removed in N*, see Listener.wait()
        # for more detail.
        msg = {
            'result': reply,
            'failure': failure,
            'ending': ending,
            '_msg_id': self.msg_id
        }
        rpc_amqp._add_unique_id(msg)
        unique_id = msg[rpc_amqp.UNIQUE_ID]

        LOG.debug(
            "sending reply msg_id: %(msg_id)s "
            "reply queue: %(reply_q)s "
            "time elapsed: %(elapsed)ss", {
                'msg_id': self.msg_id,
                'unique_id': unique_id,
                'reply_q': self.reply_q,
                'elapsed': self.stopwatch.elapsed()
            })
        conn.direct_send(self.reply_q, rpc_common.serialize_msg(msg))
    def _send_reply(self, conn, reply=None, failure=None,
                    ending=False, log_failure=True):
        if (self.reply_q and
            not self._obsolete_reply_queues.reply_q_valid(self.reply_q,
                                                          self.msg_id)):
            return

        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
            try:
                conn.direct_send(self.reply_q, rpc_common.serialize_msg(msg))
            except rpc_amqp.AMQPDestinationNotFound:
                self._obsolete_reply_queues.add(self.reply_q, self.msg_id)
        else:
            # TODO(sileht): look at which version of oslo-incubator rpc
            # send need this, but I guess this is older than icehouse
            # if this is icehouse, we can drop this at Mitaka
            # if this is havana, we can drop this now.
            conn.direct_send(self.msg_id, rpc_common.serialize_msg(msg))
Exemple #10
0
 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_serialize_remote_exception(self):
        try:
            try:
                raise self.cls(*self.args, **self.kwargs)
            except Exception as ex:
                # Note: in Python 3 ex variable will be cleared at the end of
                # the except clause, so explicitly make an extra copy of it
                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)

        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']))
Exemple #12
0
 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
Exemple #13
0
    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 test_serialize_remote_exception(self):
        try:
            try:
                raise self.cls(*self.args, **self.kwargs)
            except Exception as ex:
                # Note: in Python 3 ex variable will be cleared at the end of
                # the except clause, so explicitly make an extra copy of it
                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)

        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']))
Exemple #15
0
    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)
Exemple #16
0
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
Exemple #17
0
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 _reply(self, rpc_message, reply, failure):
     if failure is not None:
         failure = rpc_common.serialize_remote_exception(failure)
     reply = zmq_response.Reply(message_id=rpc_message.message_id,
                                reply_id=rpc_message.reply_id,
                                reply_body=reply,
                                failure=failure)
     self.reply_sender.send(rpc_message.socket, reply)
     return reply
Exemple #19
0
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, rpc_message, reply, failure):
     if failure is not None:
         failure = rpc_common.serialize_remote_exception(failure)
     reply = zmq_response.Reply(message_id=rpc_message.message_id,
                                reply_id=rpc_message.reply_id,
                                message_version=rpc_message.message_version,
                                reply_body=reply,
                                failure=failure)
     self.reply_sender.send(rpc_message.socket, reply)
     return reply
 def reply(self, reply=None, failure=None):
     if self.sender is not None:
         if failure is not None:
             failure = rpc_common.serialize_remote_exception(failure)
         reply = zmq_response.Response(msg_type=zmq_names.REPLY_TYPE,
                                       message_id=self.message_id,
                                       reply_id=self.reply_id,
                                       reply_body=reply,
                                       failure=failure)
         self.sender.send(self.socket, reply)
Exemple #22
0
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):
     if self.sender is not None:
         if failure is not None:
             failure = rpc_common.serialize_remote_exception(failure)
         reply = zmq_response.Response(msg_type=zmq_names.REPLY_TYPE,
                                       message_id=self.message_id,
                                       reply_id=self.reply_id,
                                       reply_body=reply,
                                       failure=failure)
         self.sender.send(self.socket, reply)
Exemple #24
0
 def reply(self, reply=None, failure=None):
     if self.reply_sender is not None:
         if failure is not None:
             failure = rpc_common.serialize_remote_exception(failure)
         reply = zmq_response.Reply(message_id=self.message_id,
                                    reply_id=self.reply_id,
                                    reply_body=reply,
                                    failure=failure)
         self.reply_sender.send(self.socket, reply)
         if self.replies_cache is not None:
             self.replies_cache.add(self.message_id, reply)
def marshal_response(reply=None, failure=None):
    # TODO(grs): do replies have a context?
    # NOTE(flaper87): Set inferred to True since rabbitmq-amqp-1.0 doesn't
    # have support for vbin8.
    msg = proton.Message(inferred=True)
    if failure:
        failure = common.serialize_remote_exception(failure)
        data = {"failure": failure}
    else:
        data = {"response": reply}
    msg.body = jsonutils.dumps(data)
    return msg
Exemple #26
0
    def reply(self, reply=None, failure=None):
        if failure is not None:
            failure = rpc_common.serialize_remote_exception(failure)
        response = zmq_response.Response(type=zmq_names.REPLY_TYPE,
                                         message_id=self.request.message_id,
                                         reply_id=self.reply_id,
                                         reply_body=reply,
                                         failure=failure)

        LOG.debug("Replying %s", (str(self.request.message_id)))

        self.received = True
        self.reply_socket.send(self.reply_id, zmq.SNDMORE)
        self.reply_socket.send(b'', zmq.SNDMORE)
        self.reply_socket.send_pyobj(response)
Exemple #27
0
    def reply(self, reply=None, failure=None, log_failure=True):
        if failure is not None:
            failure = rpc_common.serialize_remote_exception(failure,
                                                            log_failure)
        message_reply = {zmq_names.FIELD_REPLY: reply,
                         zmq_names.FIELD_FAILURE: failure,
                         zmq_names.FIELD_LOG_FAILURE: log_failure}

        LOG.info("Replying %s REP", (str(message_reply)))

        self.received = True
        self.reply_socket.send(self.reply_id, zmq.SNDMORE)
        self.reply_socket.send(b'', zmq.SNDMORE)
        self.reply_socket.send_pyobj(message_reply)
        self.poller.resume_polling(self.reply_socket)
    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)
Exemple #29
0
    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:
            if not data.get("method"):
                raise KeyError
            result = proxy.dispatch(ctx, data)
            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 reply(self, reply=None, failure=None):
        if failure is not None:
            failure = rpc_common.serialize_remote_exception(failure)
        response = zmq_response.Response(type=zmq_names.REPLY_TYPE,
                                         message_id=self.request.message_id,
                                         reply_id=self.reply_id,
                                         reply_body=reply,
                                         failure=failure)

        LOG.debug("Replying %s", (str(self.request.message_id)))

        self.received = True
        self.reply_socket.send(self.reply_id, zmq.SNDMORE)
        self.reply_socket.send(b'', zmq.SNDMORE)
        self.reply_socket.send_pyobj(response)
Exemple #31
0
    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 reply(self, reply=None, failure=None, log_failure=True):
        if failure is not None:
            failure = rpc_common.serialize_remote_exception(failure, log_failure)
        message_reply = {
            zmq_names.FIELD_REPLY: reply,
            zmq_names.FIELD_FAILURE: failure,
            zmq_names.FIELD_LOG_FAILURE: log_failure,
        }

        LOG.info("Replying %s REP", (str(message_reply)))

        self.received = True
        self.reply_socket.send(self.reply_id, zmq.SNDMORE)
        self.reply_socket.send(b"", zmq.SNDMORE)
        self.reply_socket.send_pyobj(message_reply)
        self.poller.resume_polling(self.reply_socket)
 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 reply(self, reply=None, failure=None, log_failure=True):
        if failure is not None:
            failure = rpc_common.serialize_remote_exception(failure,
                                                            log_failure)
        message_reply = {zmq_names.FIELD_TYPE: zmq_names.REPLY_TYPE,
                         zmq_names.FIELD_REPLY: reply,
                         zmq_names.FIELD_FAILURE: failure,
                         zmq_names.FIELD_LOG_FAILURE: log_failure,
                         zmq_names.FIELD_MSG_ID: self.request.message_id}

        LOG.debug("Replying %s", (str(self.request.message_id)))

        self.received = True
        self.reply_socket.send(self.reply_id, zmq.SNDMORE)
        self.reply_socket.send(b'', zmq.SNDMORE)
        self.reply_socket.send_pyobj(message_reply)
        self.poller.resume_polling(self.reply_socket)
    def _send_reply(self, conn, reply=None, failure=None, log_failure=True):
        if not self._obsolete_reply_queues.reply_q_valid(self.reply_q, self.msg_id):
            return

        if failure:
            failure = rpc_common.serialize_remote_exception(failure, log_failure)
        # NOTE(sileht): ending can be removed in N*, see Listener.wait()
        # for more detail.
        msg = {"result": reply, "failure": failure, "ending": True, "_msg_id": self.msg_id}
        rpc_amqp._add_unique_id(msg)
        unique_id = msg[rpc_amqp.UNIQUE_ID]

        LOG.debug(
            "sending reply msg_id: %(msg_id)s " "reply queue: %(reply_q)s",
            {"msg_id": self.msg_id, "unique_id": unique_id, "reply_q": self.reply_q},
        )
        conn.direct_send(self.reply_q, rpc_common.serialize_msg(msg))
Exemple #37
0
 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)
Exemple #39
0
    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)
Exemple #40
0
    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))
Exemple #41
0
 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)
Exemple #42
0
 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_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 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)
Exemple #45
0
    def _send_reply(self, conn, reply=None, failure=None, ending=True):
        if not self._obsolete_reply_queues.reply_q_valid(self.reply_q,
                                                         self.msg_id):
            return

        if failure:
            failure = rpc_common.serialize_remote_exception(failure)
        # NOTE(sileht): ending can be removed in N*, see Listener.wait()
        # for more detail.
        msg = {'result': reply, 'failure': failure, 'ending': ending,
               '_msg_id': self.msg_id}
        rpc_amqp._add_unique_id(msg)
        unique_id = msg[rpc_amqp.UNIQUE_ID]

        LOG.debug("sending reply msg_id: %(msg_id)s "
                  "reply queue: %(reply_q)s "
                  "time elapsed: %(elapsed)ss", {
                      'msg_id': self.msg_id,
                      'unique_id': unique_id,
                      'reply_q': self.reply_q,
                      'elapsed': self.stopwatch.elapsed()})
        conn.direct_send(self.reply_q, rpc_common.serialize_msg(msg))
Exemple #46
0
    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))
Exemple #47
0
    def reply(self, reply=None, failure=None, log_failure=True):
        if failure is not None:
            failure = rpc_common.serialize_remote_exception(
                failure, log_failure)
        message_reply = {
            zmq_names.FIELD_TYPE: zmq_names.REPLY_TYPE,
            zmq_names.FIELD_REPLY: reply,
            zmq_names.FIELD_FAILURE: failure,
            zmq_names.FIELD_LOG_FAILURE: log_failure,
            zmq_names.FIELD_ID: self.request.proxy_reply_id,
            zmq_names.FIELD_MSG_ID: self.request.message_id
        }

        LOG.debug("Replying %s", (str(self.request.message_id)))

        self.received = True
        self.reply_socket.send(self.reply_id, zmq.SNDMORE)
        self.reply_socket.send(b'', zmq.SNDMORE)
        if self.request.proxy_reply_id:
            self.reply_socket.send_string(zmq_names.REPLY_TYPE, zmq.SNDMORE)
            self.reply_socket.send(self.request.proxy_reply_id, zmq.SNDMORE)
            self.reply_socket.send(b'', zmq.SNDMORE)
        self.reply_socket.send_pyobj(message_reply)
        self.poller.resume_polling(self.reply_socket)
    def _do(self):
        """Look for a new RPC call and serve it"""
        # Get all the messages in queue
        msgs = self.RPC.query.all()
        for msg in msgs:
            # Find the first msg marked as enqueued.

            if msg.working and \
                    (self.current_time_seconds() - self.millisec_to_sec(msg.updated))\
                    > self.conf.messaging_server.response_timeout:
                msg.status = message.Message.ENQUEUED
                msg.update(condition=self.working_status_condition)

            if not msg.enqueued:
                continue
            if 'plan_name' in msg.ctxt.keys():
                LOG.info('Plan name: {}'.format(msg.ctxt['plan_name']))
            elif 'plan_name' in msg.args.keys():
                LOG.info('Plan name: {}'.format(msg.args['plan_name']))

            # Change the status to WORKING (operation with a lock)
            msg.status = message.Message.WORKING
            msg.owner = socket.gethostname()
            # All update should have a condition (status == enqueued)
            _is_updated = msg.update(condition=self.enqueued_status_condition)

            if not _is_updated or 'FAILURE' in _is_updated:
                continue

            # RPC methods must not start/end with an underscore.
            if msg.method.startswith('_') or msg.method.endswith('_'):
                error_msg = _LE("Method {} must not start or end"
                                "with underscores").format(msg.method)
                self._log_error_and_update_msg(msg, error_msg)
                return

            # The first endpoint that supports the method wins.
            method = None
            for endpoint in self.endpoints:
                if msg.method not in dir(endpoint):
                    continue
                endpoint_method = getattr(endpoint, msg.method)
                if callable(endpoint_method):
                    method = endpoint_method
                    if self.conf.messaging_server.debug:
                        LOG.debug("Message {} method {} is "
                                  "handled by endpoint {}".format(
                                      msg.id, msg.method,
                                      method.__str__.__name__))
                    break
            if not method:
                error_msg = _LE("Message {} method {} unsupported "
                                "in endpoints.").format(msg.id, msg.method)
                self._log_error_and_update_msg(msg, error_msg)
                return

            # All methods must take a ctxt and args param.
            if inspect.getargspec(method).args != ['self', 'ctx', 'arg']:
                error_msg = _LE("Method {} must take three args: "
                                "self, ctx, arg").format(msg.method)
                self._log_error_and_update_msg(msg, error_msg)
                return

            LOG.info(
                _LI("Message {} method {} received").format(
                    msg.id, msg.method))
            if self.conf.messaging_server.debug:
                LOG.debug(
                    _LI("Message {} method {} context: {}, args: {}").format(
                        msg.id, msg.method, msg.ctxt, msg.args))

            failure = None
            try:

                # Add the template to conductor.plan table
                # Methods return an opaque dictionary
                result = method(msg.ctxt, msg.args)

                # FIXME(jdandrea): Remove response/error and make it opaque.
                # That means this would just be assigned result outright.
                msg.response = result.get('response', result)
            except Exception:
                # Current sys.exc_info() content can be overridden
                # by another exception raised by a log handler during
                # LOG.exception(). So keep a copy and delete it later.
                failure = sys.exc_info()

                # Do not log details about the failure here. It will
                # be returned later upstream.
                LOG.exception(_LE('Exception during message handling'))

            try:
                if failure is None:
                    msg.status = message.Message.COMPLETED
                else:
                    msg.failure = \
                        rpc_common.serialize_remote_exception(failure)
                    msg.status = message.Message.ERROR
                LOG.info(
                    _LI("Message {} method {}, status: {}").format(
                        msg.id, msg.method, msg.status))
                if self.conf.messaging_server.debug:
                    LOG.debug("Message {} method {}, response: {}".format(
                        msg.id, msg.method, msg.response))

                _is_success = 'FAILURE'
                while 'FAILURE' in _is_success and (
                        self.current_time_seconds() -
                        self.millisec_to_sec(msg.updated)
                ) <= self.conf.messaging_server.response_timeout:
                    _is_success = msg.update()
                    LOG.info(
                        _LI("updating the message status from working to {}, "
                            "atomic update response from MUSIC {}").format(
                                msg.status, _is_success))

            except Exception:
                LOG.exception(
                    _LE("Can not send reply for message {} "
                        "method {}").format(msg.id, msg.method))
            finally:
                # Remove circular object reference between the current
                # stack frame and the traceback in exc_info.
                del failure