Add pingdom integration.

This commit is contained in:
Tomasz Kolek 2016-03-14 22:12:46 +01:00 committed by Tim Abbott
parent fe77559164
commit 44ed9da7f0
12 changed files with 293 additions and 2 deletions

View File

@ -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
not yet integrated with Zulip directly (e.g. Google Hangouts).
- Added new management command to test sending email from Zulip.
- Added Pingdom integration.
- Refactored the Zulip puppet modules to be more modular.
- Refactored the Tornado event system, fixing old memory leaks.
- Implemented running queue processors multithreaded in development,

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -164,6 +164,12 @@
<span class="integration-label">Phabricator</span>
</a>
</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">
<a class="integration-link integration-pivotal" href="#pivotal">
<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">
<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>
<p>You can follow the instructions at
@ -1248,11 +1254,41 @@ key = NAGIOS_BOT_API_KEY
</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&amp;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">
<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>
<p>First, create the stream you'd like to use for Pivotal Tracker

View 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"
}
}

View 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": {}
}

View 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"
}
}

View 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"
}
}

View File

@ -864,3 +864,71 @@ class TravisHookTests(AuthedTestCase):
u"Details: [changes](https://github.com/hl7-fhir/fhir-sv"
u"n/compare/6dccb98bcfd9...6c457d366a31), [build log](ht"
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")

View 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']

View File

@ -161,6 +161,7 @@ urlpatterns += patterns('zerver.views',
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/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'),
)