Browse Source

Merge pull request #143 from PagerTree/master

Creates a native PagerTree integration
pull/149/head
Pēteris Caune 7 years ago
committed by GitHub
parent
commit
975b7a05ae
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 200 additions and 0 deletions
  1. +3
    -0
      hc/api/models.py
  2. +12
    -0
      hc/api/tests/test_notify.py
  3. +18
    -0
      hc/api/transports.py
  4. +29
    -0
      hc/front/tests/test_add_pagertree.py
  5. +1
    -0
      hc/front/urls.py
  6. +17
    -0
      hc/front/views.py
  7. BIN
      static/img/integrations/pagertree.png
  8. BIN
      static/img/integrations/setup_pagertree_1.png
  9. BIN
      static/img/integrations/setup_pagertree_2.png
  10. BIN
      static/img/integrations/setup_pagertree_3.png
  11. +12
    -0
      templates/front/channels.html
  12. +2
    -0
      templates/front/log.html
  13. +7
    -0
      templates/front/welcome.html
  14. +93
    -0
      templates/integrations/add_pagertree.html
  15. +5
    -0
      templates/integrations/pagertree_description.html
  16. +1
    -0
      templates/integrations/pagertree_title.html

+ 3
- 0
hc/api/models.py View File

@ -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":


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

@ -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")


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

@ -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
- 0
hc/front/tests/test_add_pagertree.py View 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="[email protected]", 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="[email protected]", 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="[email protected]", password="password")
r = self.client.post(self.url, form)
self.assertContains(r, "Enter a valid URL")

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

@ -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"),


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

@ -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 View File

Before After
Width: 133  |  Height: 133  |  Size: 4.4 KiB

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

Before After
Width: 471  |  Height: 163  |  Size: 4.7 KiB

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

Before After
Width: 605  |  Height: 488  |  Size: 9.7 KiB

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

Before After
Width: 659  |  Height: 77  |  Size: 2.9 KiB

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

@ -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, &amp; 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" />


+ 2
- 0
templates/front/log.html View File

@ -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" %}


+ 7
- 0
templates/front/welcome.html View File

@ -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
- 0
templates/integrations/add_pagertree.html View 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
- 0
templates/integrations/pagertree_description.html View 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
- 0
templates/integrations/pagertree_title.html View File

@ -0,0 +1 @@
{{ check.name_then_code }} is {{ check.status|upper }}

Loading…
Cancel
Save