コード例 #1
0
def up(project, exclude):
    """
    Run/update dependent services.
    """

    os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"

    exclude = set(chain.from_iterable(x.split(",") for x in exclude))

    from sentry.runner import configure

    configure()

    from django.conf import settings

    client = get_docker_client()

    get_or_create(client, "network", project)

    containers = _prepare_containers(project)

    for name, options in settings.SENTRY_DEVSERVICES.items():
        if name in exclude:
            continue

        if name not in containers:
            continue

        _start_service(client, name, containers, project)
コード例 #2
0
def up(ctx, services, project, exclude, fast):
    """
    Run/update all devservices in the background.

    The default is everything, however you may pass positional arguments to specify
    an explicit list of services to bring up.

    You may also exclude services, for example: --exclude redis --exclude postgres.
    """
    from sentry.runner import configure

    configure()

    containers = _prepare_containers(project, silent=True)
    selected_services = set()

    if services:
        for service in services:
            if service not in containers:
                click.secho(
                    f"Service `{service}` is not known or not enabled.\n",
                    err=True,
                    fg="red",
                )
                click.secho("Services that are available:\n" +
                            "\n".join(containers.keys()) + "\n",
                            err=True)
                raise click.Abort()
            selected_services.add(service)
    else:
        selected_services = set(containers.keys())

    for service in exclude:
        if service not in containers:
            click.secho(f"Service `{service}` is not known or not enabled.\n",
                        err=True,
                        fg="red")
            click.secho("Services that are available:\n" +
                        "\n".join(containers.keys()) + "\n",
                        err=True)
            raise click.Abort()
        selected_services.remove(service)

    if fast:
        click.secho(
            "> Warning! Fast mode completely eschews any image updating, so services may be stale.",
            err=True,
            fg="red",
        )

    get_or_create(ctx.obj["client"], "network", project)

    for name in selected_services:
        _start_service(ctx.obj["client"],
                       ctx.obj["low_level_client"],
                       name,
                       containers,
                       project,
                       fast=fast)
コード例 #3
0
def up(services, project, exclude, fast):
    """
    Run/update dependent services.

    The default is everything, however you may pass positional arguments to specify
    an explicit list of services to bring up.

    You may also exclude services, for example: --exclude redis --exclude postgres.
    """
    os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"

    from sentry.runner import configure

    configure()

    containers = _prepare_containers(project, silent=True)

    for service in exclude:
        if service not in containers:
            click.secho(
                "Service `{}` is not known or not enabled.\n".format(service),
                err=True,
                fg="red")
            click.secho("Services that are available:\n" +
                        "\n".join(containers.keys()) + "\n",
                        err=True)
            raise click.Abort()

    if services:
        selected_containers = {}
        for service in services:
            if service not in containers:
                click.secho(
                    "Service `{}` is not known or not enabled.\n".format(
                        service),
                    err=True,
                    fg="red",
                )
                click.secho("Services that are available:\n" +
                            "\n".join(containers.keys()) + "\n",
                            err=True)
                raise click.Abort()
            selected_containers[service] = containers[service]
        containers = selected_containers

    if fast:
        click.secho(
            "> Warning! Fast mode completely eschews any image updating, so services may be stale.",
            err=True,
            fg="red",
        )

    client = get_docker_client()
    get_or_create(client, "network", project)

    for name, container_options in containers.items():
        if name in exclude:
            continue
        _start_service(client, name, containers, project, fast=fast)
コード例 #4
0
ファイル: decorators.py プロジェクト: 280185386/sentry
 def inner(ctx, *args, **kwargs):
     # HACK: We can't call `configure()` from within tests
     # since we don't load config files from disk, so we
     # need a way to bypass this initialization step
     if os.environ.get('_SENTRY_SKIP_CONFIGURATION') != '1':
         from sentry.runner import configure
         configure()
     return ctx.invoke(f, *args, **kwargs)
コード例 #5
0
ファイル: decorators.py プロジェクト: stefaniee2010/sentry
 def inner(ctx, *args, **kwargs):
     # HACK: We can't call `configure()` from within tests
     # since we don't load config files from disk, so we
     # need a way to bypass this initialization step
     if os.environ.get('_SENTRY_SKIP_CONFIGURATION') != '1':
         from sentry.runner import configure
         configure()
     return ctx.invoke(f, *args, **kwargs)
コード例 #6
0
ファイル: cleanup.py プロジェクト: zuolei828/sentry
def multiprocess_worker(task_queue):
    # Configure within each Process
    import logging
    from sentry.utils.imports import import_string

    logger = logging.getLogger('sentry.cleanup')

    configured = False

    while True:
        j = task_queue.get()
        if j == _STOP_WORKER:
            task_queue.task_done()
            return

        # On first task, configure Sentry environment
        if not configured:
            from sentry.runner import configure
            configure()

            from sentry import models
            from sentry import deletions
            from sentry import similarity

            skip_models = [
                # Handled by other parts of cleanup
                models.Event,
                models.EventMapping,
                models.EventAttachment,
                models.UserReport,
                models.Group,
                models.GroupEmailThread,
                models.GroupRuleStatus,
                models.GroupHashTombstone,
                # Handled by TTL
                similarity.features,
            ] + [b[0] for b in EXTRA_BULK_QUERY_DELETES]

            configured = True

        model, chunk = j
        model = import_string(model)

        try:
            task = deletions.get(
                model=model,
                query={'id__in': chunk},
                skip_models=skip_models,
                transaction_id=uuid4().hex,
            )

            while True:
                if not task.chunk():
                    break
        except Exception as e:
            logger.exception(e)
        finally:
            task_queue.task_done()
