Ejemplo n.º 1
0
def main():
    frontend = "192.168.0.179"
    parser = argparse.ArgumentParser(prog="my_megazord_program")
    parser.add_argument(
        "-f",
        "--frontend",
        help='start with localshit -f "172.17.0.2" to add frontend')
    parser.add_argument(
        "-d",
        "--debug",
        help="start localhost and wait for VS Code debugger",
        action="store_true",
    )
    args = parser.parse_args()
    if args.frontend:
        frontend = args.frontend

    if args.debug:
        import debugpy

        debugpy.listen(5678)
        print("Waiting for debugger attach: %s" % os.getpid())
        debugpy.wait_for_client()

    logging.info("Frontend server is set to %s" % frontend)

    try:
        logging.info("starting manager...")
        _ = LocalsHitManager(frontend=frontend)
    except Exception as e:
        logging.error("Error while starting app: %s" % e)
        traceback.print_exc()
    def work_func(self):
        if self.election.isLeader:
            # only run content service if elected as leader
            if self.server.isRunning is False:
                # check if WebsocketServer is running
                try:
                    self.server.run_forever()
                    self.server.isRunning = True
                except Exception as e:
                    logging.error("Error while restarting server: %s" % e)
            else:
                if config["chuck_norris"] is True:
                    # optionally publish chuck norris quotes in a intervall
                    time_diff = time.time() - self.last_update
                    if time_diff >= config["quote_intervall"]:
                        logging.info("Content: publish new quote")
                        id, quote = self._get_quote("jokes.json")
                        data = "%s:%s:%s" % ("CO", id, quote)
                        self._replicate_and_send(data)

                        self.last_update = time.time()

        else:
            if self.server.isRunning is True:
                self.server.isRunning = False
                data = "%s:%s" % ("CL", "close server")
                self.server.send_message_to_all(data)
                self.server.shutdown()
                self.server.server_close()
                logging.info("Content: publish service stopped")
Ejemplo n.º 3
0
    def handle_heartbeat_message(self, addr, parts):
        # forward heartbeat message as it is, if not leader
        if self.election.isLeader is False:
            # check, if the heartbeat comes from the neighbour
            left_neighbour = self.hosts.get_neighbour(direction="left")
            right_neighbour = self.hosts.get_neighbour(direction="right")
            # cehck, if heartbeat comes from the right neighbour
            if addr[0] == right_neighbour:
                # forward message
                logging.info("Heartbeat: received. forward to %s" %
                             left_neighbour)
                new_message = "HB:%s:%s" % (parts[1], parts[2])
                self.socket_sender.send_message(new_message,
                                                left_neighbour,
                                                type="unicast")

                # note time of last heartbeat
                self.last_heartbeat_received = time.time()
            else:
                logging.error("Heartbeat: received from wrong neighbour")
        else:
            # if leader, have a look at the message if it is from himself
            if self.heartbeat_message:
                if parts[1] == self.heartbeat_message["id"]:
                    logging.info("Heartbeat: received own heartbeat from %s." %
                                 addr[0])
                    self.heartbeat_message = None
                    self.last_heartbeat_received = time.time()
Ejemplo n.º 4
0
    def watch_heartbeat(self):
        # check, when was the last heartbeat from the left neighbour?
        time_diff = time.time() - self.last_heartbeat_received
        if time_diff >= config["heartbeat_timeout"]:
            failed_neighbour = self.hosts.get_neighbour(direction="right")

            # if own address, then do nothing
            if failed_neighbour is not self.own_address:
                # remove failed neighbour
                logging.info("Heartbeat: nothing received from %s" %
                             failed_neighbour)
                self.hosts.remove_host(failed_neighbour)

                # send failure message as multicast
                new_message = "FF:%s:%s" % (failed_neighbour, self.own_address)
                self.socket_sender.send_message(new_message, type="multicast")

                # if this was leader, then start service announcement and leader election
                if failed_neighbour == self.election.elected_leader:
                    data = "%s:%s" % ("SA", self.own_address)
                    self.socket_sender.send_message(data, type="multicast")
                    time.sleep(1)
                    self.election.start_election(await_response=True)

            self.last_heartbeat_received = time.time()
Ejemplo n.º 5
0
    def announce_service(self, timeout=1):
        data = "%s:%s" % ("SA", self.own_address)
        self.socket_sender.send_message(data, type="multicast")
        logging.debug("SA: service announcement...")

        time.sleep(timeout)

        logging.info("SA: service announcement finished.")
        logging.info("Discovered hosts: %s" % self.hosts.sorted_ring)
