Exemple #1
0
class MqttEventConsumer(BaseEventConsumer):
    """
    Subscribes to the external MQTT event topic and forwards incoming events to the given callback
    """
    def __init__(self, callback=None, event_type=None):
        super(MqttEventConsumer, self).__init__(callback, event_type)
        self.mqtt = MQTTHandler()
        self.mqtt.get_client().add_subscription('%s/events' % Environment.getInstance().domain)
        self.mqtt.set_subscription_callback(self.__process_event)

    def __process_event(self, topic, message):
        super(MqttEventConsumer, self)._process_event(etree.fromstring(message, PluginRegistry.getEventParser()))
Exemple #2
0
class MQTTRPCService(object):
    """
    The ProxyServer handles to the RPC calls from the GOsa proxies received via MQTT
    """
    mqtt = None
    _priority_ = 10
    __command_registry = None

    def __init__(self):
        self.env = Environment.getInstance()
        self.log = logging.getLogger(__name__)
        self.subtopic = "%s/proxy" % self.env.domain
        self.mqtt = MQTTHandler(host=self.env.config.get("mqtt.host"),
                                port=self.env.config.getint("mqtt.port",
                                                            default=1883))

    def serve(self):
        self.mqtt.get_client().add_subscription('%s/#' % self.subtopic)
        self.mqtt.set_subscription_callback(self.handle_request)
        self.__command_registry = PluginRegistry.getInstance('CommandRegistry')
        self.log.info(
            "MQTT RPC service started, listening on subtopic '%s/#'" %
            self.subtopic)

    def handle_request(self, topic, message):
        if topic == self.subtopic:
            # event from proxy received
            try:
                data = etree.fromstring(message,
                                        PluginRegistry.getEventParser())
                event_type = stripNs(
                    data.xpath(
                        '/g:Event/*',
                        namespaces={'g':
                                    "http://www.gonicus.de/Events"})[0].tag)
                if event_type == "ClientLeave":
                    proxy_id = str(data.ClientLeave.Id)
                    registry = PluginRegistry.getInstance("BackendRegistry")
                    registry.unregisterBackend(proxy_id)

            except etree.XMLSyntaxError as e:
                self.log.error("Event parsing error: %s" % e)

        elif topic.startswith(self.subtopic):
            response_topic = "%s/response" % "/".join(topic.split("/")[0:4])

            try:
                id_, res = self.process(topic, message)
                response = dumps({"result": res, "id": id_})

            except Exception as e:
                err = str(e)
                self.log.error("MQTT RPC call error: %s" % err)
                response = dumps({'id': topic.split("/")[-2], 'error': err})

            # Get rid of it...
            self.mqtt.send_message(response, topic=response_topic)

        else:
            self.log.warning("unhandled topic request received: %s" % topic)

    def process(self, topic, message):

        try:
            req = loads(message)
        except ValueError as e:
            raise ValueError(C.make_error("INVALID_JSON", data=str(e)))

        try:
            id_ = req['id']
            name = req['method']
            args = req['params']
            user = req['user'] if 'user' in req else topic.split("/")[2]
            sid = req['session_id'] if 'session_id' in req else None

        except KeyError as e:
            self.log.error("KeyError: %s" % e)
            raise BadServiceRequest(message)

        self.log.debug("received call [%s] for %s: %s(%s)" %
                       (id_, topic, name, args))

        try:
            return id_, self.__command_registry.dispatch(
                user, sid, name, *args)
        except Exception as e:
            # Write exception to log
            exc_type, exc_value, exc_traceback = sys.exc_info()
            self.log.error("".join(
                traceback.format_exception(exc_type, exc_value,
                                           exc_traceback)))
            raise e
