示例#1
0
    def __load_config(self):
        """
        This function is used only if servicename is not given, and
        daemon is not started by kasaya daemon.
        """
        from kasaya.conf import load_worker_settings, set_value
        try:
            config = load_worker_settings("service.conf")
        except IOError:
            import sys
            LOG.critical(
                "File 'service.conf' not found, unable to start service.")
            sys.exit(1)

        # system settings overwriting
        for k, v in config['config'].items():
            set_value(k, v)

        # worker environment
        for k, v in config['env'].items():
            os.environ[k.upper()] = v

        # service name
        svcc = config['service']
        svname = svcc['name']
        LOG.info("Service config loaded. Service name: %s" % svname)

        # set flag to load tasks automatically
        self.__auto_load_tasks_module = svcc['module']

        return svname
示例#2
0
 def worker_start_remote(self, worker_id, host_id, address, service):
     """
     Remote worker started
     """
     self.DB.worker_register(host_id, worker_id, service, address)
     LOG.info("Remote worker [%s] started, address [%s] [id:%s]" %
              (service, address, worker_id))
示例#3
0
 def on_remote_kasayad_start(self, host_id, addr):
     """
     Remote kasaya host started
     """
     # register self in database
     self.DB.host_register(host_id, addr)
     LOG.info("Remote kasaya daemon started, address: %s [id:%s]" %
              (addr, host_id))
示例#4
0
 def worker_start_local(self, worker_id, address, service, pid):
     """
     Local worker started
     """
     self.DB.worker_register(self.DAEMON.ID, worker_id, service, address,
                             pid, False)
     LOG.info("Local worker [%s] started, address [%s] [id:%s]" %
              (service, address, worker_id))
     # emit signal
     emit("worker-local-wait", worker_id)
示例#5
0
 def close(self):
     """
     Notifies network about shutting down, closes database
     and all used sockets.
     """
     LOG.info("Stopping local kasaya daemon")
     self.on_local_kasayad_stop(self.ID, local=True)
     self.WORKER.close()
     self.DB.close()
     self.BC.close()
示例#6
0
 def CTL_start(self):
     """
     Set status of worker as running. This allow to process tasks
     """
     if self.status == 1:
         self.status = 2
         LOG.info("Received status: running.")
         # call tasks after worker started listening
         g = gevent.Greenlet(self._worker_listening)
         g.start()
         return True
     return False
示例#7
0
    def __init__(self):
        super(KasayaDaemon, self).__init__(is_host=True)

        # event handlers
        add_event_handler("host-join", self.on_remote_kasayad_start)
        add_event_handler("host-leave", self.on_remote_kasayad_stop)

        self.hostname = system.get_hostname()
        LOG.info("Starting local kasaya daemon with ID: [%s]" % self.ID)

        self.DB = NetworkStateDB()  # database
        self.BC = UDPBroadcast(self.ID)  # broadcaster
        self.SYNC = Synchronizer(self.DB, self.ID)  # synchronisation
        self.WORKER = SyncWorker(server=self, database=self.DB)
        self.BC.set_own_ip(self.WORKER.own_ip)
示例#8
0
 def notify_kasayad_refresh(self, ID, services=None, local=False):
     """
     Received information on host changes
     """
     if services is not None:
         slst = ", ".join(services)
         if local:
             # local changes require broadcast new service status
             self.BC.send_host_refresh(self.ID, services=services)
             LOG.info("Local service list changed [%s]" % slst)
         else:
             # remote host services requires daabase update
             # local updates are entered to database
             # before notify_kasayad_refresh is called
             self.DB.service_update_list(self.ID, services)
             LOG.info("Remote host service list changed [%s]" % slst)
