コード例 #1
0
class HubServer(object):

    DEFAULT_FEATURES = ["config","job","dump","upload","dataplugin","source",
                        "build","diff","index","snapshot","release","inspect","sync","api",
                        "terminal","reloader","dataupload","ws"]
    DEFAULT_MANAGERS_ARGS = {"upload" : {"poll_schedule" : "* * * * * */10"}}
    DEFAULT_RELOADER_CONFIG = {"folders": None, # will use default one
                               "managers" : ["source_manager","assistant_manager"],
                               "reload_func" : None} # will use default one
    DEFAULT_DATAUPLOAD_CONFIG = {"upload_root" : getattr(config,"DATA_UPLOAD_FOLDER",None)}
    DEFAULT_WEBSOCKET_CONFIG = {}
    DEFAULT_API_CONFIG = {}

    def __init__(self, source_list, features=None, name="BioThings Hub",
                 managers_custom_args={}, api_config=None, reloader_config=None,
                 dataupload_config=None, websocket_config=None):
        """
        Helper to setup and instantiate common managers usually used in a hub
        (eg. dumper manager, uploader manager, etc...)
        "source_list" is either:
            - a list of string corresponding to paths to datasources modules
            - a package containing sub-folders with datasources modules
        Specific managers can be retrieved adjusting "features" parameter, where
        each feature corresponds to one or more managers. Parameter defaults to
        all possible available. Managers are configured/init in the same order as the list,
        so if a manager (eg. job_manager) is required by all others, it must be the first
        in the list.
        "managers_custom_args" is an optional dict used to pass specific arguments while
        init managers:
            managers_custom_args={"upload" : {"poll_schedule" : "*/5 * * * *"}}
        will set poll schedule to check upload every 5min (instead of default 10s)
        "reloader_config", "dataupload_config" and "websocket_config" can be used to
        customize reloader, dataupload and websocket. If None, default config is used.
        If explicitely False, feature is deactivated.
        """
        self.name = name
        self.source_list = source_list
        self.logger, self.logfile = get_logger("hub")
        self._passed_features = features
        self._passed_managers_custom_args = managers_custom_args
        self.features = self.clean_features(features or self.DEFAULT_FEATURES)
        self.managers_custom_args = managers_custom_args
        self.reloader_config = reloader_config or self.DEFAULT_RELOADER_CONFIG
        self.dataupload_config = dataupload_config or self.DEFAULT_DATAUPLOAD_CONFIG
        self.websocket_config = websocket_config or self.DEFAULT_WEBSOCKET_CONFIG
        self.ws_listeners = [] # collect listeners that should be connected (push data through) to websocket
        self.api_config = api_config or self.DEFAULT_API_CONFIG
        # set during configure()
        self.managers = None
        self.api_endpoints = None
        self.shell = None
        self.commands = None
        self.extra_commands = None
        self.routes = []
        # flag "do we need to configure?"
        self.configured = False

    def clean_features(self, features):
        # we can't just use "set()" because we need to preserve order
        ordered = OrderedDict()
        for feat in features:
            if not feat in ordered:
                ordered[feat] = None
        return list(ordered.keys())

    def before_configure(self):
        """
        Hook triggered before configure(),
        used eg. to adjust features list
        """
        pass

    def configure(self):
        self.before_configure()
        self.remaining_features = copy.deepcopy(self.features) # keep track of what's been configured
        self.configure_ioloop()
        self.configure_managers()
        # setup the shell
        self.shell = HubShell(self.managers["job_manager"])
        self.shell.register_managers(self.managers)
        self.shell.server = self # propagate server instance in shell
                                 # so it's accessible from the console if needed
        self.configure_remaining_features()
        self.configure_commands()
        self.configure_extra_commands()
        self.shell.set_commands(self.commands,self.extra_commands)
        # set api
        if self.api_config != False:
            self.configure_api_endpoints() # after shell setup as it adds some default commands
                                           # we want to expose throught the api
            from biothings.hub.api import generate_api_routes
            self.routes.extend(generate_api_routes(self.shell, self.api_endpoints))

        # done
        self.configured = True

    def configure_ioloop(self):
        import tornado.platform.asyncio
        tornado.platform.asyncio.AsyncIOMainLoop().install()

    def before_start(self):
        pass

    def start(self):
        if not self.configured:
            self.configure()
        self.logger.info("Starting server '%s'" % self.name)
        # can't use asyncio.get_event_loop() if python < 3.5.3 as it would return
        # another instance of aio loop, take it from job_manager to make sure
        # we share the same one
        loop = self.managers["job_manager"].loop
        if self.routes:
            self.logger.info(self.routes)
            self.logger.info("Starting Hub API server")
            import tornado.web
            # register app into current event loop
            api = tornado.web.Application(self.routes)
            self.extra_commands["api"] = api
            from biothings.hub.api import start_api
            api_server = start_api(api,config.HUB_API_PORT,settings=getattr(config,"TORNADO_SETTINGS",{}))
        else:
            self.logger.info("No route defined, API server won't start")
        # at this point, everything is ready/set, last call for customizations
        self.before_start()
        self.ssh_server = start_ssh_server(loop,self.name,passwords=config.HUB_PASSWD,
                              port=config.HUB_SSH_PORT,shell=self.shell)
        try:
            loop.run_until_complete(self.ssh_server)
        except (OSError, asyncssh.Error) as exc:
            sys.exit('Error starting server: ' + str(exc))
        loop.run_forever()

    def mixargs(self, feat, params={}):
        args = {}
        for p in params:
            args[p] = self.managers_custom_args.get(feat,{}).pop(p,None) or params[p]
        # mix remaining
        args.update(self.managers_custom_args.get(feat,{}))
        return args

    def configure_job_manager(self):
        import asyncio
        loop = asyncio.get_event_loop()
        from biothings.utils.manager import JobManager
        args = self.mixargs("job",{"num_workers":config.HUB_MAX_WORKERS,"max_memory_usage":config.HUB_MAX_MEM_USAGE})
        job_manager = JobManager(loop,**args)
        self.managers["job_manager"] = job_manager

    def configure_dump_manager(self):
        from biothings.hub.dataload.dumper import DumperManager
        args = self.mixargs("dump")
        dmanager = DumperManager(job_manager=self.managers["job_manager"],**args)
        self.managers["dump_manager"] = dmanager

    def configure_upload_manager(self):
        from biothings.hub.dataload.uploader import UploaderManager
        args = self.mixargs("upload",{"poll_schedule":"* * * * * */10"})
        upload_manager = UploaderManager(job_manager=self.managers["job_manager"],**args)
        self.managers["upload_manager"] = upload_manager

    def configure_dataplugin_manager(self):
        from biothings.hub.dataplugin.manager import DataPluginManager
        dp_manager = DataPluginManager(job_manager=self.managers["job_manager"])
        self.managers["dataplugin_manager"] = dp_manager
        from biothings.hub.dataplugin.assistant import AssistantManager
        args = self.mixargs("dataplugin")
        assistant_manager = AssistantManager(
                data_plugin_manager=dp_manager,
                dumper_manager=self.managers["dump_manager"],
                uploader_manager=self.managers["upload_manager"],
                job_manager=self.managers["job_manager"],
                **args)
        self.managers["assistant_manager"] = assistant_manager

    def configure_build_manager(self):
        from biothings.hub.databuild.builder import BuilderManager
        args = self.mixargs("build")
        build_manager = BuilderManager(job_manager=self.managers["job_manager"],**args)
        build_manager.configure()
        self.managers["build_manager"] = build_manager

    def configure_diff_manager(self):
        from biothings.hub.databuild.differ import DifferManager, SelfContainedJsonDiffer
        args = self.mixargs("diff")
        diff_manager = DifferManager(job_manager=self.managers["job_manager"],
                                     poll_schedule="* * * * * */10",**args)
        diff_manager.configure([SelfContainedJsonDiffer,])
        diff_manager.poll("diff",lambda doc: diff_manager.diff("jsondiff-selfcontained",old=None,new=doc["_id"]))
        self.managers["diff_manager"] = diff_manager

    def configure_index_manager(self):
        from biothings.hub.dataindex.indexer import IndexManager
        args = self.mixargs("index")
        index_manager = IndexManager(job_manager=self.managers["job_manager"],**args)
        index_manager.configure(config.INDEX_CONFIG)
        self.managers["index_manager"] = index_manager

    def configure_snapshot_manager(self):
        assert "index" in self.features, "'snapshot' feature requires 'index'"
        from biothings.hub.dataindex.snapshooter import SnapshotManager
        args = self.mixargs("snapshot")
        snapshot_manager = SnapshotManager(
                index_manager=self.managers["index_manager"],
                job_manager=self.managers["job_manager"],
                **args)
        snapshot_manager.configure(config.SNAPSHOT_CONFIG)
        #snapshot_manager.poll("snapshot",lambda doc: snapshot_manager.snapshot(snapshot_env=???,index=doc["_id"]))
        self.managers["snapshot_manager"] = snapshot_manager

    def configure_release_manager(self):
        assert "diff" in self.features, "'release' feature requires 'diff'"
        assert "snapshot" in self.features, "'release' feature requires 'snapshot'"
        from biothings.hub.datarelease.publisher import ReleaseManager
        args = self.mixargs("release")
        release_manager = ReleaseManager(
                diff_manager=self.managers["diff_manager"],
                snapshot_manager=self.managers["snapshot_manager"],
                job_manager=self.managers["job_manager"],
                poll_schedule="* * * * * */10",**args)
        release_manager.configure(config.RELEASE_CONFIG)
        release_manager.poll("release_note",lambda doc: release_manager.create_release_note(old=None,new=doc["_id"]))
        self.managers["release_manager"] = release_manager

    def configure_sync_manager(self):
        from biothings.hub.databuild.syncer import SyncerManager
        args = self.mixargs("sync")
        sync_manager = SyncerManager(job_manager=self.managers["job_manager"],**args)
        sync_manager.configure()
        self.managers["sync_manager"] = sync_manager

    def configure_inspect_manager(self):
        assert "upload" in self.features, "'inspect' feature requires 'upload'"
        assert "build" in self.features, "'inspect' feature requires 'build'"
        from biothings.hub.datainspect.inspector import InspectorManager
        args = self.mixargs("inspect")
        inspect_manager = InspectorManager(
                upload_manager=self.managers["upload_manager"],
                build_manager=self.managers["build_manager"],
                job_manager=self.managers["job_manager"],**args)
        self.managers["inspect_manager"] = inspect_manager

    def configure_api_manager(self):
        assert "index" in self.features, "'api' feature requires 'index'"
        from biothings.hub.api.manager import APIManager
        args = self.mixargs("api")
        api_manager = APIManager(**args)
        self.managers["api_manager"] = api_manager

    def configure_source_manager(self):
        if "dump" in self.features or "upload" in self.features:
            args = self.mixargs("source")
            from biothings.hub.dataload.source import SourceManager
            source_manager = SourceManager(
                    source_list=self.source_list,
                    dump_manager=self.managers["dump_manager"],
                    upload_manager=self.managers["upload_manager"],
                    data_plugin_manager=self.managers.get("dataplugin_manager"),
                    )
            self.managers["source_manager"] = source_manager
        # init data plugin once source_manager has been set (it inits dumper and uploader
        # managers, if assistant_manager is configured/loaded before, datasources won't appear
        # in dumper/uploader managers as they were not ready yet)
        if "dataplugin" in self.features:
            self.managers["assistant_manager"].configure()
            self.managers["assistant_manager"].load()

        # now that we have the source manager setup, we can schedule and poll
        if "dump" in self.features and not getattr(config,"SKIP_DUMPER_SCHEDULE",False):
            self.managers["dump_manager"].schedule_all()
        if "upload" in self.features and not getattr(config,"SKIP_UPLOADER_POLL",False):
            self.managers["upload_manager"].poll('upload',lambda doc:
                    self.shell.launch(partial(self.managers["upload_manager"].upload_src,doc["_id"])))

    def configure_managers(self):
        if not self.managers is None:
            raise Exception("Managers have already been configured")
        self.managers = {}

        self.logger.info("Setting up managers for following features: %s" % self.features)
        assert "job" in self.features, "'job' feature is mandatory"
        if "source" in self.features:
            assert "dump" in self.features and "upload" in self.features, \
                    "'source' feature requires both 'dump' and 'upload' features"
        if "dataplugin" in self.features:
            assert "source" in self.features, "'dataplugin' feature requires 'source' feature"

        # specific order, eg. job_manager is used by all managers
        for feat in self.features:
            if hasattr(self,"configure_%s_manager" % feat):
                getattr(self,"configure_%s_manager" % feat)()
                self.remaining_features.remove(feat)
            elif hasattr(self,"configure_%s_feature" % feat):
                # see configure_remaining_features()
                pass # this is configured after managers but should not produce an error
            else:
                raise AttributeError("Feature '%s' listed but no 'configure_%s_{manager|feature}' method found" % (feat,feat))

        self.logger.info("Active manager(s): %s" % pformat(self.managers))

    def configure_config_feature(self):
        # just a placeholder
        pass

    def configure_ws_feature(self):
        # add websocket endpoint
        import biothings.hub.api.handlers.ws as ws
        import sockjs.tornado
        from biothings.utils.hub_db import ChangeWatcher
        # monitor change in database to report activity in webapp
        self.db_listener = ws.HubDBListener()
        ChangeWatcher.add(self.db_listener)
        ChangeWatcher.publish()
        self.log_listener = ws.LogListener()
        # push log statements to the webapp
        root_logger = logging.getLogger() # careful, asyncio logger will trigger log statement while in the handler
                                          # (ie. infinite loop), root logger not recommended) 
        root_logger.addHandler(WSLogHandler(self.log_listener))
        self.ws_listeners.extend([self.db_listener,self.log_listener])

        ws_router = sockjs.tornado.SockJSRouter(
                partial(ws.WebSocketConnection,
                    listeners=self.ws_listeners),
                '/ws')
        self.routes.extend(ws_router.urls)

    def configure_terminal_feature(self):
        assert "ws" in self.features, "'terminal' feature requires 'ws'"
        assert "ws" in self.remaining_features, "'terminal' feature should configured before 'ws'"
        # shell logger/listener to communicate between webapp and hub ssh console
        import biothings.hub.api.handlers.ws as ws
        shell_listener = ws.LogListener()
        shell_logger = logging.getLogger("shell")
        assert isinstance(shell_logger,ShellLogger), "shell_logger isn't properly set"
        shell_logger.addHandler(WSShellHandler(shell_listener))
        self.ws_listeners.append(shell_listener)
        # webapp terminal to hub shell connection through /shell endpoint
        from biothings.hub.api.handlers.shell import ShellHandler
        shell_endpoint = ("/shell",ShellHandler,
                {"shell":self.shell,"shellog":shell_logger})
        self.routes.append(shell_endpoint)

    def configure_dataupload_feature(self):
        assert "ws" in self.features, "'dataupload' feature requires 'ws'"
        assert "ws" in self.remaining_features, "'dataupload' feature should configured before 'ws'"
        # this one is not bound to a specific command
        from biothings.hub.api.handlers.upload import UploadHandler
        # tuple type = interpreted as a route handler
        self.routes.append(("/dataupload/([\w\.-]+)?",UploadHandler,self.dataupload_config))

    def configure_reloader_feature(self):
        monitored_folders = self.reloader_config["folders"] or ["hub/dataload/sources",getattr(config,"DATA_PLUGIN_FOLDER",None)]
        reload_managers = [self.managers[m] for m in self.reloader_config["managers"] if m in self.managers]
        reload_func = self.reloader_config["reload_func"] or partial(self.shell.restart,force=True)
        reloader = HubReloader(monitored_folders, reload_managers, reload_func=reload_func)
        reloader.monitor()

    def configure_remaining_features(self):
        self.logger.info("Setting up remaining features: %s" % self.remaining_features)
        # specific order, eg. job_manager is used by all managers
        for feat in copy.deepcopy(self.remaining_features):
            if hasattr(self,"configure_%s_feature" % feat):
                getattr(self,"configure_%s_feature" % feat)()
                self.remaining_features.remove(feat)
                pass # this is configured after managers but should not produce an error
            else:
                raise AttributeError("Feature '%s' listed but no 'configure_%s_feature' method found" % (feat,feat))
        
    def configure_commands(self):
        """
        Configure hub commands according to available managers
        """
        assert self.managers, "No managers configured"
        self.commands = HubCommands()
        self.commands["status"] = CommandDefinition(command=partial(status,self.managers),tracked=False)
        if "config" in self.features:
            self.commands["config"] = CommandDefinition(command=config.show,tracked=False)
            self.commands["setconf"] = config.store_value_to_db
            self.commands["resetconf"] = config.reset
        # getting info
        if self.managers.get("source_manager"):
            self.commands["source_info"] = CommandDefinition(command=self.managers["source_manager"].get_source,tracked=False)
            self.commands["source_reset"] = CommandDefinition(command=self.managers["source_manager"].reset,tracked=True)
        # dump commands
        if self.managers.get("dump_manager"):
            self.commands["dump"] = self.managers["dump_manager"].dump_src
            self.commands["dump_all"] = self.managers["dump_manager"].dump_all
        # upload commands
        if self.managers.get("upload_manager"):
            self.commands["upload"] = self.managers["upload_manager"].upload_src
            self.commands["upload_all"] = self.managers["upload_manager"].upload_all
        # building/merging
        if self.managers.get("build_manager"):
            self.commands["whatsnew"] = CommandDefinition(command=self.managers["build_manager"].whatsnew,tracked=False)
            self.commands["lsmerge"] = self.managers["build_manager"].list_merge
            self.commands["rmmerge"] = self.managers["build_manager"].delete_merge
            self.commands["merge"] = self.managers["build_manager"].merge
            self.commands["archive"] = self.managers["build_manager"].archive_merge
        if hasattr(config,"INDEX_CONFIG"):
            self.commands["index_config"] = config.INDEX_CONFIG
        if hasattr(config,"SNAPSHOT_CONFIG"):
            self.commands["snapshot_config"] = config.SNAPSHOT_CONFIG
        if hasattr(config,"PUBLISH_CONFIG"):
            self.commands["publish_config"] = config.PUBLISH_CONFIG
        # diff
        if self.managers.get("diff_manager"):
            self.commands["diff"] = self.managers["diff_manager"].diff
            self.commands["report"] = self.managers["diff_manager"].diff_report
        # indexing commands
        if self.managers.get("index_manager"):
            self.commands["index"] = self.managers["index_manager"].index
        if self.managers.get("snapshot_manager"):
            self.commands["snapshot"] = self.managers["snapshot_manager"].snapshot
        # data release commands
        if self.managers.get("release_manager"):
            self.commands["create_release_note"] = self.managers["release_manager"].create_release_note
            self.commands["get_release_note"] = CommandDefinition(command=self.managers["release_manager"].get_release_note,tracked=False)
            self.commands["publish"] = self.managers["release_manager"].publish
            self.commands["publish_diff"] = self.managers["release_manager"].publish_diff
            self.commands["publish_snapshot"] = self.managers["release_manager"].publish_snapshot
        if self.managers.get("sync_manager"):
            self.commands["sync"] = CommandDefinition(command=self.managers["sync_manager"].sync)
        # inspector
        if self.managers.get("inspect_manager"):
            self.commands["inspect"] = self.managers["inspect_manager"].inspect
        # data plugins
        if self.managers.get("assistant_manager"):
            self.commands["register_url"] = partial(self.managers["assistant_manager"].register_url)
            self.commands["unregister_url"] = partial(self.managers["assistant_manager"].unregister_url)
            self.commands["export_plugin"] = partial(self.managers["assistant_manager"].export)
        if self.managers.get("dataplugin_manager"):
            self.commands["dump_plugin"] = self.managers["dataplugin_manager"].dump_src

        logging.info("Registered commands: %s" % list(self.commands.keys()))

    def configure_extra_commands(self):
        """
        Same as configure_commands() but commands are not exposed publicly in the shell
        (they are shortcuts or commands for API endpoints, supporting commands, etc...)
        """
        assert self.managers, "No managers configured"
        self.extra_commands = {} # unordered since not exposed, we don't care
        loop = self.managers.get("job_manager") and self.managers["job_manager"].loop or asyncio.get_event_loop()
        self.extra_commands["g"] = CommandDefinition(command=globals(),tracked=False)
        self.extra_commands["sch"] = CommandDefinition(command=partial(schedule,loop),tracked=False)
        # expose contant so no need to put quotes (eg. top(pending) instead of top("pending")
        self.extra_commands["pending"] = CommandDefinition(command=pending,tracked=False)
        self.extra_commands["loop"] = CommandDefinition(command=loop,tracked=False)

        if self.managers.get("job_manager"):
            self.extra_commands["pqueue"] = CommandDefinition(command=self.managers["job_manager"].process_queue,tracked=False)
            self.extra_commands["tqueue"] = CommandDefinition(command=self.managers["job_manager"].thread_queue,tracked=False)
            self.extra_commands["jm"] = CommandDefinition(command=self.managers["job_manager"],tracked=False)
            self.extra_commands["top"] = CommandDefinition(command=self.managers["job_manager"].top,tracked=False)
            self.extra_commands["job_info"] = CommandDefinition(command=self.managers["job_manager"].job_info,tracked=False)
        if self.managers.get("source_manager"):
            self.extra_commands["sm"] = CommandDefinition(command=self.managers["source_manager"],tracked=False)
            self.extra_commands["sources"] = CommandDefinition(command=self.managers["source_manager"].get_sources,tracked=False)
            self.extra_commands["source_save_mapping"] = CommandDefinition(command=self.managers["source_manager"].save_mapping)
        if self.managers.get("dump_manager"):
            self.extra_commands["dm"] = CommandDefinition(command=self.managers["dump_manager"],tracked=False)
            self.extra_commands["dump_info"] = CommandDefinition(command=self.managers["dump_manager"].dump_info,tracked=False)
        if self.managers.get("dataplugin_manager"):
            self.extra_commands["dpm"] = CommandDefinition(command=self.managers["dataplugin_manager"],tracked=False)
        if self.managers.get("assistant_manager"):
            self.extra_commands["am"] = CommandDefinition(command=self.managers["assistant_manager"],tracked=False)
        if self.managers.get("upload_manager"):
            self.extra_commands["um"] = CommandDefinition(command=self.managers["upload_manager"],tracked=False)
            self.extra_commands["upload_info"] = CommandDefinition(command=self.managers["upload_manager"].upload_info,tracked=False)
        if self.managers.get("build_manager"):
            self.extra_commands["bm"] = CommandDefinition(command=self.managers["build_manager"],tracked=False)
            self.extra_commands["builds"] = CommandDefinition(command=self.managers["build_manager"].build_info,tracked=False)
            self.extra_commands["build"] = CommandDefinition(command=lambda id: self.managers["build_manager"].build_info(id=id),tracked=False)
            self.extra_commands["build_config_info"] = CommandDefinition(command=self.managers["build_manager"].build_config_info,tracked=False)
            self.extra_commands["build_save_mapping"] = CommandDefinition(command=self.managers["build_manager"].save_mapping)
            self.extra_commands["create_build_conf"] = CommandDefinition(command=self.managers["build_manager"].create_build_configuration)
            self.extra_commands["update_build_conf"] = CommandDefinition(command=self.managers["build_manager"].update_build_configuration)
            self.extra_commands["delete_build_conf"] = CommandDefinition(command=self.managers["build_manager"].delete_build_configuration)
        if self.managers.get("diff_manager"):
            self.extra_commands["dim"] = CommandDefinition(command=self.managers["diff_manager"],tracked=False)
            self.extra_commands["diff_info"] = CommandDefinition(command=self.managers["diff_manager"].diff_info,tracked=False)
            self.extra_commands["jsondiff"] = CommandDefinition(command=jsondiff,tracked=False)
        if self.managers.get("sync_manager"):
            self.extra_commands["sym"] = CommandDefinition(command=self.managers["sync_manager"],tracked=False)
        if self.managers.get("index_manager"):
            self.extra_commands["im"] = CommandDefinition(command=self.managers["index_manager"],tracked=False)
            self.extra_commands["index_info"] = CommandDefinition(command=self.managers["index_manager"].index_info,tracked=False)
            self.extra_commands["validate_mapping"] = CommandDefinition(command=self.managers["index_manager"].validate_mapping)
        if self.managers.get("snapshot_manager"):
            self.extra_commands["ssm"] = CommandDefinition(command=self.managers["snapshot_manager"],tracked=False)
            self.extra_commands["snapshot_info"] = CommandDefinition(command=self.managers["snapshot_manager"].snapshot_info,tracked=False)
        if self.managers.get("release_manager"):
            self.extra_commands["rm"] = CommandDefinition(command=self.managers["release_manager"],tracked=False)
            self.extra_commands["release_info"] = CommandDefinition(command=self.managers["release_manager"].release_info,tracked=False)
            self.extra_commands["reset_synced"] = CommandDefinition(command=self.managers["release_manager"].reset_synced,tracked=True)
        if self.managers.get("inspect_manager"):
            self.extra_commands["ism"] = CommandDefinition(command=self.managers["inspect_manager"],tracked=False)
        if self.managers.get("api_manager"):
            self.extra_commands["api"] = CommandDefinition(command=self.managers["api_manager"],tracked=False)
            self.extra_commands["get_apis"] = CommandDefinition(command=self.managers["api_manager"].get_apis,tracked=False)
            self.extra_commands["delete_api"] = CommandDefinition(command=self.managers["api_manager"].delete_api)
            self.extra_commands["create_api"] = CommandDefinition(command=self.managers["api_manager"].create_api)
            self.extra_commands["start_api"] = CommandDefinition(command=self.managers["api_manager"].start_api)
            self.extra_commands["stop_api"] = self.managers["api_manager"].stop_api

        logging.debug("Registered extra (private) commands: %s" % list(self.extra_commands.keys()))

    def configure_api_endpoints(self):
        cmdnames = list(self.commands.keys())
        if self.extra_commands:
            cmdnames.extend(list(self.extra_commands.keys()))
        from biothings.hub.api import EndpointDefinition
        self.api_endpoints = {}
        self.api_endpoints["config"] = []
        if "config" in cmdnames:
            self.api_endpoints["config"].append(EndpointDefinition(name="config",method="get"))
            self.api_endpoints["config"].append(EndpointDefinition(name="setconf",method="put",force_bodyargs=True))
            self.api_endpoints["config"].append(EndpointDefinition(name="resetconf",method="delete",force_bodyargs=True))
        if not self.api_endpoints["config"]:
            self.api_endpoints.pop("config")
        if "builds" in cmdnames: self.api_endpoints["builds"] = EndpointDefinition(name="builds",method="get")
        self.api_endpoints["build"] = []
        if "build" in cmdnames: self.api_endpoints["build"].append(EndpointDefinition(method="get",name="build"))
        if "archive" in cmdnames: self.api_endpoints["build"].append(EndpointDefinition(method="post",name="archive",suffix="archive"))
        if "rmmerge" in cmdnames: self.api_endpoints["build"].append(EndpointDefinition(method="delete",name="rmmerge"))
        if "merge" in cmdnames: self.api_endpoints["build"].append(EndpointDefinition(name="merge",method="put",suffix="new"))
        if "build_save_mapping" in cmdnames: self.api_endpoints["build"].append(EndpointDefinition(name="build_save_mapping",method="put",suffix="mapping"))
        if not self.api_endpoints["build"]:
            self.api_endpoints.pop("build")
        self.api_endpoints["publish"] = []
        if "publish_diff" in cmdnames: self.api_endpoints["publish"].append(EndpointDefinition(name="publish_diff",method="post",suffix="incremental",force_bodyargs=True))
        if "publish_snapshot" in cmdnames: self.api_endpoints["publish"].append(EndpointDefinition(name="publish_snapshot",method="post",suffix="full",force_bodyargs=True))
        if not self.api_endpoints["publish"]:
            self.api_endpoints.pop("publish")
        if "diff" in cmdnames: self.api_endpoints["diff"] = EndpointDefinition(name="diff",method="put",force_bodyargs=True)
        if "job_info" in cmdnames: self.api_endpoints["job_manager"] = EndpointDefinition(name="job_info",method="get")
        if "dump_info" in cmdnames: self.api_endpoints["dump_manager"] = EndpointDefinition(name="dump_info", method="get")
        if "upload_info" in cmdnames: self.api_endpoints["upload_manager"] = EndpointDefinition(name="upload_info",method="get")
        if "build_config_info" in cmdnames: self.api_endpoints["build_manager"] = EndpointDefinition(name="build_config_info",method="get")
        if "index_info" in cmdnames: self.api_endpoints["index_manager"] = EndpointDefinition(name="index_info",method="get")
        if "snapshot_info" in cmdnames: self.api_endpoints["snapshot_manager"] = EndpointDefinition(name="snapshot_info",method="get")
        if "release_info" in cmdnames: self.api_endpoints["release_manager"] = EndpointDefinition(name="release_info",method="get")
        if "reset_synced" in cmdnames: self.api_endpoints["release_manager/reset_synced"] = EndpointDefinition(name="reset_synced",method="put")
        if "diff_info" in cmdnames: self.api_endpoints["diff_manager"] = EndpointDefinition(name="diff_info",method="get")
        if "commands" in cmdnames: self.api_endpoints["commands"] = EndpointDefinition(name="commands",method="get")
        if "command" in cmdnames: self.api_endpoints["command"] = EndpointDefinition(name="command",method="get")
        if "sources" in cmdnames: self.api_endpoints["sources"] = EndpointDefinition(name="sources",method="get")
        self.api_endpoints["source"] = []
        if "source_info" in cmdnames: self.api_endpoints["source"].append(EndpointDefinition(name="source_info",method="get"))
        if "source_reset" in cmdnames: self.api_endpoints["source"].append(EndpointDefinition(name="source_reset",method="post",suffix="reset"))
        if "dump" in cmdnames: self.api_endpoints["source"].append(EndpointDefinition(name="dump",method="put",suffix="dump"))
        if "upload" in cmdnames: self.api_endpoints["source"].append(EndpointDefinition(name="upload",method="put",suffix="upload"))
        if "source_save_mapping" in cmdnames: self.api_endpoints["source"].append(EndpointDefinition(name="source_save_mapping",method="put",suffix="mapping"))
        if not self.api_endpoints["source"]:
            self.api_endpoints.pop("source")
        if "inspect" in cmdnames: self.api_endpoints["inspect"] = EndpointDefinition(name="inspect",method="put",force_bodyargs=True)
        if "register_url" in cmdnames: self.api_endpoints["dataplugin/register_url"] = EndpointDefinition(name="register_url",method="post",force_bodyargs=True)
        if "unregister_url" in cmdnames: self.api_endpoints["dataplugin/unregister_url"] = EndpointDefinition(name="unregister_url",method="delete",force_bodyargs=True)
        self.api_endpoints["dataplugin"] = []
        if "dump_plugin" in cmdnames: self.api_endpoints["dataplugin"].append(EndpointDefinition(name="dump_plugin",method="put",suffix="dump"))
        if "export_plugin" in cmdnames: self.api_endpoints["dataplugin"].append(EndpointDefinition(name="export_plugin",method="put",suffix="export"))
        if not self.api_endpoints["dataplugin"]:
            self.api_endpoints.pop("dataplugin")
        if "jsondiff" in cmdnames: self.api_endpoints["jsondiff"] = EndpointDefinition(name="jsondiff",method="post",force_bodyargs=True)
        if "validate_mapping" in cmdnames: self.api_endpoints["mapping/validate"] = EndpointDefinition(name="validate_mapping",method="post",force_bodyargs=True)
        self.api_endpoints["buildconf"] = []
        if "create_build_conf" in cmdnames:
            self.api_endpoints["buildconf"].append(EndpointDefinition(name="create_build_conf",method="post",force_bodyargs=True))
            self.api_endpoints["buildconf"].append(EndpointDefinition(name="update_build_conf",method="put",force_bodyargs=True))
        if "delete_build_conf" in cmdnames: self.api_endpoints["buildconf"].append(EndpointDefinition(name="delete_build_conf",method="delete",force_bodyargs=True))
        if not self.api_endpoints["buildconf"]:
            self.api_endpoints.pop("buildconf")
        if "index" in cmdnames: self.api_endpoints["index"] = EndpointDefinition(name="index",method="put",force_bodyargs=True)
        if "snapshot" in cmdnames: self.api_endpoints["snapshot"] = EndpointDefinition(name="snapshot",method="put",force_bodyargs=True)
        if "sync" in cmdnames: self.api_endpoints["sync"] = EndpointDefinition(name="sync",method="post",force_bodyargs=True)
        if "whatsnew" in cmdnames: self.api_endpoints["whatsnew"] = EndpointDefinition(name="whatsnew",method="get")
        if "status" in cmdnames: self.api_endpoints["status"] = EndpointDefinition(name="status",method="get")
        self.api_endpoints["release_note"] = []
        if "create_release_note" in cmdnames:
            self.api_endpoints["release_note"].append(EndpointDefinition(name="create_release_note",method="put",suffix="create",force_bodyargs=True))
        if "get_release_note" in cmdnames:
            self.api_endpoints["release_note"].append(EndpointDefinition(name="get_release_note",method="get",force_bodyargs=True))
        if not self.api_endpoints["release_note"]:
            self.api_endpoints.pop("release_note")
        self.api_endpoints["api"] = []
        if "start_api" in cmdnames: self.api_endpoints["api"].append(EndpointDefinition(name="start_api",method="put",suffix="start"))
        if "stop_api" in cmdnames: self.api_endpoints["api"].append(EndpointDefinition(name="stop_api",method="put",suffix="stop"))
        if "delete_api" in cmdnames: self.api_endpoints["api"].append(EndpointDefinition(name="delete_api",method="delete",force_bodyargs=True))
        if "create_api" in cmdnames: self.api_endpoints["api"].append(EndpointDefinition(name="create_api",method="post",force_bodyargs=True))
        if not self.api_endpoints["api"]:
            self.api_endpoints.pop("api")
        if "get_apis" in cmdnames: self.api_endpoints["api/list"] = EndpointDefinition(name="get_apis",method="get")
        if "stop" in cmdnames: self.api_endpoints["stop"] = EndpointDefinition(name="stop",method="put")
        if "restart" in cmdnames: self.api_endpoints["restart"] = EndpointDefinition(name="restart",method="put")
コード例 #2
0
        EndpointDefinition(name="delete_api",
                           method="delete",
                           force_bodyargs=True),
        EndpointDefinition(name="create_api",
                           method="post",
                           force_bodyargs=True)
    ],
    "api/list":
    EndpointDefinition(name="get_apis", method="get"),
    "stop":
    EndpointDefinition(name="stop", method="put"),
    "restart":
    EndpointDefinition(name="restart", method="put"),
}

shell.set_commands(COMMANDS, EXTRA_NS)

import tornado.platform.asyncio
tornado.platform.asyncio.AsyncIOMainLoop().install()

settings = {'debug': True}
routes = generate_api_routes(shell, API_ENDPOINTS, settings=settings)
# add websocket endpoint
import biothings.hub.api.handlers.ws as ws
import sockjs.tornado
from biothings.utils.hub_db import ChangeWatcher
listener = ws.HubDBListener()
ChangeWatcher.add(listener)
ChangeWatcher.publish()
ws_router = sockjs.tornado.SockJSRouter(
    partial(ws.WebSocketConnection, listener=listener), '/ws')