def get_project_list() -> Dict[str, str]: global _project_files_list current_time = time.time() if current_time - _project_files_last_loaded > PROJECT_CACHE_TIMEOUT: _project_files_list = load_projects() return _project_files_list
async def retry_after_address_not_found_with_flushed_cache( self, project, service_name, err): """ Retry the request again (once!) with cleared caches. """ if self.request.__riptide_retried: self.pp_500(err, traceback.format_exc()) return self.request.__riptide_retried = True self.runtime_storage.projects_mapping = load_projects() self.runtime_storage.project_cache = {} self.runtime_storage.ip_cache = {} return await self.get()
def run_proxy(system_config: Config, engine: AbstractEngine, http_port, https_port, ssl_options, start_ioloop=True): """ Run proxy on the specified port. If start_ioloop is True (default), the tornado IOLoop will be started immediately. """ start_https_msg = "" if https_port: start_https_msg = f"\n https://{system_config['proxy']['url']}:{system_config['proxy']['ports']['https']:d}" logger.info( f"Starting Riptide Proxy at: \n" f" http://{system_config['proxy']['url']}:{system_config['proxy']['ports']['http']:d}{start_https_msg}" ) # Load projects initially projects = load_projects() # Configure global storage use_compression = True if 'compression' in system_config['proxy'] and system_config['proxy']['compression'] else False storage = { "config": system_config["proxy"], "engine": engine, "runtime_storage": RuntimeStorage( projects_mapping=projects, project_cache={}, ip_cache={}, engine=engine, use_compression=use_compression ) } # Configure Routes app = tornado.web.Application(load_plugin_routes(system_config, engine, https_port, storage["runtime_storage"]) + [ # http (RiptideNoWebSocketMatcher(r'^(?!/___riptide_proxy_ws).*$'), ProxyHttpHandler, storage), # Any non-autostart websockets (r'^(?!/___riptide_proxy_ws).*$', ProxyWebsocketHandler, storage), # autostart websockets (r'/___riptide_proxy_ws', AutostartHandler, storage), ], template_path=get_resources()) # xheaders enables parsing of X-Forwarded-Ip etc. headers app.listen(http_port, xheaders=True) # Prepare HTTPS if https_port: https_app = tornado.httpserver.HTTPServer(app, ssl_options=ssl_options, xheaders=True) https_app.listen(https_port) # Start! ioloop = tornado.ioloop.IOLoop.current() if start_ioloop: ioloop.start()
def load_project_and_service(project_name, service_name, runtime_storage: RuntimeStorage) \ -> Tuple[Union[Project, None], Union[Service, None]]: """ Resolves the project object and service name for the project identified by hostname Service name may be None if no service was specified, and project is None if no project could be loaded. :param project_name: Name of the requested project :param service_name: Name of the requested service :param runtime_storage: Runtime storage object :return: Tuple of loaded project and resolved service name. Both may be empty if either of them could not be resolved. """ # Get project file if project_name not in runtime_storage.projects_mapping: # Try to reload. Maybe it was added? runtime_storage.projects_mapping = load_projects() if project_name not in runtime_storage.projects_mapping: logger.debug(f'Could not find project {project_name}') # Project not found return None, None # Load project from cache. Cache times out after some time. current_time = time.time() project_file = runtime_storage.projects_mapping[project_name] project_cache = runtime_storage.project_cache if project_file not in project_cache or current_time - project_cache[project_file][1] > PROJECT_CACHE_TIMEOUT: logger.debug(f'Loading project file for {project_name} at {project_file}') try: project = _load_single_project(project_file, runtime_storage.engine) project_cache[project_file] = [project, current_time] except FileNotFoundError as ex: # Project not found return None, None except Exception as ex: # Load error :( raise ProjectLoadError(project_name) from ex else: project = project_cache[project_file][0] project_cache[project_file][1] = current_time # Resolve service - simply return the service name again if found, otherwise just the project if service_name in project["app"]["services"]: return project, service_name return project, None
def get_all_projects(runtime_storage) -> Tuple[List[Project], List[ProjectLoadError]]: """Loads all projects that are found in the projects.json. Always reloads all projects.""" logger.debug("Project listing: Requested. Reloading all projects.") runtime_storage.projects_mapping = load_projects(True) current_time = time.time() errors = [] for project_name, project_file in runtime_storage.projects_mapping.items(): logger.debug(f"Project listing: Processing {project_name} : {project_file}") try: try: project = _load_single_project(project_file, runtime_storage.engine) runtime_storage.project_cache[project_file] = [project, current_time] except FileNotFoundError as ex: # Project not found raise ProjectLoadError(project_name) from ex except Exception as ex: # Load error :( logger.warning(f"Project listing: Could not load {project_name}. Reason: {str(ex)}") # TODO: This is a bit ugly... raise ProjectLoadError(project_name) from ex except ProjectLoadError as load_error: errors.append(load_error) return sorted((tupl[0] for tupl in runtime_storage.project_cache.values()), key=lambda p: p['name']), errors
def cli(ctx, version=False, update=False, ignore_shell=False, project=None, project_file=None, verbose=False, **kwargs): """ Define development environments for web applications. See full documentation at: https://riptide-docs.readthedocs.io/en/latest/ """ SystemFlag.IS_CLI = True # Print version if requested if version: print_version() exit() ctx.riptide_options = {"verbose": verbose} # Don't allow running as root. try: if os.getuid() == 0 and 'RIPTIDE_ALLOW_ROOT' not in os.environ: raise RiptideCliError("riptide must not be run as the root user.", ctx=ctx) except AttributeError: # Windows. Ignore. pass if project and project_file: raise RiptideCliError( "--project and --project-file can not be used together.", ctx) if update: raise RiptideCliError( "--update/-u is deprecated. Please run 'riptide update' instead.", ctx) new_versions = check_for_update() if new_versions: new_versions = '\n'.join([ f" {pkg:<22}: {version}" for pkg, version in new_versions.items() ]) warn( f"A new Riptide version is available:\n" f"{new_versions}\n\n" f"Use riptide_upgrade to upgrade. You may NEED to use sudo, see:\n" f" https://riptide-docs.readthedocs.io/en/latest/user_docs/2a_linux.html#updating-riptide\n", False) if 'RIPTIDE_SHELL_LOADED' not in os.environ and not ctx.resilient_parsing and not ignore_shell: warn("Riptide shell integration not enabled.") echo() if project: projects = load_projects() if project in projects: project_file = projects[project] else: raise RiptideCliError( f"Project {project} not found. --project/-P " f"can only be used if the project was loaded with Riptide at least once.", ctx) # Setup basic variables ctx.riptide_options = { "project": project_file, "verbose": verbose, "rename": False } ctx.riptide_options.update(kwargs)