コード例 #7
0
def attach(project, fast, service):
    """
    Run a single devservice in foreground, as opposed to `up` which runs all of
    them in the background.

    Accepts a single argument, the name of the service to spawn. The service
    will run with output printed to your terminal, and the ability to kill it
    with ^C. This is used in devserver.

    Note: This does not update images, you will have to use `devservices up`
    for that.
    """

    os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"

    from sentry.runner import configure

    configure()

    client = get_docker_client()
    containers = _prepare_containers(project, silent=True)
    if service not in containers:
        raise click.ClickException(
            "Service `{}` is not known or not enabled.".format(service))

    container = _start_service(client,
                               service,
                               containers,
                               project,
                               fast=fast,
                               always_start=True)

    def exit_handler(*_):
        try:
            click.echo("Stopping {}".format(service))
            container.stop()
            click.echo("Removing {}".format(service))
            container.remove()
        except KeyboardInterrupt:
            pass

    signal.signal(signal.SIGINT, exit_handler)
    signal.signal(signal.SIGTERM, exit_handler)

    for line in container.logs(stream=True, since=int(time.time() - 20)):
        click.echo(line, nl=False)
コード例 #8
0
def attach(ctx, project, fast, service):
    """
    Run a single devservice in the foreground.

    Accepts a single argument, the name of the service to spawn. The service
    will run with output printed to your terminal, and the ability to kill it
    with ^C. This is used in devserver.

    Note: This does not update images, you will have to use `devservices up`
    for that.
    """
    from sentry.runner import configure

    configure()

    containers = _prepare_containers(project, silent=True)
    if service not in containers:
        raise click.ClickException(
            f"Service `{service}` is not known or not enabled.")

    container = _start_service(
        ctx.obj["client"],
        ctx.obj["low_level_client"],
        service,
        containers,
        project,
        fast=fast,
        always_start=True,
    )

    def exit_handler(*_):
        try:
            click.echo(f"Stopping {service}")
            container.stop()
            click.echo(f"Removing {service}")
            container.remove()
        except KeyboardInterrupt:
            pass

    signal.signal(signal.SIGINT, exit_handler)
    signal.signal(signal.SIGTERM, exit_handler)

    for line in container.logs(stream=True, since=int(time.time() - 20)):
        click.echo(line, nl=False)
コード例 #9
0
def attach(project, is_devserver, service):
    """
    Run a single devservice in foreground, as opposed to `up` which runs all of
    them in the background.

    Accepts a single argument, the name of the service to spawn. The service
    will run with output printed to your terminal, and the ability to kill it
    with ^C. This is used in devserver.

    Note: This does not update images, you will have to use `devservices up`
    for that.
    """

    os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"

    from sentry.runner import configure

    configure()

    client = get_docker_client()
    containers = _prepare_containers(project)
    container = _start_service(client,
                               service,
                               containers,
                               project,
                               devserver_override=is_devserver)

    def exit_handler(*_):
        click.echo("Shutting down {}".format(service))
        try:
            container.stop()
        except KeyboardInterrupt:
            pass

    atexit.register(exit_handler)
    signal.signal(signal.SIGINT, exit_handler)
    signal.signal(signal.SIGTERM, exit_handler)

    for line in container.logs(stream=True):
        click.echo(line, nl=False)
コード例 #10
0
def up(project, exclude, fast):
    """
    Run/update dependent services.
    """

    os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"

    exclude = set(chain.from_iterable(x.split(",") for x in exclude))

    from sentry.runner import configure

    configure()

    from django.conf import settings

    client = get_docker_client()

    get_or_create(client, "network", project)

    containers = _prepare_containers(project)

    if fast:
        click.secho(
            "> Warning! Fast mode completely eschews any image updating, so services may be stale.",
            err=True,
            fg="red",
        )

    for name, options in settings.SENTRY_DEVSERVICES.items():
        if name in exclude:
            continue

        if name not in containers:
            continue

        _start_service(client, name, containers, project, fast=fast)
コード例 #11
0
def rm(project, services):
    """
    Shut down and delete all services and associated data.
    Useful if you'd like to start with a fresh slate.

    The default is everything, however you may pass positional arguments to specify
    an explicit list of services to remove.
    """
    import docker

    client = get_docker_client()

    from sentry.runner import configure

    configure()

    containers = _prepare_containers(project, silent=True)

    if services:
        selected_containers = {}
        for service in services:
            # XXX: This code is also fairly duplicated in here at this point, so dedupe in the future.
            if service not in containers:
                click.secho(
                    "Service `{}` is not known or not enabled.\n".format(
                        service),
                    err=True,
                    fg="red",
                )
                click.secho("Services that are available:\n" +
                            "\n".join(containers.keys()) + "\n",
                            err=True)
                raise click.Abort()
            selected_containers[service] = containers[service]
        containers = selected_containers

    click.confirm(
        """
This will delete these services and all of their data:

%s

Are you sure you want to continue?""" % "\n".join(containers.keys()),
        abort=True,
    )

    for service_name, container_options in containers.items():
        try:
            container = client.containers.get(container_options["name"])
        except docker.errors.NotFound:
            click.secho(
                "> WARNING: non-existent container '%s'" %
                container_options["name"],
                err=True,
                fg="yellow",
            )
            continue

        click.secho("> Stopping '%s' container" % container_options["name"],
                    err=True,
                    fg="red")
        container.stop()
        click.secho("> Removing '%s' container" % container_options["name"],
                    err=True,
                    fg="red")
        container.remove()

    prefix = project + "_"

    for volume in client.volumes.list():
        if volume.name.startswith(prefix):
            if not services or volume.name[len(prefix):] in services:
                click.secho("> Removing '%s' volume" % volume.name,
                            err=True,
                            fg="red")
                volume.remove()

    if not services:
        try:
            network = client.networks.get(project)
        except docker.errors.NotFound:
            pass
        else:
            click.secho("> Removing '%s' network" % network.name,
                        err=True,
                        fg="red")
            network.remove()
