Exemple #1
0
def rmr_rcvall_msgs_raw(mrc, pass_filter=[]):
    """
    Same as rmr_rcvall_msgs, but the raw sbuf is also returned.
    Useful, for example, if rts is to be used.

    Parameters
    ----------
        mrc: ctypes c_void_p
            Pointer to the RMR context

        pass_filter: list (optional)
            The message type(s) to capture.

    Returns
    -------
    list of tuple:$
       List of tuples [(S, sbuf),...] where S is a message summary and sbuf is the raw message$
       the caller is responsible for calling rmr.rmr_free_msg(sbuf) for each sbuf afterwards to prevent memory leaks.
    """

    new_messages = []

    while True:
        mbuf = rmr.rmr_alloc_msg(mrc, 4096)  # allocate buffer to have something for a return status
        mbuf = rmr.rmr_torcv_msg(mrc, mbuf, 0)  # set the timeout to 0 so this doesn't block!!
        summary = rmr.message_summary(mbuf)
        if summary["message status"] != "RMR_OK":
            break

        if len(pass_filter) == 0 or mbuf.contents.mtype in pass_filter:  # no filter, or passes; capture it
            new_messages.append((summary, mbuf))
        else:
            rmr.rmr_free_msg(mbuf)

    return new_messages
Exemple #2
0
 def _send_msg(self, pay, mtype, subid):
     """
     sends a msg
     """
     for _ in range(0, RETRY_TIMES):
         sbuf = rmr.rmr_alloc_msg(self.mrc,
                                  len(pay),
                                  payload=pay,
                                  gen_transaction_id=True,
                                  mtype=mtype,
                                  sub_id=subid)
         sbuf.contents.sub_id = subid
         pre_send_summary = rmr.message_summary(sbuf)
         sbuf = rmr.rmr_send_msg(self.mrc, sbuf)  # send
         if self._assert_good_send(sbuf, pre_send_summary):
             rmr.rmr_free_msg(sbuf)  # free
             break
Exemple #3
0
def test_rcv_all():
    """
    test the ability to receive a batch of queued messages.
    """
    pay_fmt = "send to ring msg: %d"  # dynamic message format with counter

    send_burst(MRC_SEND,
               pay_fmt)  # send a bunch of 13 messages that should queue
    time.sleep(1)  # ensure underlying transport gets cycles to send/receive

    bundle = helpers.rmr_rcvall_msgs(
        MRC_BUF_RCV
    )  # use the buffered receiver to read all with a single call
    assert len(bundle) == 13

    for i, ms in enumerate(bundle):
        ms = bundle[
            i]  # validate each summary returned, and ordering preserved
        assert ms["message state"] == 0
        expected_pay = bytes(pay_fmt % i, "UTF-8")
        assert ms["payload"] == expected_pay

    send_burst(
        MRC_SEND, pay_fmt, mtype=1,
        num=10)  # send a second round with msg types 1 and 2 to test filter
    send_burst(MRC_SEND, pay_fmt, mtype=2, num=8)
    send_burst(MRC_SEND, pay_fmt, mtype=1, num=5)
    send_burst(MRC_SEND, pay_fmt, mtype=2, num=4,
               counter=8)  # total of 12 messages with type 2 should be queued
    time.sleep(1)  # ensure underlying transport gets cycles to send/receive

    bundle = helpers.rmr_rcvall_msgs_raw(
        MRC_BUF_RCV, [2])  # receive only message type 2 messages
    assert len(
        bundle) == 12  # we should only get the second batch of 12 messages

    for i, (ms, sbuf) in enumerate(bundle):  # test the raw version
        test_summary = rmr.message_summary(sbuf)
        assert test_summary == ms
        assert ms["message state"] == 0  # all should be OK
        assert ms["message type"] == 2  # only mtype 2 should have been received
        expected_pay = bytes(
            pay_fmt % i,
            "UTF-8")  # ordering should still jive with the counter
        assert ms["payload"] == expected_pay
        rmr.rmr_free_msg(sbuf)
