Add acknowledged, resolved user information on webhook payload (#4176)

# What this PR does
Adds acknowledged and resolved user information to the web hook payload

## Which issue(s) this PR closes

Closes #4126 

## 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] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.

---------

Co-authored-by: Joey Orlando <joey.orlando@grafana.com>
This commit is contained in:
Ravishankar 2024-04-27 03:20:08 +05:30 committed by GitHub
parent 2a8240ab55
commit 0e59fadf38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 152 additions and 1 deletions

View file

@ -243,6 +243,16 @@ must match the structure of how the fields are nested in the data.
"urgency": "3"
}
},
"alert_group_acknowledged_by": {
"id": "UVMX6YI9VY9PV",
"username": "admin",
"email": "admin@localhost"
},
"alert_group_resolved_by": {
"id": "UVMX6YI9VY9PV",
"username": "admin",
"email": "admin@localhost"
},
"notified_users": [],
"users_to_be_notified": [],
"responses": {
@ -335,6 +345,22 @@ first element being the user that will be notified next. Like `notified_users` d
a user in this array may have already been notified by the time this data is being processed. Access as
`{{ users_to_notify[0].username }}` for example.
#### `alert_group_acknowledged_by`
Information about the user who acknowledged the alert group
- `{{ user.id }}` - [UID](#uid) of the user within Grafana OnCall
- `{{ user.username }}` - Username in Grafana
- `{{ user.email }}` - Email associated with user's Grafana account
#### `alert_group_resolved_by`
Information about the user who resolved the alert group
- `{{ user.id }}` - [UID](#uid) of the user within Grafana OnCall
- `{{ user.username }}` - Username in Grafana
- `{{ user.email }}` - Email associated with user's Grafana account
#### `responses`
The responses field is used to access the response data of other webhooks that are associated with this alert group.

View file

@ -1,4 +1,5 @@
import json
from datetime import timedelta
from unittest.mock import call, patch
import httpretty
@ -348,7 +349,11 @@ def test_execute_webhook_ok_forward_all(
other_user = make_user_for_organization(organization)
alert_receive_channel = make_alert_receive_channel(organization)
alert_group = make_alert_group(
alert_receive_channel, acknowledged_at=timezone.now(), acknowledged=True, acknowledged_by=user.pk
alert_receive_channel,
acknowledged_at=timezone.now(),
acknowledged=True,
acknowledged_by=user.pk,
acknowledged_by_user=user,
)
for _ in range(3):
make_user_notification_policy_log_record(
@ -410,6 +415,12 @@ def test_execute_webhook_ok_forward_all(
"name": webhook.name,
"labels": {},
},
"alert_group_acknowledged_by": {
"id": user.public_primary_key,
"username": user.username,
"email": user.email,
},
"alert_group_resolved_by": None,
}
expected_call = call(
"https://something/{}/".format(alert_group.public_primary_key),
@ -427,6 +438,118 @@ def test_execute_webhook_ok_forward_all(
assert log.url == "https://something/{}/".format(alert_group.public_primary_key)
@pytest.mark.django_db
def test_execute_webhook_ok_forward_all_resolved(
make_organization,
make_user_for_organization,
make_alert_receive_channel,
make_alert_group,
make_user_notification_policy_log_record,
make_custom_webhook,
):
organization = make_organization()
user = make_user_for_organization(organization)
notified_user = make_user_for_organization(organization)
other_user = make_user_for_organization(organization)
alert_receive_channel = make_alert_receive_channel(organization)
alert_group = make_alert_group(
alert_receive_channel,
acknowledged_at=timezone.now(),
acknowledged=True,
acknowledged_by=user.pk,
acknowledged_by_user=user,
resolved=True,
resolved_at=timezone.now() + timedelta(hours=2),
resolved_by=user.pk,
resolved_by_user=user,
)
for _ in range(3):
make_user_notification_policy_log_record(
author=notified_user,
alert_group=alert_group,
type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_SUCCESS,
)
make_user_notification_policy_log_record(
author=other_user,
alert_group=alert_group,
type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED,
)
webhook = make_custom_webhook(
organization=organization,
url="https://something/{{ alert_group_id }}/",
http_method="POST",
trigger_type=Webhook.TRIGGER_RESOLVE,
forward_all=True,
)
mock_response = MockResponse()
with patch("apps.webhooks.utils.socket.gethostbyname") as mock_gethostbyname:
mock_gethostbyname.return_value = "8.8.8.8"
with patch("apps.webhooks.models.webhook.requests") as mock_requests:
mock_requests.post.return_value = mock_response
execute_webhook(webhook.pk, alert_group.pk, user.pk, None, trigger_type=Webhook.TRIGGER_RESOLVE)
assert mock_requests.post.called
expected_data = {
"event": {
"type": "resolve",
"time": alert_group.resolved_at.isoformat(),
},
"user": {
"id": user.public_primary_key,
"username": user.username,
"email": user.email,
},
"integration": {
"id": alert_receive_channel.public_primary_key,
"type": alert_receive_channel.integration,
"name": alert_receive_channel.short_name,
"team": None,
"labels": {},
},
"notified_users": [
{
"id": notified_user.public_primary_key,
"username": notified_user.username,
"email": notified_user.email,
}
],
"alert_group": {**IncidentSerializer(alert_group).data, "labels": {}},
"alert_group_id": alert_group.public_primary_key,
"alert_payload": "",
"users_to_be_notified": [],
"webhook": {
"id": webhook.public_primary_key,
"name": webhook.name,
"labels": {},
},
"alert_group_acknowledged_by": {
"id": user.public_primary_key,
"username": user.username,
"email": user.email,
},
"alert_group_resolved_by": {
"id": user.public_primary_key,
"username": user.username,
"email": user.email,
},
}
expected_call = call(
"https://something/{}/".format(alert_group.public_primary_key),
timeout=TIMEOUT,
headers={},
json=expected_data,
)
assert mock_requests.post.call_args == expected_call
# check logs
log = webhook.responses.all()[0]
assert log.trigger_type == Webhook.TRIGGER_RESOLVE
assert log.status_code == 200
assert log.content == json.dumps(mock_response.json())
assert json.loads(log.request_data) == expected_data
assert log.url == "https://something/{}/".format(alert_group.public_primary_key)
@pytest.mark.django_db
def test_execute_webhook_using_responses_data(
make_organization,

View file

@ -175,6 +175,8 @@ def serialize_event(event, alert_group, user, webhook, responses=None):
for user in set(notification.author for notification in alert_group.sent_notifications)
],
"users_to_be_notified": _extract_users_from_escalation_snapshot(alert_group.escalation_snapshot),
"alert_group_acknowledged_by": _serialize_event_user(alert_group.acknowledged_by_user),
"alert_group_resolved_by": _serialize_event_user(alert_group.resolved_by_user),
}
if responses:
data["responses"] = responses