コード例 #12
0
ファイル: devservices.py プロジェクト: getsentry/sentry
def up(project, exclude):
    "Run/update dependent services."
    os.environ['SENTRY_SKIP_BACKEND_VALIDATION'] = '1'

    from sentry.runner import configure
    configure()

    from django.conf import settings
    from sentry import options as sentry_options

    import docker
    client = get_docker_client()

    # This is brittle, but is the best way now to limit what
    # services are run if they're not needed.
    if not exclude:
        exclude = set()

    if 'bigtable' not in settings.SENTRY_NODESTORE:
        exclude |= {'bigtable'}

    if 'memcached' not in settings.CACHES.get('default', {}).get('BACKEND'):
        exclude |= {'memcached'}

    if 'kafka' in settings.SENTRY_EVENTSTREAM:
        pass
    elif 'snuba' in settings.SENTRY_EVENTSTREAM:
        click.secho(
            '! Skipping kafka and zookeeper since your eventstream backend does not require it',
            err=True,
            fg='cyan')
        exclude |= {'kafka', 'zookeeper'}
    else:
        click.secho(
            '! Skipping kafka, zookeeper, snuba, and clickhouse since your eventstream backend does not require it',
            err=True,
            fg='cyan')
        exclude |= {'kafka', 'zookeeper', 'snuba', 'clickhouse'}

    if not sentry_options.get('symbolicator.enabled'):
        exclude |= {'symbolicator'}

    get_or_create(client, 'network', project)

    containers = {}
    for name, options in settings.SENTRY_DEVSERVICES.items():
        if name in exclude:
            continue
        options = options.copy()
        options['network'] = project
        options['detach'] = True
        options['name'] = project + '_' + name
        options.setdefault('ports', {})
        options.setdefault('environment', {})
        options.setdefault('restart_policy', {'Name': 'on-failure'})
        options['ports'] = ensure_interface(options['ports'])
        containers[name] = options

    pulled = set()
    for name, options in containers.items():
        # HACK(mattrobenolt): special handle snuba backend becuase it needs to
        # handle different values based on the eventstream backend
        # For snuba, we can't run the full suite of devserver, but can only
        # run the api.
        if name == 'snuba' and 'snuba' in settings.SENTRY_EVENTSTREAM:
            options['environment'].pop('DEFAULT_BROKERS', None)
            options['command'] = ['devserver', '--no-workers']

        for key, value in options['environment'].items():
            options['environment'][key] = value.format(containers=containers)
        if options.pop('pull', False) and options['image'] not in pulled:
            click.secho("> Pulling image '%s'" % options['image'], err=True, fg='green')
            client.images.pull(options['image'])
            pulled.add(options['image'])
        for mount in options.get('volumes', {}).keys():
            if '/' not in mount:
                get_or_create(client, 'volume', project + '_' + mount)
                options['volumes'][project + '_' + mount] = options['volumes'].pop(mount)
        try:
            container = client.containers.get(options['name'])
        except docker.errors.NotFound:
            pass
        else:
            container.stop()
            container.remove()
        listening = ''
        if options['ports']:
            listening = ' (listening: %s)' % ', '.join(map(text_type, options['ports'].values()))
        click.secho("> Creating '%s' container%s" %
                    (options['name'], listening), err=True, fg='yellow')
        client.containers.run(**options)
コード例 #13
0
def up(ctx, services, project, exclude, fast, skip_only_if):
    """
    Run/update all devservices in the background.

    The default is everything, however you may pass positional arguments to specify
    an explicit list of services to bring up.

    You may also exclude services, for example: --exclude redis --exclude postgres.
    """
    from sentry.runner import configure

    configure()

    containers = _prepare_containers(project,
                                     skip_only_if=skip_only_if,
                                     silent=True)
    selected_services = set()

    if services:
        for service in services:
            if service not in containers:
                click.secho(
                    f"Service `{service}` is not known or not enabled.\n",
                    err=True,
                    fg="red",
                )
                click.secho("Services that are available:\n" +
                            "\n".join(containers.keys()) + "\n",
                            err=True)
                raise click.Abort()
            selected_services.add(service)
    else:
        selected_services = set(containers.keys())

    for service in exclude:
        if service not in containers:
            click.secho(f"Service `{service}` is not known or not enabled.\n",
                        err=True,
                        fg="red")
            click.secho("Services that are available:\n" +
                        "\n".join(containers.keys()) + "\n",
                        err=True)
            raise click.Abort()
        selected_services.remove(service)

    if fast:
        click.secho(
            "> Warning! Fast mode completely eschews any image updating, so services may be stale.",
            err=True,
            fg="red",
        )

    get_or_create(ctx.obj["client"], "network", project)

    with ThreadPoolExecutor(max_workers=len(selected_services)) as executor:
        futures = []
        for name in selected_services:
            futures.append(
                executor.submit(
                    _start_service,
                    ctx.obj["client"],
                    name,
                    containers,
                    project,
                    fast=fast,
                ))
        for future in as_completed(futures):
            # If there was an exception, reraising it here to the main thread
            # will not terminate the whole python process. We'd like to report
            # on this exception and stop as fast as possible, so terminate
            # ourselves. I believe (without verification) that the OS is now
            # free to cleanup these threads, but not sure if they'll remain running
            # in the background. What matters most is that we regain control
            # of the terminal.
            e = future.exception()
            if e:
                click.echo(e)
                me = os.getpid()
                os.kill(me, signal.SIGTERM)
コード例 #14
0
def _configure():
    # Add the project to the python path
    sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
    # Disable backend validation
    # os.environ['SENTRY_SKIP_BACKEND_VALIDATION'] = 1
    configure()
