Skip to content

Commit 73a073d

Browse files
authored
v1.10.0
2 parents 8e098cf + 7ddd05e commit 73a073d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1625
-364
lines changed

docs/sources/oncall-api-reference/alertgroups.md

+25
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ The above command returns JSON structured in the following way:
4646
"telegram": "https://t.me/c/5354/1234?thread=1234"
4747
},
4848
"silenced_at": "2020-05-19T13:37:01.429805Z",
49+
"last_alert": {
50+
"id": "AA74DN7T4JQB6",
51+
"alert_group_id": "I68T24C13IFW1",
52+
"created_at": "2020-05-11T20:08:43Z",
53+
"payload": {
54+
"state": "alerting",
55+
"title": "[Alerting] Test notification",
56+
"ruleId": 0,
57+
"message": "Someone is testing the alert notification within Grafana.",
58+
"ruleUrl": "{{API_URL}}/",
59+
"ruleName": "Test notification",
60+
"evalMatches": [
61+
{
62+
"tags": null,
63+
"value": 100,
64+
"metric": "High value"
65+
},
66+
{
67+
"tags": null,
68+
"value": 200,
69+
"metric": "Higher Value"
70+
}
71+
]
72+
}
73+
},
4974
}
5075
],
5176
"current_page_number": 1,

engine/apps/alerts/escalation_snapshot/serializers/escalation_policy_snapshot.py

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class Meta:
7777
"to_time",
7878
"num_alerts_in_window",
7979
"num_minutes_in_window",
80+
"severity",
8081
"custom_webhook",
8182
"notify_schedule",
8283
"notify_to_group",

engine/apps/alerts/escalation_snapshot/snapshot_classes/escalation_policy_snapshot.py

+32
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
from apps.alerts.models.escalation_policy import EscalationPolicy
1313
from apps.alerts.tasks import (
1414
custom_webhook_result,
15+
declare_incident,
1516
notify_all_task,
1617
notify_group_task,
1718
notify_user_task,
1819
resolve_by_last_step_task,
1920
)
21+
from apps.alerts.utils import is_declare_incident_step_enabled
2022
from apps.schedules.ical_utils import list_users_to_notify_from_ical
2123
from apps.user_management.models import User
2224

@@ -40,6 +42,7 @@ class EscalationPolicySnapshot:
4042
"notify_schedule",
4143
"notify_to_group",
4244
"notify_to_team_members",
45+
"severity",
4346
"escalation_counter",
4447
"passed_last_time",
4548
"pause_escalation",
@@ -71,6 +74,7 @@ def __init__(
7174
passed_last_time,
7275
pause_escalation,
7376
notify_to_team_members=None,
77+
severity=None,
7478
):
7579
self.id = id
7680
self.order = order
@@ -86,6 +90,7 @@ def __init__(
8690
self.notify_schedule = notify_schedule
8791
self.notify_to_group = notify_to_group
8892
self.notify_to_team_members = notify_to_team_members
93+
self.severity = severity
8994
self.escalation_counter = escalation_counter # used for STEP_REPEAT_ESCALATION_N_TIMES
9095
self.passed_last_time = passed_last_time # used for building escalation plan
9196
self.pause_escalation = pause_escalation # used for STEP_NOTIFY_IF_NUM_ALERTS_IN_TIME_WINDOW
@@ -133,6 +138,7 @@ def execute(self, alert_group: "AlertGroup", reason) -> StepExecutionResultData:
133138
EscalationPolicy.STEP_NOTIFY_IF_NUM_ALERTS_IN_TIME_WINDOW: self._escalation_step_notify_if_num_alerts_in_time_window,
134139
EscalationPolicy.STEP_NOTIFY_MULTIPLE_USERS: self._escalation_step_notify_multiple_users,
135140
EscalationPolicy.STEP_NOTIFY_MULTIPLE_USERS_IMPORTANT: self._escalation_step_notify_multiple_users,
141+
EscalationPolicy.STEP_DECLARE_INCIDENT: self._escalation_step_declare_incident,
136142
None: self._escalation_step_not_configured,
137143
}
138144
result = action_map[self.step](alert_group, reason)
@@ -407,6 +413,32 @@ def _escalation_step_notify_team_members(self, alert_group: "AlertGroup", reason
407413

408414
self._execute_tasks(tasks)
409415

416+
def _escalation_step_declare_incident(self, alert_group: "AlertGroup", _reason: str) -> None:
417+
grafana_declare_incident_enabled = is_declare_incident_step_enabled(
418+
organization=alert_group.channel.organization
419+
)
420+
if not grafana_declare_incident_enabled:
421+
AlertGroupLogRecord(
422+
type=AlertGroupLogRecord.TYPE_ESCALATION_FAILED,
423+
alert_group=alert_group,
424+
reason="Declare Incident step is not enabled",
425+
escalation_policy=self.escalation_policy,
426+
escalation_error_code=AlertGroupLogRecord.ERROR_ESCALATION_DECLARE_INCIDENT_STEP_IS_NOT_ENABLED,
427+
escalation_policy_step=self.step,
428+
).save()
429+
return
430+
tasks = []
431+
declare_incident_task = declare_incident.signature(
432+
args=(alert_group.pk,),
433+
kwargs={
434+
"escalation_policy_pk": self.id,
435+
"severity": self.severity,
436+
},
437+
immutable=True,
438+
)
439+
tasks.append(declare_incident_task)
440+
self._execute_tasks(tasks)
441+
410442
def _escalation_step_notify_if_time(self, alert_group: "AlertGroup", _reason: str) -> StepExecutionResultData:
411443
eta = None
412444

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Generated by Django 4.2.15 on 2024-09-25 20:57
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('user_management', '0022_alter_team_unique_together'),
11+
('alerts', '0058_alter_alertgroup_reason_to_skip_escalation'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='escalationpolicy',
17+
name='severity',
18+
field=models.CharField(default=None, max_length=512, null=True),
19+
),
20+
migrations.AlterField(
21+
model_name='escalationpolicy',
22+
name='step',
23+
field=models.IntegerField(choices=[(0, 'Wait'), (1, 'Notify User'), (2, 'Notify Whole Channel'), (3, 'Repeat Escalation (5 times max)'), (4, 'Resolve'), (5, 'Notify Group'), (6, 'Notify Schedule'), (7, 'Notify User (Important)'), (8, 'Notify Group (Important)'), (9, 'Notify Schedule (Important)'), (10, 'Trigger Outgoing Webhook'), (11, 'Notify User (next each time)'), (12, 'Continue escalation only if time is from'), (13, 'Notify multiple Users'), (14, 'Notify multiple Users (Important)'), (15, 'Continue escalation if >X alerts per Y minutes'), (16, 'Trigger Webhook'), (17, 'Notify all users in a Team'), (18, 'Notify all users in a Team (Important)'), (19, 'Declare Incident')], default=None, null=True),
24+
),
25+
migrations.CreateModel(
26+
name='DeclaredIncident',
27+
fields=[
28+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
29+
('incident_id', models.CharField(db_index=True, max_length=50)),
30+
('created_at', models.DateTimeField(auto_now_add=True)),
31+
('is_active', models.BooleanField(default=True)),
32+
('channel_filter', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='declared_incidents', to='alerts.channelfilter')),
33+
('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='declared_incidents', to='user_management.organization')),
34+
],
35+
),
36+
migrations.AddField(
37+
model_name='alertgroup',
38+
name='declared_incident',
39+
field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='attached_alert_groups', to='alerts.declaredincident'),
40+
),
41+
]

