def __init__(self, host, port): # Now import the girder modules. If this fails, it's up to the # administrator to make sure Girder is installed and on the PYTHONPATH. import girder.events from girder import constants from girder.api import api_main from girder import constants from girder.utility import plugin_utilities, model_importer self.root_dir = constants.ROOT_DIR api_main.addApiToNode(self) cherrypy.engine.subscribe("start", girder.events.daemon.start) cherrypy.engine.subscribe("stop", girder.events.daemon.stop) plugins = model_importer.ModelImporter().model('setting').get( constants.SettingKey.PLUGINS_ENABLED, default=()) plugin_utilities.loadPlugins(plugins, self, cherrypy.config) self.config = { "/": { "request.dispatch": cherrypy.dispatch.MethodDispatcher(), "tools.staticdir.root": self.root_dir }, "/static": { "tools.staticdir.on": "True", "tools.staticdir.dir": "clients/web/static" } }
def loadRouteTable(reconcileRoutes=False): """ Retrieves the route table from Girder and reconciles the state of it with the current application state. Reconciliation ensures that every enabled plugin has a route by assigning default routes for plugins that have none, such as newly-enabled plugins. :returns: The non empty routes (as a dict of name -> route) to be mounted by CherryPy during Girder's setup phase. """ pluginWebroots = plugin_utilities.getPluginWebroots() setting = model_importer.ModelImporter().model('setting') routeTable = setting.get(constants.SettingKey.ROUTE_TABLE) def reconcileRouteTable(routeTable): hasChanged = False for name in pluginWebroots.keys(): if name not in routeTable: routeTable[name] = os.path.join('/', name) hasChanged = True if hasChanged: setting.set(constants.SettingKey.ROUTE_TABLE, routeTable) return routeTable if reconcileRoutes: routeTable = reconcileRouteTable(routeTable) return { name: route for (name, route) in six.viewitems(routeTable) if route }
def _getPluginBuildArgs(buildAll, plugins): if buildAll: return ['--all-plugins'] elif not plugins: # build only the enabled plugins settings = model_importer.ModelImporter().model('setting') plugins = settings.get(constants.SettingKey.PLUGINS_ENABLED, default=()) plugins = ','.join( plugin_utilities.getToposortedPlugins(plugins, ignoreMissing=True)) return ['--plugins=%s' % plugins]
def _verifyOpenRegistration(): """ Raises a REST exception if registration policy on the server is not set to 'open'. This should be called by the provider-specific code in the case when a user logs in with an email that is not already tied to an existing user. """ policy = model_importer.ModelImporter().model('setting').get( SettingKey.REGISTRATION_POLICY, default='open') if policy != 'open': raise RestException( 'Registration on this instance is closed. Contact an administrator ' 'to create an account for you.')
def loadRouteTable(reconcileRoutes=False): """ Retrieves the route table from Girder and reconciles the state of it with the current application state. Reconciliation deals with 2 scenarios: 1. A plugin is no longer active (by being disabled or removed) and the route for the plugin needs to be removed. 2. A webroot was added (a new plugin was enabled) and a default route needs to be added. :returns: The non empty routes (as a dict of name -> route) to be mounted by CherryPy during Girder's setup phase. """ pluginWebroots = plugin_utilities.getPluginWebroots() setting = model_importer.ModelImporter().model('setting') routeTable = setting.get(constants.SettingKey.ROUTE_TABLE) reservedRoutes = (constants.GIRDER_ROUTE_ID, constants.GIRDER_STATIC_ROUTE_ID) def reconcileRouteTable(routeTable): hasChanged = False # GIRDER_ROUTE_ID is a special route, which can't be removed for name in routeTable.keys(): if name not in reservedRoutes and name not in pluginWebroots: del routeTable[name] hasChanged = True for name in pluginWebroots.keys(): if name not in routeTable: routeTable[name] = os.path.join('/', name) hasChanged = True if hasChanged: setting.set(constants.SettingKey.ROUTE_TABLE, routeTable) return routeTable if reconcileRoutes: routeTable = reconcileRouteTable(routeTable) return { name: route for (name, route) in six.viewitems(routeTable) if route }
def _getPluginBuildArgs(buildAll, plugins): if buildAll: return ['--all-plugins'] elif not plugins: # build only the enabled plugins settings = model_importer.ModelImporter().model('setting') plugins = settings.get(constants.SettingKey.PLUGINS_ENABLED, default=()) plugins = list(plugin_utilities.getToposortedPlugins(plugins, ignoreMissing=True)) # include static-only dependencies that are not in the runtime load set staticPlugins = plugin_utilities.getToposortedPlugins( plugins, ignoreMissing=True, keys=('dependencies', 'staticWebDependencies')) staticPlugins = [p for p in staticPlugins if p not in plugins] return [ '--plugins=%s' % ','.join(plugins), '--configure-plugins=%s' % ','.join(staticPlugins) ]
def loadPlugin(name, root, appconf, apiRoot=None): """ Loads a plugin into the application. This means allowing it to create endpoints within its own web API namespace, and to register its event listeners, and do anything else it might want to do. :param name: The name of the plugin (i.e. its directory name) :type name: str :param root: The root node of the web API. :param appconf: The cherrypy configuration for the server. :type appconf: dict """ if apiRoot is None: apiRoot = root.api.v1 pluginDir = os.path.join(getPluginDir(), name) isPluginDir = os.path.isdir(os.path.join(pluginDir, 'server')) isPluginFile = os.path.isfile(os.path.join(pluginDir, 'server.py')) pluginLoadMethod = None if not os.path.exists(pluginDir): # Try to load the plugin as an entry_point for entry_point in iter_entry_points(group='girder.plugin', name=name): pluginLoadMethod = entry_point.load() module = importlib.import_module(entry_point.module_name) pluginDir = os.path.dirname(module.__file__) module.PLUGIN_ROOT_DIR = pluginDir girder.plugins.__dict__[name] = module isPluginDir = True if not os.path.exists(pluginDir): raise Exception('Plugin directory does not exist: %s' % pluginDir) if not isPluginDir and not isPluginFile: # This plugin does not have any server-side python code. return root, appconf, apiRoot mailTemplatesDir = os.path.join(pluginDir, 'server', 'mail_templates') if os.path.isdir(mailTemplatesDir): # If the plugin has mail templates, add them to the lookup path mail_utils.addTemplateDirectory(mailTemplatesDir, prepend=True) moduleName = '.'.join((ROOT_PLUGINS_PACKAGE, name)) if moduleName not in sys.modules: fp = None try: # @todo this query is run for every plugin that's loaded setting = model_importer.ModelImporter().model('setting') routeTable = setting.get(SettingKey.ROUTE_TABLE) info = { 'name': name, 'config': appconf, 'serverRoot': root, 'serverRootPath': routeTable[GIRDER_ROUTE_ID], 'apiRoot': apiRoot, 'staticRoot': routeTable[GIRDER_STATIC_ROUTE_ID], 'pluginRootDir': os.path.abspath(pluginDir) } if pluginLoadMethod is None: fp, pathname, description = imp.find_module( 'server', [pluginDir]) module = imp.load_module(moduleName, fp, pathname, description) module.PLUGIN_ROOT_DIR = pluginDir girder.plugins.__dict__[name] = module pluginLoadMethod = getattr(module, 'load', None) if pluginLoadMethod is not None: sys.modules[moduleName] = module pluginLoadMethod(info) root, appconf, apiRoot = (info['serverRoot'], info['config'], info['apiRoot']) finally: if fp: fp.close() return root, appconf, apiRoot
def configureServer(test=False, plugins=None, curConfig=None): """ Function to setup the cherrypy server. It configures it, but does not actually start it. :param test: Set to True when running in the tests. :type test: bool :param plugins: If you wish to start the server with a custom set of plugins, pass this as a list of plugins to load. Otherwise, will use the PLUGINS_ENABLED setting value from the db. :param curConfig: The configuration dictionary to update. """ if curConfig is None: curConfig = config.getConfig() appconf = { '/': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'request.show_tracebacks': test, 'request.methods_with_bodies': ('POST', 'PUT', 'PATCH'), 'response.headers.server': 'Girder %s' % __version__, 'error_page.default': _errorDefault } } # Add MIME types for serving Fontello files from staticdir; # these may be missing or incorrect in the OS mimetypes.add_type('application/vnd.ms-fontobject', '.eot') mimetypes.add_type('application/x-font-ttf', '.ttf') mimetypes.add_type('application/font-woff', '.woff') if test: appconf['/src'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'clients/web/src', } appconf['/test'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'clients/web/test', } appconf['/clients'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'clients' } appconf['/plugins'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'plugins', } curConfig.update(appconf) if test: # Force some config params in testing mode curConfig.update({ 'server': { 'mode': 'testing', 'api_root': 'api/v1', 'static_root': 'static', 'api_static_root': '../static', 'cherrypy_server': True } }) mode = curConfig['server']['mode'].lower() logprint.info('Running in mode: ' + mode) cherrypy.config['engine.autoreload.on'] = mode == 'development' # Don't import this until after the configs have been read; some module # initialization code requires the configuration to be set up. from girder.api import api_main root = webroot.Webroot() api_main.addApiToNode(root) cherrypy.engine.subscribe('start', girder.events.daemon.start) cherrypy.engine.subscribe('stop', girder.events.daemon.stop) if plugins is None: settings = model_importer.ModelImporter().model('setting') plugins = settings.get(constants.SettingKey.PLUGINS_ENABLED, default=()) plugins = list( plugin_utilities.getToposortedPlugins(plugins, ignoreMissing=True)) _configureStaticRoutes(root, plugins) girder.events.bind( 'model.setting.save.after', '_updateStaticRoutesIfModified', functools.partial(_configureStaticRoutes, root, plugins)) root, appconf, _ = plugin_utilities.loadPlugins(plugins, root, appconf, root.api.v1, buildDag=False) return root, appconf
def configureServer(test=False, plugins=None, curConfig=None): """ Function to setup the cherrypy server. It configures it, but does not actually start it. :param test: Set to True when running in the tests. :type test: bool :param plugins: If you wish to start the server with a custom set of plugins, pass this as a list of plugins to load. Otherwise, will use the PLUGINS_ENABLED setting value from the db. :param curConfig: The configuration dictionary to update. """ if curConfig is None: curConfig = config.getConfig() routeTable = loadRouteTable() appconf = { '/': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'request.show_tracebacks': test, 'request.methods_with_bodies': ('POST', 'PUT', 'PATCH'), 'response.headers.server': 'Girder %s' % __version__, 'error_page.default': _errorDefault } } # Add MIME types for serving Fontello files from staticdir; # these may be missing or incorrect in the OS mimetypes.add_type('application/vnd.ms-fontobject', '.eot') mimetypes.add_type('application/x-font-ttf', '.ttf') mimetypes.add_type('application/font-woff', '.woff') if test: appconf['/src'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'clients/web/src', } appconf['/test'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'clients/web/test', } appconf['/clients'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'clients' } appconf['/plugins'] = { 'tools.staticdir.on': True, 'tools.staticdir.root': constants.STATIC_ROOT_DIR, 'tools.staticdir.dir': 'plugins', } curConfig.update(appconf) if test: # Force some config params in testing mode curConfig.update({ 'server': { 'mode': 'testing', 'api_root': 'api/v1', 'static_root': 'static', 'api_static_root': '../static' } }) mode = curConfig['server']['mode'].lower() logprint.info('Running in mode: ' + mode) cherrypy.config['engine.autoreload.on'] = mode == 'development' # Don't import this until after the configs have been read; some module # initialization code requires the configuration to be set up. from girder.api import api_main root = webroot.Webroot() api_main.addApiToNode(root) cherrypy.engine.subscribe('start', girder.events.daemon.start) cherrypy.engine.subscribe('stop', girder.events.daemon.stop) if plugins is None: settings = model_importer.ModelImporter().model('setting') plugins = settings.get(constants.SettingKey.PLUGINS_ENABLED, default=()) plugins = list( plugin_utilities.getToposortedPlugins(plugins, ignoreMissing=True)) root.updateHtmlVars({ 'apiRoot': curConfig['server']['api_root'], 'staticRoot': os.path.relpath(routeTable[constants.GIRDER_STATIC_ROUTE_ID], routeTable[constants.GIRDER_ROUTE_ID]), 'plugins': plugins }) # Make the staticRoot relative to the api_root, if possible. The api_root # could be relative or absolute, but it needs to be in an absolute form for # relpath to behave as expected. We always expect the api_root to # contain at least two components, but the reference from static needs to # be from only the first component. apiRootBase = os.path.split( os.path.join('/', curConfig['server']['api_root']))[0] root.api.v1.updateHtmlVars({ 'apiRoot': curConfig['server']['api_root'], 'staticRoot': os.path.relpath(routeTable[constants.GIRDER_STATIC_ROUTE_ID], apiRootBase) }) root, appconf, _ = plugin_utilities.loadPlugins(plugins, root, appconf, root.api.v1, buildDag=False) return root, appconf
def setup(test=False, plugins=None): """ Function to setup the cherrypy server. It configures it, but does not actually start it. :param test: Set to True when running in the tests. :type test: bool :param plugins: If you wish to start the server with a custom set of plugins, pass this as a list of plugins to load. Otherwise, will use the PLUGINS_ENABLED setting value from the db. """ cur_config = config.getConfig() appconf = { '/': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'tools.staticdir.root': constants.ROOT_DIR, 'request.show_tracebacks': test }, '/static': { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients/web/static' } } if test: appconf['/src'] = { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients/web/src', } appconf['/test'] = { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients/web/test', } appconf['/clients'] = { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients' } cur_config.update(appconf) if test: # Force some config params in testing mode cur_config.update({ 'server': { 'mode': 'testing', 'api_root': '/api/v1', 'static_root': '/static' } }) # Don't import this until after the configs have been read; some module # initialization code requires the configuration to be set up. from girder.api import api_main root = webroot.Webroot() api_main.addApiToNode(root) if cur_config['server']['mode'] is 'development': dev_endpoints.addDevEndpoints(root, appconf) # pragma: no cover cherrypy.engine.subscribe('start', girder.events.daemon.start) cherrypy.engine.subscribe('stop', girder.events.daemon.stop) if plugins is None: settings = model_importer.ModelImporter().model('setting') plugins = settings.get(constants.SettingKey.PLUGINS_ENABLED, default=()) root.updateHtmlVars({ 'apiRoot': cur_config['server']['api_root'], 'staticRoot': cur_config['server']['static_root'], 'plugins': plugins }) plugin_utilities.loadPlugins(plugins, root, appconf) application = cherrypy.tree.mount(root, '/', appconf) if test: application.merge({'server': {'mode': 'testing'}}) return application
def configureServer(test=False, plugins=None, curConfig=None): """ Function to setup the cherrypy server. It configures it, but does not actually start it. :param test: Set to True when running in the tests. :type test: bool :param plugins: If you wish to start the server with a custom set of plugins, pass this as a list of plugins to load. Otherwise, will use the PLUGINS_ENABLED setting value from the db. :param curConfig: The configuration dictionary to update. """ if curConfig is None: curConfig = config.getConfig() curStaticRoot = constants.STATIC_ROOT_DIR appconf = { '/': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'tools.staticdir.root': curStaticRoot, 'request.show_tracebacks': test, 'request.methods_with_bodies': ('POST', 'PUT', 'PATCH') }, '/static': { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients/web/static' } } if test: appconf['/src'] = { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients/web/src', } appconf['/test'] = { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients/web/test', } appconf['/clients'] = { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'clients' } appconf['/plugins'] = { 'tools.staticdir.on': 'True', 'tools.staticdir.dir': 'plugins', } curConfig.update(appconf) if test: # Force some config params in testing mode curConfig.update({ 'server': { 'mode': 'testing', 'api_root': 'api/v1', 'static_root': 'static', 'api_static_root': '../static' } }) # Don't import this until after the configs have been read; some module # initialization code requires the configuration to be set up. from girder.api import api_main root = webroot.Webroot() api_main.addApiToNode(root) cherrypy.engine.subscribe('start', girder.events.daemon.start) cherrypy.engine.subscribe('stop', girder.events.daemon.stop) if plugins is None: settings = model_importer.ModelImporter().model('setting') plugins = settings.get(constants.SettingKey.PLUGINS_ENABLED, default=()) root.updateHtmlVars({ 'apiRoot': curConfig['server']['api_root'], 'staticRoot': curConfig['server']['static_root'], 'plugins': plugins }) apiStaticRoot = curConfig['server'].get('api_static_root', '') if not apiStaticRoot: apiStaticRoot = curConfig['server']['static_root'] root.api.v1.updateHtmlVars({ 'apiRoot': curConfig['server']['api_root'], 'staticRoot': apiStaticRoot, }) root, appconf, _ = plugin_utilities.loadPlugins(plugins, root, appconf, root.api.v1, curConfig=curConfig) return root, appconf