Example #1
0
def actually_run_the_daemon(options):
    verbose = options.verbose
    chan = Channel(BUFSIZE)
    string = None
    (cnx, addr) = (None, None)
    string = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    string.bind(('', options.port))
    string.listen(1)
    try:
        running = True
        while running:
            print("\nWAITING FOR CONNECTION")              # DEBUG
            cnx, addr = string.accept()
            try:
                accept_msg = "CONNECTION FROM %s" % str(addr)
                if verbose:
                    print(accept_msg)
                print("BRANCH TO options.accessLog.log()")
                sys.stdout.flush()
                options.access_log.log(accept_msg)
                print("BACK FROM options.access.log()")
                sys.stdout.flush()

                while 1:
                    chan.clear()

#                   print "BRANCH TO recvFromCnx"  ; sys.stdout.flush()
                    msg_ndx = recv_from_cnx(cnx, chan)  # may raise exception

                    (msg, real_ndx) = MsgImpl.read(chan, STR_OBJ_MODEL)
#                   print "  MSG_NDX: CALCULATED %s, REAL %s" % (
#                                             msgNdx, realNdx)
                    # switch on message type
                    if msg_ndx == 0:
                        print("GOT ZONE MISMATCH MSG")
                        print("    timestamp      %s" % msg.timestamp)
                        print("    seqNbr         %s" % msg.seq_nbr)
                        print("    zoneName       %s" % msg.zone_name)
                        print("    expectedSerial %s" % msg.expected_serial)
                        print("    actualSerial   %s" % msg.actual_serial)
                        text =\
                            "mismatch, domain %s: expected serial %s, got %s" % (
                                msg.zone_name, msg.expected_serial, msg.actual_serial)
                        options.alertz_log.log(text)

                    elif msg_ndx == 1:
                        # timestamp, seqNb
                        print("GOT CORRUPT LIST MSG")
                        print("    timestamp      %s" % msg.timestamp)
                        print("    seqNbr         %s" % msg.seq_nbr)
                        text = "corrupt list: %s" % (msg.seq_nbr)
                        options.alertz_log.log(text)

                    elif msg_ndx == 2:
                        # has one field, remarks
                        print("GOT SHUTDOWN MSG")
                        print("    remarks        %s" % msg.remarks)
                        running = False
                        string.close()
                        # XXX STUB: log the message
                        text = "shutdown: %s" % (msg.remarks)
                        options.alertz_log.log(text)

                    cnx.close()
                    break                   # permit only one message/cnx

            except KeyboardInterrupt as k_exc:
                print("<keyboard interrupt received while connection open>")
                if cnx:
                    cnx.close()
                running = False

    except KeyboardInterrupt as k_exc:
        print("<keyboard interrupt received while listening>")
        # listening socket will be closed
    finally:
        if cnx:
            cnx.close()
        if string:
            string.close()

        # COMMENTING THIS OUT PREVENTS SEGFAULT ON STOCKTON ---------
#       if options.logMgr is not None:
#           options.logMgr.close()
#           options.logMgr = None
        # END COMMENTING OUT ----------------------------------------

        if options.lock_mgr is not None:
            options.lock_mgr.unlock()
            options.lock_mgr = None
Example #2
0
def actually_run_the_daemon(options):
    """
    All necessary resources having been obtained, actually runs the
    daemon.
    """
    verbose = options.verbose
    chan = Channel(BUFSIZE)
    skt = None
    (cnx, addr) = (None, None)
    skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    skt.bind(('', options.port))
    skt.listen(1)
    try:
        running = True
        while running:
            print("\nWAITING FOR CONNECTION")              # DEBUG
            cnx, addr = skt.accept()
            try:
                accept_msg = "CONNECTION FROM %s" % str(addr)
                if verbose:
                    print(accept_msg)
                print("BRANCH TO options.accessLog.log()")
                sys.stdout.flush()
                options.access_log.log(accept_msg)
                print("BACK FROM options.access.log()")
                sys.stdout.flush()

                while True:
                    chan.clear()

