Browse Source

Add VictorOps integration

pull/40/head
Spencer Sun 9 years ago
parent
commit
0ff2f1a9c7
15 changed files with 179 additions and 2 deletions
  1. +2
    -0
      hc/api/admin.py
  2. +20
    -0
      hc/api/migrations/0024_auto_20160203_2227.py
  3. +4
    -1
      hc/api/models.py
  4. +12
    -0
      hc/api/tests/test_notify.py
  5. +13
    -0
      hc/api/transports.py
  6. +1
    -1
      hc/front/tests/test_add_channel.py
  7. +1
    -0
      hc/front/urls.py
  8. +5
    -0
      hc/front/views.py
  9. BIN
      static/img/integrations/setup_victorops_1.png
  10. BIN
      static/img/integrations/setup_victorops_2.png
  11. BIN
      static/img/integrations/setup_victorops_3.png
  12. BIN
      static/img/integrations/victorops.png
  13. +11
    -0
      templates/front/channels.html
  14. +105
    -0
      templates/integrations/add_victorops.html
  15. +5
    -0
      templates/integrations/victorops_description.html

+ 2
- 0
hc/api/admin.py View File

@ -153,6 +153,8 @@ class ChannelsAdmin(admin.ModelAdmin):
def formatted_kind(self, obj):
if obj.kind == "pd":
return "PagerDuty"
elif obj.kind == "victorops":
return "VictorOps"
elif obj.kind == "po":
return "Pushover"
elif obj.kind == "webhook":


+ 20
- 0
hc/api/migrations/0024_auto_20160203_2227.py View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-02-03 22:27
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0023_auto_20160131_1919'),
]
operations = [
migrations.AlterField(
model_name='channel',
name='kind',
field=models.CharField(choices=[(b'email', b'Email'), (b'webhook', b'Webhook'), (b'hipchat', b'HipChat'), (b'slack', b'Slack'), (b'pd', b'PagerDuty'), (b'po', b'Pushover'), (b'victorops', b'VictorOps')], max_length=20),
),
]

+ 4
- 1
hc/api/models.py View File