コード例 #15
0
def up(project, exclude):
    "Run/update dependent services."
    os.environ['SENTRY_SKIP_BACKEND_VALIDATION'] = '1'

    exclude = set(chain.from_iterable(x.split(',') for x in exclude))

    from sentry.runner import configure
    configure()

    from django.conf import settings
    from sentry import options as sentry_options

    import docker
    client = get_docker_client()

    # This is brittle, but is the best way now to limit what
    # services are run if they're not needed.
    if not exclude:
        exclude = set()

    if 'bigtable' not in settings.SENTRY_NODESTORE:
        exclude |= {'bigtable'}

    if 'memcached' not in settings.CACHES.get('default', {}).get('BACKEND'):
        exclude |= {'memcached'}

    if 'kafka' in settings.SENTRY_EVENTSTREAM:
        pass
    elif 'snuba' in settings.SENTRY_EVENTSTREAM:
        click.secho(
            '! Skipping kafka and zookeeper since your eventstream backend does not require it',
            err=True,
            fg='cyan')
        exclude |= {'kafka', 'zookeeper'}
    else:
        click.secho(
            '! Skipping kafka, zookeeper, snuba, and clickhouse since your eventstream backend does not require it',
            err=True,
            fg='cyan')
        exclude |= {'kafka', 'zookeeper', 'snuba', 'clickhouse'}

    if not sentry_options.get('symbolicator.enabled'):
        exclude |= {'symbolicator'}

    get_or_create(client, 'network', project)

    containers = {}
    for name, options in settings.SENTRY_DEVSERVICES.items():
        if name in exclude:
            continue
        options = options.copy()
        options['network'] = project
        options['detach'] = True
        options['name'] = project + '_' + name
        options.setdefault('ports', {})
        options.setdefault('environment', {})
        options.setdefault('restart_policy', {'Name': 'on-failure'})
        options['ports'] = ensure_interface(options['ports'])
        containers[name] = options

    pulled = set()
    for name, options in containers.items():
        # HACK(mattrobenolt): special handle snuba backend becuase it needs to
        # handle different values based on the eventstream backend
        # For snuba, we can't run the full suite of devserver, but can only
        # run the api.
        if name == 'snuba' and 'snuba' in settings.SENTRY_EVENTSTREAM:
            options['environment'].pop('DEFAULT_BROKERS', None)
            options['command'] = ['devserver', '--no-workers']

        for key, value in options['environment'].items():
            options['environment'][key] = value.format(containers=containers)
        if options.pop('pull', False) and options['image'] not in pulled:
            click.secho("> Pulling image '%s'" % options['image'], err=True, fg='green')
            client.images.pull(options['image'])
            pulled.add(options['image'])
        for mount in options.get('volumes', {}).keys():
            if '/' not in mount:
                get_or_create(client, 'volume', project + '_' + mount)
                options['volumes'][project + '_' + mount] = options['volumes'].pop(mount)
        try:
            container = client.containers.get(options['name'])
        except docker.errors.NotFound:
            pass
        else:
            container.stop()
            container.remove()
        listening = ''
        if options['ports']:
            listening = ' (listening: %s)' % ', '.join(map(text_type, options['ports'].values()))
        click.secho("> Creating '%s' container%s" %
                    (options['name'], listening), err=True, fg='yellow')
        client.containers.run(**options)
コード例 #16
0
ファイル: generator.py プロジェクト: wenlaizhou/sentry
def cli(output_path, output_format):
    global OUTPUT_PATH
    if output_path is not None:
        OUTPUT_PATH = os.path.abspath(output_path)

    with apidoc_containers():
        from sentry.runner import configure

        configure()

        sentry = Popen([
            "sentry",
            "--config=" + SENTRY_CONFIG,
            "run",
            "web",
            "-w",
            "1",
            "--bind",
            "127.0.0.1:9000",
        ])

        from django.core.management import call_command

        call_command(
            "migrate",
            interactive=False,
            traceback=True,
            verbosity=0,
            migrate=True,
            merge=True,
            ignore_ghost_migrations=True,
        )

        utils = MockUtils()
        report("org", "Creating user and organization")
        user = utils.create_user("*****@*****.**")
        org = utils.create_org("The Interstellar Jurisdiction", owner=user)
        report("auth", "Creating api token")
        api_token = utils.create_api_token(user)

        report("org", "Creating team")
        team = utils.create_team("Powerful Abolitionist", org=org)
        utils.join_team(team, user)

        projects = []
        for project_name in "Pump Station", "Prime Mover":
            report("project", 'Creating project "%s"' % project_name)
            project = utils.create_project(project_name, teams=[team], org=org)
            release = utils.create_release(project=project, user=user)
            report("event", 'Creating event for "%s"' % project_name)

            event1 = utils.create_event(project=project,
                                        release=release,
                                        platform="python")
            event2 = utils.create_event(project=project,
                                        release=release,
                                        platform="java")
            projects.append({
                "project": project,
                "release": release,
                "events": [event1, event2]
            })

        # HACK: the scenario in ProjectDetailsEndpoint#put requires our integration docs to be in place
        # so that we can validate the platform. We create the docker container that runs generator.py
        # with SENTRY_LIGHT_BUILD=1, which doesn't run `sync_docs` and `sync_docs` requires sentry
        # to be configured, which we do in this file. So, we need to do the sync_docs here.
        sync_docs(quiet=True)

        vars = {
            "org": org,
            "me": user,
            "api_token": api_token,
            "teams": [{
                "team": team,
                "projects": projects
            }],
        }

        scenario_map = {}
        report("docs", "Collecting scenarios")
        for scenario_ident, func in iter_scenarios():
            scenario = run_scenario(vars, scenario_ident, func)
            scenario_map[scenario_ident] = scenario

        section_mapping = {}
        report("docs", "Collecting endpoint documentation")
        for endpoint in iter_endpoints():
            report("endpoint",
                   'Collecting docs for "%s"' % endpoint["endpoint_name"])

            section_mapping.setdefault(endpoint["section"],
                                       []).append(endpoint)
        sections = get_sections()

        if output_format in ("json", "both"):
            output_json(sections, scenario_map, section_mapping)
        if output_format in ("markdown", "both"):
            output_markdown(sections, scenario_map, section_mapping)

    if sentry is not None:
        report("sentry", "Shutting down sentry server")
        sentry.kill()
        sentry.wait()
