Beispiel #1
0
def subscribe_projects_to_alert_rule(alert_rule, projects):
    """
    Subscribes a list of projects to an alert rule
    :return: The list of created subscriptions
    """
    try:
        environment = alert_rule.environment.all()[:1].get()
    except Environment.DoesNotExist:
        environment = None

    subscriptions = bulk_create_snuba_subscriptions(
        projects,
        tasks.INCIDENTS_SNUBA_SUBSCRIPTION_TYPE,
        QueryDatasets(alert_rule.dataset),
        alert_rule.query,
        QueryAggregations(alert_rule.aggregation),
        timedelta(minutes=alert_rule.time_window),
        timedelta(minutes=alert_rule.resolution),
        environment,
    )
    subscription_links = [
        AlertRuleQuerySubscription(query_subscription=subscription,
                                   alert_rule=alert_rule)
        for subscription in subscriptions
    ]
    AlertRuleQuerySubscription.objects.bulk_create(subscription_links)
    return subscriptions
Beispiel #2
0
def subscribe_projects_to_alert_rule(alert_rule, projects):
    """
    Subscribes a list of projects to an alert rule
    :return: The list of created subscriptions
    """
    subscriptions = bulk_create_snuba_subscriptions(
        projects,
        tasks.INCIDENTS_SNUBA_SUBSCRIPTION_TYPE,
        alert_rule.snuba_query,
        QueryAggregations(alert_rule.aggregation),
    )
    subscription_links = [
        AlertRuleQuerySubscription(query_subscription=subscription,
                                   alert_rule=alert_rule)
        for subscription in subscriptions
    ]
    AlertRuleQuerySubscription.objects.bulk_create(subscription_links)
    return subscriptions
Beispiel #3
0
def update_alert_rule(
    alert_rule,
    projects=None,
    name=None,
    threshold_type=None,
    query=None,
    aggregation=None,
    time_window=None,
    alert_threshold=None,
    resolve_threshold=None,
    threshold_period=None,
):
    """
    Updates an alert rule.

    :param alert_rule: The alert rule to update
    :param name: Name for the alert rule. This will be used as part of the
    incident name, and must be unique per project.
    :param threshold_type: An AlertRuleThresholdType
    :param query: An event search query to subscribe to and monitor for alerts
    :param aggregation: An AlertRuleAggregation that we want to fetch for this alert rule
    :param time_window: Time period to aggregate over, in minutes.
    :param alert_threshold: Value that the subscription needs to reach to
    trigger the alert
    :param resolve_threshold: Value that the subscription needs to reach to
    resolve the alert
    :param threshold_period: How many update periods the value of the
    subscription needs to exceed the threshold before triggering
    :return: The updated `AlertRule`
    """
    if (name and alert_rule.name != name
            and AlertRule.objects.filter(organization=alert_rule.organization,
                                         name=name).exists()):
        raise AlertRuleNameAlreadyUsedError()

    updated_fields = {}
    if name:
        updated_fields["name"] = name
    if threshold_type:
        updated_fields["threshold_type"] = threshold_type.value
    if query is not None:
        validate_alert_rule_query(query)
        updated_fields["query"] = query
    if aggregation is not None:
        updated_fields["aggregation"] = aggregation.value
    if time_window:
        updated_fields["time_window"] = time_window
    if alert_threshold is not None:
        updated_fields["alert_threshold"] = alert_threshold
    if resolve_threshold is not None:
        updated_fields["resolve_threshold"] = resolve_threshold
    if threshold_period:
        updated_fields["threshold_period"] = threshold_period

    with transaction.atomic():
        alert_rule.update(**updated_fields)
        existing_subs = []
        if (query is not None or aggregation is not None
                or time_window is not None or projects is not None):
            existing_subs = alert_rule.query_subscriptions.all(
            ).select_related("project")

        if projects is not None:
            existing_project_slugs = {
                sub.project.slug
                for sub in existing_subs
            }
            # Determine whether we've added any new projects as part of this update
            new_projects = [
                project for project in projects
                if project.slug not in existing_project_slugs
            ]
            updated_project_slugs = {project.slug for project in projects}
            # Find any subscriptions that were removed as part of this update
            deleted_subs = [
                sub for sub in existing_subs
                if sub.project.slug not in updated_project_slugs
            ]
            if new_projects:
                new_subscriptions = bulk_create_snuba_subscriptions(
                    new_projects,
                    tasks.INCIDENTS_SNUBA_SUBSCRIPTION_TYPE,
                    QueryDatasets(alert_rule.dataset),
                    alert_rule.query,
                    QueryAggregations(alert_rule.aggregation),
                    alert_rule.time_window,
                    DEFAULT_ALERT_RULE_RESOLUTION,
                )
                subscription_links = [
                    AlertRuleQuerySubscription(query_subscription=subscription,
                                               alert_rule=alert_rule)
                    for subscription in new_subscriptions
                ]
                AlertRuleQuerySubscription.objects.bulk_create(
                    subscription_links)

            if deleted_subs:
                bulk_delete_snuba_subscriptions(deleted_subs)

            # Remove any deleted subscriptions from `existing_subscriptions`, so that
            # if we need to update any subscriptions we don't end up doing it twice. We
            # don't add new subscriptions here since they'll already have the updated
            # values
            existing_subs = [sub for sub in existing_subs if sub.id]

        if existing_subs and (query is not None or aggregation is not None
                              or time_window is not None):
            # If updating any subscription details, update related Snuba subscriptions
            # too
            bulk_update_snuba_subscriptions(
                existing_subs,
                alert_rule.query,
                QueryAggregations(alert_rule.aggregation),
                alert_rule.time_window,
                DEFAULT_ALERT_RULE_RESOLUTION,
            )

    return alert_rule