#                   print "BRANCH TO recvFromCnx"  ; sys.stdout.flush()
                    msg_ndx = recv_from_cnx(cnx, chan)  # may raise exception

                    # XXX s_obj_model (the former sOM) is UNDEFINIED here
                    (msg, real_ndx) = MsgImpl.read(chan, s_obj_model)
                    # DEBUG
                    print("  MSG_NDX: CALCULATED %s, REAL %s" % (
                        msg_ndx, real_ndx))
                    # END
                    # switch on message type
                    if msg_ndx == 0:
                        print("GOT ZONE MISMATCH MSG")
                        # pylint: disable=no-member
                        print("    timestamp       %s" % msg.timestamp)
                        # pylint: disable=no-member
                        print("    seq_nbr         %s" % msg.seq_nbr)
                        # pylint: disable=no-member
                        print("    zone_name       %s" % msg.zone_name)
                        # pylint: disable=no-member
                        print("    expected_serial %s" % msg.expected_serial)
                        # pylint: disable=no-member
                        print("    /Serial   %s" % msg.actual_serial)
                        # pylint: disable=no-member
                        text = \
                            "mismatch, domain %s: expected serial %s, got %s" % (
                                msg.zone_name, msg.expected_serial,
                                msg.actual_serial)
                        options.alertz_log.log(text)

                    elif msg_ndx == 1:
                        # timestamp, seq_nbr
                        print("GOT CORRUPT LIST MSG")
                        # pylint: disable=no-member
                        print("    timestamp      %s" % msg.timestamp)
                        # pylint: disable=no-member
                        print("    seq_nbr         %s" % msg.seq_nbr)
                        # pylint: disable=no-member
                        text = "corrupt list: %s" % (msg.seq_nbr)
                        options.alertz_log.log(text)

                    elif msg_ndx == 2:
                        # has one field, remarks
                        print("GOT SHUTDOWN MSG")
                        # pylint: disable=no-member
                        print("    remarks        %s" % msg.remarks)
                        running = False
                        skt.close()
                        # XXX STUB: log the message
                        # pylint: disable=no-member
                        text = "shutdown: %s" % (msg.remarks)
                        options.alertz_log.log(text)

                    cnx.close()
                    break                   # permit only one message/cnx

            except KeyboardInterrupt:
                print("<keyboard interrupt received while connection open>")
                if cnx:
                    cnx.close()
                running = False

    except KeyboardInterrupt:
        print("<keyboard interrupt received while listening>")
        # listening socket will be closed
    finally:
        if cnx:
            cnx.close()
        if skt:
            skt.close()
    def do_test_ack(self, text):
        # Create a channel ------------------------------------------
        # its buffer will be used for both serializing # the instance
        # data and, by deserializing it, for creating a second instance.
        chan = Channel(BUFSIZE)
        buf = chan.buffer
        self.assertEqual(BUFSIZE, len(buf))

        # create the ack_msg_cls class ------------------------------
        ack_spec = self.s_obj_model.msgs[0]
        msg_name = ack_spec.name
        self.assertEqual('ack', msg_name)

        ack_msg_cls = make_msg_class(self.s_obj_model, 'ack')

        # create a message instance ---------------------------------
        values = [text]
        ack = ack_msg_cls(values)
        (_) = tuple(values)             # WAS text1

        # pylint: disable=no-member
        self.assertEqual(ack_spec.name, ack.name)
        # we don't have any nested enums or messages
        # pylint: disable=no-member
        self.assertEqual(0, len(ack.enums))
        # pylint: disable=no-member
        self.assertEqual(0, len(ack.msgs))

        # pylint: disable=no-member
        self.assertEqual(1, len(ack.fieldClasses))
        self.assertEqual(1, len(ack))        # number of fields in instance
        for ndx, value in enumerate(ack):
            self.assertEqual(values[ndx], value)

        # verify fields are accessible in the object ----------------
        # pylint: disable=no-member
        self.assertEqual(text, ack.text)

        # serialize the object to the channel -----------------------
        buf = chan.buffer
        chan.clear()
        nnn = ack.write_stand_alone(chan)
        self.assertEqual(0, nnn)                         # returns msg index
        chan.flip()

        print("ACTUAL LENGTH OF SERIALIZED ACK OBJECT: %u" % chan.limit)

        # deserialize the channel, making a clone of the message ----
        (readback, _) = MsgImpl.read(chan, self.s_obj_model)
        self.assertIsNotNone(readback)
        self.assertTrue(ack.__eq__(readback))

        # produce another message from the same values --------------
        ack2 = ack_msg_cls(values)
        chan2 = Channel(BUFSIZE)
        nnn = ack2.write_stand_alone(chan2)
        chan2.flip()
        (copy2, nn3) = ack_msg_cls.read(chan2, self.s_obj_model)
        self.assertTrue(ack.__eq__(readback))
        self.assertTrue(ack2.__eq__(copy2))
        self.assertEqual(nnn, nn3)                # GEEP
    def test_le_msg_serialization(self):

        # parse the protoSpec

        # XXX highly questionable:
        #   verify that this adds 1 (msg) + 5 (field count) to the number
        #   of entries in getters, putters, etc

        self.assertIsNotNone(self.s_obj_model)
        self.assertTrue(isinstance(self.s_obj_model, M.ProtoSpec))
        self.assertEqual('org.xlattice.ringd', self.s_obj_model.name)

        self.assertEqual(0, len(self.s_obj_model.enums))
        self.assertEqual(11, len(self.s_obj_model.msgs))
        self.assertEqual(0, len(self.s_obj_model.seqs))

        # XXX a foolish test, but we use the variable 'leMsgSpec' below
        le_msg_spec = self.s_obj_model.msgs[5]
        msg_name = le_msg_spec.name
        self.assertEqual('logEntry', msg_name)

        # Create a channel ------------------------------------------
        # its buffer will be used for both serializing # the instance
        # data and, by deserializing it, for creating a second instance.
        chan = Channel(BUFSIZE)
        buf = chan.buffer
        self.assertEqual(BUFSIZE, len(buf))

        # create the LogEntryMsg class ------------------------------
        log_entry_msg = make_msg_class(self.s_obj_model, 'logEntry')

        # create a message instance ---------------------------------
        values = self.le_msg_values()        # a list of quasi-random values
        le_msg = log_entry_msg(values)
        (timestamp, key, length, node_id, src, path) = tuple(values)

        # DEBUG
        print("TIMESTAMP = %d" % timestamp)
        print("KEY       = %s" % key)
        print("LENGTH    = %s" % length)
        # END

        # pylint: disable=no-member
        self.assertEqual(le_msg_spec.name, le_msg.name)
        # we don't have any nested enums or messages
        self.assertEqual(0, len(le_msg.enums))
        self.assertEqual(0, len(le_msg.msgs))

        # pylint: disable=no-member
        self.assertEqual(6, len(le_msg.fieldClasses))
        self.assertEqual(6, len(le_msg))        # number of fields in instance
        for ndx, value in enumerate(le_msg):
            self.assertEqual(value, values[ndx])

        # verify fields are accessible in the object ----------------
        #(timestamp, key, length, nodeID, src, path) = tuple(values)
        self.assertEqual(timestamp, le_msg.timestamp)
        # pylint: disable=no-member
        self.assertEqual(key, le_msg.key)
        # pylint: disable=no-member
        self.assertEqual(length, le_msg.length)
        # pylint: disable=no-member
        self.assertEqual(node_id, le_msg.node_id)
        # pylint: disable=no-member
        self.assertEqual(src, le_msg.src)
        # pylint: disable=no-member
        self.assertEqual(path, le_msg.path)

        # serialize the object to the channel -----------------------
        buf = chan.buffer
        chan.clear()
        nnn = le_msg.write_stand_alone(chan)
        self.assertEqual(5, nnn)                         # returns msg index
        old_position = chan.position                     # TESTING flip()
        chan.flip()
        self.assertEqual(old_position, chan.limit)      # TESTING flip()
        self.assertEqual(0, chan.position)   # TESTING flip()
        actual = chan.limit

        print("ACTUAL LENGTH OF SERIALIZED OBJECT: %u" % actual)

        # deserialize the channel, making a clone of the message ----
        (readback, _) = MsgImpl.read(chan, self.s_obj_model)
        self.assertIsNotNone(readback)
        self.assertTrue(le_msg.__eq__(readback))

        # produce another message from the same values --------------
        le_msg2 = log_entry_msg(values)
        chan2 = Channel(BUFSIZE)
        nnn = le_msg2.write_stand_alone(chan2)
        chan2.flip()
        (copy2, nn3) = log_entry_msg.read(chan2, self.s_obj_model)
        self.assertTrue(le_msg.__eq__(readback))
        self.assertTrue(le_msg2.__eq__(copy2))
        self.assertEqual(nnn, nn3)                # GEEP
    def test_zone_mismatch_msg(self):
        # DEBUG
        print("\nTEST_ZONE_MISMATCH_MSG")
        # END

        # from setUp(): =============================================

        # end stuff from setup ======================================

        # -----------------------------------------------------------
        # XXX This code has been crudely hacked from another test
        # module, and so needs careful review
        # -----------------------------------------------------------

        # verify that this adds 1 (msg) + 3 (field count) to the number
        # of entries in getters, putters, etc

        self.assertIsNotNone(self.str_obj_model)
        self.assertTrue(isinstance(self.str_obj_model, M.ProtoSpec))
        self.assertEqual('org.xlattice.alertz', self.str_obj_model.name)

        self.assertEqual(0, len(self.str_obj_model.enums))
        self.assertEqual(16, len(self.str_obj_model.msgs))
        self.assertEqual(0, len(self.str_obj_model.seqs))

        msg_spec = self.str_obj_model.msgs[0]
        msg_name = msg_spec.name
        self.assertEqual('zoneMismatch', msg_name)

        # Create a channel ------------------------------------------
        # its buffer will be used for both serializing # the instance
        # data and, by deserializing it, for creating a second instance.
        chan = Channel(BUFSIZE)
        buf = chan.buffer
        self.assertEqual(BUFSIZE, len(buf))

        # create the ZoneMismatchMsg class ------------------------------
        zone_mismatch_msg_cls = make_msg_class(self.str_obj_model, msg_name)

        # create a message instance ---------------------------------
        values = self.zone_mismatch_fields()        # list of quasi-random values
        zmm_msg = zone_mismatch_msg_cls(values)

        self.assertEqual(msg_spec.name, zmm_msg._name)
        # we don't have any nested enums or messages
        self.assertEqual(0, len(zmm_msg.enums))
        self.assertEqual(0, len(zmm_msg.msgs))

        self.assertEqual(5, len(zmm_msg.field_classes))
        self.assertEqual(5, len(zmm_msg))        # number of fields in instance
        self.assertEqual(values[0], zmm_msg.timestamp)
        self.assertEqual(values[1], zmm_msg.seq_nbr)
        self.assertEqual(values[2], zmm_msg.zone_name)
        self.assertEqual(values[3], zmm_msg.expected_serial)
        self.assertEqual(values[4], zmm_msg.actual_serial)

        # serialize the object to the channel -----------------------

        # XXX WRITE HEADER FIRST!

        # DEBUG
        print("DIR (ZMM_MSG): ", end=' ')
        print(dir(zmm_msg))
        # END
        zmm_msg.write_stand_alone(chan)
        chan.flip()

        # deserialize the channel, making a clone of the message ----
        (read_back, nn2) = MsgImpl.read(chan, self.str_obj_model)
        self.assertIsNotNone(read_back)

        # DEBUG
        print("position after mis-match read back is %d" % chan.position)
        # END

        # verify that the messages are identical --------------------
        self.assertTrue(zmm_msg.__eq__(read_back))

        # produce another message from the same values --------------
        zmm_msg2 = zone_mismatch_msg_cls(values)
        chan2 = Channel(BUFSIZE)
        zmm_msg2.write_stand_alone(chan2)
        chan2.flip()

        (copy2, nn3) = MsgImpl.read(chan2, self.str_obj_model)
        self.assertTrue(zmm_msg.__eq__(copy2))
        self.assertTrue(zmm_msg2.__eq__(copy2))       # GEEP
    def test_shutdown_msg(self):
        # DEBUG
        print("\nTEST_SHUTDOWN_MSG")
        # END

        # -----------------------------------------------------------
        # XXX This code has been crudely hacked from another test
        # module, and so needs careful review
        # -----------------------------------------------------------

        # verify that this adds 1 (msg) + 3 (field count) to the number
        # of entries in getters, writeStandAlones, etc

        msg_spec = self.str_obj_model.msgs[2]          # <------
        msg_name = msg_spec.name
        self.assertEqual('shutdown', msg_name)

        # Create a channel ------------------------------------------
        # its buffer will be used for both serializing # the instance
        # data and, by deserializing it, for creating a second instance.
        chan = Channel(BUFSIZE)
        buf = chan.buffer
        self.assertEqual(BUFSIZE, len(buf))

        # create the CorruptListMsg class ------------------------------
        shutdown_msg_cls = make_msg_class(self.str_obj_model, msg_name)

        # create a message instance ---------------------------------
        values = [RNG.next_file_name(8), ]  # list of quasi-random values
        sd_msg = shutdown_msg_cls(values)

        self.assertEqual(msg_name, sd_msg._name)
        # we don't have any nested enums or messages
        self.assertEqual(0, len(sd_msg.enums))
        self.assertEqual(0, len(sd_msg.msgs))

        self.assertEqual(1, len(sd_msg.field_classes))   # <---
        self.assertEqual(1, len(sd_msg))        # number of fields in instance
        self.assertEqual(values[0], sd_msg.remarks)

        # serialize the object to the channel -----------------------
        sd_msg.write_stand_alone(chan)
        chan.flip()

        # deserialize the channel, making a clone of the message ----
        (read_back, nn5) = MsgImpl.read(chan, self.str_obj_model)
        self.assertIsNotNone(read_back)

        # DEBUG
        print("position after shutdown read back is %d" % chan.position)
        # END

        # verify that the messages are identical --------------------
        self.assertTrue(sd_msg.__eq__(read_back))

        # produce another message from the same values --------------
        sd_msg2 = shutdown_msg_cls(values)
        chan2 = Channel(BUFSIZE)
        sd_msg2.write_stand_alone(chan2)
        chan2.flip()

        (copy2, nn6) = MsgImpl.read(chan2, self.str_obj_model)
        self.assertTrue(sd_msg.__eq__(copy2))
        self.assertTrue(sd_msg2.__eq__(copy2))       # GEEP GEEP GEEP
    def test_the_daemon(self):
        chan = Channel(BUFSIZE)
        chan.clear()        # XXX should be guaranteed on new channel

        msg_count = 8 + RNG.next_int16(25)   # so 8..32
        # DEBUG
        print("MSG_COUNT = %u" % msg_count)
        # END

        # set up options ----------------------------------
        now = int(time.time())
        pgm_name_and_version = "testWithDummyClient v%s %s" % (
            __version__, __version_date__)
        with open('/etc/hostname', 'r') as file:
            this_host = file.read().strip()

        options = {}                           # a namespace, so to speak
        options['ec2Host'] = False
        options['justShow'] = False
        options['log_dir'] = 'logs'
        options['pgm_name_and_version'] = pgm_name_and_version
        options['port'] = 55555
        options['showTimestamp'] = False
        options['showVersion'] = False
        options['testing'] = True
        options['this_host'] = this_host
        options['timestamp'] = now
        options['verbose'] = False
        ns_ = Namespace(options)

        # clear the log files (so delete any files under logs/) -----
        self.do_clear_logs(ns_)

        # start the daemon --------------------------------
        daemon_t = threading.Thread(target=run_the_daemon, args=(ns_,))
        daemon_t.start()

        # give the daemon time to wake up  --------------------------
        time.sleep(0.15)    # XXX without this we get an abort saying
        # that libev cannot allocate (2G - 16)B

        # start sending (some fixed number of ) messages ------------
        msgs_sent = []
        for nnn in range(msg_count):
            msg = self.next_zone_mismatch_msg()
            seq_nbr_field = msg[1]
            # XXX by name would be better!
            self.assertEqual(nnn, seq_nbr_field.value)

            # serialize msg into the channel
            chan.clear()
            msg.write_stand_alone(chan)
            chan.flip()

            # send the msg to the daemon ------------------
            skt = send_to_end_point(chan, '127.0.0.1', 55555)
            time.sleep(0.05)
            skt.close()
            msgs_sent.append(msg)

            # DEBUG
            print("MSG %d HAS BEEN SENT" % nnn)
            # END

        self.assertEqual(msg_count, len(msgs_sent))

        # delay a few ms --------------------------------------------
        time.sleep(0.05)

        # build and send shutdown msg -------------------------------
        msg = self.next_shutdown_msg()
        chan.clear()
        msg.write_stand_alone(chan)
        chan.flip()

        skt = send_to_end_point(chan, '127.0.0.1', 55555)
        # DEBUG
        print("SHUTDOWN MSG HAS BEEN SENT")
        # END

        # delay a few ms --------------------------------------------
        time.sleep(0.05)
        skt.close()

        # join the daemon thread ------------------------------------
        time.sleep(0.05)
        daemon_t.join()