コード例 #17
0
def cleanup(days, project, concurrency, silent, model, router, timed):
    """Delete a portion of trailing data based on creation date.

    All data that is older than `--days` will be deleted.  The default for
    this is 30 days.  In the default setting all projects will be truncated
    but if you have a specific project you want to limit this to this can be
    done with the `--project` flag which accepts a project ID or a string
    with the form `org/project` where both are slugs.
    """
    if concurrency < 1:
        click.echo('Error: Minimum concurrency is 1', err=True)
        raise click.Abort()

    os.environ['_SENTRY_CLEANUP'] = '1'

    # Make sure we fork off multiprocessing pool
    # before we import or configure the app
    from multiprocessing import Process, JoinableQueue as Queue

    pool = []
    task_queue = Queue(1000)
    for _ in xrange(concurrency):
        p = Process(target=multiprocess_worker, args=(task_queue, ))
        p.daemon = True
        p.start()
        pool.append(p)

    from sentry.runner import configure
    configure()

    from django.db import router as db_router
    from sentry.app import nodestore
    from sentry.db.deletion import BulkDeleteQuery
    from sentry import models

    if timed:
        import time
        from sentry.utils import metrics
        start_time = time.time()

    # list of models which this query is restricted to
    model_list = {m.lower() for m in model}

    def is_filtered(model):
        if router is not None and db_router.db_for_write(model) != router:
            return True
        if not model_list:
            return False
        return model.__name__.lower() not in model_list

    # Deletions that use `BulkDeleteQuery` (and don't need to worry about child relations)
    # (model, datetime_field, order_by)
    BULK_QUERY_DELETES = [
        (models.EventMapping, 'date_added', '-date_added'),
        (models.EventAttachment, 'date_added', None),
        (models.UserReport, 'date_added', None),
        (models.GroupEmailThread, 'date', None),
        (models.GroupRuleStatus, 'date_added', None),
    ] + EXTRA_BULK_QUERY_DELETES

    # Deletions that use the `deletions` code path (which handles their child relations)
    # (model, datetime_field, order_by)
    DELETES = (
        (models.Event, 'datetime', 'datetime'),
        (models.Group, 'last_seen', 'last_seen'),
    )

    if not silent:
        click.echo('Removing expired values for LostPasswordHash')

    if is_filtered(models.LostPasswordHash):
        if not silent:
            click.echo('>> Skipping LostPasswordHash')
    else:
        models.LostPasswordHash.objects.filter(date_added__lte=timezone.now() -
                                               timedelta(hours=48)).delete()

    if is_filtered(models.OrganizationMember) and not silent:
        click.echo('>> Skipping OrganizationMember')
    else:
        if not silent:
            click.echo('Removing expired values for OrganizationMember')
        expired_threshold = timezone.now() - timedelta(days=days)
        models.OrganizationMember.delete_expired(expired_threshold)

    for model in [models.ApiGrant, models.ApiToken]:
        if not silent:
            click.echo(u'Removing expired values for {}'.format(
                model.__name__))

        if is_filtered(model):
            if not silent:
                click.echo(u'>> Skipping {}'.format(model.__name__))
        else:
            model.objects.filter(expires_at__lt=(
                timezone.now() -
                timedelta(days=API_TOKEN_TTL_IN_DAYS)), ).delete()

    project_id = None
    if project:
        click.echo(
            "Bulk NodeStore deletion not available for project selection",
            err=True)
        project_id = get_project(project)
        if project_id is None:
            click.echo('Error: Project not found', err=True)
            raise click.Abort()
    else:
        if not silent:
            click.echo("Removing old NodeStore values")

        cutoff = timezone.now() - timedelta(days=days)
        try:
            nodestore.cleanup(cutoff)
        except NotImplementedError:
            click.echo("NodeStore backend does not support cleanup operation",
                       err=True)

    for bqd in BULK_QUERY_DELETES:
        if len(bqd) == 4:
            model, dtfield, order_by, chunk_size = bqd
        else:
            chunk_size = 10000
            model, dtfield, order_by = bqd

        if not silent:
            click.echo(
                u"Removing {model} for days={days} project={project}".format(
                    model=model.__name__,
                    days=days,
                    project=project or '*',
                ))
        if is_filtered(model):
            if not silent:
                click.echo('>> Skipping %s' % model.__name__)
        else:
            BulkDeleteQuery(
                model=model,
                dtfield=dtfield,
                days=days,
                project_id=project_id,
                order_by=order_by,
            ).execute(chunk_size=chunk_size)

    for model, dtfield, order_by in DELETES:
        if not silent:
            click.echo(
                u"Removing {model} for days={days} project={project}".format(
                    model=model.__name__,
                    days=days,
                    project=project or '*',
                ))

        if is_filtered(model):
            if not silent:
                click.echo('>> Skipping %s' % model.__name__)
        else:
            imp = '.'.join((model.__module__, model.__name__))

            q = BulkDeleteQuery(
                model=model,
                dtfield=dtfield,
                days=days,
                project_id=project_id,
                order_by=order_by,
            )

            for chunk in q.iterator(chunk_size=100):
                task_queue.put((imp, chunk))

            task_queue.join()

    # Clean up FileBlob instances which are no longer used and aren't super
    # recent (as there could be a race between blob creation and reference)
    if not silent:
        click.echo("Cleaning up unused FileBlob references")
    if is_filtered(models.FileBlob):
        if not silent:
            click.echo('>> Skipping FileBlob')
    else:
        cleanup_unused_files(silent)

    # Shut down our pool
    for _ in pool:
        task_queue.put(_STOP_WORKER)

    # And wait for it to drain
    for p in pool:
        p.join()

    if timed:
        duration = int(time.time() - start_time)
        metrics.timing('cleanup.duration',
                       duration,
                       instance=router,
                       sample_rate=1.0)
        click.echo("Clean up took %s second(s)." % duration)