engine/apps/alerts/models/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .alert_receive_channel_connection import AlertReceiveChannelConnection # noqa: F401
99
from .channel_filter import ChannelFilter # noqa: F401
1010
from .custom_button import CustomButton # noqa: F401
11+
from .declared_incident import DeclaredIncident # noqa: F401
1112
from .escalation_chain import EscalationChain # noqa: F401
1213
from .escalation_policy import EscalationPolicy # noqa: F401
1314
from .grafana_alerting_contact_point import GrafanaAlertingContactPoint # noqa: F401

engine/apps/alerts/models/alert_group.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from apps.metrics_exporter.tasks import update_metrics_for_alert_group
3131
from apps.slack.slack_formatter import SlackFormatter
3232
from apps.user_management.models import User
33+
from common.constants.plugin_ids import PluginID
3334
from common.public_primary_keys import generate_public_primary_key, increase_public_primary_key_length
3435
from common.utils import clean_markup, str_or_backup
3536

@@ -43,6 +44,7 @@
4344
AlertGroupLogRecord,
4445
AlertReceiveChannel,
4546
BundledNotification,
47+
DeclaredIncident,
4648
ResolutionNote,
4749
ResolutionNoteSlackMessage,
4850
)
@@ -205,6 +207,7 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models.
205207
slack_messages: "RelatedManager['SlackMessage']"
206208
users: "RelatedManager['User']"
207209
labels: "RelatedManager['AlertGroupAssociatedLabel']"
210+
declared_incident: typing.Optional["DeclaredIncident"]
208211

209212
objects: models.Manager["AlertGroup"] = AlertGroupQuerySet.as_manager()
210213

@@ -420,8 +423,17 @@ def status(self) -> int:
420423
# https://code.djangoproject.com/ticket/28545
421424
is_open_for_grouping = models.BooleanField(default=None, null=True, blank=True)
422425

426+
# todo: rework using this field to use DeclaredIncident model field instead
423427
grafana_incident_id = models.CharField(max_length=100, null=True, default=None)
424428

429+
declared_incident = models.ForeignKey(
430+
"alerts.DeclaredIncident",
431+
on_delete=models.SET_NULL,
432+
null=True,
433+
default=None,
434+
related_name="attached_alert_groups",
435+
)
436+
425437
@staticmethod
426438
def get_silenced_state_filter():
427439
"""
@@ -545,7 +557,7 @@ def web_link(self) -> str:
545557
@property
546558
def declare_incident_link(self) -> str:
547559
"""Generate a link for AlertGroup to declare Grafana Incident by click"""
548-
incident_link = urljoin(self.channel.organization.grafana_url, "a/grafana-incident-app/incidents/declare/")
560+
incident_link = urljoin(self.channel.organization.grafana_url, f"a/{PluginID.INCIDENT}/incidents/declare/")
549561
caption = urllib.parse.quote_plus("OnCall Alert Group")
550562
title = urllib.parse.quote_plus(self.web_title_cache) if self.web_title_cache else DEFAULT_BACKUP_TITLE
551563
title = title[:2000] # set max title length to avoid exceptions with too long declare incident link

0 commit comments

Comments
 (0)