Source code for crossbar.edge.webservice.pairme

##############################################################################
#
#                        Crossbar.io
#     Copyright (C) typedef int GmbH. All rights reserved.
#
##############################################################################

import os
from copy import deepcopy
from pprint import pformat

from twisted.internet.defer import inlineCallbacks
from twisted.web import server
from twisted.web.resource import Resource
from txaio import make_logger, time_ns

import crossbar
from crossbar._util import hl
from crossbar.webservice.base import RouterWebService

__all__ = ("RouterWebServicePairMe",)


class PairMeResource(Resource):
    """
    Web resource to pair edge/core nodes to a master node.

    IMPORTANT: this resource is only indented to run inside edge & core nodes!
    """

    log = make_logger()

    pair_at = os.environ.get("CROSSBAR_FABRIC_URL", "http://master.local:8080")

    def __init__(self, templates, worker, node_type=None):
        Resource.__init__(self)
        self._worker = worker

        # FIXME:
        # self._service_realm = 'com.crossbario.fabric'
        # self._service_agent = self._worker.realm_by_name(self._service_realm).session

        # ./crossbar/edge/node/config/pairme.json
        self._page = templates.get_template("pairme.html")
        self._pid = "{}".format(os.getpid())
        self._node_type = node_type.strip().upper()

        assert self._node_type in ["EDGE", "CORE"]

    def _delayedRender(self, infos, request):
        try:
            peer = request.transport.getPeer()
            peer = "{}:{}".format(peer.host, peer.port)
        except:
            peer = "?:?"

        kwargs = deepcopy(infos)

        node_time = time_ns()
        pairing_url = "{}/pair-node?node_type={}&node_key={}&node_time={}".format(
            self.pair_at, self._node_type, kwargs["node_status"]["pubkey"], node_time
        )

        kwargs["node_time"] = node_time
        kwargs["is_paired"] = False
        kwargs["cb_version"] = crossbar.__version__
        kwargs["worker_pid"] = self._pid
        kwargs["peer"] = peer
        kwargs["pairing_url"] = pairing_url
        kwargs["node_type"] = self._node_type

        s = self._page.render(**kwargs)
        request.write(s.encode("utf8"))
        request.finish()

    @inlineCallbacks
    def _do_get(self, request):
        try:
            node_status = yield self._worker.call("crossbar.get_status")

            # FIXME:
            # master_status = yield self._service_agent.call('crossbarfabriccenter.domain.get_status')
            # master_license = yield self._service_agent.call('crossbarfabriccenter.domain.get_license')
            # master_version = yield self._service_agent.call('crossbarfabriccenter.domain.get_version')
            infos = {
                "node_status": node_status,
                # 'master_status': master_status,
                # 'master_license': master_license,
                # 'master_version': master_version,
            }
            self.log.debug(
                "rendering {page} page using data\n{data}", page=hl("pair-node", bold=True), data=pformat(infos)
            )
            self._delayedRender(infos, request)
        except:
            self.log.failure()
            request.finish()

    def render_GET(self, request):
        self._do_get(request)
        return server.NOT_DONE_YET

    def getChild(self, path, request):
        self.log.debug(
            "{kass}.getChild(path={path}, request={request}, prepath={prepath}, postpath={postpath})",
            kass=self.__class__.__name__,
            path=path,
            prepath=request.prepath,
            postpath=request.postpath,
            request=request,
        )

        search_path = b"/".join([path] + request.postpath).decode("utf8")

        if search_path == "" or search_path.endswith("/") or search_path in ["pair", "pair.html"]:
            return self
        else:
            return Resource.getChild(self, path, request)


[docs] class RouterWebServicePairMe(RouterWebService): """ Crossbar.io "pair-me" home page. IMPORTANT: this web service is only indented to run inside edge & core nodes! """ @staticmethod
[docs] def check(personality, config): """ Checks the configuration item. When errors are found, an InvalidConfigException exception is raised. :param personality: The node personality class. :param config: The Web service configuration item. :raises: crossbar.common.checkconfig.InvalidConfigException """ pass
@staticmethod
[docs] def create(transport, path, config): personality = transport.worker.personality personality.WEB_SERVICE_CHECKERS["pairme"](personality, config) resource = PairMeResource(transport.templates, transport.worker, node_type=personality.NAME) return RouterWebServicePairMe(transport, path, config, resource)