Pass all integration labels down to alert groups (#3299)
# What this PR does Passes ALL integration labels down to alert groups, so it's easier to create labels for alert groups locally. ## Which issue(s) this PR fixes Related to https://github.com/grafana/oncall-private/issues/2179 ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
This commit is contained in:
parent
1997d41e5b
commit
367e3c9c1d
4 changed files with 78 additions and 18 deletions
|
|
@ -12,6 +12,7 @@ from django.db.models import JSONField
|
|||
from apps.alerts import tasks
|
||||
from apps.alerts.constants import TASK_DELAY_SECONDS
|
||||
from apps.alerts.incident_appearance.templaters import TemplateLoader
|
||||
from apps.labels.utils import assign_labels
|
||||
from common.jinja_templater import apply_jinja_template
|
||||
from common.jinja_templater.apply_jinja_template import JinjaTemplateError, JinjaTemplateWarning
|
||||
from common.public_primary_keys import generate_public_primary_key, increase_public_primary_key_length
|
||||
|
|
@ -107,6 +108,7 @@ class Alert(models.Model):
|
|||
)
|
||||
|
||||
if group_created:
|
||||
assign_labels(group, alert_receive_channel)
|
||||
group.log_records.create(type=AlertGroupLogRecord.TYPE_REGISTERED)
|
||||
group.log_records.create(type=AlertGroupLogRecord.TYPE_ROUTE_ASSIGNED)
|
||||
|
||||
|
|
|
|||
48
engine/apps/labels/tests/test_alert_group.py
Normal file
48
engine/apps/labels/tests/test_alert_group.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from apps.alerts.models import Alert
|
||||
|
||||
|
||||
@mock.patch("apps.labels.utils.is_labels_feature_enabled", return_value=False)
|
||||
@pytest.mark.django_db
|
||||
def test_assign_labels_feature_flag_disabled(
|
||||
_, make_organization, make_alert_receive_channel, make_integration_label_association
|
||||
):
|
||||
organization = make_organization()
|
||||
alert_receive_channel = make_alert_receive_channel(organization)
|
||||
make_integration_label_association(organization, alert_receive_channel)
|
||||
|
||||
alert = Alert.create(
|
||||
title="the title",
|
||||
message="the message",
|
||||
alert_receive_channel=alert_receive_channel,
|
||||
raw_request_data={},
|
||||
integration_unique_data={},
|
||||
image_url=None,
|
||||
link_to_upstream_details=None,
|
||||
)
|
||||
|
||||
assert not alert.group.labels.exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_assign_labels(make_organization, make_alert_receive_channel, make_integration_label_association):
|
||||
organization = make_organization()
|
||||
alert_receive_channel = make_alert_receive_channel(organization)
|
||||
label = make_integration_label_association(organization, alert_receive_channel)
|
||||
|
||||
alert = Alert.create(
|
||||
title="the title",
|
||||
message="the message",
|
||||
alert_receive_channel=alert_receive_channel,
|
||||
raw_request_data={},
|
||||
integration_unique_data={},
|
||||
image_url=None,
|
||||
link_to_upstream_details=None,
|
||||
)
|
||||
|
||||
assert alert.group.labels.count() == 1
|
||||
assert alert.group.labels.first().key_name == label.key.name
|
||||
assert alert.group.labels.first().value_name == label.value.name
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
import logging
|
||||
import typing
|
||||
|
||||
from django.apps import apps # noqa: I251
|
||||
from django.conf import settings
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from apps.alerts.models import AlertGroup, AlertReceiveChannel
|
||||
from apps.labels.models import AssociatedLabel
|
||||
from apps.user_management.models import Organization
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
LABEL_OUTDATED_TIMEOUT_MINUTES = 30
|
||||
ASSOCIATED_MODEL_NAME = "AssociatedLabel"
|
||||
|
|
@ -42,19 +42,28 @@ def get_associating_label_model(obj_model_name: str) -> typing.Type["AssociatedL
|
|||
return label_model
|
||||
|
||||
|
||||
def is_labels_feature_enabled(organization) -> bool:
|
||||
"""
|
||||
Checks if labels feature enabled for all organizations (FEATURE_LABELS_ENABLED_FOR_ALL).
|
||||
If not, checks if current organization's grafana org_id is in the list of organizations labels feature enabled for
|
||||
(FEATURE_LABELS_ENABLED_FOR_GRAFANA_ORGS)
|
||||
"""
|
||||
logger.info(
|
||||
"is_labels_feature_enabled: "
|
||||
f"FEATURE_LABELS_ENABLED_FOR_ALL={settings.FEATURE_LABELS_ENABLED_FOR_ALL}, "
|
||||
f"organization in FEATURE_LABELS_ENABLED_FOR_GRAFANA_ORGS="
|
||||
f"{organization.id in settings.FEATURE_LABELS_ENABLED_FOR_GRAFANA_ORGS}, "
|
||||
f"organization={organization.id}"
|
||||
def is_labels_feature_enabled(organization: "Organization") -> bool:
|
||||
return (
|
||||
settings.FEATURE_LABELS_ENABLED_FOR_ALL
|
||||
or organization.org_id in settings.FEATURE_LABELS_ENABLED_FOR_GRAFANA_ORGS # Grafana org ID, not OnCall org ID
|
||||
)
|
||||
if not settings.FEATURE_LABELS_ENABLED_FOR_ALL:
|
||||
return organization.org_id in settings.FEATURE_LABELS_ENABLED_FOR_GRAFANA_ORGS
|
||||
return settings.FEATURE_LABELS_ENABLED_FOR_ALL
|
||||
|
||||
|
||||
def assign_labels(alert_group: "AlertGroup", alert_receive_channel: "AlertReceiveChannel") -> None:
|
||||
from apps.labels.models import AlertGroupAssociatedLabel
|
||||
|
||||
if not is_labels_feature_enabled(alert_receive_channel.organization):
|
||||
return
|
||||
|
||||
# inherit all labels from the integration
|
||||
# FIXME: this is a temporary solution before we have a UI for configuring inherited labels
|
||||
alert_group_labels = [
|
||||
AlertGroupAssociatedLabel(
|
||||
alert_group=alert_group,
|
||||
organization=alert_receive_channel.organization,
|
||||
key_name=label.key.name,
|
||||
value_name=label.value.name,
|
||||
)
|
||||
for label in alert_receive_channel.labels.all().select_related("key", "value")
|
||||
]
|
||||
AlertGroupAssociatedLabel.objects.bulk_create(alert_group_labels)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import time
|
|||
from functools import reduce
|
||||
|
||||
import factory
|
||||
import faker
|
||||
import markdown2
|
||||
from bs4 import BeautifulSoup
|
||||
from celery.utils.log import get_task_logger
|
||||
|
|
@ -21,7 +22,7 @@ logger = get_task_logger(__name__)
|
|||
class UniqueFaker(factory.Faker):
|
||||
@classmethod
|
||||
def _get_faker(cls, locale=None):
|
||||
return super()._get_faker(locale).unique
|
||||
return faker.Faker(locale=locale).unique
|
||||
|
||||
|
||||
# Context manager for tasks that are intended to retry
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue