oncall-engine/engine/apps/api/serializers/paging.py
Joey Orlando f905ac5246
Updates to POST /direct_paging internal API endpoint to support Grafana Incident use-cases (#3232)
# What this PR does

- Add a new column, `grafana_incident_id`, to the `AlertGroup` model.
For now this is really just needed to determine if the Alert Group was
created, via a Direct Page, that originated from Grafana Incident.
- I understand that these IDs may be cluster specific. For now we will
not need to make OnCall backend -> Incident API calls. Should we need to
start doing this we will likely need to start syncing the Incident
plugin's provisioned API url into the `organization` in OnCall, such
that we make the API call to the right Incident backend.
- Add two new optional request body parameters to `POST /direct_paging`,
`source_url` and `grafana_incident_id`
- `source_url` - will easily allow Grafana Incident to specify the URL
to the Incident and have this populate the "Source" button
- `grafana_incident_id` - Grafana Incident can specify this such that we
have a link back to Incident (+ we know that the Alert Group was
generated from Incident)
- Hide the "Declare Incident" button in the UI if the Alert Group was
generated from Grafana Incident

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
2023-11-01 17:19:44 -04:00

70 lines
2.6 KiB
Python

import typing
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import serializers
from apps.alerts.models import AlertGroup
from apps.user_management.models import Organization
from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField
from common.api_helpers.utils import CurrentTeamDefault
class SerializerContext(typing.TypedDict):
organization: Organization
class UserReferenceSerializer(serializers.Serializer):
context: SerializerContext
id = serializers.CharField()
important = serializers.BooleanField()
instance = serializers.HiddenField(default=None) # set in UserReferenceSerializer.validate
def validate(self, attrs):
id = attrs["id"]
organization = self.context["organization"]
try:
attrs["instance"] = organization.users.get(public_primary_key=id)
except ObjectDoesNotExist:
raise serializers.ValidationError(f"User {id} does not exist")
return attrs
class DirectPagingSerializer(serializers.Serializer):
context: SerializerContext
users = UserReferenceSerializer(many=True, required=False, default=list)
team = TeamPrimaryKeyRelatedField(allow_null=True, default=CurrentTeamDefault())
alert_group_id = serializers.CharField(required=False, default=None)
alert_group = serializers.HiddenField(default=None) # set in DirectPagingSerializer.validate
title = serializers.CharField(required=False, default=None)
message = serializers.CharField(required=False, default=None, allow_null=True)
source_url = serializers.URLField(required=False, default=None, allow_null=True)
grafana_incident_id = serializers.CharField(required=False, default=None, allow_null=True)
def validate(self, attrs):
organization = self.context["organization"]
alert_group_id = attrs["alert_group_id"]
title = attrs["title"]
message = attrs["message"]
source_url = attrs["source_url"]
grafana_incident_id = attrs["grafana_incident_id"]
if alert_group_id and (title or message or source_url or grafana_incident_id):
raise serializers.ValidationError(
"alert_group_id and (title, message, source_url, grafana_incident_id) are mutually exclusive"
)
if alert_group_id:
try:
attrs["alert_group"] = AlertGroup.objects.get(
public_primary_key=alert_group_id, channel__organization=organization
)
except ObjectDoesNotExist:
raise serializers.ValidationError("Alert group {} does not exist".format(alert_group_id))
return attrs