def server(db, request): """ Require a CherryPy embedded server. Provides a started CherryPy embedded server with a request method for performing local requests against it. Note: this fixture requires the db fixture. """ # The event daemon cannot be restarted since it is a threading.Thread object, however # all references to girder.events.daemon are a singular global daemon due to its side # effect on import. We have to hack around this by creating a unique event daemon # each time we startup the server and assigning it to the global. import girder.events from girder.api import docs from girder.constants import SettingKey from girder.models.setting import Setting from girder.utility import plugin_utilities from girder.utility.server import setup as setupServer oldPluginDir = plugin_utilities.getPluginDir girder.events.daemon = girder.events.AsyncEventsThread() enabledPlugins = [] testPluginMarkers = request.node.get_marker('testPlugin') if testPluginMarkers is not None: for testPluginMarker in testPluginMarkers: pluginName = testPluginMarker.args[0] enabledPlugins.append(pluginName) # testFilePath is a py.path.local object that we *assume* lives in 'test/', # with 'test/test_plugins' nearby testFilePath = request.node.fspath testPluginsPath = testFilePath.dirpath('test_plugins').strpath plugin_utilities.getPluginDir = mock.Mock(return_value=testPluginsPath) Setting().set(SettingKey.PLUGINS_ENABLED, enabledPlugins) server = setupServer(test=True, plugins=enabledPlugins) server.request = restRequest cherrypy.server.unsubscribe() cherrypy.config.update({'environment': 'embedded', 'log.screen': False, 'request.throw_errors': True}) cherrypy.engine.start() yield server cherrypy.engine.unsubscribe('start', girder.events.daemon.start) cherrypy.engine.unsubscribe('stop', girder.events.daemon.stop) cherrypy.engine.stop() cherrypy.engine.exit() cherrypy.tree.apps = {} plugin_utilities.getPluginDir = oldPluginDir plugin_utilities.getPluginWebroots().clear() plugin_utilities.getPluginFailureInfo().clear() docs.routes.clear()
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 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 setup(test=False, plugins=None, curConfig=None): """ Configure and mount the Girder server and plugins under the appropriate routes. See ROUTE_TABLE setting. :param test: Whether to start in test mode. :param plugins: List of plugins to enable. :param curConfig: The config object to update. """ logStdoutStderr() pluginWebroots = plugin_utilities.getPluginWebroots() girderWebroot, appconf = configureServer(test, plugins, curConfig) routeTable = loadRouteTable(reconcileRoutes=True) # Mount Girder application = cherrypy.tree.mount( girderWebroot, str(routeTable[constants.GIRDER_ROUTE_ID]), appconf) # Mount static files cherrypy.tree.mount( None, routeTable[constants.GIRDER_STATIC_ROUTE_ID], { '/': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(constants.STATIC_ROOT_DIR, 'clients/web/static'), 'request.show_tracebacks': appconf['/']['request.show_tracebacks'], 'response.headers.server': 'Girder %s' % __version__, 'error_page.default': _errorDefault } }) # Mount API (special case) # The API is always mounted at /api AND at api relative to the Girder root cherrypy.tree.mount(girderWebroot.api, '/api', appconf) # Mount everything else in the routeTable for (name, route) in six.viewitems(routeTable): if name != constants.GIRDER_ROUTE_ID and name in pluginWebroots: cherrypy.tree.mount(pluginWebroots[name], route, appconf) if test: application.merge({'server': {'mode': 'testing'}}) return application
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 setup(test=False, plugins=None, curConfig=None): """ Configure and mount the Girder server and plugins under the appropriate routes. See ROUTE_TABLE setting. :param test: Whether to start in test mode. :param plugins: List of plugins to enable. :param curConfig: The config object to update. """ logStdoutStderr() pluginWebroots = plugin_utilities.getPluginWebroots() girderWebroot, appconf = configureServer(test, plugins, curConfig) routeTable = loadRouteTable(reconcileRoutes=True) # Mount Girder application = cherrypy.tree.mount(girderWebroot, str(routeTable[constants.GIRDER_ROUTE_ID]), appconf) # Mount static files cherrypy.tree.mount(None, routeTable[constants.GIRDER_STATIC_ROUTE_ID], {'/': {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(constants.STATIC_ROOT_DIR, 'clients/web/static'), 'request.show_tracebacks': appconf['/']['request.show_tracebacks'], 'response.headers.server': 'Girder %s' % __version__, 'error_page.default': _errorDefault}}) # Mount API (special case) # The API is always mounted at /api AND at api relative to the Girder root cherrypy.tree.mount(girderWebroot.api, '/api', appconf) # Mount everything else in the routeTable for (name, route) in six.viewitems(routeTable): if name != constants.GIRDER_ROUTE_ID and name in pluginWebroots: cherrypy.tree.mount(pluginWebroots[name], route, appconf) if test: application.merge({'server': {'mode': 'testing'}}) return application