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
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
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
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