forked from GithubBackups/healthchecks
Add support for OpsGenie EU region. Fixes #294
This commit is contained in:
parent
4625196ded
commit
1dea8b6050
@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Send monthly reports on 1st of every month, not randomly during the month
|
||||
- Signup form sets the "auto-login" cookie to avoid an extra click during first login
|
||||
- Autofocus the email field in the signup form, and submit on enter key
|
||||
- Add support for OpsGenie EU region (#294)
|
||||
|
||||
### Bug Fixes
|
||||
- Prevent double-clicking the submit button in signup form
|
||||
|
@ -650,6 +650,24 @@ class Channel(models.Model):
|
||||
doc = json.loads(self.value)
|
||||
return doc["down"]
|
||||
|
||||
@property
|
||||
def opsgenie_key(self):
|
||||
assert self.kind == "opsgenie"
|
||||
if not self.value.startswith("{"):
|
||||
return self.value
|
||||
|
||||
doc = json.loads(self.value)
|
||||
return doc["key"]
|
||||
|
||||
@property
|
||||
def opsgenie_region(self):
|
||||
assert self.kind == "opsgenie"
|
||||
if not self.value.startswith("{"):
|
||||
return "us"
|
||||
|
||||
doc = json.loads(self.value)
|
||||
return doc["region"]
|
||||
|
||||
|
||||
class Notification(models.Model):
|
||||
class Meta:
|
||||
|
@ -149,3 +149,14 @@ class ChannelModelTestCase(BaseTestCase):
|
||||
"headers": {"X-Status": "OK"},
|
||||
},
|
||||
)
|
||||
|
||||
def test_it_handles_legacy_opsgenie_value(self):
|
||||
c = Channel(kind="opsgenie", value="foo123")
|
||||
self.assertEqual(c.opsgenie_key, "foo123")
|
||||
self.assertEqual(c.opsgenie_region, "us")
|
||||
|
||||
def test_it_handles_json_opsgenie_value(self):
|
||||
c = Channel(kind="opsgenie")
|
||||
c.value = json.dumps({"key": "abc", "region": "eu"})
|
||||
self.assertEqual(c.opsgenie_key, "abc")
|
||||
self.assertEqual(c.opsgenie_region, "eu")
|
||||
|
@ -421,7 +421,7 @@ class NotifyTestCase(BaseTestCase):
|
||||
self.assertEqual(Notification.objects.count(), 0)
|
||||
|
||||
@patch("hc.api.transports.requests.request")
|
||||
def test_opsgenie(self, mock_post):
|
||||
def test_opsgenie_with_legacy_value(self, mock_post):
|
||||
self._setup_data("opsgenie", "123")
|
||||
mock_post.return_value.status_code = 202
|
||||
|
||||
@ -431,6 +431,7 @@ class NotifyTestCase(BaseTestCase):
|
||||
|
||||
self.assertEqual(mock_post.call_count, 1)
|
||||
args, kwargs = mock_post.call_args
|
||||
self.assertIn("api.opsgenie.com", args[1])
|
||||
payload = kwargs["json"]
|
||||
self.assertIn("DOWN", payload["message"])
|
||||
|
||||
@ -448,6 +449,19 @@ class NotifyTestCase(BaseTestCase):
|
||||
method, url = args
|
||||
self.assertTrue(str(self.check.code) in url)
|
||||
|
||||
@patch("hc.api.transports.requests.request")
|
||||
def test_opsgenie_with_json_value(self, mock_post):
|
||||
self._setup_data("opsgenie", json.dumps({"key": "456", "region": "eu"}))
|
||||
mock_post.return_value.status_code = 202
|
||||
|
||||
self.channel.notify(self.check)
|
||||
n = Notification.objects.first()
|
||||
self.assertEqual(n.error, "")
|
||||
|
||||
self.assertEqual(mock_post.call_count, 1)
|
||||
args, kwargs = mock_post.call_args
|
||||
self.assertIn("api.eu.opsgenie.com", args[1])
|
||||
|
||||
@patch("hc.api.transports.requests.request")
|
||||
def test_pushover(self, mock_post):
|
||||
self._setup_data("po", "123|0")
|
||||
|
@ -223,7 +223,7 @@ class OpsGenie(HttpTransport):
|
||||
def notify(self, check):
|
||||
headers = {
|
||||
"Conent-Type": "application/json",
|
||||
"Authorization": "GenieKey %s" % self.channel.value,
|
||||
"Authorization": "GenieKey %s" % self.channel.opsgenie_key,
|
||||
}
|
||||
|
||||
payload = {"alias": str(check.code), "source": settings.SITE_NAME}
|
||||
@ -235,6 +235,9 @@ class OpsGenie(HttpTransport):
|
||||
payload["description"] = tmpl("opsgenie_description.html", check=check)
|
||||
|
||||
url = "https://api.opsgenie.com/v2/alerts"
|
||||
if self.channel.opsgenie_region == "eu":
|
||||
url = "https://api.eu.opsgenie.com/v2/alerts"
|
||||
|
||||
if check.status == "up":
|
||||
url += "/%s/close?identifierType=alias" % check.code
|
||||
|
||||
@ -468,6 +471,7 @@ class Trello(HttpTransport):
|
||||
|
||||
return self.post(self.URL, params=params)
|
||||
|
||||
|
||||
class Apprise(HttpTransport):
|
||||
def notify(self, check):
|
||||
|
||||
@ -481,8 +485,14 @@ class Apprise(HttpTransport):
|
||||
|
||||
a.add(self.channel.value)
|
||||
|
||||
notify_type = apprise.NotifyType.SUCCESS \
|
||||
if check.status == "up" else apprise.NotifyType.FAILURE
|
||||
notify_type = (
|
||||
apprise.NotifyType.SUCCESS
|
||||
if check.status == "up"
|
||||
else apprise.NotifyType.FAILURE
|
||||
)
|
||||
|
||||
return "Failed" if not \
|
||||
a.notify(body=body, title=title, notify_type=notify_type) else None
|
||||
return (
|
||||
"Failed"
|
||||
if not a.notify(body=body, title=title, notify_type=notify_type)
|
||||
else None
|
||||
)
|
||||
|
@ -85,7 +85,8 @@ class CronForm(forms.Form):
|
||||
|
||||
class AddOpsGenieForm(forms.Form):
|
||||
error_css_class = "has-error"
|
||||
value = forms.CharField(max_length=40)
|
||||
region = forms.ChoiceField(initial="us", choices=(("us", "US"), ("eu", "EU")))
|
||||
key = forms.CharField(max_length=40)
|
||||
|
||||
|
||||
class AddEmailForm(forms.Form):
|
||||
|
@ -1,3 +1,5 @@
|
||||
import json
|
||||
|
||||
from hc.api.models import Channel
|
||||
from hc.test import BaseTestCase
|
||||
|
||||
@ -11,7 +13,7 @@ class AddOpsGenieTestCase(BaseTestCase):
|
||||
self.assertContains(r, "escalation policies and incident tracking")
|
||||
|
||||
def test_it_works(self):
|
||||
form = {"value": "123456"}
|
||||
form = {"key": "123456", "region": "us"}
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, form)
|
||||
@ -19,14 +21,28 @@ class AddOpsGenieTestCase(BaseTestCase):
|
||||
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "opsgenie")
|
||||
self.assertEqual(c.value, "123456")
|
||||
|
||||
payload = json.loads(c.value)
|
||||
self.assertEqual(payload["key"], "123456")
|
||||
self.assertEqual(payload["region"], "us")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
def test_it_trims_whitespace(self):
|
||||
form = {"value": " 123456 "}
|
||||
form = {"key": " 123456 ", "region": "us"}
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
self.client.post(self.url, form)
|
||||
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.value, "123456")
|
||||
payload = json.loads(c.value)
|
||||
self.assertEqual(payload["key"], "123456")
|
||||
|
||||
def test_it_saves_eu_region(self):
|
||||
form = {"key": "123456", "region": "eu"}
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, form)
|
||||
|
||||
c = Channel.objects.get()
|
||||
payload = json.loads(c.value)
|
||||
self.assertEqual(payload["region"], "eu")
|
||||
|
@ -1138,13 +1138,14 @@ def add_opsgenie(request):
|
||||
form = AddOpsGenieForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(project=request.project, kind="opsgenie")
|
||||
channel.value = form.cleaned_data["value"]
|
||||
v = {"region": form.cleaned_data["region"], "key": form.cleaned_data["key"]}
|
||||
channel.value = json.dumps(v)
|
||||
channel.save()
|
||||
|
||||
channel.assign_all_checks()
|
||||
return redirect("hc-channels")
|
||||
else:
|
||||
form = AddUrlForm()
|
||||
form = AddOpsGenieForm()
|
||||
|
||||
ctx = {"page": "channels", "project": request.project, "form": form}
|
||||
return render(request, "integrations/add_opsgenie.html", ctx)
|
||||
|
@ -71,13 +71,42 @@
|
||||
id="api-key"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="value"
|
||||
name="key"
|
||||
placeholder=""
|
||||
value="{{ form.value.value|default:"" }}">
|
||||
value="{{ form.key.value|default:"" }}">
|
||||
|
||||
{% if form.value.errors %}
|
||||
{% if form.key.errors %}
|
||||
<div class="help-block">
|
||||
{{ form.value.errors|join:"" }}
|
||||
{{ form.key.errors|join:"" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group {{ form.region.css_classes }}">
|
||||
<label for="api-key" class="col-sm-2 control-label">Region</label>
|
||||
<div class="col-sm-4">
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="region"
|
||||
value="us"
|
||||
{% if form.region.value == "us" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
US (default)
|
||||
</label>
|
||||
<label class="radio-container">
|
||||
<input
|
||||
type="radio"
|
||||
name="region"
|
||||
value="eu"
|
||||
{% if form.region.value == "eu" %} checked {% endif %}>
|
||||
<span class="radiomark"></span>
|
||||
EU
|
||||
</label>
|
||||
|
||||
{% if form.region.errors %}
|
||||
<div class="help-block">
|
||||
{{ form.region.errors|join:"" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user