def serve(self): """ Start AMQP service for this clacks service provider. """ # Load AMQP and Command registry instances amqp = PluginRegistry.getInstance('AMQPHandler') self.__cr = PluginRegistry.getInstance('CommandRegistry') # Create a list of queues we need here queues = {} for dsc in self.__cr.commands.values(): queues[dsc['target']] = True # Finally create the queues for queue in queues: # Add round robin processor for queue self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(), r_address='%s.command.%s; { create:always, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s" } ] } }' % (self.env.domain, queue, self.env.domain, queue), workers=int(self.env.config.get('amqp.worker', default=1)), callback=self.commandReceived) # Add private processor for queue self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(), r_address='%s.command.%s.%s; { create:always, delete:receiver, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s.%s" } ] } }' % (self.env.domain, queue, self.env.id, self.env.domain, queue, self.env.id), workers=int(self.env.config.get('amqp.worker', default=1)), callback=self.commandReceived) # Announce service if self.env.config.get("amqp.announce", default="True").lower() == "true": url = parseURL(self.env.config.get("amqp.url")) self.__zeroconf = ZeroconfService(name="Clacks RPC service", port=url['port'], stype="_%s._tcp" % url['scheme'], text=dict_to_txt_array({'path': self.env.domain, 'service': 'clacks'})) self.__zeroconf.publish() self.log.info("ready to process incoming requests")
def serve(self): """ Start JSONRPC service for this clacks service provider. """ # Get http service instance self.__http = PluginRegistry.getInstance('HTTPService') cr = PluginRegistry.getInstance('CommandRegistry') # Register ourselves self.__app = JsonRpcApp(cr) self.__http.app.register(self.path, AuthCookieHandler(self.__app, timeout=self.env.config.get('http.cookie-lifetime', default=1800), cookie_name='ClacksRPC', secret=self.env.config.get('http.cookie-secret', default="TecloigJink4"))) # Announce service if self.env.config.get("http.announce", default="True").lower() == "true": self.__zeroconf = ZeroconfService(name="Clacks RPC service", port=self.__http.port, stype="_%s._tcp" % self.__http.scheme, text=dict_to_txt_array({'path': self.path, 'service': 'clacks'})) self.__zeroconf.publish() self.log.info("ready to process incoming requests")
class AMQPService(object): """ Class to serve all available queues and commands to the AMQP broker. It makes use of a couple of configuration flags provided by the clacks configurations file ``[amqp]`` section: ============== ============= Key Description ============== ============= url AMQP URL to connect to the broker id User name to connect with key Password to connect with command-worker Number of worker processes ============== ============= Example:: [amqp] url = amqps://amqp.intranet.gonicus.de:5671 id = node1 key = secret """ implements(IInterfaceHandler) _priority_ = 1 def __init__(self): env = Environment.getInstance() self.log = logging.getLogger(__name__) self.log.info("initializing AMQP service provider") self.env = env self.__cr = None self.__zeroconf = None self.__cmdWorker = None def serve(self): """ Start AMQP service for this clacks service provider. """ # Load AMQP and Command registry instances amqp = PluginRegistry.getInstance('AMQPHandler') self.__cr = PluginRegistry.getInstance('CommandRegistry') # Create a list of queues we need here queues = {} for dsc in self.__cr.commands.values(): queues[dsc['target']] = True # Finally create the queues for queue in queues: # Add round robin processor for queue self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(), r_address='%s.command.%s; { create:always, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s" } ] } }' % (self.env.domain, queue, self.env.domain, queue), workers=int(self.env.config.get('amqp.worker', default=1)), callback=self.commandReceived) # Add private processor for queue self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(), r_address='%s.command.%s.%s; { create:always, delete:receiver, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s.%s" } ] } }' % (self.env.domain, queue, self.env.id, self.env.domain, queue, self.env.id), workers=int(self.env.config.get('amqp.worker', default=1)), callback=self.commandReceived) # Announce service if self.env.config.get("amqp.announce", default="True").lower() == "true": url = parseURL(self.env.config.get("amqp.url")) self.__zeroconf = ZeroconfService(name="Clacks RPC service", port=url['port'], stype="_%s._tcp" % url['scheme'], text=dict_to_txt_array({'path': self.env.domain, 'service': 'clacks'})) self.__zeroconf.publish() self.log.info("ready to process incoming requests") def stop(self): """ Stop AMQP service for this clacks service provider. """ if self.__zeroconf: self.__zeroconf.unpublish() def commandReceived(self, ssn, message): """ Process incoming commands, coming in with session and message information. ================= ========================== Parameter Description ================= ========================== ssn AMQP session object message Received AMQP message ================= ========================== Incoming messages are coming from an :class:`clacks.common.components.amqp_proxy.AMQPServiceProxy` which is providing a *reply to* queue as a return channel. The command result is written to that queue. """ # Check for id if not message.user_id: raise ValueError(C.make_error("AMQP_MESSAGE_WITHOUT_UID")) id_ = '' name = args = err = res = None try: req = loads(message.content) except ServiceRequestNotTranslatable, e: err = str(e) req = {'id': id_} if err is None: try: id_ = req['id'] name = req['method'] args = req['params'] if not isinstance(args, list) and not isinstance(args, dict): raise ValueError(C.make_error("AMQP_BAD_PARAMETERS")) except KeyError: err = str(BadServiceRequest(message.content)) # Extract source queue p = re.compile(r';.*$') queue = p.sub('', message._receiver.source) self.log.debug("received call [%s/%s] for %s: %s(%s)" % (id_, queue, message.user_id, name or "unknown", args or "unknown")) # Don't process messages if the command registry thinks it's not ready if not self.__cr.processing.is_set(): self.log.warning("waiting for registry to get ready") if not self.__cr.processing.wait(5): self.log.error("releasing call [%s/%s] for %s: %s(%s) - timed out" % (id_, queue, message.user_id, name, args)) ssn.acknowledge(message, Disposition(RELEASED, set_redelivered=True)) return # Try to execute either with or without keyword arguments if err is None: try: if isinstance(args, dict): res = self.__cr.dispatch(message.user_id, queue, name, **args) else: res = self.__cr.dispatch(message.user_id, queue, name, *args) # Catch everything that might happen in the dispatch, pylint: disable=W0703 except Exception as e: text = traceback.format_exc() self.log.exception(text) err = str(e) exc_value = sys.exc_info()[1] # If message starts with [, it's a translateable message in # repr format if err.startswith("[") or err.startswith("("): if err.startswith("("): err = "[" + err[1:-1] + "]" err = loads(repr2json(err)) err = dict( name='JSONRPCError', code=100, message=str(exc_value), error=err) self.log.debug("returning call [%s]: %s / %s" % (id_, res, err)) response = dumps({"result": res, "id": id_, "error": err}) ssn.acknowledge(message) try: # Talk to client generated reply queue sender = ssn.sender(message.reply_to) # Get rid of it... sender.send(Message(response)) except NotFound: self.log.warning("RPC reply queue does not exist anymore - caller not present: dropping %s" % id_)
class JSONRPCService(object): """ This is the JSONRPC clacks agent plugin which is registering an instance of :class:`clacks.agent.jsonrpc_service.JsonRpcApp` into the :class:`clacks.agent.httpd.HTTPService`. It is configured thru the ``[jsonrpc]`` section of your clacks configuration: =============== ============ Key Description =============== ============ path Path to register the service in HTTP cookie-lifetime Seconds of authentication cookie lifetime =============== ============ Example:: [jsonrpc] path = /rpc cookie-lifetime = 3600 """ implements(IInterfaceHandler) _priority_ = 11 __proxy = {} def __init__(self): env = Environment.getInstance() self.env = env self.log = logging.getLogger(__name__) self.log.info("initializing JSON RPC service provider") self.path = self.env.config.get('jsonrpc.path', default="/rpc") self.__zeroconf = None self.__http = None self.__app = None def serve(self): """ Start JSONRPC service for this clacks service provider. """ # Get http service instance self.__http = PluginRegistry.getInstance('HTTPService') cr = PluginRegistry.getInstance('CommandRegistry') # Register ourselves self.__app = JsonRpcApp(cr) self.__http.app.register(self.path, AuthCookieHandler(self.__app, timeout=self.env.config.get('http.cookie-lifetime', default=1800), cookie_name='ClacksRPC', secret=self.env.config.get('http.cookie-secret', default="TecloigJink4"))) # Announce service if self.env.config.get("http.announce", default="True").lower() == "true": self.__zeroconf = ZeroconfService(name="Clacks RPC service", port=self.__http.port, stype="_%s._tcp" % self.__http.scheme, text=dict_to_txt_array({'path': self.path, 'service': 'clacks'})) self.__zeroconf.publish() self.log.info("ready to process incoming requests") def stop(self): """ Stop serving the JSONRPC service for this clacks service provider. """ self.log.debug("shutting down JSON RPC service provider") if hasattr(self.__http, 'app'): self.__http.app.unregister(self.path) def check_session(self, sid, user): return self.__app.check_session(sid, user) def user_sessions_available(self, user=None): return self.__app.user_sessions_available(user)