示例#9
0
    def run_task(self, funcname, args, kwargs):
        # find task in worker db
        try:
            task = worker_methods_db[funcname]
        except KeyError:
            self._tasks_nonex += 1
            LOG.info("Unknown worker task called [%s]" % funcname)
            return exception_serialize_internal('Method %s not found' %
                                                funcname)

        # try to run function and catch exceptions
        try:
            LOG.debug("task %s, args %s, kwargs %s" %
                      (funcname, repr(args), repr(kwargs)))
            func = task['func']
            tout = task['timeout']
            if tout is None:
                # call task without timeout
                result = func(*args, **kwargs)
            else:
                # call task with timeout
                with gevent.Timeout(tout, TaskTimeout):
                    result = func(*args, **kwargs)
            self._tasks_succes += 1
            task['res_succ'] += 1

            return {'message': messages.RESULT, 'result': result}

        except TaskTimeout as e:
            # timeout exceeded
            self._tasks_error += 1
            task['res_tout'] += 1
            err = exception_serialize(e, internal=False)
            LOG.info("Task [%s] timeout (after %i s)." % (funcname, tout))
            return err

        except Exception as e:
            # exception occured
            self._tasks_error += 1
            task['res_err'] += 1
            err = exception_serialize(e, internal=False)
            LOG.info("Task [%s] exception [%s]. Message: %s" %
                     (funcname, err['name'], err['description']))
            LOG.debug(err['traceback'])
            return err

        finally:
            # close django connection
            # if worker is using Django ORM we must close database connection manually,
            # or each task will leave one unclosed connection. This is done automatically.
            if task['close_djconn']:
                try:
                    _close_dj_connection()
                except Exception as e:
                    if e.__class__.__name__ == "ImproperlyConfigured":
                        # django connection is not required or diango orm is not used at all,
                        # because of that we replace _close_dj_connection function by empty lambda
                        global _close_dj_connection
                        _close_dj_connection = lambda: None
示例#10
0
    def notify_kasayad_start(self, ID, hostname, ip, services, local=False):
        """
        Send information about startup of host to all other hosts in network.
        """
        isnew = self.DB.host_register(ID, hostname, ip, services)
        if local:
            # it is ourself starting, send broadcast to other kasaya daemons
            self.BC.send_host_start(ID, hostname, ip, services)

        if isnew:
            # new kasayad
            # send request to local workers to send immadiately ping broadcast
            # to inform new kasaya daemon about self
            #self.WORKER.request_workers_broadcast()
            # it's remote host starting, information is from broadcast
            LOG.info(
                "Remote kasaya daemon [%s] started, address [%s], ID [%s]" %
                (hostname, ip, ID))
            # if registered new kasayad AND it's not local host, then
            # it must be new host in network, which don't know other hosts.
            # We send again registering information about self syncd instance.
            gevent.sleep(0.5)
            self.notify_kasayad_self_start()
示例#11
0
 def worker_stop_remote(self, worker_id):
     """
     Remote worker stopped
     """
     self.DB.worker_unregister(ID=worker_id)
     LOG.info("Remote worker stopped [id:%s]" % worker_id)
示例#12
0
 def worker_stop_local(self, worker_id):
     """
     Local worker stopped
     """
     self.DB.worker_unregister(ID=worker_id)
     LOG.info("Local worker stopped [id:%s]" % worker_id)