Beispiel #4
0
def create_alert_rule(
    organization,
    projects,
    name,
    threshold_type,
    query,
    aggregation,
    time_window,
    alert_threshold,
    resolve_threshold,
    threshold_period,
):
    """
    Creates an alert rule for an organization.

    :param organization:
    :param projects:
    :param name: Name for the alert rule. This will be used as part of the
    incident name, and must be unique per project.
    :param threshold_type: An AlertRuleThresholdType
    :param query: An event search query to subscribe to and monitor for alerts
    :param aggregation: A QueryAggregation to fetch for this alert rule
    :param time_window: Time period to aggregate over, in minutes.
    :param alert_threshold: Value that the subscription needs to reach to
    trigger the alert
    :param resolve_threshold: Value that the subscription needs to reach to
    resolve the alert
    :param threshold_period: How many update periods the value of the
    subscription needs to exceed the threshold before triggering
    :return: The created `AlertRule`
    """
    dataset = QueryDatasets.EVENTS
    resolution = DEFAULT_ALERT_RULE_RESOLUTION
    validate_alert_rule_query(query)
    if AlertRule.objects.filter(organization=organization, name=name).exists():
        raise AlertRuleNameAlreadyUsedError()
    with transaction.atomic():
        alert_rule = AlertRule.objects.create(
            organization=organization,
            name=name,
            threshold_type=threshold_type.value,
            dataset=dataset.value,
            query=query,
            aggregation=aggregation.value,
            time_window=time_window,
            resolution=resolution,
            alert_threshold=alert_threshold,
            resolve_threshold=resolve_threshold,
            threshold_period=threshold_period,
        )
        subscriptions = bulk_create_snuba_subscriptions(
            projects,
            tasks.INCIDENTS_SNUBA_SUBSCRIPTION_TYPE,
            dataset,
            query,
            aggregation,
            time_window,
            resolution,
        )
        subscription_links = [
            AlertRuleQuerySubscription(query_subscription=subscription,
                                       alert_rule=alert_rule)
            for subscription in subscriptions
        ]
        AlertRuleQuerySubscription.objects.bulk_create(subscription_links)
    return alert_rule