Beispiel #1
0
 def InitXMLRPCServer(self):
     self.rpcserver = SimpleXMLRPCServer(("", self.port), allow_none=True)
     self.rpcserver.register_function(self.set_client_version, "set_client_version")
     self.rpcserver.register_function(self.get_client_version, "get_client_version")
     self.rpcserver.register_function(self.set_tags, "set_tags")
     self.rpcserver.register_function(self.register_tags_events, "register_tags_events")
     self.rpcserver.register_function(self.list_clients, "list_clients")
     self.rpcserver.register_function(self.list_tags, "list_tags")
     self.rpcserver.register_function(self.suspend_client, "suspend_client")
     self.rpcserver.register_function(self.resume_client, "resume_client")
     self.rpcserver.register_function(self.reload_config, "reload_config")
     self.rpcserver.register_function(self.register_share, "register_share")
     self.rpcserver.register_function(self.unregister_share, "unregister_share")
     self.rpcserver.register_function(self.get_client_info, "get_client_info")
     self.rpcserver.register_function(self.list_shares, "list_shares")
     self.rpcserver.register_function(self.list_shared_events, "list_shared_events")
     self.rpcserver.register_function(self.list_subscriptions, "list_subscriptions")
     self.rpcserver.register_function(self.check_connection, "check_connection")
     self.rpcserver.register_function(self.ping, "ping")
