Browse Source

Add support for OpsGenie EU region. Fixes #294

pull/307/head
Pēteris Caune 5 years ago
parent
commit
1dea8b6050
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
9 changed files with 118 additions and 17 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +18
    -0
      hc/api/models.py
  3. +11
    -0
      hc/api/tests/test_channel_model.py
  4. +15
    -1
      hc/api/tests/test_notify.py
  5. +15
    -5
      hc/api/transports.py
  6. +2
    -1
      hc/front/forms.py
  7. +20
    -4
      hc/front/tests/test_add_opsgenie.py
  8. +3
    -2
      hc/front/views.py
  9. +33
    -4
      templates/integrations/add_opsgenie.html

+ 1
- 0
CHANGELOG.md View File

@ -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 - 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 - 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 - Autofocus the email field in the signup form, and submit on enter key
- Add support for OpsGenie EU region (#294)
### Bug Fixes ### Bug Fixes
- Prevent double-clicking the submit button in signup form - Prevent double-clicking the submit button in signup form


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

@ -650,6 +650,24 @@ class Channel(models.Model):
doc = json.loads(self.value) doc = json.loads(self.value)
return doc["down"] 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 Notification(models.Model):
class Meta: class Meta:


+ 11
- 0
hc/api/tests/test_channel_model.py View File

@ -149,3 +149,14 @@ class ChannelModelTestCase(BaseTestCase):
"headers": {"X-Status": "OK"}, "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")

+ 15
- 1
hc/api/tests/test_notify.py View File

@ -421,7 +421,7 @@ class NotifyTestCase(BaseTestCase):
self.assertEqual(Notification.objects.count(), 0) self.assertEqual(Notification.objects.count(), 0)
@patch("hc.api.transports.requests.request") @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") self._setup_data("opsgenie", "123")
mock_post.return_value.status_code = 202 mock_post.return_value.status_code = 202
@ -431,6 +431,7 @@ class NotifyTestCase(BaseTestCase):
self.assertEqual(mock_post.call_count, 1) self.assertEqual(mock_post.call_count, 1)
args, kwargs = mock_post.call_args args, kwargs = mock_post.call_args
self.assertIn("api.opsgenie.com", args[1])
payload = kwargs["json"] payload = kwargs["json"]
self.assertIn("DOWN", payload["message"]) self.assertIn("DOWN", payload["message"])
@ -448,6 +449,19 @@ class NotifyTestCase(BaseTestCase):
method, url = args method, url = args
self.assertTrue(str(self.check.code) in url) 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") @patch("hc.api.transports.requests.request")
def test_pushover(self, mock_post): def test_pushover(self, mock_post):
self._setup_data("po", "123|0") self._setup_data("po", "123|0")


+ 15
- 5
hc/api/transports.py View File

@ -223,7 +223,7 @@ class OpsGenie(HttpTransport):
def notify(self, check): def notify(self, check):
headers = { headers = {
"Conent-Type": "application/json", "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} payload = {"alias": str(check.code), "source": settings.SITE_NAME}
@ -235,6 +235,9 @@ class OpsGenie(HttpTransport):
payload["description"] = tmpl("opsgenie_description.html", check=check) payload["description"] = tmpl("opsgenie_description.html", check=check)
url = "https://api.opsgenie.com/v2/alerts" 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": if check.status == "up":
url += "/%s/close?identifierType=alias" % check.code url += "/%s/close?identifierType=alias" % check.code
@ -468,6 +471,7 @@ class Trello(HttpTransport):
return self.post(self.URL, params=params) return self.post(self.URL, params=params)
class Apprise(HttpTransport): class Apprise(HttpTransport):
def notify(self, check): def notify(self, check):
@ -481,8 +485,14 @@ class Apprise(HttpTransport):
a.add(self.channel.value) 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
)

+ 2
- 1
hc/front/forms.py View File

@ -85,7 +85,8 @@ class CronForm(forms.Form):
class AddOpsGenieForm(forms.Form): class AddOpsGenieForm(forms.Form):
error_css_class = "has-error" 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): class AddEmailForm(forms.Form):


+ 20
- 4
hc/front/tests/test_add_opsgenie.py View File

@ -1,3 +1,5 @@
import json
from hc.api.models import Channel from hc.api.models import Channel
from hc.test import BaseTestCase from hc.test import BaseTestCase
@ -11,7 +13,7 @@ class AddOpsGenieTestCase(BaseTestCase):
self.assertContains(r, "escalation policies and incident tracking") self.assertContains(r, "escalation policies and incident tracking")
def test_it_works(self): def test_it_works(self):
form = {"value": "123456"}
form = {"key": "123456", "region": "us"}
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
r = self.client.post(self.url, form) r = self.client.post(self.url, form)
@ -19,14 +21,28 @@ class AddOpsGenieTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.kind, "opsgenie") 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) self.assertEqual(c.project, self.project)
def test_it_trims_whitespace(self): def test_it_trims_whitespace(self):
form = {"value": " 123456 "}
form = {"key": " 123456 ", "region": "us"}
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
self.client.post(self.url, form) self.client.post(self.url, form)
c = Channel.objects.get() 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="[email protected]", password="password")
r = self.client.post(self.url, form)
c = Channel.objects.get()
payload = json.loads(c.value)
self.assertEqual(payload["region"], "eu")

+ 3
- 2
hc/front/views.py View File

@ -1138,13 +1138,14 @@ def add_opsgenie(request):
form = AddOpsGenieForm(request.POST) form = AddOpsGenieForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(project=request.project, kind="opsgenie") 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.save()
channel.assign_all_checks() channel.assign_all_checks()
return redirect("hc-channels") return redirect("hc-channels")
else: else:
form = AddUrlForm()
form = AddOpsGenieForm()
ctx = {"page": "channels", "project": request.project, "form": form} ctx = {"page": "channels", "project": request.project, "form": form}
return render(request, "integrations/add_opsgenie.html", ctx) return render(request, "integrations/add_opsgenie.html", ctx)


+ 33
- 4
templates/integrations/add_opsgenie.html View File

@ -71,13 +71,42 @@
id="api-key" id="api-key"
type="text" type="text"
class="form-control" class="form-control"
name="value"
name="key"
placeholder="" placeholder=""
value="{{ form.value.value|default:"" }}">
value="{{ form.key.value|default:"" }}">
{% if form.value.errors %}
{% if form.key.errors %}
<div class="help-block"> <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> </div>
{% endif %} {% endif %}
</div> </div>


Loading…
Cancel
Save