diff --git a/promgen/prometheus.py b/promgen/prometheus.py index bab2518d6..144826309 100644 --- a/promgen/prometheus.py +++ b/promgen/prometheus.py @@ -276,20 +276,25 @@ def silence(*, labels, duration=None, **kwargs): end = start + datetime.timedelta(days=int(duration[:-1])) else: raise ValidationError("Unknown time modifier") + kwargs["startsAt"] = start.isoformat() kwargs["endsAt"] = end.isoformat() - kwargs.pop("startsAt", False) else: local_timezone = pytz.timezone(util.setting("timezone", "UTC")) for key in ["startsAt", "endsAt"]: kwargs[key] = local_timezone.localize(parser.parse(kwargs[key])).isoformat() kwargs["matchers"] = [ - {"name": name, "value": value, "isRegex": True if value.endswith("*") else False} + { + "name": name, + "value": value, + "isEqual": True, # Right now we only support =~ + "isRegex": True if value.endswith("*") else False, + } for name, value in labels.items() ] logger.debug("Sending silence for %s", kwargs) - url = urljoin(util.setting("alertmanager:url"), "/api/v1/silences") + url = urljoin(util.setting("alertmanager:url"), "/api/v2/silences") response = util.post(url, json=kwargs) response.raise_for_status() return response diff --git a/promgen/proxy.py b/promgen/proxy.py index b38f097b8..c08c3fa59 100644 --- a/promgen/proxy.py +++ b/promgen/proxy.py @@ -4,6 +4,7 @@ import concurrent.futures import json import logging +from http import HTTPStatus from urllib.parse import urljoin import requests @@ -168,11 +169,11 @@ def get(self, request): class ProxyAlerts(View): def get(self, request): try: - url = urljoin(util.setting("alertmanager:url"), "/api/v1/alerts") + url = urljoin(util.setting("alertmanager:url"), "/api/v2/alerts") response = util.get(url) except requests.exceptions.ConnectionError: logger.error("Error connecting to %s", url) - return JsonResponse({}) + return JsonResponse({}, status=HTTPStatus.INTERNAL_SERVER_ERROR) else: return HttpResponse(response.content, content_type="application/json") @@ -180,11 +181,11 @@ def get(self, request): class ProxySilences(View): def get(self, request): try: - url = urljoin(util.setting("alertmanager:url"), "/api/v1/silences") + url = urljoin(util.setting("alertmanager:url"), "/api/v2/silences") response = util.get(url, params={"silenced": False}) except requests.exceptions.ConnectionError: logger.error("Error connecting to %s", url) - return JsonResponse({}) + return JsonResponse({}, status=HTTPStatus.INTERNAL_SERVER_ERROR) else: return HttpResponse(response.content, content_type="application/json") @@ -203,15 +204,24 @@ def post(self, request): for m in form.errors[k] ] }, - status=422, + status=HTTPStatus.UNPROCESSABLE_ENTITY, ) try: response = prometheus.silence(**form.cleaned_data) + except requests.HTTPError as e: + return JsonResponse( + { + "messages": [ + {"class": "alert alert-danger", "message": e.response.text} + ] + }, + status=e.response.status_code, + ) except Exception as e: return JsonResponse( {"messages": [{"class": "alert alert-danger", "message": str(e)}]}, - status=400, + status=HTTPStatus.UNPROCESSABLE_ENTITY, ) return HttpResponse( @@ -221,7 +231,7 @@ def post(self, request): class ProxyDeleteSilence(View): def delete(self, request, silence_id): - url = urljoin(util.setting("alertmanager:url"), "/api/v1/silence/%s" % silence_id) + url = urljoin(util.setting("alertmanager:url"), f"/api/v2/silence/{silence_id}") response = util.delete(url) return HttpResponse( response.text, status=response.status_code, content_type="application/json" diff --git a/promgen/static/js/promgen.vue.js b/promgen/static/js/promgen.vue.js index 1381d3407..18b44b04e 100644 --- a/promgen/static/js/promgen.vue.js +++ b/promgen/static/js/promgen.vue.js @@ -86,7 +86,7 @@ const app = Vue.createApp({ fetch('/proxy/v1/silences') .then(response => response.json()) .then(response => { - let silences = response.data.sort(silence => silence.startsAt); + let silences = response.sort(silence => silence.startsAt); // Pull out the matchers and do a simpler label map // to make other code easier @@ -104,7 +104,7 @@ const app = Vue.createApp({ fetch('/proxy/v1/alerts') .then(response => response.json()) .then(response => { - this.globalAlerts = response.data.sort(alert => alert.startsAt); + this.globalAlerts = response.sort(alert => alert.startsAt); }); }, diff --git a/promgen/tests/__init__.py b/promgen/tests/__init__.py index a63fdc0b8..c5ec053c9 100644 --- a/promgen/tests/__init__.py +++ b/promgen/tests/__init__.py @@ -29,6 +29,7 @@ def raw(self): class PromgenTest(TestCase): longMessage = True + maxDiff = None fixtures = ["testcases.yaml"] def fireAlert(self, source="alertmanager.json", data=None): diff --git a/promgen/tests/examples/silence.duration.json b/promgen/tests/examples/silence.duration.json index 130aad19c..f468c9c9f 100644 --- a/promgen/tests/examples/silence.duration.json +++ b/promgen/tests/examples/silence.duration.json @@ -3,8 +3,10 @@ "matchers": [{ "value": "example.com:[0-9]*", "isRegex": true, + "isEqual": true, "name": "instance" }], "comment": "Silenced from Promgen", + "startsAt": "2017-12-14T00:00:00+00:00", "endsAt": "2017-12-14T00:01:00+00:00" } diff --git a/promgen/tests/examples/silence.range.json b/promgen/tests/examples/silence.range.json index 0459b9dc5..7277afc58 100644 --- a/promgen/tests/examples/silence.range.json +++ b/promgen/tests/examples/silence.range.json @@ -3,6 +3,7 @@ "matchers": [{ "value": "example.com:[0-9]*", "isRegex": true, + "isEqual": true, "name": "instance" }], "comment": "Silenced from Promgen", diff --git a/promgen/tests/test_silence.py b/promgen/tests/test_silence.py index 070ac2f95..9a76ac034 100644 --- a/promgen/tests/test_silence.py +++ b/promgen/tests/test_silence.py @@ -41,8 +41,8 @@ def test_duration(self, mock_post): }, content_type="application/json", ) - self.assertMockCalls( - mock_post, "http://alertmanager:9093/api/v1/silences", json=TEST_DURATION + mock_post.assert_called_with( + "http://alertmanager:9093/api/v2/silences", json=TEST_DURATION ) @override_settings(PROMGEN=TEST_SETTINGS) @@ -62,7 +62,9 @@ def test_range(self, mock_post): content_type="application/json", ) - self.assertMockCalls(mock_post, "http://alertmanager:9093/api/v1/silences", json=TEST_RANGE) + mock_post.assert_called_with( + "http://alertmanager:9093/api/v2/silences", json=TEST_RANGE + ) @override_settings(PROMGEN=TEST_SETTINGS) def test_site_silence_errors(self):