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
Exemple #2
0
    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()
Exemple #3
0
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()
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
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)