コード例 #18
0
ファイル: cleanup.py プロジェクト: getsentry/sentry
def cleanup(days, project, concurrency, silent, model, router, timed):
    """Delete a portion of trailing data based on creation date.

    All data that is older than `--days` will be deleted.  The default for
    this is 30 days.  In the default setting all projects will be truncated
    but if you have a specific project you want to limit this to this can be
    done with the `--project` flag which accepts a project ID or a string
    with the form `org/project` where both are slugs.
    """
    if concurrency < 1:
        click.echo('Error: Minimum concurrency is 1', err=True)
        raise click.Abort()

    os.environ['_SENTRY_CLEANUP'] = '1'

    # Make sure we fork off multiprocessing pool
    # before we import or configure the app
    from multiprocessing import Process, JoinableQueue as Queue

    pool = []
    task_queue = Queue(1000)
    for _ in xrange(concurrency):
        p = Process(target=multiprocess_worker, args=(task_queue,))
        p.daemon = True
        p.start()
        pool.append(p)

    from sentry.runner import configure
    configure()

    from django.db import router as db_router
    from sentry.app import nodestore
    from sentry.db.deletion import BulkDeleteQuery
    from sentry import models

    if timed:
        import time
        from sentry.utils import metrics
        start_time = time.time()

    # list of models which this query is restricted to
    model_list = {m.lower() for m in model}

    def is_filtered(model):
        if router is not None and db_router.db_for_write(model) != router:
            return True
        if not model_list:
            return False
        return model.__name__.lower() not in model_list

    # Deletions that use `BulkDeleteQuery` (and don't need to worry about child relations)
    # (model, datetime_field, order_by)
    BULK_QUERY_DELETES = [
        (models.EventMapping, 'date_added', '-date_added'),
        (models.EventAttachment, 'date_added', None),
        (models.UserReport, 'date_added', None),
        (models.GroupEmailThread, 'date', None),
        (models.GroupRuleStatus, 'date_added', None),
    ] + EXTRA_BULK_QUERY_DELETES

    # Deletions that use the `deletions` code path (which handles their child relations)
    # (model, datetime_field, order_by)
    DELETES = (
        (models.Event, 'datetime', 'datetime'),
        (models.Group, 'last_seen', 'last_seen'),
    )

    if not silent:
        click.echo('Removing expired values for LostPasswordHash')

    if is_filtered(models.LostPasswordHash):
        if not silent:
            click.echo('>> Skipping LostPasswordHash')
    else:
        models.LostPasswordHash.objects.filter(
            date_added__lte=timezone.now() - timedelta(hours=48)
        ).delete()

    if is_filtered(models.OrganizationMember) and not silent:
        click.echo('>> Skipping OrganizationMember')
    else:
        click.echo('Removing expired values for OrganizationMember')
        expired_threshold = timezone.now() - timedelta(days=days)
        models.OrganizationMember.delete_expired(expired_threshold)

    for model in [models.ApiGrant, models.ApiToken]:
        if not silent:
            click.echo(u'Removing expired values for {}'.format(model.__name__))

        if is_filtered(model):
            if not silent:
                click.echo(u'>> Skipping {}'.format(model.__name__))
        else:
            model.objects.filter(
                expires_at__lt=(timezone.now() - timedelta(days=days)),
            ).delete()

    project_id = None
    if project:
        click.echo(
            "Bulk NodeStore deletion not available for project selection", err=True)
        project_id = get_project(project)
        if project_id is None:
            click.echo('Error: Project not found', err=True)
            raise click.Abort()
    else:
        if not silent:
            click.echo("Removing old NodeStore values")

        cutoff = timezone.now() - timedelta(days=days)
        try:
            nodestore.cleanup(cutoff)
        except NotImplementedError:
            click.echo(
                "NodeStore backend does not support cleanup operation", err=True)

    for bqd in BULK_QUERY_DELETES:
        if len(bqd) == 4:
            model, dtfield, order_by, chunk_size = bqd
        else:
            chunk_size = 10000
            model, dtfield, order_by = bqd

        if not silent:
            click.echo(
                u"Removing {model} for days={days} project={project}".format(
                    model=model.__name__,
                    days=days,
                    project=project or '*',
                )
            )
        if is_filtered(model):
            if not silent:
                click.echo('>> Skipping %s' % model.__name__)
        else:
            BulkDeleteQuery(
                model=model,
                dtfield=dtfield,
                days=days,
                project_id=project_id,
                order_by=order_by,
            ).execute(chunk_size=chunk_size)

    for model, dtfield, order_by in DELETES:
        if not silent:
            click.echo(
                u"Removing {model} for days={days} project={project}".format(
                    model=model.__name__,
                    days=days,
                    project=project or '*',
                )
            )

        if is_filtered(model):
            if not silent:
                click.echo('>> Skipping %s' % model.__name__)
        else:
            imp = '.'.join((model.__module__, model.__name__))

            q = BulkDeleteQuery(
                model=model,
                dtfield=dtfield,
                days=days,
                project_id=project_id,
                order_by=order_by,
            )

            for chunk in q.iterator(chunk_size=100):
                task_queue.put((imp, chunk))

            task_queue.join()

    # Clean up FileBlob instances which are no longer used and aren't super
    # recent (as there could be a race between blob creation and reference)
    if not silent:
        click.echo("Cleaning up unused FileBlob references")
    if is_filtered(models.FileBlob):
        if not silent:
            click.echo('>> Skipping FileBlob')
    else:
        cleanup_unused_files(silent)

    # Shut down our pool
    for _ in pool:
        task_queue.put(_STOP_WORKER)

    # And wait for it to drain
    for p in pool:
        p.join()

    if timed:
        duration = int(time.time() - start_time)
        metrics.timing('cleanup.duration', duration, instance=router)
        click.echo("Clean up took %s second(s)." % duration)
コード例 #19
0
import click
import urlparse
import logging

from datetime import datetime
from subprocess import Popen, PIPE
from contextlib import contextmanager

HERE = os.path.abspath(os.path.dirname(__file__))
SENTRY_CONFIG = os.environ['SENTRY_CONF'] = os.path.join(
    HERE, 'sentry.conf.py')
os.environ['SENTRY_SKIP_BACKEND_VALIDATION'] = '1'

# No sentry or django imports before that point
from sentry.runner import configure
configure()
from django.conf import settings

# Fair game from here
from django.core.management import call_command

from sentry.utils.apidocs import Runner, MockUtils, iter_scenarios, \
    iter_endpoints, get_sections

OUTPUT_PATH = os.path.join(HERE, 'cache')
HOST = urlparse.urlparse(settings.SENTRY_OPTIONS['system.url-prefix']).netloc

