2016-03-13 15:28:44 +01:00
|
|
|
# Webhooks for external integrations.
|
2016-06-06 00:33:59 +02:00
|
|
|
|
2017-11-16 00:43:10 +01:00
|
|
|
import pprint
|
|
|
|
from typing import Any, Dict, Iterable, Optional, Text
|
|
|
|
|
|
|
|
import ujson
|
|
|
|
from django.http import HttpRequest, HttpResponse
|
|
|
|
|
2017-10-31 04:25:48 +01:00
|
|
|
from zerver.decorator import api_key_only_webhook_view
|
2017-09-30 04:18:16 +02:00
|
|
|
from zerver.lib.actions import check_send_stream_message
|
2017-10-31 04:25:48 +01:00
|
|
|
from zerver.lib.request import REQ, has_request_variables
|
2017-11-16 00:43:10 +01:00
|
|
|
from zerver.lib.response import json_success
|
2016-06-06 00:33:59 +02:00
|
|
|
from zerver.models import Client, UserProfile
|
|
|
|
|
2016-03-13 15:28:44 +01:00
|
|
|
PAGER_DUTY_EVENT_NAMES = {
|
|
|
|
'incident.trigger': 'triggered',
|
|
|
|
'incident.acknowledge': 'acknowledged',
|
|
|
|
'incident.unacknowledge': 'unacknowledged',
|
|
|
|
'incident.resolve': 'resolved',
|
|
|
|
'incident.assign': 'assigned',
|
|
|
|
'incident.escalate': 'escalated',
|
|
|
|
'incident.delegate': 'delineated',
|
|
|
|
}
|
|
|
|
|
2017-11-04 07:47:46 +01:00
|
|
|
def build_pagerduty_formatdict(message: Dict[str, Any]) -> Dict[str, Any]:
|
2016-03-13 15:28:44 +01:00
|
|
|
# Normalize the message dict, after this all keys will exist. I would
|
|
|
|
# rather some strange looking messages than dropping pages.
|
|
|
|
|
2017-05-07 20:09:30 +02:00
|
|
|
format_dict = {} # type: Dict[str, Any]
|
2016-03-13 15:28:44 +01:00
|
|
|
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_url'] = message['data']['incident']['html_url']
|
|
|
|
|
|
|
|
format_dict['service_name'] = message['data']['incident']['service']['name']
|
|
|
|
format_dict['service_url'] = message['data']['incident']['service']['html_url']
|
|
|
|
|
|
|
|
# This key can be missing on null
|
|
|
|
if message['data']['incident'].get('assigned_to_user', None):
|
2017-11-05 02:48:25 +01:00
|
|
|
assigned_to_user = message['data']['incident']['assigned_to_user']
|
|
|
|
format_dict['assigned_to_email'] = assigned_to_user['email']
|
|
|
|
format_dict['assigned_to_username'] = assigned_to_user['email'].split('@')[0]
|
|
|
|
format_dict['assigned_to_url'] = assigned_to_user['html_url']
|
2016-03-13 15:28:44 +01:00
|
|
|
else:
|
|
|
|
format_dict['assigned_to_email'] = 'nobody'
|
|
|
|
format_dict['assigned_to_username'] = 'nobody'
|
|
|
|
format_dict['assigned_to_url'] = ''
|
|
|
|
|
|
|
|
# This key can be missing on null
|
|
|
|
if message['data']['incident'].get('resolved_by_user', None):
|
2017-11-05 02:48:25 +01:00
|
|
|
resolved_by_user = message['data']['incident']['resolved_by_user']
|
|
|
|
format_dict['resolved_by_email'] = resolved_by_user['email']
|
|
|
|
format_dict['resolved_by_username'] = resolved_by_user['email'].split('@')[0]
|
|
|
|
format_dict['resolved_by_url'] = resolved_by_user['html_url']
|
2016-03-13 15:28:44 +01:00
|
|
|
else:
|
|
|
|
format_dict['resolved_by_email'] = 'nobody'
|
|
|
|
format_dict['resolved_by_username'] = 'nobody'
|
|
|
|
format_dict['resolved_by_url'] = ''
|
|
|
|
|
|
|
|
trigger_message = []
|
|
|
|
trigger_subject = message['data']['incident']['trigger_summary_data'].get('subject', '')
|
|
|
|
if trigger_subject:
|
|
|
|
trigger_message.append(trigger_subject)
|
|
|
|
trigger_description = message['data']['incident']['trigger_summary_data'].get('description', '')
|
|
|
|
if trigger_description:
|
|
|
|
trigger_message.append(trigger_description)
|
|
|
|
format_dict['trigger_message'] = u'\n'.join(trigger_message)
|
|
|
|
return format_dict
|
|
|
|
|
|
|
|
|
2017-11-04 07:47:46 +01:00
|
|
|
def send_raw_pagerduty_json(user_profile: UserProfile,
|
|
|
|
client: Client,
|
|
|
|
stream: Text,
|
|
|
|
message: Dict[str, Any],
|
|
|
|
topic: Optional[Text]) -> None:
|
2016-03-13 15:28:44 +01:00
|
|
|
subject = topic or 'pagerduty'
|
|
|
|
body = (
|
|
|
|
u'Unknown pagerduty message\n'
|
2016-07-13 21:38:04 +02:00
|
|
|
u'```\n'
|
2016-03-13 15:28:44 +01:00
|
|
|
u'%s\n'
|
2016-07-13 21:38:04 +02:00
|
|
|
u'```') % (ujson.dumps(message, indent=2),)
|
2017-09-30 04:18:16 +02:00
|
|
|
check_send_stream_message(user_profile, client, stream, subject, body)
|
2016-03-13 15:28:44 +01:00
|
|
|
|
|
|
|
|
2017-11-04 07:47:46 +01:00
|
|
|
def send_formated_pagerduty(user_profile: UserProfile,
|
|
|
|
client: Client,
|
|
|
|
stream: Text,
|
|
|
|
message_type: Text,
|
|
|
|
format_dict: Dict[str, Any],
|
|
|
|
topic: Optional[Text]) -> None:
|
2016-03-13 15:28:44 +01:00
|
|
|
if message_type in ('incident.trigger', 'incident.unacknowledge'):
|
|
|
|
template = (u':imp: Incident '
|
2016-12-03 00:04:17 +01:00
|
|
|
u'[{incident_num}]({incident_url}) {action} by '
|
|
|
|
u'[{service_name}]({service_url}) and assigned to '
|
|
|
|
u'[{assigned_to_username}@]({assigned_to_url})\n\n>{trigger_message}')
|
2016-03-13 15:28:44 +01:00
|
|
|
|
|
|
|
elif message_type == 'incident.resolve' and format_dict['resolved_by_url']:
|
|
|
|
template = (u':grinning: Incident '
|
2016-12-03 00:04:17 +01:00
|
|
|
u'[{incident_num}]({incident_url}) resolved by '
|
|
|
|
u'[{resolved_by_username}@]({resolved_by_url})\n\n>{trigger_message}')
|
2016-03-13 15:28:44 +01:00
|
|
|
elif message_type == 'incident.resolve' and not format_dict['resolved_by_url']:
|
|
|
|
template = (u':grinning: Incident '
|
2016-12-03 00:04:17 +01:00
|
|
|
u'[{incident_num}]({incident_url}) resolved\n\n>{trigger_message}')
|
2016-03-13 15:28:44 +01:00
|
|
|
else:
|
|
|
|
template = (u':no_good: Incident [{incident_num}]({incident_url}) '
|
2016-12-03 00:04:17 +01:00
|
|
|
u'{action} by [{assigned_to_username}@]({assigned_to_url})\n\n>{trigger_message}')
|
2016-03-13 15:28:44 +01:00
|
|
|
|
|
|
|
subject = topic or u'incident {incident_num}'.format(**format_dict)
|
|
|
|
body = template.format(**format_dict)
|
|
|
|
|
2017-09-30 04:18:16 +02:00
|
|
|
check_send_stream_message(user_profile, client, stream, subject, body)
|
2016-03-13 15:28:44 +01:00
|
|
|
|
|
|
|
|
2016-05-12 22:49:36 +02:00
|
|
|
@api_key_only_webhook_view('PagerDuty')
|
2016-03-13 15:28:44 +01:00
|
|
|
@has_request_variables
|
2017-12-30 08:52:28 +01:00
|
|
|
def api_pagerduty_webhook(request: HttpRequest, user_profile: UserProfile,
|
|
|
|
payload: Dict[str, Iterable[Dict[str, Any]]]=REQ(argument_type='body'),
|
|
|
|
stream: Text=REQ(default='pagerduty'),
|
|
|
|
topic: Optional[Text]=REQ(default=None)) -> HttpResponse:
|
2016-03-13 15:28:44 +01:00
|
|
|
for message in payload['messages']:
|
|
|
|
message_type = message['type']
|
|
|
|
|
|
|
|
if message_type not in PAGER_DUTY_EVENT_NAMES:
|
2017-05-02 01:00:50 +02:00
|
|
|
send_raw_pagerduty_json(user_profile, request.client, stream, message, topic)
|
2016-03-13 15:28:44 +01:00
|
|
|
|
|
|
|
try:
|
|
|
|
format_dict = build_pagerduty_formatdict(message)
|
2017-03-05 10:25:27 +01:00
|
|
|
except Exception:
|
2017-05-02 01:00:50 +02:00
|
|
|
send_raw_pagerduty_json(user_profile, request.client, stream, message, topic)
|
2016-03-13 15:28:44 +01:00
|
|
|
else:
|
2017-05-02 01:00:50 +02:00
|
|
|
send_formated_pagerduty(user_profile, request.client, stream, message_type, format_dict, topic)
|
2016-03-13 15:28:44 +01:00
|
|
|
|
|
|
|
return json_success()
|