Beispiel #2
0
class ConnectionManager(Unpickable(topologyInfo=TopologyInfo,
                                   lock=PickableLock,
                                   alive=(bool, False),
                                   tags_file=str),
                        ICallbackAcceptor):
    def InitXMLRPCServer(self):
        self.rpcserver = SimpleXMLRPCServer(("", self.port), allow_none=True)
        self.rpcserver.register_function(self.set_client_version, "set_client_version")
        self.rpcserver.register_function(self.get_client_version, "get_client_version")
        self.rpcserver.register_function(self.set_tags, "set_tags")
        self.rpcserver.register_function(self.register_tags_events, "register_tags_events")
        self.rpcserver.register_function(self.list_clients, "list_clients")
        self.rpcserver.register_function(self.list_tags, "list_tags")
        self.rpcserver.register_function(self.suspend_client, "suspend_client")
        self.rpcserver.register_function(self.resume_client, "resume_client")
        self.rpcserver.register_function(self.reload_config, "reload_config")
        self.rpcserver.register_function(self.register_share, "register_share")
        self.rpcserver.register_function(self.unregister_share, "unregister_share")
        self.rpcserver.register_function(self.get_client_info, "get_client_info")
        self.rpcserver.register_function(self.list_shares, "list_shares")
        self.rpcserver.register_function(self.list_shared_events, "list_shared_events")
        self.rpcserver.register_function(self.list_subscriptions, "list_subscriptions")
        self.rpcserver.register_function(self.check_connection, "check_connection")
        self.rpcserver.register_function(self.ping, "ping")

    def UpdateContext(self, context):
        self.scheduler = context.Scheduler
        self.network_name = context.network_name
        self.tags_file = context.remote_tags_db_file
        self.port = context.system_port
        if self.tags_file:
            self.acceptors = MapSetDB(self.tags_file)
        self.topologyInfo.UpdateContext(context)
        self.max_remotetags_resend_delay = context.max_remotetags_resend_delay

    def Start(self):
        if not self.network_name or not self.tags_file or not self.port:
            logging.warning("ConnectionManager could'n start: wrong configuration. " +
                            "network_name: %s, remote_tags_db_file: %s, system_port: %r",
                            self.network_name, self.tags_file, self.port)
            return

        self.ReloadConfig()
        logging.debug("after_reload_config")

        for client in self.topologyInfo.servers.values():
            if client.active and client.name != self.network_name:
                client.TryInitializePeersVersions(self.network_name)
        logging.debug("after_clients_versions_init")

        self.alive = True
        self.InitXMLRPCServer()
        self._accept_loop_thread = ProfiledThread(target=self.ServerLoop, name_prefix='ConnManager')
        self._accept_loop_thread.start()
        logging.debug("after_connection_manager_loop_start")

        for client in self.topologyInfo.servers.values():
            self.scheduler.ScheduleTaskT(0, self.SendData, client, skip_logging=True)

    def Stop(self):
        self.alive = False
        self._accept_loop_thread.join()
        self.rpcserver = None # shutdown listening socket

    def ServerLoop(self):
        rpc_fd = self.rpcserver.fileno()
        while self.alive:
            rout, _, _ = select.select((rpc_fd,), (), (), 0.01)
            if rpc_fd in rout:
                self.rpcserver.handle_request()

    def SendData(self, client):
        if self.alive and client.active:
            client.SendDataIfNeed(self.network_name)

        if hasattr(self, "scheduler"):
            self.scheduler.ScheduleTaskT(
                min(client.PENALTY_FACTOR ** client.errorsCnt, self.max_remotetags_resend_delay),
                self.SendData,
                client,
                skip_logging=True
            )

    def RegisterTagEvent(self, tag, event, message=None):
        if not isinstance(tag, TagBase):
            raise RuntimeError("%s is not Tag class instance", tag.GetName())
        if tag.IsRemote():
            return

        tagname = tag.GetName()
        with self.lock: # see register_share
            acceptors = self.acceptors.get(tagname)
            if acceptors:
                logging.debug("on %s connmanager %s with acceptors list %s", TagEventName[event], tagname, acceptors)
                for clientname in acceptors:
                    self.RegisterTagEventForClient(clientname, tagname, event, message)

    def RegisterTagEventForClient(self, clientname, tagname, event, message=None):
        logging.debug("%s remote tag %s on host %s", TagEventName[event], tagname, clientname)
        client = self.topologyInfo.GetClient(clientname, checkname=False)
        if client is None:
            logging.error("unknown client %s appeared", clientname)
            return False
        client.RegisterTagEvent("%s:%s" % (self.network_name, tagname), event, message)

    def ReloadConfig(self, filename=None):
        old_servers = set(self.topologyInfo.servers.keys())
        self.topologyInfo.ReloadConfig()
        new_servers = set(self.topologyInfo.servers.keys())
        new_servers -= old_servers
        if self.alive:
            for client in new_servers:
                self.scheduler.ScheduleTaskT(0, self.SendData, self.topologyInfo.servers[client], skip_logging=True)

    def Subscribe(self, tag):
        if tag.IsRemote():
            client = self.topologyInfo.GetClient(tag.GetRemoteHost(), checkname=True)
            client.Subscribe(tag.GetName())
            return True
        return False

    @traced_rpc_method()
    def set_tags(self, tags): # obsolete
        logging.debug("set %d remote tags", len(tags))
        for tagname in tags:
            self.scheduler.tagRef.AcquireTag(tagname).CheckRemote().Set()
        return True

    @traced_rpc_method()
    def set_client_version(self, clientname, version):
        self.topologyInfo.GetClient(clientname, checkname=True).SetVersion(int(version))
        logging.debug("set client version for %s to %s", clientname, version)
        return True

    @traced_rpc_method()
    def get_client_version(self):
        return PROTOCOL_VERSION

    @traced_rpc_method()
    def register_tags_events(self, updates):
        tagRef = self.scheduler.tagRef
        logging.debug("register_tags_events %d: %s", len(updates), updates)
        for update in updates:
            tagRef.AcquireTag(update[0]).CheckRemote().Modify(*update[1:])
            logging.debug("done with: %s", update)
        logging.debug("register_tags_events %d: done", len(updates))
        return True

    @traced_rpc_method()
    def list_clients(self):

        return [{"name": client.name,
                 "url": client.url,
                 "systemUrl": client.systemUrl,
                 "active": client.active,
                 "version": client.version,
                 "errorsCount": client.errorsCnt,
                 "tagsCount": len(client.events),
                 "subscriptionsCount": len(client.subscriptions),
                 "lastError": str(client.lastError)} for client in self.topologyInfo.servers.values()]

    @traced_rpc_method()
    def list_tags(self, name_prefix):
        data = set()
        for server in self.topologyInfo.servers.values():
            if name_prefix is None or server.name.startswith(name_prefix):
                data.update(server.GetEventsAsTagsToSet())
        return list(data)

    @traced_rpc_method()
    def suspend_client(self, name):
        client = self.topologyInfo.GetClient(name)
        return client.Suspend()

    @traced_rpc_method()
    def resume_client(self, name):
        client = self.topologyInfo.GetClient(name)
        return client.Resume()

    @traced_rpc_method()
    def reload_config(self, location=None):
        self.ReloadConfig(location)

    @traced_rpc_method()
    def register_share(self, tags, clientname):
        tagRef = self.scheduler.tagRef
        logging.debug("register_share %d tags for %s: %s", len(tags), clientname, tags)
        for tagname in tags:
            # XXX
            # 1. this lock only guarantee eventual-consistency of tag's history
            # 2. clients of self may see duplicates of events (even Reset)
            # 3. also guard self.acceptors
            with self.lock:
                self.acceptors.add(tagname, clientname)
                if tagRef._RawTag(tagname).IsLocallySet():
                    self.RegisterTagEventForClient(clientname, tagname, ETagEvent.Set)
        logging.debug("register_share %d tags for %s: done", len(tags), clientname)

    @traced_rpc_method()
    def unregister_share(self, tagname, clientname):
        with self.lock:
            return self.acceptors.remove(tagname, clientname)

    @traced_rpc_method()
    def get_client_info(self, clientname):
        client = self.topologyInfo.GetClient(clientname)
        res = {"name": client.name,
               "url": client.url,
               "systemUrl": client.systemUrl,
               "active": client.active,
               "version": client.version,
               "errorsCount": client.errorsCnt,
               "deferedTagsCount": len(client.events),
               "subscriptionsCount": len(client.subscriptions),
               "lastError": str(client.lastError)}
        return res

    @traced_rpc_method()
    def list_shares(self, clientname):
        client = self.topologyInfo.GetClient(clientname)
        return _get_tags_to_set(client.GetEventsAsList())

    @traced_rpc_method()
    def list_shared_events(self, clientname):
        client = self.topologyInfo.GetClient(clientname)
        return client.GetEventsAsList()

    @traced_rpc_method()
    def list_subscriptions(self, clientname):
        client = self.topologyInfo.GetClient(clientname)
        return list(client.subscriptions)

    @traced_rpc_method()
    def check_connection(self, clientname):
        client = self.topologyInfo.GetClient(clientname)
        return client.connection.ping()

    @traced_rpc_method()
    def ping(self):
        return True

    def __getstate__(self):
        sdict = self.__dict__.copy()
        sdict.pop("scheduler", None)
        sdict.pop("rpcserver", None)
        sdict.pop("acceptors", None)
        sdict.pop("_accept_loop_thread", None)
        sdict["alive"] = False
        return getattr(super(ConnectionManager, self), "__getstate__", lambda: sdict)()