Skip to content

Commit

Permalink
Webhook labels (#3383)
Browse files Browse the repository at this point in the history
This PR add labels for webhooks. 
1. Make webhook "labelable" with ability to filter by labels.
2. Add labels to the webhook payload. It contain new field webhook with
it's name, id and labels. Field integration and alert_group has a
corresponding label field as well. See example of a new payload below:
```
{
    "event": {
        "type": "escalation"
    },
    "user": null,
    "alert_group": {
        "id": "IRFN6ZD31N31B",
        "integration_id": "CTWM7U4A2QG97",
        "route_id": "RUE7U7Z46SKGY",
        "alerts_count": 1,
        "state": "firing",
        "created_at": "2023-11-22T08:54:55.178243Z",
        "resolved_at": null,
        "acknowledged_at": null,
        "title": "Incident",
        "permalinks": {
            "slack": null,
            "telegram": null,
            "web": "http://grafana:3000/a/grafana-oncall-app/alert-groups/IRFN6ZD31N31B"
        },
        "labels": {
            "severity": "critical"
        }
    },
    "alert_group_id": "IRFN6ZD31N31B",
    "alert_payload": {
        "message": "This alert was sent by user for demonstration purposes"
    },
    "integration": {
        "id": "CTWM7U4A2QG97",
        "type": "webhook",
        "name": "hi - Webhook",
        "team": null,
        "labels": {
            "hello": "world",
            "severity": "critical"
        }
    },
    "notified_users": [],
    "users_to_be_notified": [],
    "webhook": {
        "id": "WHAXK4BTC7TAEQ",
        "name": "test",
        "labels": {
            "hello": "kesha"
        }
    }
}
```

I feel that there is an opportunity to make code cleaner - remove all
label logic from serializers, views and utils to models or dedicated
LabelerService and introduce Labelable interface with something like
label_verbal, update_labels methods. However, I don't want to tie
webhook labels with a refactoring.

---------

Co-authored-by: Dominik <[email protected]>
  • Loading branch information
Konstantinov-Innokentii and brojd authored Nov 22, 2023
1 parent 92ed226 commit 9628bdc
Show file tree
Hide file tree
Showing 38 changed files with 653 additions and 279 deletions.
2 changes: 1 addition & 1 deletion Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ local_resource(
allow_parallel=True,
)

yaml = helm("helm/oncall", name=HELM_PREFIX, values=["./dev/helm-local.yml"])
yaml = helm("helm/oncall", name=HELM_PREFIX, values=["./dev/helm-local.yml", "./dev/helm-local.dev.yml"])

k8s_yaml(yaml)

Expand Down
15 changes: 15 additions & 0 deletions engine/apps/api/label_filtering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import List, Tuple


def parse_label_query(label_query: List[str]) -> List[Tuple[str, str]]:
"""
parse_label_query returns list of key-value tuples from a list of "raw" labels – key-value pairs separated with ':'.
"""
kv_pairs = []
for label in label_query:
label_data = label.split(":")
# Check if label_data is a valid key-value label pair]: ["key1", "value1"]
if len(label_data) != 2:
continue
kv_pairs.append((label_data[0], label_data[1]))
return kv_pairs
20 changes: 19 additions & 1 deletion engine/apps/api/serializers/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator

from apps.api.serializers.labels import LabelsSerializerMixin
from apps.webhooks.models import Webhook, WebhookResponse
from apps.webhooks.models.webhook import PUBLIC_WEBHOOK_HTTP_METHODS, WEBHOOK_FIELD_PLACEHOLDER
from apps.webhooks.presets.preset_options import WebhookPresetOptions
Expand All @@ -27,7 +28,7 @@ class Meta:
]


