From 3dad6717ad9ab635ef8246853e5c910122d2c99d Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 18 Nov 2024 10:46:36 +0100 Subject: [PATCH 01/15] Add migration to merge static and integration labels --- .../alerts/migrations/0065_migrate_labels.py | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 engine/apps/alerts/migrations/0065_migrate_labels.py diff --git a/engine/apps/alerts/migrations/0065_migrate_labels.py b/engine/apps/alerts/migrations/0065_migrate_labels.py new file mode 100644 index 0000000000..94fe96412c --- /dev/null +++ b/engine/apps/alerts/migrations/0065_migrate_labels.py @@ -0,0 +1,58 @@ +# Generated by Django 4.2.15 on 2024-11-12 09:33 +import logging + +from django.db import migrations +import django_migration_linter as linter + +logger = logging.getLogger(__name__) + + +def migrate_static_labels(apps, schema_editor): + AlertReceiveChannelAssociatedLabel = apps.get_model("labels", "AlertReceiveChannelAssociatedLabel") + AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel") + + logging.info("Start migrating alert group static labels to integration labels") + + labels_associations_to_create = [] + alert_receive_channels_to_update = [] + + alert_receive_channels = AlertReceiveChannel.objects.filter(alert_group_labels_custom__isnull=False) + logging.info(f"Found {alert_receive_channels.count()} integrations with custom alert groups labels") + for alert_receive_channel in alert_receive_channels: + update_labels = False + labels = alert_receive_channel.alert_group_labels_custom[:] + for label in labels: + if label[1] is not None: + labels_associations_to_create.append( + AlertReceiveChannelAssociatedLabel( + key_id=label[0], + value_id=label[1], + organization=alert_receive_channel.organization, + alert_receive_channel=alert_receive_channel + ) + ) + alert_receive_channel.alert_group_labels_custom.remove(label) + update_labels = True + if update_labels: + alert_receive_channels_to_update.append(alert_receive_channel) + + AlertReceiveChannelAssociatedLabel.objects.bulk_create( + labels_associations_to_create, ignore_conflicts=True, batch_size=5000 + ) + logging.info("Bulk created label associations") + AlertReceiveChannel.objects.bulk_update(alert_receive_channels_to_update, fields=["alert_group_labels_custom"], batch_size=5000) + logging.info("Bulk updated integrations") + logging.info("Finished migrating static labels to integration labels") + + +class Migration(migrations.Migration): + + dependencies = [ + ('alerts', '0064_migrate_resolutionnoteslackmessage_slack_channel_id'), + ] + + operations = [ + # migrate static alert group labels to integration labels + linter.IgnoreMigration(), + migrations.RunPython(migrate_static_labels, migrations.RunPython.noop), + ] From c5fb0e098c8ee667c1aa0d64f9040c25eb073dff Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 18 Nov 2024 11:35:21 +0100 Subject: [PATCH 02/15] Save static labels as integration labels --- .../api/serializers/alert_receive_channel.py | 31 +++++++++++++++++-- .../api/tests/test_alert_receive_channel.py | 15 ++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/engine/apps/api/serializers/alert_receive_channel.py b/engine/apps/api/serializers/alert_receive_channel.py index 33bf240faa..105ec98c31 100644 --- a/engine/apps/api/serializers/alert_receive_channel.py +++ b/engine/apps/api/serializers/alert_receive_channel.py @@ -1,8 +1,10 @@ import typing from collections import OrderedDict +from functools import partial from django.conf import settings from django.core.exceptions import ValidationError as DjangoValidationError +from django.db import transaction from django.db.models import Q from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field from jinja2 import TemplateSyntaxError @@ -14,7 +16,7 @@ from apps.alerts.models import AlertReceiveChannel from apps.base.messaging import get_messaging_backends from apps.integrations.legacy_prefix import has_legacy_prefix -from apps.labels.models import LabelKeyCache, LabelValueCache +from apps.labels.models import AlertReceiveChannelAssociatedLabel, LabelKeyCache, LabelValueCache from apps.labels.types import LabelKey from apps.user_management.models import Organization from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField @@ -132,7 +134,13 @@ def update( instance.labels.filter(~Q(key_id__in=inheritable_key_ids)).update(inheritable=False) # update DB cache for custom labels - cls._create_custom_labels(instance.organization, alert_group_labels["custom"]) + with transaction.atomic(): + cls._create_custom_labels(instance.organization, alert_group_labels["custom"]) + # save static labels as integration labels + # todo: it's needed to cover delay between backend and frontend rollout, and can be removed later + transaction.on_commit( + partial(cls._save_static_labels_as_integration_labels, instance, alert_group_labels["custom"]) + ) # update custom labels instance.alert_group_labels_custom = cls._custom_labels_to_internal_value(alert_group_labels["custom"]) @@ -170,6 +178,25 @@ def _create_custom_labels(organization: Organization, labels: AlertGroupCustomLa LabelKeyCache.objects.bulk_create(label_keys, ignore_conflicts=True, batch_size=5000) LabelValueCache.objects.bulk_create(label_values, ignore_conflicts=True, batch_size=5000) + @staticmethod + def _save_static_labels_as_integration_labels(instance: AlertReceiveChannel, labels: AlertGroupCustomLabelsAPI): + labels_associations_to_create = [] + labels_copy = labels[:] + for label in labels_copy: + if label["value"]["id"] is not None: + labels_associations_to_create.append( + AlertReceiveChannelAssociatedLabel( + key_id=label["key"]["id"], + value_id=label["value"]["id"], + organization=instance.organization, + alert_receive_channel=instance, + ) + ) + labels.remove(label) + AlertReceiveChannelAssociatedLabel.objects.bulk_create( + labels_associations_to_create, ignore_conflicts=True, batch_size=5000 + ) + @classmethod def to_representation(cls, instance: AlertReceiveChannel) -> IntegrationAlertGroupLabels: """ diff --git a/engine/apps/api/tests/test_alert_receive_channel.py b/engine/apps/api/tests/test_alert_receive_channel.py index 4569cc2ec8..767eaae013 100644 --- a/engine/apps/api/tests/test_alert_receive_channel.py +++ b/engine/apps/api/tests/test_alert_receive_channel.py @@ -1712,19 +1712,26 @@ def test_alert_group_labels_put( response = client.put(url, data, format="json", **make_user_auth_headers(user, token)) assert response.status_code == status.HTTP_200_OK + # check static labels were saved as integration labels assert response.json()["alert_group_labels"] == { - "inheritable": {label_1.key_id: False, label_2.key_id: True, label_3.key_id: False}, - "custom": custom, + "inheritable": {label_1.key_id: False, label_2.key_id: True, label_3.key_id: False, "hello": True}, + "custom": [ + { + "key": {"id": label_3.key.id, "name": label_3.key.name, "prescribed": False}, + "value": {"id": None, "name": "{{ payload.foo }}", "prescribed": False}, + } + ], "template": template, } alert_receive_channel.refresh_from_db() + # check static labels are not in the custom labels list assert alert_receive_channel.alert_group_labels_custom == [ - [label_2.key_id, label_2.value_id, None], - ["hello", "foo", None], [label_3.key_id, None, "{{ payload.foo }}"], ] assert alert_receive_channel.alert_group_labels_template == template + # check static labels were assigned to integration + assert alert_receive_channel.labels.filter(key_id__in=[label_2.key_id, "hello"]).count() == 2 # check label keys & values are created key = LabelKeyCache.objects.filter(id="hello", name="world", organization=organization).first() From 3e1ad96c65b7413738c0d64c1df2639fa7bb25db Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 18 Nov 2024 11:50:11 +0100 Subject: [PATCH 03/15] Update doc --- .../configure/integrations/labels/index.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/docs/sources/configure/integrations/labels/index.md b/docs/sources/configure/integrations/labels/index.md index 07da1730a0..aba7ef4b00 100644 --- a/docs/sources/configure/integrations/labels/index.md +++ b/docs/sources/configure/integrations/labels/index.md @@ -74,19 +74,14 @@ Alert Group labeling can be configured for each integration. To find the Alert G A maximum of 15 labels can be assigned to an alert group. If there are more than 15 labels, only the first 15 will be assigned. -### Dynamic & Static Labels +### Dynamic Labels -Dynamic and Static labels allow you to assign arbitrary labels to alert groups. +Dynamic labels allow you to assign arbitrary labels to alert groups. Dynamic labels have values extracted from the alert payload using Jinja, with keys remaining static. -Static labels have both key and value as static and are not derived from the payload. These labels will not be attached to the integration. +These labels will not be attached to the integration. -1. In the **Alert Group Labeling** tab, navigate to **Dynamic & Static Labels**. -2. Press the **Add Label** button and choose between dynamic or static. - -#### Add Static Labels - -1. Select or create key and value from the dropdown list. -2. These labels will be assigned to all alert groups received by this integration. +1. In the **Alert Group Labeling** tab, navigate to **Dynamic Labels**. +2. Press the **Add Label** button. #### Add Dynamic Labels From 74667781217fd452f7f1586876b0924e7fbb5ac6 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 18 Nov 2024 12:17:42 +0100 Subject: [PATCH 04/15] update saving labels --- engine/apps/api/serializers/alert_receive_channel.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/engine/apps/api/serializers/alert_receive_channel.py b/engine/apps/api/serializers/alert_receive_channel.py index 105ec98c31..4d9aebfc87 100644 --- a/engine/apps/api/serializers/alert_receive_channel.py +++ b/engine/apps/api/serializers/alert_receive_channel.py @@ -1,10 +1,8 @@ import typing from collections import OrderedDict -from functools import partial from django.conf import settings from django.core.exceptions import ValidationError as DjangoValidationError -from django.db import transaction from django.db.models import Q from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field from jinja2 import TemplateSyntaxError @@ -134,13 +132,10 @@ def update( instance.labels.filter(~Q(key_id__in=inheritable_key_ids)).update(inheritable=False) # update DB cache for custom labels - with transaction.atomic(): - cls._create_custom_labels(instance.organization, alert_group_labels["custom"]) + cls._create_custom_labels(instance.organization, alert_group_labels["custom"]) # save static labels as integration labels # todo: it's needed to cover delay between backend and frontend rollout, and can be removed later - transaction.on_commit( - partial(cls._save_static_labels_as_integration_labels, instance, alert_group_labels["custom"]) - ) + cls._save_static_labels_as_integration_labels(instance, alert_group_labels["custom"]) # update custom labels instance.alert_group_labels_custom = cls._custom_labels_to_internal_value(alert_group_labels["custom"]) From 10dbcd3b61229427eea9a05ad12ef2d3ab0cd8b2 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 18 Nov 2024 12:34:49 +0100 Subject: [PATCH 05/15] fix test --- .../api/tests/test_alert_receive_channel.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/engine/apps/api/tests/test_alert_receive_channel.py b/engine/apps/api/tests/test_alert_receive_channel.py index 767eaae013..7e118a74ca 100644 --- a/engine/apps/api/tests/test_alert_receive_channel.py +++ b/engine/apps/api/tests/test_alert_receive_channel.py @@ -1773,6 +1773,20 @@ def test_alert_group_labels_post(alert_receive_channel_internal_api_setup, make_ { "key": {"id": "test", "name": "test", "prescribed": False}, "value": {"id": "123", "name": "123", "prescribed": False}, + }, + { + "key": {"id": "test2", "name": "test2", "prescribed": False}, + "value": {"id": None, "name": "{{ payload.foo }}", "prescribed": False}, + }, + ], + "template": "{{ payload.labels | tojson }}", + } + expected_alert_group_labels = { + "inheritable": {"test": False}, + "custom": [ + { + "key": {"id": "test2", "name": "test2", "prescribed": False}, + "value": {"id": None, "name": "{{ payload.foo }}", "prescribed": False}, } ], "template": "{{ payload.labels | tojson }}", @@ -1790,10 +1804,10 @@ def test_alert_group_labels_post(alert_receive_channel_internal_api_setup, make_ assert response.status_code == status.HTTP_201_CREATED assert response.json()["labels"] == labels - assert response.json()["alert_group_labels"] == alert_group_labels + assert response.json()["alert_group_labels"] == expected_alert_group_labels alert_receive_channel = AlertReceiveChannel.objects.get(public_primary_key=response.json()["id"]) - assert alert_receive_channel.alert_group_labels_custom == [["test", "123", None]] + assert alert_receive_channel.alert_group_labels_custom == [["test2", None, "{{ payload.foo }}"]] assert alert_receive_channel.alert_group_labels_template == "{{ payload.labels | tojson }}" From 392168d99b3859a69772c443c26ea3f65da676a2 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 19 Nov 2024 14:11:00 +0100 Subject: [PATCH 06/15] fix migration --- engine/apps/alerts/migrations/0065_migrate_labels.py | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/apps/alerts/migrations/0065_migrate_labels.py b/engine/apps/alerts/migrations/0065_migrate_labels.py index 94fe96412c..c2f352bac6 100644 --- a/engine/apps/alerts/migrations/0065_migrate_labels.py +++ b/engine/apps/alerts/migrations/0065_migrate_labels.py @@ -49,6 +49,7 @@ class Migration(migrations.Migration): dependencies = [ ('alerts', '0064_migrate_resolutionnoteslackmessage_slack_channel_id'), + ('labels', '0005_labelkeycache_prescribed_labelvaluecache_prescribed'), ] operations = [ From 291b15b2bc34b571b247def6639917520638e262 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 19 Nov 2024 14:52:34 +0100 Subject: [PATCH 07/15] fix migration --- .../{0065_migrate_labels.py => 0066_migrate_labels.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename engine/apps/alerts/migrations/{0065_migrate_labels.py => 0066_migrate_labels.py} (96%) diff --git a/engine/apps/alerts/migrations/0065_migrate_labels.py b/engine/apps/alerts/migrations/0066_migrate_labels.py similarity index 96% rename from engine/apps/alerts/migrations/0065_migrate_labels.py rename to engine/apps/alerts/migrations/0066_migrate_labels.py index c2f352bac6..cc4f97e799 100644 --- a/engine/apps/alerts/migrations/0065_migrate_labels.py +++ b/engine/apps/alerts/migrations/0066_migrate_labels.py @@ -48,7 +48,7 @@ def migrate_static_labels(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('alerts', '0064_migrate_resolutionnoteslackmessage_slack_channel_id'), + ('alerts', '0065_alertreceivechannel_service_account'), ('labels', '0005_labelkeycache_prescribed_labelvaluecache_prescribed'), ] From ac968c71536918604abcd3751a48726dd5a85cea Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 22 Nov 2024 15:30:05 +0100 Subject: [PATCH 08/15] fix migration --- .../{0066_migrate_labels.py => 0071_migrate_labels.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename engine/apps/alerts/migrations/{0066_migrate_labels.py => 0071_migrate_labels.py} (96%) diff --git a/engine/apps/alerts/migrations/0066_migrate_labels.py b/engine/apps/alerts/migrations/0071_migrate_labels.py similarity index 96% rename from engine/apps/alerts/migrations/0066_migrate_labels.py rename to engine/apps/alerts/migrations/0071_migrate_labels.py index cc4f97e799..787b5fdbc8 100644 --- a/engine/apps/alerts/migrations/0066_migrate_labels.py +++ b/engine/apps/alerts/migrations/0071_migrate_labels.py @@ -48,7 +48,7 @@ def migrate_static_labels(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('alerts', '0065_alertreceivechannel_service_account'), + ('alerts', '0070_remove_resolutionnoteslackmessage__slack_channel_id_db'), ('labels', '0005_labelkeycache_prescribed_labelvaluecache_prescribed'), ] From 730831ba2eaf91bb95775862abee59e6921f9574 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 26 Nov 2024 14:15:26 +0100 Subject: [PATCH 09/15] Remove "inheritable" field from integration labels. --- engine/apps/labels/alert_group_labels.py | 3 +-- ...ceivechannelassociatedlabel_inheritable.py | 19 +++++++++++++++++++ engine/apps/labels/models.py | 3 --- 3 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable.py diff --git a/engine/apps/labels/alert_group_labels.py b/engine/apps/labels/alert_group_labels.py index f63e60cdff..60bfad7c18 100644 --- a/engine/apps/labels/alert_group_labels.py +++ b/engine/apps/labels/alert_group_labels.py @@ -29,8 +29,7 @@ def gather_labels_from_alert_receive_channel_and_raw_request_data( # inherit labels from the integration labels = { - label.key.name: label.value.name - for label in alert_receive_channel.labels.filter(inheritable=True).select_related("key", "value") + label.key.name: label.value.name for label in alert_receive_channel.labels.all().select_related("key", "value") } # apply custom labels diff --git a/engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable.py b/engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable.py new file mode 100644 index 0000000000..26a241565c --- /dev/null +++ b/engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.15 on 2024-11-26 12:42 + +from django.db import migrations +import django_migration_linter as linter + + +class Migration(migrations.Migration): + + dependencies = [ + ('labels', '0005_labelkeycache_prescribed_labelvaluecache_prescribed'), + ] + + operations = [ + linter.IgnoreMigration(), # this field is deprecated + migrations.RemoveField( + model_name='alertreceivechannelassociatedlabel', + name='inheritable', + ), + ] diff --git a/engine/apps/labels/models.py b/engine/apps/labels/models.py index 8a4a626d6f..ecd06c268d 100644 --- a/engine/apps/labels/models.py +++ b/engine/apps/labels/models.py @@ -118,9 +118,6 @@ class AlertReceiveChannelAssociatedLabel(AssociatedLabel): "alerts.AlertReceiveChannel", on_delete=models.CASCADE, related_name="labels" ) - # If inheritable is True, then the label will be passed down to alert groups - inheritable = models.BooleanField(default=True, null=True) - class Meta: unique_together = ["key_id", "value_id", "alert_receive_channel_id"] From 2fc12464a1c3a3ed82eb990a1e8bbd121b016b5c Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 26 Nov 2024 14:20:26 +0100 Subject: [PATCH 10/15] Update integration api --- .../api/serializers/alert_receive_channel.py | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/engine/apps/api/serializers/alert_receive_channel.py b/engine/apps/api/serializers/alert_receive_channel.py index 4d9aebfc87..9065ca6801 100644 --- a/engine/apps/api/serializers/alert_receive_channel.py +++ b/engine/apps/api/serializers/alert_receive_channel.py @@ -3,7 +3,6 @@ from django.conf import settings from django.core.exceptions import ValidationError as DjangoValidationError -from django.db.models import Q from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field from jinja2 import TemplateSyntaxError from rest_framework import serializers @@ -55,7 +54,7 @@ class AlertGroupCustomLabelAPI(typing.TypedDict): class IntegrationAlertGroupLabels(typing.TypedDict): - inheritable: dict[str, bool] + inheritable: dict[str, bool] | None # Deprecated custom: AlertGroupCustomLabelsAPI template: str | None @@ -99,7 +98,8 @@ class CustomLabelValueSerializer(serializers.Serializer): class IntegrationAlertGroupLabelsSerializer(serializers.Serializer): """Alert group labels configuration for the integration. See AlertReceiveChannel.alert_group_labels for details.""" - inheritable = serializers.DictField(child=serializers.BooleanField()) + # todo: inheritable field is deprecated. Remove in a future release + inheritable = serializers.DictField(child=serializers.BooleanField(), required=False) custom = CustomLabelSerializer(many=True) template = serializers.CharField(allow_null=True) @@ -107,12 +107,13 @@ class IntegrationAlertGroupLabelsSerializer(serializers.Serializer): def pop_alert_group_labels(validated_data: dict) -> IntegrationAlertGroupLabels | None: """Get alert group labels from validated data.""" - # the "alert_group_labels" field is optional, so either all 3 fields are present or none - if "inheritable" not in validated_data: + # the "alert_group_labels" field is optional, so either all 2 fields are present or none + # "inheritable" field is deprecated + if "custom" not in validated_data: return None return { - "inheritable": validated_data.pop("inheritable"), + "inheritable": validated_data.pop("inheritable", None), # deprecated "custom": validated_data.pop("custom"), "template": validated_data.pop("template"), } @@ -124,13 +125,6 @@ def update( if alert_group_labels is None: return instance - # update inheritable labels - inheritable_key_ids = [ - key_id for key_id, inheritable in alert_group_labels["inheritable"].items() if inheritable - ] - instance.labels.filter(key_id__in=inheritable_key_ids).update(inheritable=True) - instance.labels.filter(~Q(key_id__in=inheritable_key_ids)).update(inheritable=False) - # update DB cache for custom labels cls._create_custom_labels(instance.organization, alert_group_labels["custom"]) # save static labels as integration labels @@ -197,13 +191,14 @@ def to_representation(cls, instance: AlertReceiveChannel) -> IntegrationAlertGro """ The API representation of alert group labels is very different from the underlying model. - "inheritable" is based on AlertReceiveChannelAssociatedLabel.inheritable, a property of another model. + "inheritable" field is deprecated. Kept for api-backward compatibility. Will be removed in a future release "custom" is based on AlertReceiveChannel.alert_group_labels_custom, a JSONField with a different schema. "template" is based on AlertReceiveChannel.alert_group_labels_template, this one is straightforward. """ return { - "inheritable": {label.key_id: label.inheritable for label in instance.labels.all()}, + # todo: "inheritable" field is deprecated, remove in a future release. + "inheritable": {label.key_id: True for label in instance.labels.all()}, "custom": cls._custom_labels_to_representation(instance.alert_group_labels_custom), "template": instance.alert_group_labels_template, } From 770d23673073d9c98281eb23749b9cce110dbe7a Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 26 Nov 2024 14:20:49 +0100 Subject: [PATCH 11/15] update tests --- engine/apps/api/tests/test_alert_receive_channel.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/apps/api/tests/test_alert_receive_channel.py b/engine/apps/api/tests/test_alert_receive_channel.py index 7e118a74ca..ac040cde1c 100644 --- a/engine/apps/api/tests/test_alert_receive_channel.py +++ b/engine/apps/api/tests/test_alert_receive_channel.py @@ -1674,8 +1674,8 @@ def test_alert_group_labels_put( organization, user, token = make_organization_and_user_with_plugin_token() alert_receive_channel = make_alert_receive_channel(organization) label_1 = make_integration_label_association(organization, alert_receive_channel) - label_2 = make_integration_label_association(organization, alert_receive_channel, inheritable=False) - label_3 = make_integration_label_association(organization, alert_receive_channel, inheritable=False) + label_2 = make_integration_label_association(organization, alert_receive_channel) + label_3 = make_integration_label_association(organization, alert_receive_channel) custom = [ # plain label @@ -1714,7 +1714,7 @@ def test_alert_group_labels_put( assert response.status_code == status.HTTP_200_OK # check static labels were saved as integration labels assert response.json()["alert_group_labels"] == { - "inheritable": {label_1.key_id: False, label_2.key_id: True, label_3.key_id: False, "hello": True}, + "inheritable": {label_1.key_id: True, label_2.key_id: True, label_3.key_id: True, "hello": True}, "custom": [ { "key": {"id": label_3.key.id, "name": label_3.key.name, "prescribed": False}, @@ -1782,7 +1782,7 @@ def test_alert_group_labels_post(alert_receive_channel_internal_api_setup, make_ "template": "{{ payload.labels | tojson }}", } expected_alert_group_labels = { - "inheritable": {"test": False}, + "inheritable": {"test": True}, "custom": [ { "key": {"id": "test2", "name": "test2", "prescribed": False}, From 2cbfa5578f443a9d89f7db65901005db0e0cfeb2 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 26 Nov 2024 14:24:55 +0100 Subject: [PATCH 12/15] Update docs --- docs/sources/configure/integrations/labels/index.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/sources/configure/integrations/labels/index.md b/docs/sources/configure/integrations/labels/index.md index aba7ef4b00..32011d6eb7 100644 --- a/docs/sources/configure/integrations/labels/index.md +++ b/docs/sources/configure/integrations/labels/index.md @@ -37,8 +37,8 @@ To assign labels to an integration: 1. Go to the **Integrations** tab and select an integration from the list. 2. Click the **three dots** next to the integration name and select **Integration settings**. -3. Define a Key and Value pair for the label, either by selecting from an existing list or typing new ones in the fields. Press enter/return to accept. -4. To add more labels, click on the **Add** button. You can remove a label using the X button next to the key-value pair. +3. Click **Add** button in the **Integration labels** section. You can remove a label using the X button next to the key-value pair. +4. Define a Key and Value pair for the label, either by selecting from an existing list or typing new ones in the fields. Press enter/return to accept. 5. Click **Save** when finished. To filter integrations by labels: @@ -47,12 +47,7 @@ To filter integrations by labels: 2. Locate the **Search or filter results…** dropdown and select **Label**. 3. Start typing to find suggestions and select the key-value pair you’d like to filter by. -### Pass down integration labels - Labels are automatically assigned to each alert group based on the labels assigned to the integration. -You can choose to pass down specific labels in the Alert Group Labeling tab. - -To do this, navigate to the Integration Labels section in the Alert Group Labeling tab and enable/disable specific labels using the toggler. ## Alert Group labels @@ -70,7 +65,7 @@ Alert Group labeling can be configured for each integration. To find the Alert G 1. Navigate to the **Integrations** tab. 2. Select an integration from the list of enabled integrations. 3. Click the three dots next to the integration name. -4. Choose **Alert Group Labeling**. +4. Choose **Integration settings**. You can configure alert group labels mapping in the **Mapping** section. A maximum of 15 labels can be assigned to an alert group. If there are more than 15 labels, only the first 15 will be assigned. From 1f01baefa5abed1db29fc7d5deea91b2392ec6db Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 26 Nov 2024 14:43:36 +0100 Subject: [PATCH 13/15] Update migration --- ...rtreceivechannelassociatedlabel_inheritable_state.py} | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) rename engine/apps/labels/migrations/{0006_remove_alertreceivechannelassociatedlabel_inheritable.py => 0006_remove_alertreceivechannelassociatedlabel_inheritable_state.py} (50%) diff --git a/engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable.py b/engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable_state.py similarity index 50% rename from engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable.py rename to engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable_state.py index 26a241565c..8e71cc998b 100644 --- a/engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable.py +++ b/engine/apps/labels/migrations/0006_remove_alertreceivechannelassociatedlabel_inheritable_state.py @@ -1,7 +1,7 @@ -# Generated by Django 4.2.15 on 2024-11-26 12:42 +# Generated by Django 4.2.15 on 2024-11-26 13:37 +import common.migrations.remove_field from django.db import migrations -import django_migration_linter as linter class Migration(migrations.Migration): @@ -11,9 +11,8 @@ class Migration(migrations.Migration): ] operations = [ - linter.IgnoreMigration(), # this field is deprecated - migrations.RemoveField( - model_name='alertreceivechannelassociatedlabel', + common.migrations.remove_field.RemoveFieldState( + model_name='AlertReceiveChannelAssociatedLabel', name='inheritable', ), ] From 236025d7a7f1d8a250912b769155187c1a3a47c2 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 28 Nov 2024 14:23:17 +0100 Subject: [PATCH 14/15] Add second migration to /labels directory --- ...vechannelassociatedlabel_inheritable_db.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 engine/apps/labels/0007_remove_alertreceivechannelassociatedlabel_inheritable_db.py diff --git a/engine/apps/labels/0007_remove_alertreceivechannelassociatedlabel_inheritable_db.py b/engine/apps/labels/0007_remove_alertreceivechannelassociatedlabel_inheritable_db.py new file mode 100644 index 0000000000..91504bd9a6 --- /dev/null +++ b/engine/apps/labels/0007_remove_alertreceivechannelassociatedlabel_inheritable_db.py @@ -0,0 +1,21 @@ +# TODO: MOVE IT TO /migrations DIRECTORY IN FUTURE RELEASE + +# Generated by Django 4.2.15 on 2024-11-26 13:37 + +from django.db import migrations + +import common.migrations.remove_field + + +class Migration(migrations.Migration): + dependencies = [ + ("labels", "0006_remove_alertreceivechannelassociatedlabel_inheritable_state"), + ] + + operations = [ + common.migrations.remove_field.RemoveFieldDB( + model_name="AlertReceiveChannelAssociatedLabel", + name="inheritable", + remove_state_migration=("labels", "0007_remove_alertreceivechannelassociatedlabel_inheritable_state"), + ), + ] From e96c8269e97853072472dab2af0aa33c75bb6752 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 28 Nov 2024 16:34:34 +0100 Subject: [PATCH 15/15] Update docs --- docs/sources/configure/integrations/labels/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/configure/integrations/labels/index.md b/docs/sources/configure/integrations/labels/index.md index 32011d6eb7..9f29a7fba2 100644 --- a/docs/sources/configure/integrations/labels/index.md +++ b/docs/sources/configure/integrations/labels/index.md @@ -75,7 +75,7 @@ Dynamic labels allow you to assign arbitrary labels to alert groups. Dynamic labels have values extracted from the alert payload using Jinja, with keys remaining static. These labels will not be attached to the integration. -1. In the **Alert Group Labeling** tab, navigate to **Dynamic Labels**. +1. In the **Integration settings** tab, navigate to **Dynamic Labels**. 2. Press the **Add Label** button. #### Add Dynamic Labels