You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.5 KiB

  1. from django.conf import settings
  2. from django.template.loader import render_to_string
  3. from django.utils import timezone
  4. import json
  5. import requests
  6. from hc.lib import emails
  7. def tmpl(template_name, **ctx):
  8. template_path = "integrations/%s" % template_name
  9. return render_to_string(template_path, ctx).strip()
  10. class Transport(object):
  11. def __init__(self, channel):
  12. self.channel = channel
  13. def notify(self, check):
  14. """ Send notification about current status of the check.
  15. This method returns None on success, and error message
  16. on error.
  17. """
  18. raise NotImplementedError()
  19. def test(self):
  20. """ Send test message.
  21. This method returns None on success, and error message
  22. on error.
  23. """
  24. raise NotImplementedError()
  25. def checks(self):
  26. return self.channel.user.check_set.order_by("created")
  27. class Email(Transport):
  28. def notify(self, check):
  29. if not self.channel.email_verified:
  30. return "Email not verified"
  31. ctx = {
  32. "check": check,
  33. "checks": self.checks(),
  34. "now": timezone.now()
  35. }
  36. emails.alert(self.channel.value, ctx)
  37. class Webhook(Transport):
  38. def notify(self, check):
  39. # Webhook integration only fires when check goes down.
  40. if check.status != "down":
  41. return "no-op"
  42. # Webhook transport sends no arguments, so the
  43. # notify and test actions are the same
  44. return self.test()
  45. def test(self):
  46. headers = {"User-Agent": "healthchecks.io"}
  47. try:
  48. r = requests.get(self.channel.value, timeout=5, headers=headers)
  49. if r.status_code not in (200, 201):
  50. return "Received status code %d" % r.status_code
  51. except requests.exceptions.Timeout:
  52. # Well, we tried
  53. return "Connection timed out"
  54. except requests.exceptions.ConnectionError:
  55. return "A connection to %s failed" % self.channel.value
  56. class JsonTransport(Transport):
  57. def post(self, url, payload):
  58. headers = {"User-Agent": "healthchecks.io"}
  59. try:
  60. r = requests.post(url, json=payload, timeout=5, headers=headers)
  61. if r.status_code not in (200, 201):
  62. return "Received status code %d" % r.status_code
  63. except requests.exceptions.Timeout:
  64. # Well, we tried
  65. return "Connection timed out"
  66. except requests.exceptions.ConnectionError:
  67. return "A connection to %s failed" % url
  68. class Slack(JsonTransport):
  69. def notify(self, check):
  70. text = tmpl("slack_message.json", check=check)
  71. payload = json.loads(text)
  72. return self.post(self.channel.value, payload)
  73. class HipChat(JsonTransport):
  74. def notify(self, check):
  75. text = tmpl("hipchat_message.html", check=check)
  76. payload = {
  77. "message": text,
  78. "color": "green" if check.status == "up" else "red",
  79. }
  80. return self.post(self.channel.value, payload)
  81. class PagerDuty(JsonTransport):
  82. URL = "https://events.pagerduty.com/generic/2010-04-15/create_event.json"
  83. def notify(self, check):
  84. description = tmpl("pd_description.html", check=check)
  85. payload = {
  86. "service_key": self.channel.value,
  87. "incident_key": str(check.code),
  88. "event_type": "trigger" if check.status == "down" else "resolve",
  89. "description": description,
  90. "client": "healthchecks.io",
  91. "client_url": settings.SITE_ROOT
  92. }
  93. return self.post(self.URL, payload)
  94. class Pushover(JsonTransport):
  95. URL = "https://api.pushover.net/1/messages.json"
  96. def notify(self, check):
  97. others = self.checks().filter(status="down").exclude(code=check.code)
  98. ctx = {
  99. "check": check,
  100. "down_checks": others,
  101. }
  102. text = tmpl("pushover_message.html", **ctx)
  103. title = tmpl("pushover_title.html", **ctx)
  104. user_key, prio = self.channel.value.split("|")
  105. payload = {
  106. "token": settings.PUSHOVER_API_TOKEN,
  107. "user": user_key,
  108. "message": text,
  109. "title": title,
  110. "html": 1,
  111. "priority": int(prio),
  112. }
  113. # Emergency notification
  114. if prio == "2":
  115. payload["retry"] = settings.PUSHOVER_EMERGENCY_RETRY_DELAY
  116. payload["expire"] = settings.PUSHOVER_EMERGENCY_EXPIRATION
  117. return self.post(self.URL, payload)