class WebhookSerializer(serializers.ModelSerializer):
class WebhookSerializer(LabelsSerializerMixin, serializers.ModelSerializer):
id = serializers.CharField(read_only=True, source="public_primary_key")
organization = serializers.HiddenField(default=CurrentOrganizationDefault())
team = TeamPrimaryKeyRelatedField(allow_null=True, default=CurrentTeamDefault())
Expand All @@ -37,6 +38,8 @@ class WebhookSerializer(serializers.ModelSerializer):
trigger_type = serializers.CharField(allow_null=True)
trigger_type_name = serializers.SerializerMethodField()

PREFETCH_RELATED = ["labels", "labels__key", "labels__value"]

class Meta:
model = Webhook
fields = [
Expand All @@ -61,10 +64,25 @@ class Meta:
"last_response_log",
"integration_filter",
"preset",
"labels",
]

validators = [UniqueTogetherValidator(queryset=Webhook.objects.all(), fields=["name", "organization"])]

def create(self, validated_data):
organization = self.context["request"].auth.organization
labels = validated_data.pop("labels", None)

instance = super().create(validated_data)
self.update_labels_association_if_needed(labels, instance, organization)
return instance

def update(self, instance, validated_data):
labels = validated_data.pop("labels", None)
organization = self.context["request"].auth.organization
self.update_labels_association_if_needed(labels, instance, organization)
return super().update(instance, validated_data)

def to_representation(self, instance):
result = super().to_representation(instance)
if instance.password:
Expand Down
2 changes: 0 additions & 2 deletions engine/apps/api/tests/test_alert_receive_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,6 @@ def test_integration_filter_by_labels(
def test_update_alert_receive_channel_labels(
make_organization_and_user_with_plugin_token,
make_alert_receive_channel,
make_integration_label_association,
make_user_auth_headers,
):
organization, user, token = make_organization_and_user_with_plugin_token()
Expand Down Expand Up @@ -1353,7 +1352,6 @@ def test_update_alert_receive_channel_labels(
def test_update_alert_receive_channel_labels_duplicate_key(
make_organization_and_user_with_plugin_token,
make_alert_receive_channel,
make_integration_label_association,
make_user_auth_headers,
):
organization, user, token = make_organization_and_user_with_plugin_token()
Expand Down
9 changes: 0 additions & 9 deletions engine/apps/api/tests/test_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def test_get_update_key_get(
mocked_get_values,
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
client = APIClient()
Expand All @@ -68,7 +67,6 @@ def test_get_update_key_put(
mocked_rename_key,
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
client = APIClient()
Expand All @@ -94,7 +92,6 @@ def test_add_value(
mocked_add_value,
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
client = APIClient()
Expand All @@ -120,7 +117,6 @@ def test_rename_value(
mocked_rename_value,
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
client = APIClient()
Expand All @@ -146,7 +142,6 @@ def test_get_value(
mocked_get_value,
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
client = APIClient()
Expand All @@ -171,7 +166,6 @@ def test_labels_create_label(
mocked_create_label,
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
):
organization, user, token = make_organization_and_user_with_plugin_token()
client = APIClient()
Expand All @@ -189,7 +183,6 @@ def test_labels_create_label(
def test_labels_feature_false(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
settings,
):
setattr(settings, "FEATURE_LABELS_ENABLED_FOR_ALL", False)
Expand Down Expand Up @@ -239,7 +232,6 @@ def test_labels_feature_false(
def test_labels_permissions_get_actions(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
role,
expected_status,
):
Expand Down Expand Up @@ -274,7 +266,6 @@ def test_labels_permissions_get_actions(
def test_labels_permissions_create_update_actions(
make_organization_and_user_with_plugin_token,
make_user_auth_headers,
make_alert_receive_channel,
role,
expected_status,
):
Expand Down
1 change: 1 addition & 0 deletions engine/apps/api/tests/test_webhook_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def test_create_webhook_from_preset(
"http_method": "GET",
"integration_filter": None,
"is_webhook_enabled": True,
"labels": [],
"is_legacy": False,
"last_response_log": {
"request_data": "",
Expand Down
Loading

0 comments on commit 9628bdc

Please sign in to comment.