Ejemplo n.º 6
0
    def _wait_for_response(self, timeout):

        # wait a leader is elected or timeout is over
        last_response = time.time()
        while self.elected_leader == "":
            if time.time() - last_response > timeout:
                logging.info("Leader Election: No response within timeout.")
                self.elected_leader = self.current_member_ip
                self.isLeader = True
                self.send_election_to_frontend()
                break
            time.sleep(0.1)
Ejemplo n.º 7
0
    def __init__(self, socket_sender, hosts, frontend):
        # first, mark member as non-participant
        self.participant = False
        self.socket_sender = socket_sender
        self.hosts = hosts
        self.current_member_ip = self.hosts.current_member_ip
        self.frontend_address = frontend
        self.isLeader = False
        self.got_response = False
        self.elected_leader = ""
        self.CONTENT_PORT = config.config["frontend_unicast_port"]

        logging.info("Election Class initialized")
Ejemplo n.º 8
0
    def start_election(self, await_response=False, timeout=1):
        logging.info("starting election")
        # mark self as a participant
        self.participant = True

        # send message to left neighbour
        message = "SE:%s:%s" % (self.current_member_ip, self.isLeader)
        neighbour = self.hosts.get_neighbour()

        self.socket_sender.send_message(message, neighbour, type="unicast")

        if await_response is True:
            self._wait_for_response(timeout)
    def message_received(self, client, server, message):
        """Callback function of WebsocketServer on message received from client"""
        logging.info("Content: Message from client %d: %s" %
                     (client["id"], message))

        parts = message.split(":")
        if parts[0] == "CR":
            new_message = "%s:%s:%s" % (parts[0], parts[1], parts[2])
            self._replicate_and_send(new_message)
            # self.server.send_message_to_all(new_message)
        elif parts[0] == "CO":
            quote_id = uuid.uuid4()
            data = "%s:%s:%s" % ("CO", quote_id, parts[1])
            self._replicate_and_send(data)
    def run(self):
        """ Initialize and start all threads. """
        thread_routines = [
            self.ack_handler,
            self.message_queue_handler,
            self.incoming_message_handler,
        ]

        count = 1
        for thread_routine in thread_routines:
            thread = threading.Thread(
                target=thread_routine,
                args=(self.running,),
                name="ReliableSocketWorker-%s" % count,
            )
            thread.daemon = True
            thread.start()
            logging.info("Thread %s started." % thread.name)
            self.threads.append(thread)
            count += 1
Ejemplo n.º 11
0
    def send_heartbeat(self):
        # create heartbeat message and send it every 3 sec.
        time_diff = time.time() - self.last_heartbeat_sent
        if time_diff >= config["heartbeat_intervall"]:
            self.heartbeat_message = {
                "id": str(uuid.uuid4()),
                "sender": self.own_address,
                "timestamp": time.time(),
            }

            new_message = "HB:%s:%s" % (
                self.heartbeat_message["id"],
                self.heartbeat_message["sender"],
            )

            self.socket_sender.send_message(new_message,
                                            self.hosts.get_neighbour(),
                                            type="unicast")

            logging.info("Heartbeat: send to %s" % self.hosts.get_neighbour())
            self.last_heartbeat_sent = time.time()
Ejemplo n.º 12
0
    def form_ring(self, own_ip):
        self.sorted_ring = self._form_ring(self.members)
        logging.info("Discovered hosts: %s" % self.sorted_ring)
        left_member = self.get_neighbour(direction="left")
        logging.info("Own IP: %s | left Neighbour: %s" % (own_ip, left_member))

        right_member = self.get_neighbour(direction="right")
        logging.info("Own IP: %s | right Neighbour: %s" % (own_ip, right_member))
