Esempio n. 1
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, ["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)
Esempio n. 2
0
def _wait_for_reply(msg_id, token, tenant_id, timeout):
    _ensure_tenant_lock_exists(tenant_id)

    LOG.debug('Waiting for reply to %s, type - %s' % (msg_id, type(msg_id)))

    with tenant_lock[tenant_id]:
        tenant_awaiters[tenant_id][msg_id] = Queue.Queue()

        if not tenant_poller[tenant_id]:
            try:
                t = threading.Thread(target=_poll,
                                     name='%s-messaging-poller' % tenant_id,
                                     args=(token, tenant_id))

                tenant_poller[tenant_id] = t

                t.start()
            except BaseException:
                del tenant_awaiters[tenant_id][msg_id]
                raise

    try:
        queue = tenant_awaiters[tenant_id][msg_id]
        envelope = queue.get(block=True, timeout=timeout)
    finally:
        with tenant_lock[tenant_id]:
            del tenant_awaiters[tenant_id][msg_id]

    if envelope['failure']:
        exc = rpc_common.deserialize_remote_exception(envelope['failure'])
        raise exc

    return envelope['body']
Esempio n. 3
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
Esempio n. 4
0
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")
Esempio n. 5
0
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")
Esempio n. 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
Esempio n. 7
0
 def _process_data(self, data):
     result = None
     self.msg_id_cache.check_duplicate_message(data)
     if data['failure']:
         failure = data['failure']
         result = rpc_common.deserialize_remote_exception(self._conf,
                                                          failure)
     elif data.get('ending', False):
         self._got_ending = True
     else:
         result = data['result']
     return result
Esempio n. 8
0
 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
Esempio n. 9
0
 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
Esempio n. 10
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)
        expected = {'code': 500,
                    'error': {'message': msg['error']['message'],
                              'traceback': None,
                              'type': 'RemoteError'},
                    'explanation': msg['explanation'],
                    'title': 'Internal Server Error'}
        self.assertEqual(expected, msg)
Esempio n. 11
0
 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)
Esempio n. 12
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)
        expected = {
            'code': 500,
            'error': {
                'message': msg['error']['message'],
                'traceback': None,
                'type': 'RemoteError'
            },
            'explanation': msg['explanation'],
            'title': 'Internal Server Error'
        }
        self.assertEqual(expected, msg)
Esempio n. 13
0
    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 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)
Esempio n. 15
0
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]
Esempio n. 16
0
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")
            _cast(addr, context, topic, payload, envelope=envelope)

            LOG.debug("Cast sent; Waiting reply")
            # Blocks until receives reply
            msg = msg_waiter.recv()
            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]