improve errors for alertmanager

This commit is contained in:
HgO 2022-07-09 10:38:40 +02:00
parent 5d2d109da1
commit 687afe32ef
5 changed files with 37 additions and 156 deletions

View file

@ -9,7 +9,7 @@ from aiohttp import ClientError
from diskcache import Cache from diskcache import Cache
from matrix_alertbot.errors import ( from matrix_alertbot.errors import (
AlertmanagerError, AlertmanagerServerError,
AlertNotFoundError, AlertNotFoundError,
SilenceNotFoundError, SilenceNotFoundError,
) )
@ -30,7 +30,9 @@ class AlertmanagerClient:
response.raise_for_status() response.raise_for_status()
return await response.json() return await response.json()
except ClientError as e: except ClientError as e:
raise AlertmanagerError(f"Cannot fetch alerts from Alertmanager") from e raise AlertmanagerServerError(
f"Cannot fetch alerts from Alertmanager"
) from e
async def get_alert(self, fingerprint: str) -> Dict: async def get_alert(self, fingerprint: str) -> Dict:
alerts = await self.get_alerts() alerts = await self.get_alerts()
@ -66,7 +68,7 @@ class AlertmanagerClient:
response.raise_for_status() response.raise_for_status()
data = await response.json() data = await response.json()
except ClientError as e: except ClientError as e:
raise AlertmanagerError( raise AlertmanagerServerError(
f"Cannot create silence for alert fingerprint {fingerprint}" f"Cannot create silence for alert fingerprint {fingerprint}"
) from e ) from e
@ -93,7 +95,9 @@ class AlertmanagerClient:
) as response: ) as response:
response.raise_for_status() response.raise_for_status()
except ClientError as e: except ClientError as e:
raise AlertmanagerError(f"Cannot delete silence with ID {silence}") from e raise AlertmanagerServerError(
f"Cannot delete silence with ID {silence}"
) from e
@staticmethod @staticmethod
def _find_alert(fingerprint: str, alerts: List[Dict]) -> Dict: def _find_alert(fingerprint: str, alerts: List[Dict]) -> Dict:

View file

