mirror of
https://github.com/zulip/zulip.git
synced 2025-11-10 00:46:03 +00:00
Add pingdom integration.
This commit is contained in:
@@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Added documentation on using Hubot to integrate with useful services
|
- Added documentation on using Hubot to integrate with useful services
|
||||||
not yet integrated with Zulip directly (e.g. Google Hangouts).
|
not yet integrated with Zulip directly (e.g. Google Hangouts).
|
||||||
- Added new management command to test sending email from Zulip.
|
- Added new management command to test sending email from Zulip.
|
||||||
|
- Added Pingdom integration.
|
||||||
- Refactored the Zulip puppet modules to be more modular.
|
- Refactored the Zulip puppet modules to be more modular.
|
||||||
- Refactored the Tornado event system, fixing old memory leaks.
|
- Refactored the Tornado event system, fixing old memory leaks.
|
||||||
- Implemented running queue processors multithreaded in development,
|
- Implemented running queue processors multithreaded in development,
|
||||||
|
|||||||
BIN
static/images/integrations/logos/pingdom.png
Normal file
BIN
static/images/integrations/logos/pingdom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
static/images/integrations/pingdom/001.png
Normal file
BIN
static/images/integrations/pingdom/001.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
static/images/integrations/pingdom/002.png
Normal file
BIN
static/images/integrations/pingdom/002.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -164,6 +164,12 @@
|
|||||||
<span class="integration-label">Phabricator</span>
|
<span class="integration-label">Phabricator</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="integration-lozenge integration-pingdom">
|
||||||
|
<a class="integration-link integration-pingdom" href="#pingdom">
|
||||||
|
<img class="integration-logo" src="/static/images/integrations/logos/pingdom.png" alt="Pingdom logo" />
|
||||||
|
<span class="integration-label">Pingdom</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div class="integration-lozenge integration-pivotal">
|
<div class="integration-lozenge integration-pivotal">
|
||||||
<a class="integration-link integration-pivotal" href="#pivotal">
|
<a class="integration-link integration-pivotal" href="#pivotal">
|
||||||
<img class="integration-logo" src="/static/images/integrations/logos/pivotal.png" alt="Pivotal logo" />
|
<img class="integration-logo" src="/static/images/integrations/logos/pivotal.png" alt="Pivotal logo" />
|
||||||
@@ -1236,7 +1242,7 @@ key = NAGIOS_BOT_API_KEY
|
|||||||
<div id="phabricator" class="integration-instructions">
|
<div id="phabricator" class="integration-instructions">
|
||||||
|
|
||||||
|
|
||||||
<p>Zulip supports Phabricator integration and can notify you of the
|
<p>Zulip supports integration with Phabricator and can notify you of the
|
||||||
latest items in your Phabricator feed.</p>
|
latest items in your Phabricator feed.</p>
|
||||||
|
|
||||||
<p>You can follow the instructions at
|
<p>You can follow the instructions at
|
||||||
@@ -1248,11 +1254,41 @@ key = NAGIOS_BOT_API_KEY
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="pingdom" class="integration-instructions">
|
||||||
|
|
||||||
|
<p>Zulip supports integration with Pingdom and can notify you of
|
||||||
|
uptime status changes from your Pingdom dashboard.</p>
|
||||||
|
|
||||||
|
<p>First, create the stream you'd like to use for Pingdom notifications,
|
||||||
|
and subscribe all interested parties to this stream. We
|
||||||
|
recommend the name <code>pingdom</code>.</p>
|
||||||
|
|
||||||
|
<p><code>{{ external_api_uri }}/v1/external/pingdom?api_key=abcdefgh&stream=pingdom</code></p>
|
||||||
|
|
||||||
|
<p>where <code>api_key</code> is the API key of your Zulip bot,
|
||||||
|
and <code>stream</code> is the stream name you want the
|
||||||
|
notifications sent to.</p>
|
||||||
|
|
||||||
|
<p>Next, under following url: </p>
|
||||||
|
<p><code>https://my.pingdom.com/reports/integration/settings</code></p>
|
||||||
|
<p>create your integration by clicking on <code>Add Integration</code> button and filling form as following:</p>
|
||||||
|
<img class="screenshot" src="/static/images/integrations/pingdom/001.png" />
|
||||||
|
|
||||||
|
<p>Last, during creating or editing your check, scroll down to <code>Connect Integrations</code>
|
||||||
|
section and ensure your integration is checked</p>
|
||||||
|
|
||||||
|
<p><b>Congratulations! You're done!</b><br /> Example Zulip notification
|
||||||
|
looks like this:</p>
|
||||||
|
|
||||||
|
<img class="screenshot" src="/static/images/integrations/pingdom/002.png" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div id="pivotal" class="integration-instructions">
|
<div id="pivotal" class="integration-instructions">
|
||||||
|
|
||||||
|
|
||||||
<p>Zulip supports Pivotal Tracker integration and can notify you of changes
|
<p>Zulip supports integration with Pivotal Tracker and can notify you of changes
|
||||||
to the stories in your Pivotal Tracker project.</p>
|
to the stories in your Pivotal Tracker project.</p>
|
||||||
|
|
||||||
<p>First, create the stream you'd like to use for Pivotal Tracker
|
<p>First, create the stream you'd like to use for Pivotal Tracker
|
||||||
|
|||||||
34
zerver/fixtures/pingdom/pingdom_http_up_to_down.json
Normal file
34
zerver/fixtures/pingdom/pingdom_http_up_to_down.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"check_id": 2048467,
|
||||||
|
"check_name": "Test check",
|
||||||
|
"check_type": "HTTP",
|
||||||
|
"check_params": {
|
||||||
|
"basic_auth": false,
|
||||||
|
"encryption": false,
|
||||||
|
"full_url": "http:\/\/someurl.com\/",
|
||||||
|
"header": "User-Agent:Pingdom.com_bot_version_1.4_(http:\/\/www.pingdom.com\/)",
|
||||||
|
"hostname": "someurl.com",
|
||||||
|
"ipv6": false,
|
||||||
|
"port": 80,
|
||||||
|
"url": "\/"
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"previous_state": "UP",
|
||||||
|
"current_state": "DOWN",
|
||||||
|
"state_changed_timestamp": 1457939434,
|
||||||
|
"state_changed_utc_time": "2016-03-14T07:10:34",
|
||||||
|
"long_description": "Non-recoverable failure in name resolution",
|
||||||
|
"description": "DNS error",
|
||||||
|
"first_probe": {
|
||||||
|
"ip": "85.17.156.99",
|
||||||
|
"ipv6": "2001:1af8:4100:a09b::454",
|
||||||
|
"location": "Amsterdam 5, Netherlands"
|
||||||
|
},
|
||||||
|
"second_probe": {
|
||||||
|
"ip": "64.141.100.136",
|
||||||
|
"ipv6": "",
|
||||||
|
"location": "Calgary, Canada"
|
||||||
|
}
|
||||||
|
}
|
||||||
25
zerver/fixtures/pingdom/pingdom_imap_down_to_up.json
Normal file
25
zerver/fixtures/pingdom/pingdom_imap_down_to_up.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"check_id": 2051859,
|
||||||
|
"check_name": "IMAP check",
|
||||||
|
"check_type": "IMAP",
|
||||||
|
"check_params": {
|
||||||
|
"basic_auth": false,
|
||||||
|
"encryption": true,
|
||||||
|
"hostname": "imap.someurl.com",
|
||||||
|
"ipv6": false,
|
||||||
|
"port": 993
|
||||||
|
},
|
||||||
|
"tags": [],
|
||||||
|
"previous_state": "DOWN",
|
||||||
|
"current_state": "UP",
|
||||||
|
"state_changed_timestamp": 1458070380,
|
||||||
|
"state_changed_utc_time": "2016-03-15T19:33:00",
|
||||||
|
"long_description": "OK",
|
||||||
|
"description": "OK",
|
||||||
|
"first_probe": {
|
||||||
|
"ip": "69.64.56.47",
|
||||||
|
"ipv6": "",
|
||||||
|
"location": "St. Louis, MO"
|
||||||
|
},
|
||||||
|
"second_probe": {}
|
||||||
|
}
|
||||||
29
zerver/fixtures/pingdom/pingdom_imap_up_to_down.json
Normal file
29
zerver/fixtures/pingdom/pingdom_imap_up_to_down.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"check_id": 2051859,
|
||||||
|
"check_name": "IMAP check",
|
||||||
|
"check_type": "IMAP",
|
||||||
|
"check_params": {
|
||||||
|
"basic_auth": false,
|
||||||
|
"encryption": true,
|
||||||
|
"hostname": "imap.someurl.com",
|
||||||
|
"ipv6": false,
|
||||||
|
"port": 993
|
||||||
|
},
|
||||||
|
"tags": [],
|
||||||
|
"previous_state": "UP",
|
||||||
|
"current_state": "DOWN",
|
||||||
|
"state_changed_timestamp": 1458069480,
|
||||||
|
"state_changed_utc_time": "2016-03-15T19:18:00",
|
||||||
|
"long_description": "Invalid hostname, address or socket",
|
||||||
|
"description": "Unknown target",
|
||||||
|
"first_probe": {
|
||||||
|
"ip": "188.138.118.184",
|
||||||
|
"ipv6": "",
|
||||||
|
"location": "Strasbourg 2, France"
|
||||||
|
},
|
||||||
|
"second_probe": {
|
||||||
|
"ip": "76.164.194.74",
|
||||||
|
"ipv6": "2605:6f80:0:c::449",
|
||||||
|
"location": "Las Vegas 2, NV"
|
||||||
|
}
|
||||||
|
}
|
||||||
29
zerver/fixtures/pingdom/pingdom_smtp_up_to_down.json
Normal file
29
zerver/fixtures/pingdom/pingdom_smtp_up_to_down.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"check_id": 2051844,
|
||||||
|
"check_name": "SMTP check",
|
||||||
|
"check_type": "SMTP",
|
||||||
|
"check_params": {
|
||||||
|
"basic_auth": false,
|
||||||
|
"encryption": false,
|
||||||
|
"hostname": "smtp.someurl.com",
|
||||||
|
"ipv6": false,
|
||||||
|
"port": 25
|
||||||
|
},
|
||||||
|
"tags": [],
|
||||||
|
"previous_state": "UP",
|
||||||
|
"current_state": "DOWN",
|
||||||
|
"state_changed_timestamp": 1458068544,
|
||||||
|
"state_changed_utc_time": "2016-03-15T19:02:24",
|
||||||
|
"long_description": "Connection refused",
|
||||||
|
"description": "Connection refused",
|
||||||
|
"first_probe": {
|
||||||
|
"ip": "174.34.162.242",
|
||||||
|
"ipv6": "",
|
||||||
|
"location": "Atlanta, GA"
|
||||||
|
},
|
||||||
|
"second_probe": {
|
||||||
|
"ip": "64.141.100.136",
|
||||||
|
"ipv6": "",
|
||||||
|
"location": "Calgary, Canada"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -864,3 +864,71 @@ class TravisHookTests(AuthedTestCase):
|
|||||||
u"Details: [changes](https://github.com/hl7-fhir/fhir-sv"
|
u"Details: [changes](https://github.com/hl7-fhir/fhir-sv"
|
||||||
u"n/compare/6dccb98bcfd9...6c457d366a31), [build log](ht"
|
u"n/compare/6dccb98bcfd9...6c457d366a31), [build log](ht"
|
||||||
u"tps://travis-ci.org/hl7-fhir/fhir-svn/builds/92495257)"))
|
u"tps://travis-ci.org/hl7-fhir/fhir-svn/builds/92495257)"))
|
||||||
|
|
||||||
|
|
||||||
|
class PingdomHookTests(AuthedTestCase):
|
||||||
|
STREAM_NAME = 'pingdom'
|
||||||
|
TEST_USER_EMAIL = 'hamlet@zulip.com'
|
||||||
|
URL_TEMPLATE = "/api/v1/external/pingdom?stream={stream}&api_key={api_key}"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
api_key = self.get_api_key(self.TEST_USER_EMAIL)
|
||||||
|
self._url = self.URL_TEMPLATE.format(stream=self.STREAM_NAME, api_key=api_key)
|
||||||
|
self.subscribe_to_stream(self.TEST_USER_EMAIL, self.STREAM_NAME)
|
||||||
|
|
||||||
|
def test_pingdom_from_up_to_down_http_check_message(self):
|
||||||
|
"""
|
||||||
|
Tests if pingdom http check from up to down is handled correctly
|
||||||
|
"""
|
||||||
|
body = self._get_fixture_data('http_up_to_down')
|
||||||
|
self._send_post_request_with_params(body)
|
||||||
|
|
||||||
|
expected_message = u"Service someurl.com changed its HTTP status from UP to DOWN.\nDescription: Non-recoverable failure in name resolution."
|
||||||
|
msg = self._get_recently_added_message()
|
||||||
|
self.assertEqual(msg.subject, u"Test check status.")
|
||||||
|
self.assertEqual(msg.content, expected_message)
|
||||||
|
|
||||||
|
def test_pingdom_from_up_to_down_smtp_check_message(self):
|
||||||
|
"""
|
||||||
|
Tests if pingdom smtp check from up to down is handled correctly
|
||||||
|
"""
|
||||||
|
body = self._get_fixture_data('smtp_up_to_down')
|
||||||
|
self._send_post_request_with_params(body)
|
||||||
|
|
||||||
|
expected_message = u"Service smtp.someurl.com changed its SMTP status from UP to DOWN.\nDescription: Connection refused."
|
||||||
|
msg = self._get_recently_added_message()
|
||||||
|
self.assertEqual(msg.subject, u"SMTP check status.")
|
||||||
|
self.assertEqual(msg.content, expected_message)
|
||||||
|
|
||||||
|
def test_pingdom_from_up_to_down_imap_check_message(self):
|
||||||
|
"""
|
||||||
|
Tests if pingdom imap check from up to down is handled correctly
|
||||||
|
"""
|
||||||
|
body = self._get_fixture_data('imap_up_to_down')
|
||||||
|
self._send_post_request_with_params(body)
|
||||||
|
|
||||||
|
expected_message = u"Service imap.someurl.com changed its IMAP status from UP to DOWN.\nDescription: Invalid hostname, address or socket."
|
||||||
|
msg = self._get_recently_added_message()
|
||||||
|
self.assertEqual(msg.subject, u"IMAP check status.")
|
||||||
|
self.assertEqual(msg.content, expected_message)
|
||||||
|
|
||||||
|
def test_pingdom_from_down_to_up_imap_check_message(self):
|
||||||
|
"""
|
||||||
|
Tests if pingdom imap check from down to up is handled correctly
|
||||||
|
"""
|
||||||
|
body = self._get_fixture_data('imap_down_to_up')
|
||||||
|
self._send_post_request_with_params(body)
|
||||||
|
|
||||||
|
expected_message = u"Service imap.someurl.com changed its IMAP status from DOWN to UP."
|
||||||
|
msg = self._get_recently_added_message()
|
||||||
|
self.assertEqual(msg.subject, u"IMAP check status.")
|
||||||
|
self.assertEqual(msg.content, expected_message)
|
||||||
|
|
||||||
|
def _get_recently_added_message(self):
|
||||||
|
return Message.objects.filter().order_by('-id')[0]
|
||||||
|
|
||||||
|
def _get_fixture_data(self, name):
|
||||||
|
return ujson.dumps(ujson.loads(self.fixture_data('pingdom', name)))
|
||||||
|
|
||||||
|
def _send_post_request_with_params(self, json):
|
||||||
|
return self.client.post(self._url, json, stream_name=self.STREAM_NAME, content_type="application/json")
|
||||||
|
|||||||
68
zerver/views/webhooks/pingdom.py
Normal file
68
zerver/views/webhooks/pingdom.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Webhooks for external integrations.
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from zerver.models import get_client
|
||||||
|
from zerver.lib.actions import check_send_message
|
||||||
|
from zerver.lib.response import json_success, json_error
|
||||||
|
from zerver.decorator import REQ, has_request_variables, api_key_only_webhook_view
|
||||||
|
|
||||||
|
import ujson
|
||||||
|
|
||||||
|
|
||||||
|
PINGDOM_SUBJECT_TEMPLATE = '{name} status.'
|
||||||
|
PINGDOM_MESSAGE_TEMPLATE = 'Service {service_url} changed its {type} status from {previous_state} to {current_state}.'
|
||||||
|
PINGDOM_MESSAGE_DESCRIPTION_TEMPLATE = 'Description: {description}.'
|
||||||
|
|
||||||
|
|
||||||
|
SUPPORTED_CHECK_TYPES = (
|
||||||
|
'HTTP',
|
||||||
|
'HTTP_CUSTOM'
|
||||||
|
'HTTPS',
|
||||||
|
'SMTP',
|
||||||
|
'POP3',
|
||||||
|
'IMAP',
|
||||||
|
'PING',
|
||||||
|
'DNS',
|
||||||
|
'UDP',
|
||||||
|
'PORT_TCP',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@api_key_only_webhook_view
|
||||||
|
@has_request_variables
|
||||||
|
def api_pingdom_webhook(request, user_profile, stream=REQ(default='pingdom')):
|
||||||
|
payload = ujson.loads(request.body)
|
||||||
|
check_type = get_check_type(payload)
|
||||||
|
|
||||||
|
if check_type in SUPPORTED_CHECK_TYPES:
|
||||||
|
subject = get_subject_for_http_request(payload)
|
||||||
|
body = get_body_for_http_request(payload)
|
||||||
|
else:
|
||||||
|
return json_error('Unsupported check_type: {check_type}'.format(check_type=check_type))
|
||||||
|
|
||||||
|
check_send_message(user_profile, get_client('ZulipPingdomWebhook'), 'stream', [stream], subject, body)
|
||||||
|
return json_success()
|
||||||
|
|
||||||
|
|
||||||
|
def get_subject_for_http_request(payload):
|
||||||
|
return PINGDOM_SUBJECT_TEMPLATE.format(name=payload['check_name'])
|
||||||
|
|
||||||
|
|
||||||
|
def get_body_for_http_request(payload):
|
||||||
|
current_state = payload['current_state']
|
||||||
|
previous_state = payload['previous_state']
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'service_url': payload['check_params']['hostname'],
|
||||||
|
'previous_state': previous_state,
|
||||||
|
'current_state': current_state,
|
||||||
|
'type': get_check_type(payload)
|
||||||
|
}
|
||||||
|
body = PINGDOM_MESSAGE_TEMPLATE.format(**data)
|
||||||
|
if current_state == 'DOWN' and previous_state == 'UP':
|
||||||
|
description = PINGDOM_MESSAGE_DESCRIPTION_TEMPLATE.format(description=payload['long_description'])
|
||||||
|
body += '\n{description}'.format(description=description)
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
def get_check_type(payload):
|
||||||
|
return payload['check_type']
|
||||||
@@ -161,6 +161,7 @@ urlpatterns += patterns('zerver.views',
|
|||||||
url(r'^api/v1/external/zendesk$', 'webhooks.zendesk.api_zendesk_webhook'),
|
url(r'^api/v1/external/zendesk$', 'webhooks.zendesk.api_zendesk_webhook'),
|
||||||
url(r'^api/v1/external/pagerduty$', 'webhooks.pagerduty.api_pagerduty_webhook'),
|
url(r'^api/v1/external/pagerduty$', 'webhooks.pagerduty.api_pagerduty_webhook'),
|
||||||
url(r'^api/v1/external/travis$', 'webhooks.travis.api_travis_webhook'),
|
url(r'^api/v1/external/travis$', 'webhooks.travis.api_travis_webhook'),
|
||||||
|
url(r'^api/v1/external/pingdom$', 'webhooks.pingdom.api_pingdom_webhook'),
|
||||||
|
|
||||||
url(r'^user_uploads/(?P<realm_id>(\d*|unk))/(?P<filename>.*)', 'get_uploaded_file'),
|
url(r'^user_uploads/(?P<realm_id>(\d*|unk))/(?P<filename>.*)', 'get_uploaded_file'),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user