Exemple #4
0
def rmr_rcvall_msgs(mrc, pass_filter=[]):
    """
    Assemble an array of all messages which can be received without
    blocking.  Effectively draining the message queue if RMR is started
    in mt-call mode, or draining any waiting TCP buffers.  If the
    pass_filter parameter is supplied it is treated as one or more message
    types to accept (pass through). Using the default, an empty list, results
    in messages with any type being captured.

    Parameters
    ----------
        mrc: ctypes c_void_p
            Pointer to the RMR context

        pass_filter: list (optional)
            The message type(s) to capture.

    Returns
    -------
        list of dict
        List of message summaries, one for each message captured.
    """

    new_messages = []
    mbuf = rmr.rmr_alloc_msg(mrc, 4096)  # allocate buffer to have something for a return status

    while True:
        mbuf = rmr.rmr_torcv_msg(mrc, mbuf, 0)  # set the timeout to 0 so this doesn't block!!

        summary = rmr.message_summary(mbuf)
        if summary["message status"] != "RMR_OK":  # ok indicates msg received, stop on all other states
            break

        if len(pass_filter) == 0 or summary["message type"] in pass_filter:  # no filter, or passes; capture it
            new_messages.append(summary)

    rmr.rmr_free_msg(mbuf)  # must free message to avoid leak
    return new_messages
Exemple #5
0
    def loop(self):
        """
        This loop runs forever, and has 3 jobs:
        - send out any messages that have to go out (create instance, delete instance)
        - read a1s mailbox and update the status of all instances based on acks from downstream policy handlers
        - clean up the database (eg delete the instance) under certain conditions based on those statuses (NOT DONE YET)
        """
        # loop forever
        mdc_logger.debug("Work loop starting")
        while self.keep_going:

            # send out all messages waiting for us
            while not self.instance_send_queue.empty():
                work_item = self.instance_send_queue.get(block=False,
                                                         timeout=None)
                payload = json.dumps(
                    messages.a1_to_handler(*work_item)).encode("utf-8")
                self._send_msg(payload, A1_POLICY_REQUEST, work_item[1])

            # read our mailbox
            for (msg, sbuf) in self.rcv_func():
                # TODO: in the future we may also have to catch SDL errors
                try:
                    mtype = msg["message type"]
                except (KeyError, TypeError, json.decoder.JSONDecodeError):
                    mdc_logger.debug(
                        "Dropping malformed policy ack/query message: {0}".
                        format(msg))

                if mtype == A1_POLICY_RESPONSE:
                    try:
                        # got a policy response, update status
                        pay = json.loads(msg["payload"])
                        data.set_policy_instance_status(
                            pay["policy_type_id"], pay["policy_instance_id"],
                            pay["handler_id"], pay["status"])
                        mdc_logger.debug(
                            "Successfully received status update: {0}".format(
                                pay))
                    except (PolicyTypeNotFound, PolicyInstanceNotFound):
                        mdc_logger.debug(
                            "Received a response  for a non-existent instance")
                    except (KeyError, TypeError, json.decoder.JSONDecodeError):
                        mdc_logger.debug(
                            "Dropping malformed policy ack message: {0}".
                            format(msg))

                elif mtype == A1_POLICY_QUERY:
                    try:
                        # got a query, do a lookup and send out all instances
                        pti = json.loads(msg["payload"])["policy_type_id"]
                        mdc_logger.debug("Received query for: {0}".format(pti))
                        for pii in data.get_instance_list(pti):
                            instance = data.get_policy_instance(pti, pii)
                            payload = json.dumps(
                                messages.a1_to_handler(
                                    "CREATE", pti, pii,
                                    instance)).encode("utf-8")
                            sbuf = self._rts_msg(payload, sbuf,
                                                 A1_POLICY_REQUEST)
                    except (PolicyTypeNotFound, PolicyInstanceNotFound):
                        mdc_logger.debug(
                            "Received a query for a non-existent type: {0}".
                            format(msg))
                    except (KeyError, TypeError, json.decoder.JSONDecodeError):
                        mdc_logger.debug(
                            "Dropping malformed policy query message: {0}".
                            format(msg))

                else:
                    mdc_logger.debug(
                        "Received message type {0} but A1 does not handle this"
                        .format(mtype))

                # we must free each sbuf
                rmr.rmr_free_msg(sbuf)

            self.last_ran = time.time()
            time.sleep(1)