@ -6,11 +6,7 @@ from nio import AsyncClient, MatrixRoom, RoomMessageText
from matrix_alertbot.alertmanager import AlertmanagerClient from matrix_alertbot.alertmanager import AlertmanagerClient
from matrix_alertbot.chat_functions import react_to_event, send_text_to_room from matrix_alertbot.chat_functions import react_to_event, send_text_to_room
from matrix_alertbot.config import Config from matrix_alertbot.config import Config
from matrix_alertbot.errors import ( from matrix_alertbot.errors import AlertmanagerError
AlertmanagerError,
AlertNotFoundError,
SilenceNotFoundError,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -93,7 +89,7 @@ class Command:
alert_fingerprint, duration, self.room.user_name(self.event.sender) alert_fingerprint, duration, self.room.user_name(self.event.sender)
) )
count_created_silences += 1 count_created_silences += 1
except (AlertNotFoundError, AlertmanagerError) as e: except AlertmanagerError as e:
logger.exception(f"Unable to create silence: {e}", exc_info=e) logger.exception(f"Unable to create silence: {e}", exc_info=e)
await send_text_to_room( await send_text_to_room(
@ -128,7 +124,7 @@ class Command:
alert_fingerprint alert_fingerprint
) )
count_removed_silences += len(removed_silences) count_removed_silences += len(removed_silences)
except (AlertNotFoundError, SilenceNotFoundError, AlertmanagerError) as e: except AlertmanagerError as e:
logger.exception(f"Unable to delete silence: {e}", exc_info=e) logger.exception(f"Unable to delete silence: {e}", exc_info=e)
await send_text_to_room( await send_text_to_room(

View file

@ -1,29 +1,31 @@
# This file holds custom error types that you can define for your application. # This file holds custom error types that you can define for your application.
class ConfigError(RuntimeError): class ConfigError(Exception):
"""An error encountered during reading the config file. """An error encountered during reading the config file."""
Args:
msg: The message displayed to the user on error.
"""
pass pass
class AlertNotFoundError(RuntimeError): class AlertmanagerError(Exception):
"""An error encountered when an alert cannot be found in database. """An error encountered with Alertmanager."""
Args:
msg: The message displayed to the user on error.
"""
pass pass
class SilenceNotFoundError(RuntimeError): class AlertNotFoundError(AlertmanagerError):
"""An error encountered when an alert cannot be found in Alertmanager."""
pass pass
class AlertmanagerError(RuntimeError): class SilenceNotFoundError(AlertmanagerError):
"""An error encountered when a silence cannot be found in Alertmanager."""
pass
class AlertmanagerServerError(AlertmanagerError):
"""An error encountered with Alertmanager server."""
pass pass

View file

@ -13,7 +13,7 @@ from diskcache import Cache
from matrix_alertbot.alertmanager import AlertmanagerClient from matrix_alertbot.alertmanager import AlertmanagerClient
from matrix_alertbot.errors import ( from matrix_alertbot.errors import (
AlertmanagerError, AlertmanagerServerError,
AlertNotFoundError, AlertNotFoundError,
SilenceNotFoundError, SilenceNotFoundError,
) )
@ -163,7 +163,7 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
f"http://localhost:{port}", self.fake_cache f"http://localhost:{port}", self.fake_cache
) )
async with aiotools.closing_async(alertmanager) as alertmanager: async with aiotools.closing_async(alertmanager) as alertmanager:
with self.assertRaises(AlertmanagerError): with self.assertRaises(AlertmanagerServerError):
await alertmanager.get_alerts() await alertmanager.get_alerts()
async def test_get_alert_happy(self) -> None: async def test_get_alert_happy(self) -> None:
@ -200,7 +200,7 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
f"http://localhost:{port}", self.fake_cache f"http://localhost:{port}", self.fake_cache
) )
async with aiotools.closing_async(alertmanager) as alertmanager: async with aiotools.closing_async(alertmanager) as alertmanager:
with self.assertRaises(AlertmanagerError): with self.assertRaises(AlertmanagerServerError):
await alertmanager.get_alert("fingerprint1") await alertmanager.get_alert("fingerprint1")
async def test_create_silence_happy(self) -> None: async def test_create_silence_happy(self) -> None:
@ -234,7 +234,7 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
async with aiotools.closing_async(alertmanager) as alertmanager: async with aiotools.closing_async(alertmanager) as alertmanager:
await alertmanager.get_alert("fingerprint1") await alertmanager.get_alert("fingerprint1")
with self.assertRaises(AlertmanagerError): with self.assertRaises(AlertmanagerServerError):
await alertmanager.create_silence("fingerprint1", "1d", "user") await alertmanager.create_silence("fingerprint1", "1d", "user")
async def test_delete_silences_happy(self) -> None: async def test_delete_silences_happy(self) -> None:
@ -276,7 +276,7 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
async with aiotools.closing_async(alertmanager) as alertmanager: async with aiotools.closing_async(alertmanager) as alertmanager:
await alertmanager.get_alert("fingerprint1") await alertmanager.get_alert("fingerprint1")
with self.assertRaises(AlertmanagerError): with self.assertRaises(AlertmanagerServerError):
await alertmanager.delete_silences("fingerprint2") await alertmanager.delete_silences("fingerprint2")
async def test_find_alert_happy(self) -> None: async def test_find_alert_happy(self) -> None:

View file

