forked from GithubBackups/healthchecks
Add VictorOps integration
This commit is contained in:
parent
713f65865c
commit
0ff2f1a9c7
@ -153,6 +153,8 @@ class ChannelsAdmin(admin.ModelAdmin):
|
|||||||
def formatted_kind(self, obj):
|
def formatted_kind(self, obj):
|
||||||
if obj.kind == "pd":
|
if obj.kind == "pd":
|
||||||
return "PagerDuty"
|
return "PagerDuty"
|
||||||
|
elif obj.kind == "victorops":
|
||||||
|
return "VictorOps"
|
||||||
elif obj.kind == "po":
|
elif obj.kind == "po":
|
||||||
return "Pushover"
|
return "Pushover"
|
||||||
elif obj.kind == "webhook":
|
elif obj.kind == "webhook":
|
||||||
|
20
hc/api/migrations/0024_auto_20160203_2227.py
Normal file
20
hc/api/migrations/0024_auto_20160203_2227.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
@ -22,7 +22,8 @@ DEFAULT_TIMEOUT = td(days=1)
|
|||||||
DEFAULT_GRACE = td(hours=1)
|
DEFAULT_GRACE = td(hours=1)
|
||||||
CHANNEL_KINDS = (("email", "Email"), ("webhook", "Webhook"),
|
CHANNEL_KINDS = (("email", "Email"), ("webhook", "Webhook"),
|
||||||
("hipchat", "HipChat"),
|
("hipchat", "HipChat"),
|
||||||
("slack", "Slack"), ("pd", "PagerDuty"), ("po", "Pushover"))
|
("slack", "Slack"), ("pd", "PagerDuty"), ("po", "Pushover"),
|
||||||
|
("victorops", "VictorOps"))
|
||||||
|
|
||||||
PO_PRIORITIES = {
|
PO_PRIORITIES = {
|
||||||
-2: "lowest",
|
-2: "lowest",
|
||||||
@ -140,6 +141,8 @@ class Channel(models.Model):
|
|||||||
return transports.HipChat(self)
|
return transports.HipChat(self)
|
||||||
elif self.kind == "pd":
|
elif self.kind == "pd":
|
||||||
return transports.PagerDuty(self)
|
return transports.PagerDuty(self)
|
||||||
|
elif self.kind == "victorops":
|
||||||
|
return transports.VictorOps(self)
|
||||||
elif self.kind == "po":
|
elif self.kind == "po":
|
||||||
return transports.Pushover(self)
|
return transports.Pushover(self)
|
||||||
else:
|
else:
|
||||||
|
@ -152,3 +152,15 @@ class NotifyTestCase(BaseTestCase):
|
|||||||
args, kwargs = mock_post.call_args
|
args, kwargs = mock_post.call_args
|
||||||
json = kwargs["data"]
|
json = kwargs["data"]
|
||||||
self.assertIn("DOWN", json["title"])
|
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")
|
||||||
|
@ -152,3 +152,16 @@ class Pushover(HttpTransport):
|
|||||||
payload["expire"] = settings.PUSHOVER_EMERGENCY_EXPIRATION
|
payload["expire"] = settings.PUSHOVER_EMERGENCY_EXPIRATION
|
||||||
|
|
||||||
return self.post_form(self.URL, payload)
|
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)
|
||||||
|
@ -40,7 +40,7 @@ class AddChannelTestCase(BaseTestCase):
|
|||||||
|
|
||||||
def test_instructions_work(self):
|
def test_instructions_work(self):
|
||||||
self.client.login(username="alice@example.org", password="password")
|
self.client.login(username="alice@example.org", 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
|
url = "/integrations/add_%s/" % frag
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
self.assertContains(r, "Integration Settings", status_code=200)
|
self.assertContains(r, "Integration Settings", status_code=200)
|
||||||
|
@ -22,6 +22,7 @@ urlpatterns = [
|
|||||||
url(r'^integrations/add_slack/$', views.add_slack, name="hc-add-slack"),
|
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_hipchat/$', views.add_hipchat, name="hc-add-hipchat"),
|
||||||
url(r'^integrations/add_pushover/$', views.add_pushover, name="hc-add-pushover"),
|
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-]+)/checks/$', views.channel_checks, name="hc-channel-checks"),
|
||||||
url(r'^integrations/([\w-]+)/remove/$', views.remove_channel, name="hc-remove-channel"),
|
url(r'^integrations/([\w-]+)/remove/$', views.remove_channel, name="hc-remove-channel"),
|
||||||
url(r'^integrations/([\w-]+)/verify/([\w-]+)/$',
|
url(r'^integrations/([\w-]+)/verify/([\w-]+)/$',
|
||||||
|
@ -439,6 +439,11 @@ def add_pushover(request):
|
|||||||
}
|
}
|
||||||
return render(request, "integrations/add_pushover.html", ctx)
|
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):
|
def privacy(request):
|
||||||
return render(request, "front/privacy.html", {})
|
return render(request, "front/privacy.html", {})
|
||||||
|
BIN
static/img/integrations/setup_victorops_1.png
Normal file
BIN
static/img/integrations/setup_victorops_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
static/img/integrations/setup_victorops_2.png
Normal file
BIN
static/img/integrations/setup_victorops_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
BIN
static/img/integrations/setup_victorops_3.png
Normal file
BIN
static/img/integrations/setup_victorops_3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 79 KiB |
BIN
static/img/integrations/victorops.png
Normal file
BIN
static/img/integrations/victorops.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
@ -25,12 +25,14 @@
|
|||||||
{% if ch.kind == "hipchat" %} HipChat {% endif %}
|
{% if ch.kind == "hipchat" %} HipChat {% endif %}
|
||||||
{% if ch.kind == "pd" %} PagerDuty {% endif %}
|
{% if ch.kind == "pd" %} PagerDuty {% endif %}
|
||||||
{% if ch.kind == "po" %} Pushover {% endif %}
|
{% if ch.kind == "po" %} Pushover {% endif %}
|
||||||
|
{% if ch.kind == "victorops" %} VictorOps {% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="value-cell">
|
<td class="value-cell">
|
||||||
<span class="preposition">
|
<span class="preposition">
|
||||||
{% if ch.kind == "email" %} to {% endif %}
|
{% if ch.kind == "email" %} to {% endif %}
|
||||||
{% if ch.kind == "pd" %} API key {% endif %}
|
{% if ch.kind == "pd" %} API key {% endif %}
|
||||||
{% if ch.kind == "po" %} user key {% endif %}
|
{% if ch.kind == "po" %} user key {% endif %}
|
||||||
|
{% if ch.kind == "victorops" %} Post URL {% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{% if ch.kind == "po" %}
|
{% if ch.kind == "po" %}
|
||||||
@ -131,6 +133,15 @@
|
|||||||
|
|
||||||
<a href="{% url 'hc-add-hipchat' %}" class="btn btn-primary">Add Integration</a>
|
<a href="{% url 'hc-add-hipchat' %}" class="btn btn-primary">Add Integration</a>
|
||||||
</li>
|
</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 %}
|
{% if enable_pushover %}
|
||||||
<li>
|
<li>
|
||||||
<img src="{% static 'img/integrations/pushover.png' %}"
|
<img src="{% static 'img/integrations/pushover.png' %}"
|
||||||
|
105
templates/integrations/add_victorops.html
Normal file
105
templates/integrations/add_victorops.html
Normal 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
templates/integrations/victorops_description.html
Normal file
5
templates/integrations/victorops_description.html
Normal 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…
x
Reference in New Issue
Block a user