diff --git a/humbug/urls.py b/humbug/urls.py index 910db8b874..288398641d 100644 --- a/humbug/urls.py +++ b/humbug/urls.py @@ -136,6 +136,7 @@ urlpatterns += patterns('zephyr.views', url(r'^api/v1/external/github$', 'api_github_landing'), url(r'^api/v1/external/jira$', 'api_jira_webhook'), url(r'^api/v1/external/pivotal$', 'api_pivotal_webhook'), + url(r'^api/v1/external/newrelic$', 'api_newrelic_webhook'), ) v1_api_and_json_patterns = patterns('zephyr.views', diff --git a/templates/zephyr/integrations.html b/templates/zephyr/integrations.html index 987d0a80dd..6ada2b9fc6 100644 --- a/templates/zephyr/integrations.html +++ b/templates/zephyr/integrations.html @@ -52,6 +52,7 @@
  • Jira (hosted or v5.2+)
  • Jira (locally installed)
  • Nagios
  • +
  • New Relic
  • Pivotal Tracker
  • Subversion
  • Trac
  • @@ -394,6 +395,29 @@ key=NAGIOS_BOT_API_KEY ^ Back to top

    +{#--------------------------------------------------------------------#} +
    +

    New Relic

    + +

    New Relic can send messages to a Zulip stream for alerts and deploys. + In your Account Settings page, click "Integrations", then + "Alerting notifications". On the "Webhook" tab, enter the following + webhook URL:

    + +

    https://api.humbughq.com/v1/external/newrelic?api_key=abcdefgh&stream=newrelic

    + +

    where api_key is the API key of the user you + want updates to be sent as, and stream is the stream name you want the notifications sent to. The stream must already exist.

    + + + +

    Congratulations! You're done!
    Your New Relic events will + appear in Zulip: + +

    + ^ Back to top +

    +
    {#--------------------------------------------------------------------#}

    Subversion

    diff --git a/zephyr/fixtures/newrelic/newrelic_alert.txt b/zephyr/fixtures/newrelic/newrelic_alert.txt new file mode 100644 index 0000000000..21a2ac3fb3 --- /dev/null +++ b/zephyr/fixtures/newrelic/newrelic_alert.txt @@ -0,0 +1 @@ +alert=%7B%22created_at%22%3A%222013-07-23T20%3A14%3A15%2B00%3A00%22%2C%22application_name%22%3A%22Application%20name%22%2C%22account_name%22%3A%22Account%20name%22%2C%22severity%22%3A%22critical%22%2C%22message%22%3A%22Apdex%20score%20fell%20below%20critical%20level%20of%200.90%22%2C%22short_description%22%3A%22%5Bapplication%20name%5D%20alert%20opened%22%2C%22long_description%22%3A%22Alert%20opened%20on%20%5Bapplication%20name%5D%3A%20Apdex%20score%20fell%20below%20critical%20level%20of%200.90%22%2C%22alert_url%22%3A%22https%3A%2F%2Frpm.newrelc.com%2Faccounts%2F%5Baccount_id%5D%2Fapplications%2F%5Bapplication_id%5D%2Fincidents%2F%5Bincident_id%5D%22%7D \ No newline at end of file diff --git a/zephyr/fixtures/newrelic/newrelic_deployment.txt b/zephyr/fixtures/newrelic/newrelic_deployment.txt new file mode 100644 index 0000000000..cfa343d7ae --- /dev/null +++ b/zephyr/fixtures/newrelic/newrelic_deployment.txt @@ -0,0 +1 @@ +deployment=%7B%22created_at%22%3A%222013-07-23T20%3A14%3A25Z%22%2C%22deployed_by%22%3A%22Zulip%20Test%22%2C%22revision%22%3A%221242%22%2C%22description%22%3A%22Description%20sent%20via%20curl%22%2C%22application_name%22%3A%22Test%20App%22%2C%22account_name%22%3A%22Zulip%20Test%22%2C%22changelog%22%3A%22Changelog%20string%22%2C%22deployment_url%22%3A%22https%3A%2F%2Frpm.newrelic.com%2Faccounts%2F382116%2Fapplications%2F2135922%2Fdeployments%2F679885%22%7D \ No newline at end of file diff --git a/zephyr/static/images/integrations/newrelic/001.png b/zephyr/static/images/integrations/newrelic/001.png new file mode 100644 index 0000000000..f34b95d2fb Binary files /dev/null and b/zephyr/static/images/integrations/newrelic/001.png differ diff --git a/zephyr/static/images/integrations/newrelic/002.png b/zephyr/static/images/integrations/newrelic/002.png new file mode 100644 index 0000000000..9c0bcdb59b Binary files /dev/null and b/zephyr/static/images/integrations/newrelic/002.png differ diff --git a/zephyr/tests.py b/zephyr/tests.py index 3d3e4429b1..aed7e648d3 100644 --- a/zephyr/tests.py +++ b/zephyr/tests.py @@ -2988,6 +2988,28 @@ class PivotalHookTests(AuthedTestCase): self.assertEqual(msg.content, 'Leo Franchi edited "My new Feature story" \ [(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') +class NewRelicHookTests(AuthedTestCase): + def send_new_relic_message(self, name): + email = "hamlet@humbughq.com" + api_key = self.get_api_key(email) + return self.send_json_payload(email, "/api/v1/external/newrelic?api_key=%s&stream=%s" % (api_key,"newrelic"), + self.fixture_data('newrelic', name, file_type='txt'), + stream_name="newrelic", + content_type="application/x-www-form-urlencoded") + + def test_alert(self): + msg = self.send_new_relic_message('alert') + self.assertEqual(msg.subject, "Apdex score fell below critical level of 0.90") + self.assertEqual(msg.content, 'Alert opened on [application name]: \ +Apdex score fell below critical level of 0.90\n\ +[View alert](https://rpm.newrelc.com/accounts/[account_id]/applications/[application_id]/incidents/[incident_id])') + + def test_deployment(self): + msg = self.send_new_relic_message('deployment') + self.assertEqual(msg.subject, 'Test App deploy') + self.assertEqual(msg.content, '`1242` deployed by **Zulip Test**\n\ +Description sent via curl\n\nChangelog string') + class RateLimitTests(AuthedTestCase): def setUp(self): diff --git a/zephyr/views.py b/zephyr/views.py index 80650b37aa..298dc36e12 100644 --- a/zephyr/views.py +++ b/zephyr/views.py @@ -1829,6 +1829,45 @@ def api_beanstalk_webhook(request, user_profile, return json_error(ret) return json_success() +@csrf_exempt +@has_request_variables +def api_newrelic_webhook(request, alert=REQ(converter=json_to_dict, default=None), + deployment=REQ(converter=json_to_dict, default=None)): + try: + api_key = request.GET['api_key'] + stream = request.GET['stream'] + except (AttributeError, KeyError): + return json_error("Missing api_key or stream parameter.") + + try: + user_profile = UserProfile.objects.get(api_key=api_key) + request.user = user_profile + except UserProfile.DoesNotExist: + return json_error("Failed to find user with API key: %s" % (api_key,)) + + rate_limit_user(request, user_profile, domain='all') + + if alert: + # Use the message as the subject because it stays the same for + # "opened", "acknowledged", and "closed" messages that should be + # grouped. + subject = alert['message'] + content = "%(long_description)s\n[View alert](%(alert_url)s)" % (alert) + elif deployment: + subject = "%s deploy" % (deployment['application_name']) + content = """`%(revision)s` deployed by **%(deployed_by)s** +%(description)s + +%(changelog)s""" % (deployment) + else: + return json_error("Unknown webhook request") + + subject = elide_subject(subject) + ret = check_send_message(user_profile, get_client("API"), "stream", [stream], subject, content) + if ret is not None: + return json_error(ret) + return json_success() + def get_status_list(requesting_user_profile): return {'presences': get_status_dict(requesting_user_profile), 'server_timestamp': time.time()}