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:
Vadim Stepanov 2023-11-08 13:17:05 +00:00 committed by GitHub
parent 1997d41e5b
commit 367e3c9c1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 18 deletions

View file

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

View 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

View file

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

View file

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