Add unacknowledge trigger for new webhooks (#1768)
- Add trigger for unacknowledge events in new webhooks - Improve test coverage to include is_webhook_enabled and integration_filter logic
This commit is contained in:
parent
2af4398e01
commit
a99e9a5686
7 changed files with 104 additions and 2 deletions
23
engine/apps/webhooks/migrations/0004_auto_20230418_0109.py
Normal file
23
engine/apps/webhooks/migrations/0004_auto_20230418_0109.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.18 on 2023-04-18 01:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webhooks', '0003_auto_20230412_0006'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='webhook',
|
||||
name='trigger_type',
|
||||
field=models.IntegerField(choices=[(0, 'Escalation step'), (1, 'Firing'), (2, 'Acknowledged'), (3, 'Resolved'), (4, 'Silenced'), (5, 'Unsilenced'), (6, 'Unresolved'), (7, 'Unacknowledged')], default=None, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='webhookresponse',
|
||||
name='trigger_type',
|
||||
field=models.IntegerField(choices=[(0, 'Escalation step'), (1, 'Firing'), (2, 'Acknowledged'), (3, 'Resolved'), (4, 'Silenced'), (5, 'Unsilenced'), (6, 'Unresolved'), (7, 'Unacknowledged')]),
|
||||
),
|
||||
]
|
||||
|
|
@ -63,7 +63,8 @@ class Webhook(models.Model):
|
|||
TRIGGER_SILENCE,
|
||||
TRIGGER_UNSILENCE,
|
||||
TRIGGER_UNRESOLVE,
|
||||
) = range(7)
|
||||
TRIGGER_UNACKNOWLEDGE,
|
||||
) = range(8)
|
||||
|
||||
# Must be the same order as previous
|
||||
TRIGGER_TYPES = (
|
||||
|
|
@ -74,6 +75,7 @@ class Webhook(models.Model):
|
|||
(TRIGGER_SILENCE, "Silenced"),
|
||||
(TRIGGER_UNSILENCE, "Unsilenced"),
|
||||
(TRIGGER_UNRESOLVE, "Unresolved"),
|
||||
(TRIGGER_UNACKNOWLEDGE, "Unacknowledged"),
|
||||
)
|
||||
|
||||
public_primary_key = models.CharField(
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ ACTION_TO_TRIGGER_TYPE = {
|
|||
AlertGroupLogRecord.TYPE_SILENCE: Webhook.TRIGGER_SILENCE,
|
||||
AlertGroupLogRecord.TYPE_UN_SILENCE: Webhook.TRIGGER_UNSILENCE,
|
||||
AlertGroupLogRecord.TYPE_UN_RESOLVED: Webhook.TRIGGER_UNRESOLVE,
|
||||
AlertGroupLogRecord.TYPE_UN_ACK: Webhook.TRIGGER_UNACKNOWLEDGE,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ from apps.webhooks.utils import (
|
|||
)
|
||||
from common.custom_celery_tasks import shared_dedicated_queue_retry_task
|
||||
|
||||
NOT_FROM_SELECTED_INTEGRATION = "Alert group was not from a selected integration"
|
||||
|
||||
logger = get_task_logger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
|
@ -32,6 +34,7 @@ TRIGGER_TYPE_TO_LABEL = {
|
|||
Webhook.TRIGGER_UNSILENCE: "unsilence",
|
||||
Webhook.TRIGGER_UNRESOLVE: "unresolve",
|
||||
Webhook.TRIGGER_ESCALATION_STEP: "escalation",
|
||||
Webhook.TRIGGER_UNACKNOWLEDGE: "unacknowledge",
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -102,7 +105,7 @@ def make_request(webhook, alert_group, data):
|
|||
exception = error = None
|
||||
try:
|
||||
if not webhook.check_integration_filter(alert_group):
|
||||
status["request_trigger"] = f"Alert group was not from a selected integration"
|
||||
status["request_trigger"] = NOT_FROM_SELECTED_INTEGRATION
|
||||
return status, None, None
|
||||
|
||||
triggered, status["request_trigger"] = webhook.check_trigger(data)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ def test_alert_group_created_does_not_exist(make_organization, make_custom_webho
|
|||
(AlertGroupLogRecord.TYPE_SILENCE, Webhook.TRIGGER_SILENCE),
|
||||
(AlertGroupLogRecord.TYPE_UN_SILENCE, Webhook.TRIGGER_UNSILENCE),
|
||||
(AlertGroupLogRecord.TYPE_UN_RESOLVED, Webhook.TRIGGER_UNRESOLVE),
|
||||
(AlertGroupLogRecord.TYPE_UN_ACK, Webhook.TRIGGER_UNACKNOWLEDGE),
|
||||
],
|
||||
)
|
||||
def test_alert_group_status_change(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from apps.base.models import UserNotificationPolicyLogRecord
|
|||
from apps.public_api.serializers import IncidentSerializer
|
||||
from apps.webhooks.models import Webhook
|
||||
from apps.webhooks.tasks import execute_webhook, send_webhook_event
|
||||
from apps.webhooks.tasks.trigger_webhook import NOT_FROM_SELECTED_INTEGRATION
|
||||
|
||||
|
||||
class MockResponse:
|
||||
|
|
@ -63,6 +64,72 @@ def test_send_webhook_event_filters(
|
|||
assert mock_execute.call_args == call((other_org_webhook.pk, alert_group.pk, None, None))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_execute_webhook_disabled(
|
||||
make_organization, make_team, make_alert_receive_channel, make_alert_group, make_custom_webhook
|
||||
):
|
||||
organization = make_organization()
|
||||
alert_receive_channel = make_alert_receive_channel(organization)
|
||||
alert_group = make_alert_group(alert_receive_channel)
|
||||
make_custom_webhook(organization=organization, trigger_type=Webhook.TRIGGER_FIRING)
|
||||
make_custom_webhook(organization=organization, trigger_type=Webhook.TRIGGER_FIRING, is_webhook_enabled=False)
|
||||
|
||||
with patch("apps.webhooks.tasks.trigger_webhook.execute_webhook.apply_async") as mock_execute:
|
||||
send_webhook_event(Webhook.TRIGGER_FIRING, alert_group.pk, organization_id=organization.pk)
|
||||
mock_execute.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_execute_webhook_integration_filter_not_matching(
|
||||
make_organization, make_team, make_alert_receive_channel, make_alert_group, make_custom_webhook
|
||||
):
|
||||
organization = make_organization()
|
||||
alert_receive_channel = make_alert_receive_channel(organization)
|
||||
alert_group = make_alert_group(alert_receive_channel)
|
||||
webhook = make_custom_webhook(
|
||||
organization=organization, trigger_type=Webhook.TRIGGER_FIRING, integration_filter=["does-not-match"]
|
||||
)
|
||||
|
||||
with patch("apps.webhooks.models.webhook.requests") as mock_requests:
|
||||
execute_webhook(webhook.pk, alert_group.pk, None, None)
|
||||
|
||||
assert not mock_requests.post.called
|
||||
# check log should exist but have no status code
|
||||
assert (
|
||||
webhook.responses.count() == 1
|
||||
and webhook.responses.first().status_code is None
|
||||
and webhook.responses.first().request_trigger == NOT_FROM_SELECTED_INTEGRATION
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_execute_webhook_integration_filter_matching(
|
||||
make_organization, make_team, make_alert_receive_channel, make_alert_group, make_custom_webhook
|
||||
):
|
||||
organization = make_organization()
|
||||
alert_receive_channel = make_alert_receive_channel(organization, public_primary_key="test-integration-1")
|
||||
alert_group = make_alert_group(alert_receive_channel)
|
||||
webhook = make_custom_webhook(
|
||||
organization=organization,
|
||||
trigger_type=Webhook.TRIGGER_FIRING,
|
||||
integration_filter=["test-integration-1"],
|
||||
# Check we get past integration filter but exit early to keep test simple
|
||||
trigger_template="False",
|
||||
)
|
||||
|
||||
with patch("apps.webhooks.models.webhook.requests") as mock_requests:
|
||||
execute_webhook(webhook.pk, alert_group.pk, None, None)
|
||||
|
||||
assert not mock_requests.post.called
|
||||
# check log should exist but have no status code
|
||||
assert (
|
||||
webhook.responses.count() == 1
|
||||
and webhook.responses.first().status_code is None
|
||||
# Matches evaluated trigger_template
|
||||
and webhook.responses.first().request_trigger == "False"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_execute_webhook_ok(
|
||||
make_organization, make_user_for_organization, make_alert_receive_channel, make_alert_group, make_custom_webhook
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const WebhookTriggerType = {
|
|||
Silenced: new KeyValuePair('4', 'Silenced'),
|
||||
Unsilenced: new KeyValuePair('5', 'Unsilenced'),
|
||||
Unresolved: new KeyValuePair('6', 'Unresolved'),
|
||||
Unacknowledged: new KeyValuePair('7', 'Unacknowledged'),
|
||||
};
|
||||
|
||||
export const form: { name: string; fields: FormItem[] } = {
|
||||
|
|
@ -78,6 +79,10 @@ export const form: { name: string; fields: FormItem[] } = {
|
|||
value: WebhookTriggerType.Unresolved.key,
|
||||
label: WebhookTriggerType.Unresolved.value,
|
||||
},
|
||||
{
|
||||
value: WebhookTriggerType.Unacknowledged.key,
|
||||
label: WebhookTriggerType.Unacknowledged.value,
|
||||
},
|
||||
],
|
||||
},
|
||||
validation: { required: true },
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue