Browse Source

Add Ping.exitstatus field, store received exit status values in db

Fixes #455
pull/456/head
Pēteris Caune 4 years ago
parent
commit
617bd92434
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
9 changed files with 59 additions and 8 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +23
    -0
      hc/api/migrations/0076_auto_20201128_0951.py
  3. +3
    -1
      hc/api/models.py
  4. +4
    -1
      hc/api/tests/test_ping.py
  5. +3
    -3
      hc/api/views.py
  6. +14
    -0
      hc/front/tests/test_ping_details.py
  7. +3
    -1
      templates/front/details_events.html
  8. +3
    -1
      templates/front/log.html
  9. +5
    -1
      templates/front/ping_details.html

+ 1
- 0
CHANGELOG.md View File

@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file.
- Require confirmation codes (sent to email) before sensitive actions
- Implement WebAuthn two-factor authentication
- Implement badge mode (up/down vs up/late/down) selector (#282)
- Add Ping.exitstatus field, store client's reported exit status values (#455)
## v1.17.0 - 2020-10-14


+ 23
- 0
hc/api/migrations/0076_auto_20201128_0951.py View File

@ -0,0 +1,23 @@
# Generated by Django 3.1.2 on 2020-11-28 09:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0075_auto_20200805_1004'),
]
operations = [
migrations.AddField(
model_name='ping',
name='exitstatus',
field=models.SmallIntegerField(null=True),
),
migrations.AlterField(
model_name='channel',
name='kind',
field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('pagerteam', 'Pager Team'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS'), ('zendesk', 'Zendesk'), ('trello', 'Trello'), ('matrix', 'Matrix'), ('whatsapp', 'WhatsApp'), ('apprise', 'Apprise'), ('mattermost', 'Mattermost'), ('msteams', 'Microsoft Teams'), ('shell', 'Shell Command'), ('zulip', 'Zulip'), ('spike', 'Spike'), ('call', 'Phone Call'), ('linenotify', 'LINE Notify')], max_length=20),
),
]

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

@ -252,7 +252,7 @@ class Check(models.Model):
return result
def ping(self, remote_addr, scheme, method, ua, body, action):
def ping(self, remote_addr, scheme, method, ua, body, action, exitstatus=None):
now = timezone.now()
if self.status == "paused" and self.manual_resume:
@ -299,6 +299,7 @@ class Check(models.Model):
# If User-Agent is longer than 200 characters, truncate it:
ping.ua = ua[:200]
ping.body = body[: settings.PING_BODY_LIMIT]
ping.exitstatus = exitstatus
ping.save()
def downtimes(self, months=3):
@ -351,6 +352,7 @@ class Ping(models.Model):
method = models.CharField(max_length=10, blank=True)
ua = models.CharField(max_length=200, blank=True)
body = models.TextField(blank=True, null=True)
exitstatus = models.SmallIntegerField(null=True)
def to_dict(self):
return {


+ 4
- 1
hc/api/tests/test_ping.py View File

@ -11,7 +11,7 @@ class PingTestCase(BaseTestCase):
def setUp(self):
super().setUp()
self.check = Check.objects.create(project=self.project)
self.url = "/ping/%s/" % self.check.code
self.url = "/ping/%s" % self.check.code
def test_it_works(self):
r = self.client.get(self.url)
@ -26,6 +26,7 @@ class PingTestCase(BaseTestCase):
self.assertEqual(ping.scheme, "http")
self.assertEqual(ping.kind, None)
self.assertEqual(ping.created, self.check.last_ping)
self.assertIsNone(ping.exitstatus)
def test_it_changes_status_of_paused_check(self):
self.check.status = "paused"
@ -234,6 +235,7 @@ class PingTestCase(BaseTestCase):
ping = Ping.objects.latest("id")
self.assertEqual(ping.kind, None)
self.assertEqual(ping.exitstatus, 0)
def test_nonzero_exit_status_works(self):
r = self.client.get("/ping/%s/123" % self.check.code)
@ -244,3 +246,4 @@ class PingTestCase(BaseTestCase):
ping = Ping.objects.latest("id")
self.assertEqual(ping.kind, "fail")
self.assertEqual(ping.exitstatus, 123)

+ 3
- 3
hc/api/views.py View File

@ -30,7 +30,7 @@ class BadChannelException(Exception):
@csrf_exempt
@never_cache
def ping(request, code, action="success", exitstatus=0):
def ping(request, code, action="success", exitstatus=None):
check = get_object_or_404(Check, code=code)
headers = request.META
@ -41,13 +41,13 @@ def ping(request, code, action="success", exitstatus=0):
ua = headers.get("HTTP_USER_AGENT", "")
body = request.body.decode()
if exitstatus > 0:
if exitstatus is not None and exitstatus > 0:
action = "fail"
if check.methods == "POST" and method != "POST":
action = "ign"
check.ping(remote_addr, scheme, method, ua, body, action)
check.ping(remote_addr, scheme, method, ua, body, action, exitstatus)
response = HttpResponse("OK")
response["Access-Control-Allow-Origin"] = "*"


+ 14
- 0
hc/front/tests/test_ping_details.py View File

@ -59,3 +59,17 @@ class PingDetailsTestCase(BaseTestCase):
self.client.login(username="[email protected]", password="password")
r = self.client.get("/checks/%s/pings/123/" % self.check.code)
self.assertContains(r, "No additional information is", status_code=200)
def test_it_shows_nonzero_exitstatus(self):
Ping.objects.create(owner=self.check, kind="fail", exitstatus=42)
self.client.login(username="[email protected]", password="password")
r = self.client.get(self.url)
self.assertContains(r, "(failure, exit status 42)", status_code=200)
def test_it_shows_zero_exitstatus(self):
Ping.objects.create(owner=self.check, exitstatus=0)
self.client.login(username="[email protected]", password="password")
r = self.client.get(self.url)
self.assertContains(r, "(exit status 0)", status_code=200)

+ 3
- 1
templates/front/details_events.html View File

@ -10,7 +10,9 @@
<td class="date"></td>
<td class="time"></td>
<td class="event">
{% if event.kind == "fail" %}
{% if event.exitstatus > 0 %}
<span class="label label-danger">Status {{ event.exitstatus }}</span>
{% elif event.kind == "fail" %}
<span class="label label-danger">Failure</span>
{% elif event.kind == "start" %}
<span class="label label-start">Started</span>


+ 3
- 1
templates/front/log.html View File

@ -51,7 +51,9 @@
<td class="date"></td>
<td class="time"></td>
<td class="event">
{% if event.kind == "fail" %}
{% if event.exitstatus %}
<span class="label label-danger">Status {{ event.exitstatus }}</span>
{% elif event.kind == "fail" %}
<span class="label label-danger">Failure</span>
{% elif event.kind == "start" %}
<span class="label label-start">Started</span>


+ 5
- 1
templates/front/ping_details.html View File

@ -1,6 +1,10 @@
<div class="modal-body">
<h3>Ping #{{ ping.n }}
{% if ping.kind == "fail" %}
{% if ping.exitstatus > 0 %}
<span class="text-danger">(failure, exit status {{ ping.exitstatus }})</span>
{% elif ping.exitstatus == 0 %}
<span class="text-success">(exit status 0)</span>
{% elif ping.kind == "fail" %}
<span class="text-danger">(received via the <code>/fail</code> endpoint)</span>
{% elif ping.kind == "start" %}
<span class="text-success">(received via the <code>/start</code> endpoint)</span>


Loading…
Cancel
Save