@ -22,7 +22,8 @@ DEFAULT_TIMEOUT = td(days=1)
DEFAULT_GRACE = td(hours=1)
CHANNEL_KINDS = (("email", "Email"), ("webhook", "Webhook"),
("hipchat", "HipChat"),
("slack", "Slack"), ("pd", "PagerDuty"), ("po", "Pushover"))
("slack", "Slack"), ("pd", "PagerDuty"), ("po", "Pushover"),
("victorops", "VictorOps"))
PO_PRIORITIES = {
-2: "lowest",
@ -140,6 +141,8 @@ class Channel(models.Model):
return transports.HipChat(self)
elif self.kind == "pd":
return transports.PagerDuty(self)
elif self.kind == "victorops":
return transports.VictorOps(self)
elif self.kind == "po":
return transports.Pushover(self)
else:


+ 12
- 0
hc/api/tests/test_notify.py View File

@ -152,3 +152,15 @@ class NotifyTestCase(BaseTestCase):
args, kwargs = mock_post.call_args
json = kwargs["data"]
self.assertIn("DOWN", json["title"])
@patch("hc.api.transports.requests.request")
def test_victorops(self, mock_post):
self._setup_data("victorops", "123")
mock_post.return_value.status_code = 200
self.channel.notify(self.check)
assert Notification.objects.count() == 1
args, kwargs = mock_post.call_args
json = kwargs["json"]
self.assertEqual(json["message_type"], "CRITICAL")

+ 13
- 0
hc/api/transports.py View File

@ -152,3 +152,16 @@ class Pushover(HttpTransport):
payload["expire"] = settings.PUSHOVER_EMERGENCY_EXPIRATION
return self.post_form(self.URL, payload)
class VictorOps(HttpTransport):
def notify(self, check):
description = tmpl("victorops_description.html", check=check)
payload = {
"entity_id": str(check.code),
"message_type": "CRITICAL" if check.status == "down" else "RECOVERY",
"entity_display_name": description,
"monitoring_tool": "healthchecks.io",
}
return self.post(self.channel.value, payload)

+ 1
- 1
hc/front/tests/test_add_channel.py View File

@ -40,7 +40,7 @@ class AddChannelTestCase(BaseTestCase):
def test_instructions_work(self):
self.client.login(username="[email protected]", password="password")
for frag in ("email", "webhook", "pd", "pushover", "slack", "hipchat"):
for frag in ("email", "webhook", "pd", "pushover", "slack", "hipchat", "victorops"):
url = "/integrations/add_%s/" % frag
r = self.client.get(url)
self.assertContains(r, "Integration Settings", status_code=200)


+ 1
- 0
hc/front/urls.py View File

@ -22,6 +22,7 @@ urlpatterns = [
url(r'^integrations/add_slack/$', views.add_slack, name="hc-add-slack"),
url(r'^integrations/add_hipchat/$', views.add_hipchat, name="hc-add-hipchat"),
url(r'^integrations/add_pushover/$', views.add_pushover, name="hc-add-pushover"),
url(r'^integrations/add_victorops/$', views.add_victorops, name="hc-add-victorops"),
url(r'^integrations/([\w-]+)/checks/$', views.channel_checks, name="hc-channel-checks"),
url(r'^integrations/([\w-]+)/remove/$', views.remove_channel, name="hc-remove-channel"),
url(r'^integrations/([\w-]+)/verify/([\w-]+)/$',


+ 5
- 0
hc/front/views.py View File

@ -439,6 +439,11 @@ def add_pushover(request):
}
return render(request, "integrations/add_pushover.html", ctx)
@login_required
def add_victorops(request):
ctx = {"page": "channels"}
return render(request, "integrations/add_victorops.html", ctx)
def privacy(request):
return render(request, "front/privacy.html", {})

BIN
static/img/integrations/setup_victorops_1.png View File

Before After
Width: 1125  |  Height: 248  |  Size: 36 KiB

BIN
static/img/integrations/setup_victorops_2.png View File

Before After
Width: 1164  |  Height: 314  |  Size: 56 KiB

BIN
static/img/integrations/setup_victorops_3.png View File

Before After
Width: 1212  |  Height: 590  |  Size: 79 KiB

BIN
static/img/integrations/victorops.png View File

Before After
Width: 100  |  Height: 100  |  Size: 7.6 KiB

+ 11
- 0
templates/front/channels.html View File

@ -25,12 +25,14 @@
{% if ch.kind == "hipchat" %} HipChat {% endif %}
{% if ch.kind == "pd" %} PagerDuty {% endif %}
{% if ch.kind == "po" %} Pushover {% endif %}
{% if ch.kind == "victorops" %} VictorOps {% endif %}
</td>
<td class="value-cell">
<span class="preposition">
{% if ch.kind == "email" %} to {% endif %}
{% if ch.kind == "pd" %} API key {% endif %}
{% if ch.kind == "po" %} user key {% endif %}
{% if ch.kind == "victorops" %} Post URL {% endif %}
</span>
{% if ch.kind == "po" %}
@ -131,6 +133,15 @@
<a href="{% url 'hc-add-hipchat' %}" class="btn btn-primary">Add Integration</a>
</li>
<li>
<img src="{% static 'img/integrations/victorops.png' %}"
alt="VictorOp icon" />
<h2>VictorOps</h2>
<p>On-call scheduling, alerting, and incident tracking.</p>
<a href="{% url 'hc-add-victorops' %}" class="btn btn-primary">Add Integration</a>
</li>
{% if enable_pushover %}
<li>
<img src="{% static 'img/integrations/pushover.png' %}"


+ 105
- 0
templates/integrations/add_victorops.html View File

@ -0,0 +1,105 @@
{% extends "base.html" %}
{% load compress humanize staticfiles hc_extras %}
{% block title %}Add VictorOps - healthchecks.io{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<h1>VictorOps</h1>
<p><a href="https://victorops.com//">VictorOps</a> is
another incident management system similar to PagerDuty.
If you use or plan on using VitorOps, you can can integrate it
with your healthchecks.io account in few simple steps.</p>
<h2>Setup Guide</h2>
<div class="row ai-step">
<div class="col-sm-6">
<span class="step-no">1</span>
<p>
Log into your VictorOps account,
go to <strong>Settings > Schedules</strong>,
and find or create the Team Schedule you
would like to use for healthchecks.io alerts.
</p>
</div>
<div class="col-sm-6">
<img
class="ai-guide-screenshot"
src="{% static 'img/integrations/setup_victorops_1.png' %}">
</div>
</div>
<div class="row ai-step">
<div class="col-sm-6">
<span class="step-no">2</span>
<p>
Make note of the routing key. If this team schedule
does not already have a routing key,
click <strong>Setup Routing</strong>
or go to <strong>Integrations</strong>
and scroll to the bottom to create a routing rule and routing key
for this team.
</p>
</div>
<div class="col-sm-6">
<img
class="ai-guide-screenshot"
src="{% static 'img/integrations/setup_victorops_2.png' %}">
</div>
</div>
<div class="row ai-step">
<div class="col-sm-6">
<span class="step-no">3</span>
Go to <strong>Settings > Integrations</strong>
and click on <strong>REST Endpoint</strong>.
Make note of the <strong>Post URL</strong>.
</div>
<div class="col-sm-6">
<img
class="ai-guide-screenshot"
src="{% static 'img/integrations/setup_victorops_3.png' %}">
</div>
</div>
<div class="row ai-step">
<div class="col-sm-6">
<span class="step-no">4</span>
<p>Paste the <strong>Post URL</strong> from step 3 in the field below, being careful to replace <strong>$routing_key</strong> with your actual routing key from step 2. Save the integration, and it's done!</p>
</div>
</div>
<h2>Integration Settings</h2>
<form method="post" class="form-horizontal" action="{% url 'hc-add-channel' %}">
{% csrf_token %}
<input type="hidden" name="kind" value="victorops" />
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">API Key</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="value" placeholder="">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">Save Integration</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
{% compress js %}
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
{% endcompress %}
{% endblock %}

+ 5
- 0
templates/integrations/victorops_description.html View File

@ -0,0 +1,5 @@
{% if check.status == "down" %}
{{ check.name_then_code }} is DOWN
{% else %}
{{ check.name_then_code }} received a ping and is now UP
{% endif %}

Loading…
Cancel
Save