From 7a038270477204a4c8f6296cabbc58dae497df5f Mon Sep 17 00:00:00 2001 From: PIG208 <359101898@qq.com> Date: Fri, 4 Jun 2021 23:26:13 +0800 Subject: [PATCH] integrations: Add V3 support for PagerDuty. --- zerver/webhooks/pagerduty/doc.md | 13 +- .../pagerduty/fixtures/acknowledged_v3.json | 53 ++++ .../pagerduty/fixtures/reassigned_v3.json | 53 ++++ .../pagerduty/fixtures/resolved_v3.json | 45 +++ .../pagerduty/fixtures/triggered_v3.json | 53 ++++ .../pagerduty/fixtures/unacknowledged_v3.json | 53 ++++ .../pagerduty/fixtures/unsupported_v1.json | 51 ++++ .../pagerduty/fixtures/unsupported_v2.json | 278 ++++++++++++++++++ .../pagerduty/fixtures/unsupported_v3.json | 53 ++++ zerver/webhooks/pagerduty/tests.py | 30 ++ zerver/webhooks/pagerduty/view.py | 136 ++++++--- 11 files changed, 778 insertions(+), 40 deletions(-) create mode 100644 zerver/webhooks/pagerduty/fixtures/acknowledged_v3.json create mode 100644 zerver/webhooks/pagerduty/fixtures/reassigned_v3.json create mode 100644 zerver/webhooks/pagerduty/fixtures/resolved_v3.json create mode 100644 zerver/webhooks/pagerduty/fixtures/triggered_v3.json create mode 100644 zerver/webhooks/pagerduty/fixtures/unacknowledged_v3.json create mode 100644 zerver/webhooks/pagerduty/fixtures/unsupported_v1.json create mode 100644 zerver/webhooks/pagerduty/fixtures/unsupported_v2.json create mode 100644 zerver/webhooks/pagerduty/fixtures/unsupported_v3.json diff --git a/zerver/webhooks/pagerduty/doc.md b/zerver/webhooks/pagerduty/doc.md index 6b44ee1dfb..130a29c0a8 100644 --- a/zerver/webhooks/pagerduty/doc.md +++ b/zerver/webhooks/pagerduty/doc.md @@ -4,13 +4,14 @@ Get Zulip notifications for your PagerDuty services! 1. {!create-bot-construct-url-indented.md!} -1. On your PagerDuty homepage, click on **Configuration**, and - select **Services**. Select the service you'd like to be notified - about. Click the **Integration** tab, and click **+ New Extension**. +1. Open the **Integrations** tab, and click **Generic Webhooks (v3)**. -1. Set **Extension Type** to **Generic V2 Webhook**. Set **Name** to a name - of your choice, such as `Zulip`. Under **Details**, set **URL** to the - URL constructed above, and click **Save**. +1. Click **Add Webhook**. + +1. Set **Webhook URL** to the URL constructed above, + configure the **Scope Type** and **Scope** you want to receive notifications for, + select the events you want to send under **Events to Send**, + and click **Add Webhook**. {!congrats.md!} diff --git a/zerver/webhooks/pagerduty/fixtures/acknowledged_v3.json b/zerver/webhooks/pagerduty/fixtures/acknowledged_v3.json new file mode 100644 index 0000000000..d7618445b5 --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/acknowledged_v3.json @@ -0,0 +1,53 @@ +{ + "event": { + "id": "01BZYK8N47N5JG55J1EEEHPEJI", + "event_type": "incident.acknowledged", + "resource_type": "incident", + "occurred_at": "2021-06-04T13:55:30.394Z", + "agent": { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + }, + "client": null, + "data": { + "id": "PQ1K5C8", + "type": "incident", + "self": "https://api.pagerduty.com/incidents/PQ1K5C8", + "html_url": "https://pig208.pagerduty.com/incidents/PQ1K5C8", + "number": 10, + "status": "acknowledged", + "title": "Test Incident", + "service": { + "html_url": "https://pig208.pagerduty.com/services/PA2P440", + "id": "PA2P440", + "self": "https://api.pagerduty.com/services/PA2P440", + "summary": "pig208", + "type": "service_reference" + }, + "assignees": [ + { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + } + ], + "escalation_policy": { + "html_url": "https://pig208.pagerduty.com/escalation_policies/PY82TC6", + "id": "PY82TC6", + "self": "https://api.pagerduty.com/escalation_policies/PY82TC6", + "summary": "Default", + "type": "escalation_policy_reference" + }, + "teams": [], + "priority": null, + "urgency": "high", + "conference_bridge": null, + "resolve_reason": null + } + } +} diff --git a/zerver/webhooks/pagerduty/fixtures/reassigned_v3.json b/zerver/webhooks/pagerduty/fixtures/reassigned_v3.json new file mode 100644 index 0000000000..41ee5ded2c --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/reassigned_v3.json @@ -0,0 +1,53 @@ +{ + "event": { + "id": "01BZY282OVDQMFPDC3VB98DR1L", + "event_type": "incident.reassigned", + "resource_type": "incident", + "occurred_at": "2021-06-04T10:17:54.838Z", + "agent": { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + }, + "client": null, + "data": { + "id": "PIQUG8X", + "type": "incident", + "self": "https://api.pagerduty.com/incidents/PIQUG8X", + "html_url": "https://pig208.pagerduty.com/incidents/PIQUG8X", + "number": 3, + "status": "triggered", + "title": "Test Incident", + "service": { + "html_url": "https://pig208.pagerduty.com/services/PA2P440", + "id": "PA2P440", + "self": "https://api.pagerduty.com/services/PA2P440", + "summary": "pig208", + "type": "service_reference" + }, + "assignees": [ + { + "html_url": "https://pig208.pagerduty.com/users/PI9DT01", + "id": "PI9DT01", + "self": "https://api.pagerduty.com/users/PI9DT01", + "summary": "Test User", + "type": "user_reference" + } + ], + "escalation_policy": { + "html_url": "https://pig208.pagerduty.com/escalation_policies/PY82TC6", + "id": "PY82TC6", + "self": "https://api.pagerduty.com/escalation_policies/PY82TC6", + "summary": "Default", + "type": "escalation_policy_reference" + }, + "teams": [], + "priority": null, + "urgency": "high", + "conference_bridge": null, + "resolve_reason": null + } + } +} diff --git a/zerver/webhooks/pagerduty/fixtures/resolved_v3.json b/zerver/webhooks/pagerduty/fixtures/resolved_v3.json new file mode 100644 index 0000000000..366bd5c8e0 --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/resolved_v3.json @@ -0,0 +1,45 @@ +{ + "event": { + "id": "01BZYH1JJY09P9LEIST8HG2PMN", + "event_type": "incident.resolved", + "resource_type": "incident", + "occurred_at": "2021-06-04T13:16:53.816Z", + "agent": { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + }, + "client": null, + "data": { + "id": "PCPZE64", + "type": "incident", + "self": "https://api.pagerduty.com/incidents/PCPZE64", + "html_url": "https://pig208.pagerduty.com/incidents/PCPZE64", + "number": 6, + "status": "resolved", + "title": "Test Incident", + "service": { + "html_url": "https://pig208.pagerduty.com/services/PA2P440", + "id": "PA2P440", + "self": "https://api.pagerduty.com/services/PA2P440", + "summary": "pig208", + "type": "service_reference" + }, + "assignees": [], + "escalation_policy": { + "html_url": "https://pig208.pagerduty.com/escalation_policies/PY82TC6", + "id": "PY82TC6", + "self": "https://api.pagerduty.com/escalation_policies/PY82TC6", + "summary": "Default", + "type": "escalation_policy_reference" + }, + "teams": [], + "priority": null, + "urgency": "high", + "conference_bridge": null, + "resolve_reason": null + } + } +} diff --git a/zerver/webhooks/pagerduty/fixtures/triggered_v3.json b/zerver/webhooks/pagerduty/fixtures/triggered_v3.json new file mode 100644 index 0000000000..017e4da56f --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/triggered_v3.json @@ -0,0 +1,53 @@ +{ + "event": { + "id": "01BZYIL05THJDFF2Y08X9SVMTU", + "event_type": "incident.triggered", + "resource_type": "incident", + "occurred_at": "2021-06-04T13:35:29.781Z", + "agent": { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + }, + "client": null, + "data": { + "id": "PFQZPSY", + "type": "incident", + "self": "https://api.pagerduty.com/incidents/PFQZPSY", + "html_url": "https://pig208.pagerduty.com/incidents/PFQZPSY", + "number": 9, + "status": "triggered", + "title": "Test Incident 3", + "service": { + "html_url": "https://pig208.pagerduty.com/services/PA2P440", + "id": "PA2P440", + "self": "https://api.pagerduty.com/services/PA2P440", + "summary": "pig208", + "type": "service_reference" + }, + "assignees": [ + { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + } + ], + "escalation_policy": { + "html_url": "https://pig208.pagerduty.com/escalation_policies/PY82TC6", + "id": "PY82TC6", + "self": "https://api.pagerduty.com/escalation_policies/PY82TC6", + "summary": "Default", + "type": "escalation_policy_reference" + }, + "teams": [], + "priority": null, + "urgency": "high", + "conference_bridge": null, + "resolve_reason": null + } + } +} diff --git a/zerver/webhooks/pagerduty/fixtures/unacknowledged_v3.json b/zerver/webhooks/pagerduty/fixtures/unacknowledged_v3.json new file mode 100644 index 0000000000..9665379075 --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/unacknowledged_v3.json @@ -0,0 +1,53 @@ +{ + "event": { + "id": "01BZYK5B3WC0QI62S87MJX7FCD", + "event_type": "incident.unacknowledged", + "resource_type": "incident", + "occurred_at": "2021-06-04T13:54:23.185Z", + "agent": { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + }, + "client": null, + "data": { + "id": "PQ1K5C8", + "type": "incident", + "self": "https://api.pagerduty.com/incidents/PQ1K5C8", + "html_url": "https://pig208.pagerduty.com/incidents/PQ1K5C8", + "number": 10, + "status": "triggered", + "title": "Test Incident", + "service": { + "html_url": "https://pig208.pagerduty.com/services/PA2P440", + "id": "PA2P440", + "self": "https://api.pagerduty.com/services/PA2P440", + "summary": "pig208", + "type": "service_reference" + }, + "assignees": [ + { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + } + ], + "escalation_policy": { + "html_url": "https://pig208.pagerduty.com/escalation_policies/PY82TC6", + "id": "PY82TC6", + "self": "https://api.pagerduty.com/escalation_policies/PY82TC6", + "summary": "Default", + "type": "escalation_policy_reference" + }, + "teams": [], + "priority": null, + "urgency": "high", + "conference_bridge": null, + "resolve_reason": null + } + } +} diff --git a/zerver/webhooks/pagerduty/fixtures/unsupported_v1.json b/zerver/webhooks/pagerduty/fixtures/unsupported_v1.json new file mode 100644 index 0000000000..d391dba3d6 --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/unsupported_v1.json @@ -0,0 +1,51 @@ +{ + "messages": [ + { + "created_on": "2015-02-07T21:31:53Z", + "data": { + "incident": { + "assigned_to": [], + "assigned_to_user": null, + "created_on": "2015-02-07T21:05:47Z", + "escalation_policy": { + "deleted_at": null, + "id": "PUIGL4T", + "name": "Default" + }, + "html_url": "https://zulip-test.pagerduty.com/incidents/PO1XIJ5", + "id": "PO1XIJ5", + "incident_key": "It is on fire", + "incident_number": 1, + "last_status_change_by": { + "email": "armooo@zulip.com", + "html_url": "https://zulip-test.pagerduty.com/users/POBCFRJ", + "id": "POBCFRJ", + "name": "Jason MIchalski" + }, + "last_status_change_on": "2015-02-07T21:31:53Z", + "number_of_escalations": 0, + "resolved_by_user": { + "email": "armooo@zulip.com", + "html_url": "https://zulip-test.pagerduty.com/users/POBCFRJ", + "id": "POBCFRJ", + "name": "Jason MIchalski" + }, + "service": { + "deleted_at": null, + "html_url": "https://zulip-test.pagerduty.com/services/PIL5CUQ", + "id": "PIL5CUQ", + "name": "Test service" + }, + "status": "resolved", + "trigger_details_html_url": "https://zulip-test.pagerduty.com/incidents/PO1XIJ5/log_entries/Q01ZH27LNRIAUB", + "trigger_summary_data": { + "subject": "It is on fire" + }, + "trigger_type": "email_trigger" + } + }, + "id": "bc3d9ed0-af10-11e4-947f-22000ad9bf74", + "type": "incident.unsupported" + } + ] +} diff --git a/zerver/webhooks/pagerduty/fixtures/unsupported_v2.json b/zerver/webhooks/pagerduty/fixtures/unsupported_v2.json new file mode 100644 index 0000000000..46494b0881 --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/unsupported_v2.json @@ -0,0 +1,278 @@ +{ + "messages":[ + { + "event":"incident.unsupported", + "log_entries":[ + { + "id":"R6XNGC35VF6U1TUSVIE2DWXD4Z", + "type":"assign_log_entry", + "summary":"Assigned to Wiley Jacobson by Laura Haley", + "self":"https://api.pagerduty.com/log_entries/R6XNGC35VF6U1TUSVIE2DWXD4Z", + "html_url":null, + "created_at":"2017-09-26T15:16:05Z", + "agent":{ + "id":"P553OPV", + "type":"user_reference", + "summary":"Laura Haley", + "self":"https://api.pagerduty.com/users/P553OPV", + "html_url":"https://webdemo.pagerduty.com/users/P553OPV" + }, + "channel":{ + "type":"website" + }, + "service":{ + "id":"PN49J75", + "type":"service_reference", + "summary":"Production XDB Cluster", + "self":"https://api.pagerduty.com/services/PN49J75", + "html_url":"https://webdemo.pagerduty.com/services/PN49J75" + }, + "incident":{ + "id":"PRORDTY", + "type":"incident_reference", + "summary":"[#33] My new incident", + "self":"https://api.pagerduty.com/incidents/PRORDTY", + "html_url":"https://webdemo.pagerduty.com/incidents/PRORDTY" + }, + "teams":[ + { + "id":"P4SI59S", + "type":"team_reference", + "summary":"Engineering", + "self":"https://api.pagerduty.com/teams/P4SI59S", + "html_url":"https://webdemo.pagerduty.com/teams/P4SI59S" + } + ], + "contexts":[ + + ], + "assignees":[ + { + "id":"PFBSJ2Z", + "type":"user_reference", + "summary":"Wiley Jacobson", + "self":"https://api.pagerduty.com/users/PFBSJ2Z", + "html_url":"https://webdemo.pagerduty.com/users/PFBSJ2Z" + } + ] + } + ], + "webhook":{ + "endpoint_url":"https://requestb.in/18ao6fs1", + "name":"V2 wabhook", + "description":null, + "webhook_object":{ + "id":"PN49J75", + "type":"service_reference", + "summary":"Production XDB Cluster", + "self":"https://api.pagerduty.com/services/PN49J75", + "html_url":"https://webdemo.pagerduty.com/services/PN49J75" + }, + "config":{ + + }, + "outbound_integration":{ + "id":"PJFWPEP", + "type":"outbound_integration_reference", + "summary":"Generic V2 Webhook", + "self":"https://api.pagerduty.com/outbound_integrations/PJFWPEP", + "html_url":null + }, + "accounts_addon":null, + "id":"PKT9NNX", + "type":"webhook", + "summary":"V2 wabhook", + "self":"https://api.pagerduty.com/webhooks/PKT9NNX", + "html_url":null + }, + "incident":{ + "incident_number":33, + "title":"My new incident", + "description":"My new incident", + "created_at":"2017-09-26T15:14:36Z", + "status":"triggered", + "pending_actions":[ + { + "type":"resolve", + "at":"2017-09-26T19:14:36Z" + } + ], + "incident_key":null, + "service":{ + "id":"PN49J75", + "name":"Production XDB Cluster", + "description":"This service was created during onboarding on July 5, 2017.", + "auto_resolve_timeout":14400, + "acknowledgement_timeout":1800, + "created_at":"2017-07-05T17:33:09Z", + "status":"critical", + "last_incident_timestamp":"2017-09-26T15:14:36Z", + "teams":[ + { + "id":"P4SI59S", + "type":"team_reference", + "summary":"Engineering", + "self":"https://api.pagerduty.com/teams/P4SI59S", + "html_url":"https://webdemo.pagerduty.com/teams/P4SI59S" + } + ], + "incident_urgency_rule":{ + "type":"constant", + "urgency":"high" + }, + "scheduled_actions":[ + + ], + "support_hours":null, + "escalation_policy":{ + "id":"PINYWEF", + "type":"escalation_policy_reference", + "summary":"Default", + "self":"https://api.pagerduty.com/escalation_policies/PINYWEF", + "html_url":"https://webdemo.pagerduty.com/escalation_policies/PINYWEF" + }, + "addons":[ + + ], + "privilege":null, + "alert_creation":"create_alerts_and_incidents", + "integrations":[ + { + "id":"PUAYF96", + "type":"generic_events_api_inbound_integration_reference", + "summary":"API", + "self":"https://api.pagerduty.com/services/PN49J75/integrations/PUAYF96", + "html_url":"https://webdemo.pagerduty.com/services/PN49J75/integrations/PUAYF96" + }, + { + "id":"P90GZUH", + "type":"generic_email_inbound_integration_reference", + "summary":"Email", + "self":"https://api.pagerduty.com/services/PN49J75/integrations/P90GZUH", + "html_url":"https://webdemo.pagerduty.com/services/PN49J75/integrations/P90GZUH" + } + ], + "metadata":{ + + }, + "type":"service", + "summary":"Production XDB Cluster", + "self":"https://api.pagerduty.com/services/PN49J75", + "html_url":"https://webdemo.pagerduty.com/services/PN49J75" + }, + "assignments":[ + { + "at":"2017-09-26T15:16:05Z", + "assignee":{ + "id":"PFBSJ2Z", + "type":"user_reference", + "summary":"Wiley Jacobson", + "self":"https://api.pagerduty.com/users/PFBSJ2Z", + "html_url":"https://webdemo.pagerduty.com/users/PFBSJ2Z" + } + } + ], + "acknowledgements":[ + + ], + "last_status_change_at":"2017-09-26T15:16:05Z", + "last_status_change_by":{ + "id":"PN49J75", + "type":"service_reference", + "summary":"Production XDB Cluster", + "self":"https://api.pagerduty.com/services/PN49J75", + "html_url":"https://webdemo.pagerduty.com/services/PN49J75" + }, + "first_trigger_log_entry":{ + "id":"R2XGXEI3W0FHMSDXHDIBQGBQ5E", + "type":"trigger_log_entry_reference", + "summary":"Triggered through the website", + "self":"https://api.pagerduty.com/log_entries/R2XGXEI3W0FHMSDXHDIBQGBQ5E", + "html_url":"https://webdemo.pagerduty.com/incidents/PRORDTY/log_entries/R2XGXEI3W0FHMSDXHDIBQGBQ5E" + }, + "escalation_policy":{ + "id":"PINYWEF", + "type":"escalation_policy_reference", + "summary":"Default", + "self":"https://api.pagerduty.com/escalation_policies/PINYWEF", + "html_url":"https://webdemo.pagerduty.com/escalation_policies/PINYWEF" + }, + "privilege":null, + "teams":[ + { + "id":"P4SI59S", + "type":"team_reference", + "summary":"Engineering", + "self":"https://api.pagerduty.com/teams/P4SI59S", + "html_url":"https://webdemo.pagerduty.com/teams/P4SI59S" + } + ], + "alert_counts":{ + "all":0, + "triggered":0, + "resolved":0 + }, + "impacted_services":[ + { + "id":"PN49J75", + "type":"service_reference", + "summary":"Production XDB Cluster", + "self":"https://api.pagerduty.com/services/PN49J75", + "html_url":"https://webdemo.pagerduty.com/services/PN49J75" + } + ], + "is_mergeable":true, + "basic_alert_grouping":null, + "alert_grouping":null, + "metadata":{ + + }, + "external_references":[ + { + "id":"PLF5V5G", + "type":"incident_external_reference", + "summary":"Slack", + "self":null, + "html_url":null, + "external_id":"1506438878.000302", + "external_url":"http://webdemo.slack.com/archives/C6975FLAZ/p1506438878.000302", + "sync":false, + "webhook":{ + "id":"PRXV5AH", + "type":"webhook_reference", + "summary":"Slack M2M", + "self":"https://api.pagerduty.com/webhooks/PRXV5AH", + "html_url":null + } + } + ], + "importance":null, + "incidents_responders":[ + + ], + "responder_requests":[ + + ], + "subscriber_requests":[ + + ], + "urgency":"high", + "id":"PRORDTY", + "type":"incident", + "summary":"[#33] My new incident", + "self":"https://api.pagerduty.com/incidents/PRORDTY", + "html_url":"https://webdemo.pagerduty.com/incidents/PRORDTY", + "alerts":[ + { + "alert_key":"c24117fc42e44b44b4d6876190583378" + }, + { + "alert_key":"2d6ee0a6b58040f7996a4047ae5edcd7" + } + ] + }, + "id":"9e7850d0-a2cd-11e7-8f69-22000affca53", + "created_on":"2017-09-26T15:16:05Z" + } + ] +} diff --git a/zerver/webhooks/pagerduty/fixtures/unsupported_v3.json b/zerver/webhooks/pagerduty/fixtures/unsupported_v3.json new file mode 100644 index 0000000000..bdb376d4ef --- /dev/null +++ b/zerver/webhooks/pagerduty/fixtures/unsupported_v3.json @@ -0,0 +1,53 @@ +{ + "event": { + "id": "01BZY282OVDQMFPDC3VB98DR1L", + "event_type": "incident.unsupported", + "resource_type": "incident", + "occurred_at": "2021-06-04T10:17:54.838Z", + "agent": { + "html_url": "https://pig208.pagerduty.com/users/PJ0LVEB", + "id": "PJ0LVEB", + "self": "https://api.pagerduty.com/users/PJ0LVEB", + "summary": "PIG 208", + "type": "user_reference" + }, + "client": null, + "data": { + "id": "PIQUG8X", + "type": "incident", + "self": "https://api.pagerduty.com/incidents/PIQUG8X", + "html_url": "https://pig208.pagerduty.com/incidents/PIQUG8X", + "number": 3, + "status": "triggered", + "title": "Test Incident", + "service": { + "html_url": "https://pig208.pagerduty.com/services/PA2P440", + "id": "PA2P440", + "self": "https://api.pagerduty.com/services/PA2P440", + "summary": "pig208", + "type": "service_reference" + }, + "assignees": [ + { + "html_url": "https://pig208.pagerduty.com/users/PI9DT01", + "id": "PI9DT01", + "self": "https://api.pagerduty.com/users/PI9DT01", + "summary": "Test User", + "type": "user_reference" + } + ], + "escalation_policy": { + "html_url": "https://pig208.pagerduty.com/escalation_policies/PY82TC6", + "id": "PY82TC6", + "self": "https://api.pagerduty.com/escalation_policies/PY82TC6", + "summary": "Default", + "type": "escalation_policy_reference" + }, + "teams": [], + "priority": null, + "urgency": "high", + "conference_bridge": null, + "resolve_reason": null + } + } +} diff --git a/zerver/webhooks/pagerduty/tests.py b/zerver/webhooks/pagerduty/tests.py index 6354e38c8e..9d5c2e03af 100644 --- a/zerver/webhooks/pagerduty/tests.py +++ b/zerver/webhooks/pagerduty/tests.py @@ -14,6 +14,10 @@ class PagerDutyHookTests(WebhookTestCase): expected_message = "Incident [33](https://webdemo.pagerduty.com/incidents/PRORDTY) triggered by [Production XDB Cluster](https://webdemo.pagerduty.com/services/PN49J75) (assigned to [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV)).\n\n``` quote\nMy new incident\n```" self.check_webhook("trigger_v2", "Incident 33", expected_message) + def test_triggerer_v3(self) -> None: + expected_message = "Incident [Test Incident 3 (#9)](https://pig208.pagerduty.com/incidents/PFQZPSY) triggered by [pig208](https://pig208.pagerduty.com/services/PA2P440) (assigned to [PIG 208](https://pig208.pagerduty.com/users/PJ0LVEB))." + self.check_webhook("triggered_v3", "Incident Test Incident 3 (#9)", expected_message) + def test_trigger_without_assignee_v2(self) -> None: expected_message = "Incident [33](https://webdemo.pagerduty.com/incidents/PRORDTY) triggered by [Production XDB Cluster](https://webdemo.pagerduty.com/services/PN49J75) (assigned to nobody).\n\n``` quote\nMy new incident\n```" self.check_webhook("trigger_without_assignee_v2", "Incident 33", expected_message) @@ -22,6 +26,10 @@ class PagerDutyHookTests(WebhookTestCase): expected_message = "Incident [3](https://zulip-test.pagerduty.com/incidents/P140S4Y) unacknowledged by [Test service](https://zulip-test.pagerduty.com/services/PIL5CUQ) (assigned to [armooo](https://zulip-test.pagerduty.com/users/POBCFRJ)).\n\n``` quote\nfoo\n```" self.check_webhook("unacknowledge", "Incident 3", expected_message) + def test_unacknowledged_v3(self) -> None: + expected_message = "Incident [Test Incident (#10)](https://pig208.pagerduty.com/incidents/PQ1K5C8) unacknowledged by [pig208](https://pig208.pagerduty.com/services/PA2P440) (assigned to [PIG 208](https://pig208.pagerduty.com/users/PJ0LVEB))." + self.check_webhook("unacknowledged_v3", "Incident Test Incident (#10)", expected_message) + def test_resolved(self) -> None: expected_message = "Incident [1](https://zulip-test.pagerduty.com/incidents/PO1XIJ5) resolved by [armooo](https://zulip-test.pagerduty.com/users/POBCFRJ).\n\n``` quote\nIt is on fire\n```" self.check_webhook("resolved", "Incident 1", expected_message) @@ -30,6 +38,10 @@ class PagerDutyHookTests(WebhookTestCase): expected_message = "Incident [33](https://webdemo.pagerduty.com/incidents/PRORDTY) resolved by [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV).\n\n``` quote\nMy new incident\n```" self.check_webhook("resolve_v2", "Incident 33", expected_message) + def test_resolved_v3(self) -> None: + expected_message = "Incident [Test Incident (#6)](https://pig208.pagerduty.com/incidents/PCPZE64) resolved by [PIG 208](https://pig208.pagerduty.com/users/PJ0LVEB)." + self.check_webhook("resolved_v3", "Incident Test Incident (#6)", expected_message) + def test_auto_resolved(self) -> None: expected_message = "Incident [2](https://zulip-test.pagerduty.com/incidents/PX7K9J2) resolved.\n\n``` quote\nnew\n```" self.check_webhook("auto_resolved", "Incident 2", expected_message) @@ -44,6 +56,10 @@ class PagerDutyHookTests(WebhookTestCase): "acknowledge_without_trigger_summary_data", "Incident 1", expected_message ) + def test_acknowledged_v3(self) -> None: + expected_message = "Incident [Test Incident (#10)](https://pig208.pagerduty.com/incidents/PQ1K5C8) acknowledged by [PIG 208](https://pig208.pagerduty.com/users/PJ0LVEB)." + self.check_webhook("acknowledged_v3", "Incident Test Incident (#10)", expected_message) + def test_acknowledge_v2(self) -> None: expected_message = "Incident [33](https://webdemo.pagerduty.com/incidents/PRORDTY) acknowledged by [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV).\n\n``` quote\nMy new incident\n```" self.check_webhook("acknowledge_v2", "Incident 33", expected_message) @@ -52,6 +68,20 @@ class PagerDutyHookTests(WebhookTestCase): expected_message = "Incident [33](https://webdemo.pagerduty.com/incidents/PRORDTY) assigned to [Wiley Jacobson](https://webdemo.pagerduty.com/users/PFBSJ2Z).\n\n``` quote\nMy new incident\n```" self.check_webhook("assign_v2", "Incident 33", expected_message) + def test_reassigned_v3(self) -> None: + expected_message = "Incident [Test Incident (#3)](https://pig208.pagerduty.com/incidents/PIQUG8X) reassigned to [Test User](https://pig208.pagerduty.com/users/PI9DT01)." + self.check_webhook("reassigned_v3", "Incident Test Incident (#3)", expected_message) + def test_no_subject(self) -> None: expected_message = "Incident [48219](https://dropbox.pagerduty.com/incidents/PJKGZF9) resolved.\n\n``` quote\nmp_error_block_down_critical\u2119\u01b4\n```" self.check_webhook("mp_fail", "Incident 48219", expected_message) + + def test_unsupported_webhook_event(self) -> None: + post_params = dict(content_type="application/json") + for version in range(1, 4): + payload = self.get_body(f"unsupported_v{version}") + result = self.client_post(self.url, payload, **post_params) + self.assert_json_error( + result, + "The 'incident.unsupported' event isn't currently supported by the PagerDuty webhook", + ) diff --git a/zerver/webhooks/pagerduty/view.py b/zerver/webhooks/pagerduty/view.py index defb3b4639..8efbcc5e2a 100644 --- a/zerver/webhooks/pagerduty/view.py +++ b/zerver/webhooks/pagerduty/view.py @@ -1,5 +1,5 @@ # Webhooks for external integrations. -from typing import Any, Dict, Sequence +from typing import Any, Dict from django.http import HttpRequest, HttpResponse @@ -27,35 +27,45 @@ PAGER_DUTY_EVENT_NAMES_V2 = { "incident.assign": "assigned", } +PAGER_DUTY_EVENT_NAMES_V3 = { + "incident.triggered": "triggered", + "incident.acknowledged": "acknowledged", + "incident.unacknowledged": "unacknowledged", + "incident.resolved": "resolved", + "incident.reassigned": "reassigned", +} + AGENT_TEMPLATE = "[{username}]({url})" INCIDENT_WITH_SERVICE_AND_ASSIGNEE = ( - "Incident [{incident_num}]({incident_url}) {action} by [{service_name}]" + "Incident [{incident_num_title}]({incident_url}) {action} by [{service_name}]" "({service_url}) (assigned to {assignee_info}).\n\n{trigger_message}" ) TRIGGER_MESSAGE = "``` quote\n{message}\n```" +NUM_TITLE = "{incident_title} (#{incident_num})" + INCIDENT_WITH_ASSIGNEE = """ -Incident [{incident_num}]({incident_url}) {action} by {assignee_info}. +Incident [{incident_num_title}]({incident_url}) {action} by {assignee_info}. {trigger_message} """.strip() INCIDENT_ASSIGNED = """ -Incident [{incident_num}]({incident_url}) {action} to {assignee_info}. +Incident [{incident_num_title}]({incident_url}) {action} to {assignee_info}. {trigger_message} """.strip() INCIDENT_RESOLVED_WITH_AGENT = """ -Incident [{incident_num}]({incident_url}) resolved by {agent_info}. +Incident [{incident_num_title}]({incident_url}) resolved by {agent_info}. {trigger_message} """.strip() INCIDENT_RESOLVED = """ -Incident [{incident_num}]({incident_url}) resolved. +Incident [{incident_num_title}]({incident_url}) resolved. {trigger_message} """.strip() @@ -66,7 +76,7 @@ def build_pagerduty_formatdict(message: Dict[str, Any]) -> Dict[str, Any]: format_dict["action"] = PAGER_DUTY_EVENT_NAMES[message["type"]] format_dict["incident_id"] = message["data"]["incident"]["id"] - format_dict["incident_num"] = message["data"]["incident"]["incident_number"] + format_dict["incident_num_title"] = message["data"]["incident"]["incident_number"] format_dict["incident_url"] = message["data"]["incident"]["html_url"] format_dict["service_name"] = message["data"]["incident"]["service"]["name"] @@ -108,7 +118,7 @@ def build_pagerduty_formatdict_v2(message: Dict[str, Any]) -> Dict[str, Any]: format_dict["action"] = PAGER_DUTY_EVENT_NAMES_V2[message["event"]] format_dict["incident_id"] = message["incident"]["id"] - format_dict["incident_num"] = message["incident"]["incident_number"] + format_dict["incident_num_title"] = message["incident"]["incident_number"] format_dict["incident_url"] = message["incident"]["html_url"] format_dict["service_name"] = message["incident"]["service"]["name"] @@ -136,21 +146,65 @@ def build_pagerduty_formatdict_v2(message: Dict[str, Any]) -> Dict[str, Any]: return format_dict +def build_pagerduty_formatdict_v3(event: Dict[str, Any]) -> Dict[str, Any]: + format_dict = {} + format_dict["action"] = PAGER_DUTY_EVENT_NAMES_V3[event["event_type"]] + + format_dict["incident_id"] = event["data"]["id"] + format_dict["incident_url"] = event["data"]["html_url"] + format_dict["incident_num_title"] = NUM_TITLE.format( + incident_num=event["data"]["number"], incident_title=event["data"]["title"] + ) + + format_dict["service_name"] = event["data"]["service"]["summary"] + format_dict["service_url"] = event["data"]["service"]["html_url"] + + assignees = event["data"]["assignees"] + if assignees: + assignee = assignees[0] + format_dict["assignee_info"] = AGENT_TEMPLATE.format( + username=assignee["summary"], url=assignee["html_url"] + ) + else: + format_dict["assignee_info"] = "nobody" + + agent = event.get("agent") + if agent is not None: + format_dict["agent_info"] = AGENT_TEMPLATE.format( + username=agent["summary"], + url=agent["html_url"], + ) + + # V3 doesn't have trigger_message + format_dict["trigger_message"] = "" + + return format_dict + + def send_formated_pagerduty( request: HttpRequest, user_profile: UserProfile, message_type: str, format_dict: Dict[str, Any] ) -> None: - if message_type in ("incident.trigger", "incident.unacknowledge"): + if message_type in ( + "incident.trigger", + "incident.triggered", + "incident.unacknowledge", + "incident.unacknowledged", + ): template = INCIDENT_WITH_SERVICE_AND_ASSIGNEE - elif message_type == "incident.resolve" and format_dict.get("agent_info") is not None: + elif ( + message_type == "incident.resolve" or message_type == "incident.resolved" + ) and format_dict.get("agent_info") is not None: template = INCIDENT_RESOLVED_WITH_AGENT - elif message_type == "incident.resolve" and format_dict.get("agent_info") is None: + elif ( + message_type == "incident.resolve" or message_type == "incident.resolved" + ) and format_dict.get("agent_info") is None: template = INCIDENT_RESOLVED - elif message_type == "incident.assign": + elif message_type == "incident.assign" or message_type == "incident.reassigned": template = INCIDENT_ASSIGNED else: template = INCIDENT_WITH_ASSIGNEE - subject = "Incident {incident_num}".format(**format_dict) + subject = "Incident {incident_num_title}".format(**format_dict) body = template.format(**format_dict) check_send_webhook_message(request, user_profile, subject, body) @@ -160,34 +214,48 @@ def send_formated_pagerduty( def api_pagerduty_webhook( request: HttpRequest, user_profile: UserProfile, - payload: Dict[str, Sequence[Dict[str, Any]]] = REQ(argument_type="body"), + payload: Dict[str, Any] = REQ(argument_type="body"), ) -> HttpResponse: - for message in payload["messages"]: - message_type = message.get("type") + messages = payload.get("messages") - # If the message has no "type" key, then this payload came from a - # Pagerduty Webhook V2. - if message_type is None: - break + if messages is not None: + for message in messages: + message_type = message.get("type") - if message_type not in PAGER_DUTY_EVENT_NAMES: - raise UnsupportedWebhookEventType(message_type) + # If the message has no "type" key, then this payload came from a + # Pagerduty Webhook V2. + if message_type is None: + break - format_dict = build_pagerduty_formatdict(message) - send_formated_pagerduty(request, user_profile, message_type, format_dict) + if message_type not in PAGER_DUTY_EVENT_NAMES: + raise UnsupportedWebhookEventType(message_type) - for message in payload["messages"]: - event = message.get("event") + format_dict = build_pagerduty_formatdict(message) + send_formated_pagerduty(request, user_profile, message_type, format_dict) - # If the message has no "event" key, then this payload came from a - # Pagerduty Webhook V1. - if event is None: - break + for message in messages: + event = message.get("event") - if event not in PAGER_DUTY_EVENT_NAMES_V2: - raise UnsupportedWebhookEventType(event) + # If the message has no "event" key, then this payload came from a + # Pagerduty Webhook V1. + if event is None: + break - format_dict = build_pagerduty_formatdict_v2(message) - send_formated_pagerduty(request, user_profile, event, format_dict) + if event not in PAGER_DUTY_EVENT_NAMES_V2: + raise UnsupportedWebhookEventType(event) + + format_dict = build_pagerduty_formatdict_v2(message) + send_formated_pagerduty(request, user_profile, event, format_dict) + else: + if "event" in payload: + # V3 has no "messages" field, and it has key "event" instead + event = payload["event"] + event_type = event.get("event_type") + + if event_type not in PAGER_DUTY_EVENT_NAMES_V3: + raise UnsupportedWebhookEventType(event_type) + + format_dict = build_pagerduty_formatdict_v3(event) + send_formated_pagerduty(request, user_profile, event_type, format_dict) return json_success()