Exemple #3
0
class MQTTRelayService(object):
    """
     This service acts as a proxy between the backend and proxy MQTT brokers
     to forward messages from one to the other.

     In detail this service listens to (event-)messages from the backend to the clients on the backends MQTT broker
     and forwards then to the clients (via the proxies MQTT broker) and the other way around.

     In addition to that this service also handles events sent from the backend to the proxy (those are not forwarded
     to the clients)
    """

    _priority_ = 10
    backend_mqtt = None
    proxy_mqtt = None

    def __init__(self):
        self.env = Environment.getInstance()
        self.log = logging.getLogger(__name__)

    def serve(self):
        self.backend_mqtt = MQTTHandler(
            host=self.env.config.get("backend.mqtt-host"),
            port=self.env.config.getint("backend.mqtt-port", default=1883))

        # subscribe to all client relevant topics
        self.backend_mqtt.get_client().add_subscription("%s/client/#" % self.env.domain, qos=1)
        # subscribe to proxy topic
        self.backend_mqtt.get_client().add_subscription("%s/proxy" % self.env.domain, qos=1)
        self.backend_mqtt.set_subscription_callback(self._handle_backend_message)

        # set our last will and testament
        e = EventMaker()
        goodbye = e.Event(e.ClientLeave(e.Id(self.env.core_uuid)))
        self.backend_mqtt.will_set("%s/proxy" % self.env.domain, goodbye, qos=1)

        # connect to the proxy MQTT broker (where the clients are listening)
        self.proxy_mqtt = MQTTHandler(
            host=self.env.config.get("mqtt.host"),
            port=self.env.config.getint("mqtt.port", default=1883))
        self.proxy_mqtt.get_client().add_subscription("%s/client/#" % self.env.domain, qos=1)
        self.proxy_mqtt.set_subscription_callback(self._handle_proxy_message)

    def _handle_backend_message(self, topic, message):
        """ forwards backend messages to proxy MQTT and handles received events"""

        forward = not topic.startswith("%s/proxy" % self.env.domain)
        if message[0:1] != "{":
            # event received
            try:
                xml = objectify.fromstring(message)
                if hasattr(xml, "ClientPoll"):
                    self.__handleClientPoll()
                elif hasattr(xml, "Trigger"):
                    if xml.Trigger.Type == "ACLChanged":
                        self.log.debug("ACLChanged trigger received, reloading ACLs")
                        resolver = PluginRegistry.getInstance("ACLResolver")
                        resolver.load_acls()
                    else:
                        self.log.warning("unhandled Trigger event of type: %s received" % xml.Trigger.Type)

            except etree.XMLSyntaxError as e:
                self.log.error("Message parsing error: %s" % e)

        if forward is True:
            self.proxy_mqtt.send_message(message, topic, qos=1)

    def _handle_proxy_message(self, topic, message):
        """ forwards backend messages to proxy MQTT """
        self.backend_mqtt.send_message(message, topic, qos=1)

    def __handleClientPoll(self):
        """ register proxy-backend again """
        index = PluginRegistry.getInstance("ObjectIndex")
        index.registerProxy()

    def close(self):
        self.backend_mqtt.close()
        self.proxy_mqtt.close()

    def stop(self):
        self.close()
        self.backend_mqtt = None
        self.proxy_mqtt = None
Exemple #4
0
class MQTTRPCService(object):
    """
    The ProxyServer handles to the RPC calls from the GOsa proxies received via MQTT
    """
    mqtt = None
    _priority_ = 0
    __command_registry = None

    def __init__(self):
        self.env = Environment.getInstance()
        self.log = logging.getLogger(__name__)
        self.subtopic = "%s/proxy" % self.env.domain

    def serve(self):
        self.mqtt = MQTTHandler(host=self.env.config.get("mqtt.host"),
                                port=self.env.config.getint("mqtt.port", default=1883),
                                client_id_prefix="MQTTRPCService")

        self.__command_registry = PluginRegistry.getInstance('CommandRegistry')
        self.log.info("MQTT RPC service started, listening on subtopic '%s/#'" % self.subtopic)
        self.mqtt.get_client().add_subscription('%s/#' % self.subtopic, qos=2, callback=self.handle_request)

    @gen.coroutine
    def handle_request(self, topic, message):
        if topic == self.subtopic:
            # event from proxy received
            try:
                data = etree.fromstring(message, PluginRegistry.getEventParser())
                event_type = stripNs(data.xpath('/g:Event/*', namespaces={'g': "http://www.gonicus.de/Events"})[0].tag)
                if event_type == "ClientLeave":
                    proxy_id = str(data.ClientLeave.Id)
                    registry = PluginRegistry.getInstance("BackendRegistry")
                    registry.unregisterBackend(proxy_id)

            except etree.XMLSyntaxError as e:
                self.log.error("Event parsing error: %s" % e)

        elif topic.startswith(self.subtopic):
            response_topic = "%s/response" % "/".join(topic.split("/")[0:4])

            try:
                id_, res = self.process(topic, message)
                if is_future(res):
                    res = yield res
                response = dumps({"result": res, "id": id_})
                self.log.debug("MQTT-RPC response: %s on topic %s" % (response, topic))

            except Exception as e:
                err = str(e)
                self.log.error("MQTT RPC call error: %s" % err)
                response = dumps({'id': topic.split("/")[-2], 'error': err})

            # Get rid of it...
            self.mqtt.send_message(response, topic=response_topic, qos=2)

        else:
            self.log.warning("unhandled topic request received: %s" % topic)

    def process(self, topic, message):

        try:
            req = loads(message)
        except ValueError as e:
            raise ValueError(C.make_error("INVALID_JSON", data=str(e)))

        try:
            id_ = req['id']
            name = req['method']
            args = req['params']
            kwargs = req['kwparams']
            if 'user' in req:
                user = req['user']
            else:
                user = topic.split("/")[2]
            sid = req['session_id'] if 'session_id' in req else None

        except KeyError as e:
            self.log.error("KeyError: %s" % e)
            raise BadServiceRequest(message)

        self.log.debug("received call [%s, user=%s, session-id=%s] for %s: %s(%s,%s)" % (id_, user, sid, topic, name, args, kwargs))

        try:
            return id_, self.__command_registry.dispatch(user, sid, name, *args, **kwargs)
        except Exception as e:
            # Write exception to log
            exc_type, exc_value, exc_traceback = sys.exc_info()
            self.log.error("".join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
            raise e