# We don't care about you, go away
_logger = logging.getLogger('sentry.events')
_logger.disabled = True
コード例 #20
0
def devserver(reload, watchers, workers, browser_reload, styleguide, prefix,
              environment, bind, vscode_debug, search_index):
    "Starts a lightweight web server for development."

    if ':' in bind:
        host, port = bind.split(':', 1)
        port = int(port)
    else:
        host = bind
        port = None

    import os

    os.environ['CLIMS_ENVIRONMENT'] = environment

    from sentry.runner import configure
    configure()

    from django.conf import settings
    from sentry import options
    from sentry.services.http import SentryHTTPServer

    # NOTE: We have to set this variable here rather than directly in the config file
    # because the config file is imported before we're able to set the _ENVIRONMENT variable
    settings.DEBUG = environment == 'development'

    url_prefix = options.get('system.url-prefix', '')
    parsed_url = urlparse(url_prefix)
    # Make sure we're trying to use a port that we can actually bind to
    needs_https = (parsed_url.scheme == 'https'
                   and (parsed_url.port or 443) > 1024)
    has_https = False

    if needs_https:
        from subprocess import check_output
        try:
            check_output(['which', 'https'])
            has_https = True
        except Exception:
            has_https = False
            from sentry.runner.initializer import show_big_error
            show_big_error([
                'missing `https` on your `$PATH`, but https is needed',
                '`$ brew install mattrobenolt/stuff/https`',
            ])

    uwsgi_overrides = {
        # Make sure we don't try and use uwsgi protocol
        'protocol': 'http',
        # Make sure we reload really quickly for local dev in case it
        # doesn't want to shut down nicely on it's own, NO MERCY
        'worker-reload-mercy': 2,
        # We need stdin to support pdb in devserver
        'honour-stdin': True,
        # accept ridiculously large files
        'limit-post': 1 << 30,
        # do something with chunked
        'http-chunked-input': True,
    }

    if reload:
        uwsgi_overrides['py-autoreload'] = 1

    daemons = []

    if watchers and not browser_reload:
        daemons += settings.SENTRY_WATCHERS

    # For javascript dev, if browser reload and watchers, then:
    # devserver listen on PORT + 1
    # webpack dev server listen on PORT + 2
    # proxy listen on PORT
    if watchers and browser_reload:
        new_port = port + 1
        os.environ['WEBPACK_DEV_PROXY'] = '%s' % port
        os.environ['WEBPACK_DEV_PORT'] = '%s' % (new_port + 1)
        os.environ['SENTRY_DEVSERVER_PORT'] = '%s' % new_port
        port = new_port

        daemons += [('jsproxy', ['yarn', 'dev-proxy']),
                    ('webpack', ['yarn', 'dev-server'])]

    if workers:
        if settings.CELERY_ALWAYS_EAGER:
            raise click.ClickException(
                'Disable CELERY_ALWAYS_EAGER in your settings file to spawn workers.'
            )

        daemons += [
            ('worker', ['lims', 'run', 'worker', '-c', '1', '--autoreload']),
            ('cron', ['lims', 'run', 'cron', '--autoreload']),
        ]

    if needs_https and has_https:
        https_port = six.text_type(parsed_url.port)
        https_host = parsed_url.hostname

        # Determine a random port for the backend http server
        import socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, 0))
        port = s.getsockname()[1]
        s.close()
        bind = '%s:%d' % (host, port)

        daemons += [
            ('https', [
                'https', '-host', https_host, '-listen',
                host + ':' + https_port, bind
            ]),
        ]

    # A better log-format for local dev when running through honcho,
    # but if there aren't any other daemons, we don't want to override.
    if daemons:
        uwsgi_overrides[
            'log-format'] = '"%(method) %(uri) %(proto)" %(status) %(size)'
    else:
        uwsgi_overrides[
            'log-format'] = '[%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size)'

    server = SentryHTTPServer(host=host,
                              port=port,
                              workers=1,
                              extra_options=uwsgi_overrides)

    # If using vscode_debug, currently we're only starting the builtin django server:
    if vscode_debug:
        from django.core.management import execute_from_command_line
        execute_from_command_line(
            ['', 'runserver', '--noreload', '--nothreading'])
        return
    # If we don't need any other daemons, just launch a normal uwsgi webserver
    # and avoid dealing with subprocesses

    if not daemons:
        return server.run()

    import sys
    from subprocess import list2cmdline
    from honcho.manager import Manager
    from honcho.printer import Printer

    os.environ['PYTHONUNBUFFERED'] = 'true'

    # Make sure that the environment is prepared before honcho takes over
    # This sets all the appropriate uwsgi env vars, etc
    server.prepare_environment()
    daemons += [
        ('server', ['lims', 'run', 'web']),
    ]

    if styleguide:
        daemons += [('storybook', ['yarn', 'storybook'])]

    if search_index and False:
        daemons += [('search_index', ['lims', 'run', 'search_index'])]

    cwd = os.path.realpath(
        os.path.join(settings.PROJECT_ROOT, os.pardir, os.pardir))

    manager = Manager(Printer(prefix=prefix))
    for name, cmd in daemons:
        manager.add_process(
            name,
            list2cmdline(cmd),
            quiet=False,
            cwd=cwd,
        )

    manager.loop()
    sys.exit(manager.returncode)
コード例 #21
0
ファイル: wsgi.py プロジェクト: ForkRepo/sentry
"""
from __future__ import absolute_import

import os
import os.path
import sys


# Add the project to the python path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))

# Configure the application only if it seemingly isnt already configured
from django.conf import settings
if not settings.configured:
    from sentry.runner import configure
    configure()

if settings.SESSION_FILE_PATH and not os.path.exists(settings.SESSION_FILE_PATH):
    try:
        os.makedirs(settings.SESSION_FILE_PATH)
    except OSError:
        pass

from django.core.handlers.wsgi import WSGIHandler


class FileWrapperWSGIHandler(WSGIHandler):
    """A WSGIHandler implementation that handles a StreamingHttpResponse
    from django to leverage wsgi.file_wrapper for delivering large streaming
    responses.