示例#13
0
    def __init__(self,
                 servicename=None,
                 load_config=True,
                 skip_loading_modules=False):

        super(WorkerDaemon, self).__init__()

        # config loader
        if servicename is None:
            load_config = True
        if load_config:
            LOG.info("Loading service.conf")
            if servicename is None:
                servicename = self.__load_config()
        self.servicename = servicename
        self.__skip_loading_modules = skip_loading_modules

        # worker status
        # 0 - initialized
        # 1 - starting or waiting for reconnect to kasaya
        # 2 - working
        # 3 - stopping
        # 4 - dead
        self.status = 0
        LOG.info("Starting worker daemon, service [%s], ID: [%s]" %
                 (self.servicename, self.ID))
        adr = "tcp://%s:%i" % (settings.BIND_WORKER_TO,
                               settings.WORKER_MIN_PORT)
        self.loop = MessageLoop(adr, settings.WORKER_MAX_PORT)

        add_event_handler("sender-conn-closed", self.kasaya_connection_broken)
        add_event_handler("sender-conn-started",
                          self.kasaya_connection_started)

        self.SYNC = KasayaLocalClient(autoreconnect=True, sessionid=self.ID)
        self.SYNC.setup(servicename, self.loop.address, self.ID, os.getpid())
        LOG.debug("Binded to socket [%s]" %
                  (",".join(self.loop.binded_ip_list())))

        # registering handlers
        self.loop.register_message(messages.SYNC_CALL,
                                   self.handle_sync_call,
                                   raw_msg_response=True)
        self.loop.register_message(messages.CTL_CALL,
                                   self.handle_control_request)
        # heartbeat
        self.__hbloop = True
        #exposing methods
        self.exposed_methods = []
        # control tasks
        self.ctl = ControlTasks()
        self.ctl.register_task("stop", self.CTL_stop)
        self.ctl.register_task("start", self.CTL_start)
        self.ctl.register_task("stats", self.CTL_stats)
        self.ctl.register_task("tasks", self.CTL_methods)
        # stats
        #self._sb_errors = 0 # internal service bus errors
        self._tasks_succes = 0  # succesfully processed tasks
        self._tasks_error = 0  # task which triggered exceptions
        self._tasks_nonex = 0  # non existing tasks called
        self._tasks_control = 0  # control tasks received
        self._start_time = datetime.datetime.now()  # time of worker start
示例#14
0
    def connection_handler(self, SOCK, address):
        ssid = None
        while True:
            try:
                msgdata, resreq = _receive_and_deserialize(
                    SOCK, self.serializer)
            except (NoData, ConnectionClosed):
                return

            try:
                msg = msgdata['message']
            except KeyError:
                if resreq:
                    self._send_noop(SOCK)
                LOG.debug("Decoded message is incomplete. Message dump: %s" %
                          repr(msgdata))
                continue

            # message SET_SESSION_ID is special message
            # it never return reply and is not propagated to handlers
            if msg == messages.SET_SESSION_ID:
                try:
                    ssid = msgdata['id']
                    #print("conn session id" , address, ssid)
                except KeyError:
                    pass
                if resreq:
                    self._send_noop(SOCK)
                continue

            # find message handler
            try:
                handler, rawmsg = self._msgdb[msg]
            except KeyError:
                # unknown messages are ignored
                if resreq:
                    self._send_noop(SOCK)
                LOG.warning("Unknown message received [%s]" % msg)
                LOG.debug("Message body dump:\n%s" % repr(msgdata))
                continue

            # run handler
            try:
                result = handler(msgdata)
            except Exception as e:
                result = exception_serialize(e, False)
                LOG.info(
                    "Exception [%s] when processing message [%s]. Message: %s."
                    % (result['name'], msg, result['description']))
                #LOG.debug("Message dump: %s" % repr(msgdata) )
                #LOG.debug(result['traceback'])

                if not resreq:
                    # if response is not required, then don't send exceptions
                    continue

                _serialize_and_send(
                    SOCK,
                    self.serializer,
                    exception_serialize(e, False),
                    resreq=False,  # response never require another response
                )
                continue

            # response is not expected, throw result and back to loop
            if not resreq:
                continue

            try:
                # send result
                if rawmsg:
                    _serialize_and_send(
                        SOCK,
                        self.serializer,
                        result,
                        resreq=False,
                    )
                else:
                    _serialize_and_send(SOCK,
                                        self.serializer, {
                                            "message": messages.RESULT,
                                            "result": result,
                                        },
                                        resreq=False)
            except ConnectionClosed:
                return
示例#15
0
 def on_remote_kasayad_stop(self, host_id):
     """
     received information about kasaya host leaving network
     """
     self.DB.host_unregister(self.ID)
     LOG.info("Remote kasaya daemon stopped, [id:%s]" % host_id)