Skip to content

Commit

Permalink
[IMPROVEMENT] Update to Alertmanager v2 API #481
Browse files Browse the repository at this point in the history
  • Loading branch information
kfdm authored Feb 15, 2024
2 parents 011fbca + e1cf952 commit b87ed89
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 15 deletions.
11 changes: 8 additions & 3 deletions promgen/prometheus.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
24 changes: 17 additions & 7 deletions promgen/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import concurrent.futures
import json
import logging
from http import HTTPStatus
from urllib.parse import urljoin

import requests
Expand Down Expand Up @@ -168,23 +169,23 @@ 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")


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")

Expand All @@ -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(
Expand All @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions promgen/static/js/promgen.vue.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
});

},
Expand Down
1 change: 1 addition & 0 deletions promgen/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 2 additions & 0 deletions promgen/tests/examples/silence.duration.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
1 change: 1 addition & 0 deletions promgen/tests/examples/silence.range.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"matchers": [{
"value": "example.com:[0-9]*",
"isRegex": true,
"isEqual": true,
"name": "instance"
}],
"comment": "Silenced from Promgen",
Expand Down
8 changes: 5 additions & 3 deletions promgen/tests/test_silence.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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):
Expand Down

0 comments on commit b87ed89

Please sign in to comment.