@ -8,20 +8,16 @@ from diskcache import Cache
import matrix_alertbot.callback import matrix_alertbot.callback
from matrix_alertbot.alertmanager import AlertmanagerClient from matrix_alertbot.alertmanager import AlertmanagerClient
from matrix_alertbot.command import Command from matrix_alertbot.command import Command
from matrix_alertbot.errors import ( from matrix_alertbot.errors import AlertmanagerError
AlertmanagerError,
AlertNotFoundError,
SilenceNotFoundError,
)
from tests.utils import make_awaitable from tests.utils import make_awaitable
async def create_silence_raise_alert_not_found( async def create_silence_raise_alert_manager_error(
fingerprint: str, duration: str, user: str fingerprint: str, duration: str, user: str
) -> str: ) -> str:
if fingerprint == "fingerprint1": if fingerprint == "fingerprint1":
raise AlertNotFoundError raise AlertmanagerError
return "silence1" return "silence1"
@ -33,22 +29,10 @@ async def create_silence_raise_alertmanager_error(
return "silence2" return "silence2"
async def delete_silence_raise_silence_not_found(fingerprint: str) -> List[str]:
if fingerprint == "fingerprint1":
raise SilenceNotFoundError
return ["silence1"]
async def delete_silence_raise_alert_not_found(fingerprint: str) -> List[str]:
if fingerprint == "fingerprint1":
raise AlertNotFoundError
return ["silence1", "silence2"]
async def delete_silence_raise_alertmanager_error(fingerprint: str) -> List[str]: async def delete_silence_raise_alertmanager_error(fingerprint: str) -> List[str]:
if fingerprint == "fingerprint1": if fingerprint == "fingerprint1":
raise AlertmanagerError raise AlertmanagerError
return ["silence1", "silence2", "silence3"] return ["silence1"]
class CommandTestCase(unittest.IsolatedAsyncioTestCase): class CommandTestCase(unittest.IsolatedAsyncioTestCase):
@ -283,47 +267,6 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
"Created 2 silences with a duration of 2d.", "Created 2 silences with a duration of 2d.",
) )
@patch.object(matrix_alertbot.command, "send_text_to_room")
async def test_ack_raise_alert_not_found(
self, fake_send_text_to_room: Mock
) -> None:
"""Tests the callback for InviteMemberEvents"""
# Tests that the bot attempts to join a room after being invited to it
self.fake_message_event.source = self.fake_source_in_reply
command = Command(
self.fake_client,
self.fake_cache,
self.fake_alertmanager,
self.fake_config,
"ack",
self.fake_room,
self.fake_message_event,
)
self.fake_alertmanager.create_silence.side_effect = (
create_silence_raise_alert_not_found
)
await command._ack()
# Check that we attempted to create silences
self.fake_alertmanager.create_silence.assert_has_calls(
[
call(
fingerprint,
"1d",
self.fake_message_event.sender,
)
for fingerprint in self.fake_fingerprints
]
)
fake_send_text_to_room.assert_called_once_with(
self.fake_client,
self.fake_room.room_id,
"Created 1 silences with a duration of 1d.",
)
@patch.object(matrix_alertbot.command, "send_text_to_room") @patch.object(matrix_alertbot.command, "send_text_to_room")
async def test_ack_raise_alertmanager_error( async def test_ack_raise_alertmanager_error(
self, fake_send_text_to_room: Mock self, fake_send_text_to_room: Mock
@ -391,70 +334,6 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
self.fake_client, self.fake_room.room_id, "Removed 4 silences." self.fake_client, self.fake_room.room_id, "Removed 4 silences."
) )
@patch.object(matrix_alertbot.command, "send_text_to_room")
async def test_unack_raise_silence_not_found(
self, fake_send_text_to_room: Mock
) -> None:
"""Tests the callback for InviteMemberEvents"""
# Tests that the bot attempts to join a room after being invited to it
self.fake_message_event.source = self.fake_source_in_reply
command = Command(
self.fake_client,
self.fake_cache,
self.fake_alertmanager,
self.fake_config,
"unack",
self.fake_room,
self.fake_message_event,
)
self.fake_alertmanager.delete_silences.side_effect = (
delete_silence_raise_silence_not_found
)
await command._unack()
# Check that we attempted to create silences
self.fake_alertmanager.delete_silences.assert_has_calls(
[call(fingerprint) for fingerprint in self.fake_fingerprints]
)
fake_send_text_to_room.assert_called_with(
self.fake_client, self.fake_room.room_id, "Removed 1 silences."
)
@patch.object(matrix_alertbot.command, "send_text_to_room")
async def test_unack_raise_alert_not_found(
self, fake_send_text_to_room: Mock
) -> None:
"""Tests the callback for InviteMemberEvents"""
# Tests that the bot attempts to join a room after being invited to it
self.fake_message_event.source = self.fake_source_in_reply
command = Command(
self.fake_client,
self.fake_cache,
self.fake_alertmanager,
self.fake_config,
"unack",
self.fake_room,
self.fake_message_event,
)
self.fake_alertmanager.delete_silences.side_effect = (
delete_silence_raise_alert_not_found
)
await command._unack()
# Check that we attempted to create silences
self.fake_alertmanager.delete_silences.assert_has_calls(
[call(fingerprint) for fingerprint in self.fake_fingerprints]
)
fake_send_text_to_room.assert_called_with(
self.fake_client, self.fake_room.room_id, "Removed 2 silences."
)
@patch.object(matrix_alertbot.command, "send_text_to_room") @patch.object(matrix_alertbot.command, "send_text_to_room")
async def test_unack_silence_raise_alertmanager_error( async def test_unack_silence_raise_alertmanager_error(
self, fake_send_text_to_room: Mock self, fake_send_text_to_room: Mock
@ -484,7 +363,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
[call(fingerprint) for fingerprint in self.fake_fingerprints] [call(fingerprint) for fingerprint in self.fake_fingerprints]
) )
fake_send_text_to_room.assert_called_with( fake_send_text_to_room.assert_called_with(
self.fake_client, self.fake_room.room_id, "Removed 3 silences." self.fake_client, self.fake_room.room_id, "Removed 1 silences."
) )