Ejemplo n.º 13
0
    def forward_election_message(self, message):
        compare = utils.compare_adresses(message[1], self.current_member_ip)

        sender_id = message[1]
        leader_elected = eval(message[2])

        if leader_elected is False:
            if compare is CompareResult.LARGER:
                # 4.1 if id is larger, forward message to next member
                logging.info("Leader Election: Forward message as it is.")
                self.participant = True
                new_message = "SE:%s:%s" % (sender_id, False)
                self.socket_sender.send_message(new_message,
                                                self.hosts.get_neighbour(),
                                                type="unicast")
            elif compare is CompareResult.LOWER and self.participant is False:
                # 4.2 if id is smaller and not yes marked as participant, replace id and forward message to next member.
                self.participant = True
                logging.info("Leader Election: Forward message with own id.")
                new_message = "SE:%s:%s" % (self.current_member_ip, False)
                self.socket_sender.send_message(new_message,
                                                self.hosts.get_neighbour(),
                                                type="unicast")
            elif compare is CompareResult.LOWER and self.participant is True:
                # 4.3 if id is smaller but already participant, then discard message
                logging.info(
                    "Leader Election: Already participant of an election. Discard message."
                )
            elif compare is CompareResult.SAME:
                # 4.4 if message came back, set itself as leader and start second part algorithm. Inform others about elected leader.
                logging.info(
                    "Leader Election: Message came back to sender. Elected as leader."
                )
                self.participant = False
                self.isLeader = True
                self.elected_leader = self.current_member_ip
                # start second part of algorithm, inform others about election
                new_message = "SE:%s:%s" % (self.current_member_ip, True)
                self.socket_sender.send_message(new_message,
                                                self.hosts.get_neighbour(),
                                                type="unicast")
                self.send_election_to_frontend()
            else:
                logging.error("Leader Election: invalid result")
        else:
            # forward message about elected leader
            if sender_id is self.current_member_ip:
                logging.info(
                    "Leader Election: Message came back to sender. Election is over. Elected Leader: %s"
                    % self.elected_leader)
                self.send_election_to_frontend()
            elif self.participant is True:
                # elected message received. mark as non-participant, record election and forward message
                self.participant = False
                self.isLeader = False
                self.elected_leader = sender_id
                logging.info(
                    "Leader Election: Forward election message. Elected Leader: %s"
                    % self.elected_leader)
                new_message = "SE:%s:%s" % (message[1], message[2])
                self.socket_sender.send_message(new_message,
                                                self.hosts.get_neighbour(),
                                                type="unicast")
            else:
                logging.info(
                    "Leader Election: Election is over. Elected Leader: %s" %
                    self.elected_leader)
                self.send_election_to_frontend()
Ejemplo n.º 14
0
    def __init__(self, frontend=None):
        self.threads = []
        if frontend is None:
            self.frontend = config["frontend_server"]
        else:
            self.frontend = frontend
        self.running = True
        self.isActive = False
        logging.info("manager started!")

        # init socket connections
        self.socket_sender = SocketSender()

        self.own_address = utils.get_host_address()

        # init Ring
        self.hosts = Ring(self.own_address)
        # init service announcement object
        self.service_announcement = ServiceAnnouncement(
            self.hosts, self.socket_sender)
        # init election
        self.election = Election(self.socket_sender,
                                 self.hosts,
                                 frontend=frontend)
        # init database
        self.database = Database()

        # init ReliableSocketWorker
        self.reliable_socket = ReliableSocketWorker(
            self.running, self.hosts, port=config["reliable_socket"])

        try:
            self.reliable_socket.run()
            self.heartbeat = Heartbeat(self.hosts, self.election,
                                       self.socket_sender)

            # initiate service discovery thread
            self.discovery_thread = ServiceDiscovery(
                self.service_announcement,
                self.hosts,
                self.election,
                self.heartbeat,
                self.isActive,
            )
            self.discovery_thread.start()
            self.threads.append(self.discovery_thread)

            # start service announcement after discovery
            self.service_announcement.announce_service(
                timeout=config["announcement_timeout"])

            # start election after discovery
            self.election.start_election(await_response=True, timeout=1)

            self.discovery_thread.isActive = True

            # initiate Content Provider
            content_provider = ContentProvider(self.election,
                                               self.reliable_socket,
                                               self.database)
            content_provider.start()
            self.threads.append(content_provider)

            # monitor threads and exit on failing
            while self.running:
                for th in self.threads:
                    if not th.is_alive():
                        logging.info("Thread %s died." % th.__class__.__name__)
                        self.running = False
                        break

                time.sleep(0.2)

        except KeyboardInterrupt:
            logging.info("Process terminated by user")
        except Exception as e:
            logging.error("Error in run.py: %s" % e)
            traceback.print_exc()
        finally:
            # graceful shutdown
            self.isActive = False
            self.discovery_thread.isActive = False
            logging.info("stopping threads...")
            for th in self.threads:
                logging.info("Stopping thread %s." % th.__class__.__name__)
                th.stop()
            for th in self.threads:
                logging.info("Joining thread %s." % th.__class__.__name__)
                th.join()

            for thread in self.reliable_socket.threads:
                logging.info("Joining Thread %s." % thread.name)
                thread.join(0.2)

            main_thread = threading.currentThread()
            for t in threading.enumerate():
                if t is main_thread:
                    continue
                logging.info("Joining Thread %s." % thread.name)
                t.join(0.2)

            logging.info("threads stopped")
 def client_left(self, client, server):
     """Callback function of WebsocketServer on client left"""
     logging.info("Content: Client(%d) disconnected" % client["id"])
 def new_client(self, client, server):
     """Callback function of WebsocketServer on new client connected"""
     logging.info("Content: New client connected and was given id %d" %
                  client["id"])