コード例 #22
0
def initializer() -> None:
    from sentry.runner import configure

    configure()
コード例 #23
0
def cli(ctx):
    from sentry.runner import configure
    configure()
コード例 #24
0
def up(project, exclude):
    "Run/update dependent services."
    os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"

    exclude = set(chain.from_iterable(x.split(",") for x in exclude))

    from sentry.runner import configure

    configure()

    from django.conf import settings
    from sentry import options as sentry_options

    import docker

    client = get_docker_client()

    get_or_create(client, "network", project)

    containers = {}
    for name, options in settings.SENTRY_DEVSERVICES.items():
        if name in exclude:
            continue
        options = options.copy()

        test_fn = options.pop("only_if", None)
        if test_fn and not test_fn(settings, sentry_options):
            click.secho("! Skipping {} due to only_if condition".format(name),
                        err=True,
                        fg="cyan")
            continue

        options["network"] = project
        options["detach"] = True
        options["name"] = project + "_" + name
        options.setdefault("ports", {})
        options.setdefault("environment", {})
        options.setdefault("restart_policy", {"Name": "on-failure"})
        options["ports"] = ensure_interface(options["ports"])
        containers[name] = options

    pulled = set()
    for name, options in containers.items():
        # HACK(mattrobenolt): special handle snuba backend because it needs to
        # handle different values based on the eventstream backend
        # For snuba, we can't run the full suite of devserver, but can only
        # run the api.
        if name == "snuba" and "snuba" in settings.SENTRY_EVENTSTREAM:
            options["environment"].pop("DEFAULT_BROKERS", None)
            options["command"] = ["devserver", "--no-workers"]

        for key, value in options["environment"].items():
            options["environment"][key] = value.format(containers=containers)
        if options.pop("pull", False) and options["image"] not in pulled:
            click.secho("> Pulling image '%s'" % options["image"],
                        err=True,
                        fg="green")
            client.images.pull(options["image"])
            pulled.add(options["image"])
        for mount in options.get("volumes", {}).keys():
            if "/" not in mount:
                get_or_create(client, "volume", project + "_" + mount)
                options["volumes"][project + "_" +
                                   mount] = options["volumes"].pop(mount)
        try:
            container = client.containers.get(options["name"])
        except docker.errors.NotFound:
            pass
        else:
            container.stop()
            container.remove()
        listening = ""
        if options["ports"]:
            listening = " (listening: %s)" % ", ".join(
                map(text_type, options["ports"].values()))
        click.secho("> Creating '%s' container%s" %
                    (options["name"], listening),
                    err=True,
                    fg="yellow")
        client.containers.run(**options)
コード例 #25
0
ファイル: devservices.py プロジェクト: Ali-Tahir/sentry
def up(project, exclude):
    "Run/update dependent services."
    os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"

    exclude = set(chain.from_iterable(x.split(",") for x in exclude))

    from sentry.runner import configure

    configure()

    from django.conf import settings
    from sentry import options as sentry_options

    import docker

    client = get_docker_client()

    # This is brittle, but is the best way now to limit what
    # services are run if they're not needed.
    if not exclude:
        exclude = set()

    if "bigtable" not in settings.SENTRY_NODESTORE:
        exclude |= {"bigtable"}

    if "memcached" not in settings.CACHES.get("default", {}).get("BACKEND"):
        exclude |= {"memcached"}

    if "kafka" in settings.SENTRY_EVENTSTREAM:
        pass
    elif "snuba" in settings.SENTRY_EVENTSTREAM:
        click.secho(
            "! Skipping kafka and zookeeper since your eventstream backend does not require it",
            err=True,
            fg="cyan",
        )
        exclude |= {"kafka", "zookeeper"}
    else:
        click.secho(
            "! Skipping kafka, zookeeper, snuba, and clickhouse since your eventstream backend does not require it",
            err=True,
            fg="cyan",
        )
        exclude |= {"kafka", "zookeeper", "snuba", "clickhouse"}

    if not sentry_options.get("symbolicator.enabled"):
        exclude |= {"symbolicator"}

    get_or_create(client, "network", project)

    containers = {}
    for name, options in settings.SENTRY_DEVSERVICES.items():
        if name in exclude:
            continue
        options = options.copy()
        options["network"] = project
        options["detach"] = True
        options["name"] = project + "_" + name
        options.setdefault("ports", {})
        options.setdefault("environment", {})
        options.setdefault("restart_policy", {"Name": "on-failure"})
        options["ports"] = ensure_interface(options["ports"])
        containers[name] = options

    pulled = set()
    for name, options in containers.items():
        # HACK(mattrobenolt): special handle snuba backend because it needs to
        # handle different values based on the eventstream backend
        # For snuba, we can't run the full suite of devserver, but can only
        # run the api.
        if name == "snuba" and "snuba" in settings.SENTRY_EVENTSTREAM:
            options["environment"].pop("DEFAULT_BROKERS", None)
            options["command"] = ["devserver", "--no-workers"]

        for key, value in options["environment"].items():
            options["environment"][key] = value.format(containers=containers)
        if options.pop("pull", False) and options["image"] not in pulled:
            click.secho("> Pulling image '%s'" % options["image"],
                        err=True,
                        fg="green")
            client.images.pull(options["image"])
            pulled.add(options["image"])
        for mount in options.get("volumes", {}).keys():
            if "/" not in mount:
                get_or_create(client, "volume", project + "_" + mount)
                options["volumes"][project + "_" +
                                   mount] = options["volumes"].pop(mount)
        try:
            container = client.containers.get(options["name"])
        except docker.errors.NotFound:
            pass
        else:
            container.stop()
            container.remove()
        listening = ""
        if options["ports"]:
            listening = " (listening: %s)" % ", ".join(
                map(text_type, options["ports"].values()))
        click.secho("> Creating '%s' container%s" %
                    (options["name"], listening),
                    err=True,
                    fg="yellow")
        client.containers.run(**options)