forked from GithubBackups/healthchecks
Merge pull request #143 from PagerTree/master
Creates a native PagerTree integration
This commit is contained in:
commit
975b7a05ae
@ -32,6 +32,7 @@ CHANNEL_KINDS = (("email", "Email"),
|
||||
("hipchat", "HipChat"),
|
||||
("slack", "Slack"),
|
||||
("pd", "PagerDuty"),
|
||||
("pagertree", "PagerTree"),
|
||||
("po", "Pushover"),
|
||||
("pushbullet", "Pushbullet"),
|
||||
("opsgenie", "OpsGenie"),
|
||||
@ -260,6 +261,8 @@ class Channel(models.Model):
|
||||
return transports.HipChat(self)
|
||||
elif self.kind == "pd":
|
||||
return transports.PagerDuty(self)
|
||||
elif self.kind == "pagertree":
|
||||
return transports.PagerTree(self)
|
||||
elif self.kind == "victorops":
|
||||
return transports.VictorOps(self)
|
||||
elif self.kind == "pushbullet":
|
||||
|
@ -283,6 +283,18 @@ class NotifyTestCase(BaseTestCase):
|
||||
self.assertEqual(payload["event_type"], "trigger")
|
||||
self.assertEqual(payload["service_key"], "456")
|
||||
|
||||
@patch("hc.api.transports.requests.request")
|
||||
def test_pagertree(self, mock_post):
|
||||
self._setup_data("pagertree", "123")
|
||||
mock_post.return_value.status_code = 200
|
||||
|
||||
self.channel.notify(self.check)
|
||||
assert Notification.objects.count() == 1
|
||||
|
||||
args, kwargs = mock_post.call_args
|
||||
payload = kwargs["json"]
|
||||
self.assertEqual(payload["event_type"], "trigger")
|
||||
|
||||
@patch("hc.api.transports.requests.request")
|
||||
def test_slack(self, mock_post):
|
||||
self._setup_data("slack", "123")
|
||||
|
@ -230,6 +230,24 @@ class PagerDuty(HttpTransport):
|
||||
|
||||
return self.post(self.URL, json=payload)
|
||||
|
||||
class PagerTree(HttpTransport):
|
||||
def notify(self, check):
|
||||
url = self.channel.value
|
||||
headers = {
|
||||
"Conent-Type": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"incident_key": str(check.code),
|
||||
"event_type": "trigger" if check.status == "down" else "resolve",
|
||||
"title": tmpl("pagertree_title.html", check=check),
|
||||
"description": tmpl("pagertree_description.html", check=check),
|
||||
"client": settings.SITE_NAME,
|
||||
"client_url": settings.SITE_ROOT,
|
||||
"tags": ",".join(check.tags_list())
|
||||
}
|
||||
|
||||
return self.post(url, json=payload, headers=headers)
|
||||
|
||||
|
||||
class Pushbullet(HttpTransport):
|
||||
def notify(self, check):
|
||||
|
29
hc/front/tests/test_add_pagertree.py
Normal file
29
hc/front/tests/test_add_pagertree.py
Normal file
@ -0,0 +1,29 @@
|
||||
from hc.api.models import Channel
|
||||
from hc.test import BaseTestCase
|
||||
|
||||
|
||||
class AddPagerTreeTestCase(BaseTestCase):
|
||||
url = "/integrations/add_pagertree/"
|
||||
|
||||
def test_instructions_work(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "PagerTree")
|
||||
|
||||
def test_it_works(self):
|
||||
form = {"value": "http://example.org"}
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, form)
|
||||
self.assertRedirects(r, "/integrations/")
|
||||
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "pagertree")
|
||||
self.assertEqual(c.value, "http://example.org")
|
||||
|
||||
def test_it_rejects_bad_url(self):
|
||||
form = {"value": "not an URL"}
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, form)
|
||||
self.assertContains(r, "Enter a valid URL")
|
@ -17,6 +17,7 @@ channel_urls = [
|
||||
url(r'^add_webhook/$', views.add_webhook, name="hc-add-webhook"),
|
||||
url(r'^add_pd/$', views.add_pd, name="hc-add-pd"),
|
||||
url(r'^add_pd/([\w]{12})/$', views.add_pd, name="hc-add-pd-state"),
|
||||
url(r'^add_pagertree/$', views.add_pagertree, name="hc-add-pagertree"),
|
||||
url(r'^add_slack/$', views.add_slack, name="hc-add-slack"),
|
||||
url(r'^add_slack_btn/$', views.add_slack_btn, name="hc-add-slack-btn"),
|
||||
url(r'^add_hipchat/$', views.add_hipchat, name="hc-add-hipchat"),
|
||||
|
@ -512,6 +512,23 @@ def add_pd(request, state=None):
|
||||
ctx = {"page": "channels", "connect_url": connect_url}
|
||||
return render(request, "integrations/add_pd.html", ctx)
|
||||
|
||||
@login_required
|
||||
def add_pagertree(request):
|
||||
if request.method == "POST":
|
||||
form = AddUrlForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="pagertree")
|
||||
channel.value = form.cleaned_data["value"]
|
||||
channel.save()
|
||||
|
||||
channel.assign_all_checks()
|
||||
return redirect("hc-channels")
|
||||
else:
|
||||
form = AddUrlForm()
|
||||
|
||||
ctx = {"page": "channels", "form": form}
|
||||
return render(request, "integrations/add_pagertree.html", ctx)
|
||||
|
||||
|
||||
def add_slack(request):
|
||||
if not settings.SLACK_CLIENT_ID and not request.user.is_authenticated:
|
||||
|
BIN
static/img/integrations/pagertree.png
Normal file
BIN
static/img/integrations/pagertree.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
static/img/integrations/setup_pagertree_1.png
Normal file
BIN
static/img/integrations/setup_pagertree_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
static/img/integrations/setup_pagertree_2.png
Normal file
BIN
static/img/integrations/setup_pagertree_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
BIN
static/img/integrations/setup_pagertree_3.png
Normal file
BIN
static/img/integrations/setup_pagertree_3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
@ -50,6 +50,9 @@
|
||||
{% endif %}
|
||||
<span class="preposition">service key</span>
|
||||
{{ ch.pd_service_key }}
|
||||
{% elif ch.kind == "pagertree" %}
|
||||
<span class="preposition">URL</span>
|
||||
{{ ch.value }}
|
||||
{% elif ch.kind == "opsgenie" %}
|
||||
<span class="preposition">API key</span>
|
||||
{{ ch.value }}
|
||||
@ -227,6 +230,15 @@
|
||||
<a href="{% url 'hc-add-pd' %}" class="btn btn-primary">Add Integration</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<img src="{% static 'img/integrations/pagertree.png' %}"
|
||||
class="icon" alt="PagerTree icon" />
|
||||
|
||||
<h2>PagerTree</h2>
|
||||
<p>DevOps Incident Management - On-Call Schedules, Alerts, & Notifications</p>
|
||||
|
||||
<a href="{% url 'hc-add-pagertree' %}" class="btn btn-primary">Add Integration</a>
|
||||
</li>
|
||||
<li>
|
||||
<img src="{% static 'img/integrations/hipchat.png' %}"
|
||||
class="icon" alt="HipChat icon" />
|
||||
|
@ -89,6 +89,8 @@
|
||||
{% endif %}
|
||||
{% elif event.channel.kind == "pd" %}
|
||||
Sent alert to PagerDuty
|
||||
{% elif event.channel.kind == "pagertree" %}
|
||||
Sent alert to PagerTree
|
||||
{% elif event.channel.kind == "opsgenie" %}
|
||||
Sent alert to OpsGenie
|
||||
{% elif event.channel.kind == "hipchat" %}
|
||||
|
@ -319,6 +319,13 @@
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<img width="22" height="22" alt="PagerTree icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAACW1BMVEVMaXEpr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Uor+Upr+Upr+Upr+Uor+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Uor+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Upr+Uor+Upr+UrsOUor+Upr+Upr+Upr+Upr+Upr+Upr+UssOUpr+Upr+Upr+Upr+Upr+Upr+U4tOcpr+Upr+Uor+UmruV6zO9QveossOVIuulNvOmW1/ElruUoruUuseY0s+Y3tOc7tedBt+hCuOhLu+lVv+pgw+x2y+98ze+Az++Cz++J0vCV1/GY2PKv4fWx4fW65fYqr+UtsOUtseYvseY5tec/tuhHuulKuulKu+lRvepSvupTvupcwetvyO5wye51yu5+zu+H0fCL0/CR1fGU1vGo3vSr3/S+5vYrsOUwsuYzsuYzs+Y1s+Y2tOc6tec7tuc9tuc+tuhCt+hDuOhEuehFuehHuelHuuhMu+lOvOlPvOlPvOpPvepRvupUv+pWv+pZwOtfwutgwuthw+xjxOxkxOxnxextyO1tyO5uyO1vyO1vye1xye5zyu50yu53y+94y+55zO55zO+Bz++D0O+F0O+G0e+H0vCI0vCO1PCO1PGP1PCP1fGS1fGV1vGU1/GX1/Kc2fKd2vKf2/Og2/Oj3POk3fOl3fOm3fSm3vSn3vOn3vSy4vW04/W24/W24/a75fbF6fh3jVHtAAAASXRSTlMAAgMEBQYHCAoLDhkaGy8wMTQ1OjtKWltfaG1tcXqEhYiLjY6Pl5mao6OkqKutubzLzNLT2NnZ3d3q6u/w8vP19/j5+vv8/f3+chuXrQAAAcJJREFUeNpjYAABRj4pXSNTUwN1cR4GBOCRNXb2BANbfTFOmKigHkQwHUTYqfJCRIUMPb2DPT29c6rzvLyCPN00uEGi3HqemTGRXl5ZiUf7vHtmZGQ4KbAChWVdvNrT1nhnrU329fPbkhq+aYGlKAMDn5GnV/ii5LkV1cXHZ5ZUdU2rneelw8Ug5eLpubwuek9t9P7d5YlhEwMLvTzNRRh0Pb28uzfHBSQdO1DpE+YbOD073dNDisEoZOlkL/+K+MVpc7y8fQMLy1NDgzyVGMwaa3YF1MXPmr9qe0tB4ISYlBW++Z66DKae2QmJ61KKPJu2JSWVJaQeXJ1SVa/JYOAZ3OCTsONIaUf8pOKtC31b2/wjPOUY1Dw9vULyp8ZU+vvkLCk7vNHPy8vLUYJBwh4o3r8+d2WeT0RsWk0AKFyM+Rh49IHCRSc2xPn7RCbvDQsGCSszMzCI2QHFc/cdivLpjI0OAomaCADDhEPVFRh8UTsDlkWUFHgDRW0kGUFByKvl5ukVGhfZ21w6BShsLcMOCXBeRSvP0Nhwb7/ZUd4eppJssOhhEdWxcM/09AxxMFbhZ0KKTS5haSVdbXkJPhYIHwDXP44RDT0o3QAAAABJRU5ErkJggg==" />
|
||||
</td>
|
||||
<td>Open and resolve incidents in <a href="https://pagertree.com/">PagerTree</a>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<img width="22" height="22" alt="HipChat icon" src="data:image/gif;base64,R0lGODdhLAAsAMIIAAQyZSFOez9ljWKEooOetqa2ycvV4P3//CwAAAAALAAsAAAD/ni63P4wykmrNUSIEMQghiUeRiEAaKqiQhGOjzGsNB0ML6ycdU8POkNg1SG4GKXBhpijEFatJqQ0VBUqhdUVllURJl2WbmHgobYx77jxTEXMwHVjhgo8wnF5w/xtpOx6D39sKX2BDWFoB1UAhxBVeQaFjg90gAdhUpSYbgptjZsNkigvbQKhDilbpqh+KH1tl60Hqp6ds6MAL5mia1JhDCl5CgACmhJlsgeWDGZ7rxZtw4sow2GGClUBIFME2oSkDdpNZSodHgNKjMWig+1i4D6T4rUOcA4yZlDTCnTsacKmYCBA0MCxA2aUvYM3RoiKgwvCvII4RUuFXHVwiMgVPYCig3V1uCHB0KTeCG/yaBiiwy9aSiYkbo0xAdKHMR4KgxQoQJDgTgw2PQbyR0NooAwgjR4yyNPIrKetEgAAOw==" />
|
||||
|
93
templates/integrations/add_pagertree.html
Normal file
93
templates/integrations/add_pagertree.html
Normal file
@ -0,0 +1,93 @@
|
||||
{% extends "base.html" %}
|
||||
{% load compress humanize staticfiles hc_extras %}
|
||||
|
||||
{% block title %}Add PagerTree - {% site_name %}{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h1>PagerTree</h1>
|
||||
|
||||
<p>If your team uses <a href="https://pagertree.com">PagerTree</a>,
|
||||
you can set up {% site_name %} to create a PagerTree incident when
|
||||
a check goes down, and resolve it when a check goes back up.</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 PagerTree account, select the team you wish to add this integration to. Click the <strong>Integrations</strong> tab. Then click the <strong>+ Integration</strong> button.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<img
|
||||
class="ai-guide-screenshot"
|
||||
alt="Click create integration button"
|
||||
src="{% static 'img/integrations/setup_pagertree_1.png' %}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row ai-step">
|
||||
<div class="col-sm-6">
|
||||
<span class="step-no">2</span>
|
||||
<p>
|
||||
In the Create Integration Form, fill out the details with apprpriate values, but most importantly make sure the <strong>Integration Type</strong> is set to <strong>Healthchecks.io</strong>. Then click the <strong>Create</strong> button.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<img
|
||||
class="ai-guide-screenshot"
|
||||
alt="Create Healthchecks.io integration with details"
|
||||
src="{% static 'img/integrations/setup_pagertree_2.png' %}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row ai-step">
|
||||
<div class="col-sm-6">
|
||||
<span class="step-no">3</span>
|
||||
<p>
|
||||
Copy the <strong>Webhook URL</strong> and paste it below. Save the integration, and you are done!
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<img
|
||||
class="ai-guide-screenshot"
|
||||
alt="Copy the Webhook URL"
|
||||
src="{% static 'img/integrations/setup_pagertree_3.png' %}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Integration Settings</h2>
|
||||
|
||||
<form method="post" class="form-horizontal" action="{% url 'hc-add-pagertree' %}">
|
||||
{% csrf_token %}
|
||||
<div class="form-group {{ form.value.css_classes }}">
|
||||
<label for="post-url" class="col-sm-2 control-label">URL</label>
|
||||
<div class="col-sm-10">
|
||||
<input
|
||||
id="post-url"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="value"
|
||||
placeholder="https://"
|
||||
value="{{ form.value.value|default:"" }}">
|
||||
|
||||
{% if form.value.errors %}
|
||||
<div class="help-block">
|
||||
{{ form.value.errors|join:"" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</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>
|
||||
{% endblock %}
|
5
templates/integrations/pagertree_description.html
Normal file
5
templates/integrations/pagertree_description.html
Normal file
@ -0,0 +1,5 @@
|
||||
{% load humanize %}
|
||||
{{ check.name_then_code }} is {{ check.status|upper }}.
|
||||
{% if check.status == "down" %}
|
||||
Last ping was {{ check.last_ping|naturaltime }}.
|
||||
{% endif %}
|
1
templates/integrations/pagertree_title.html
Normal file
1
templates/integrations/pagertree_title.html
Normal file
@ -0,0 +1 @@
|
||||
{{ check.name_then_code }} is {{ check.status|upper }}
|
Loading…
x
Reference in New Issue
Block a user