add force option for update silence

This commit is contained in:
HgO 2022-08-08 11:26:08 +02:00
parent f284486570
commit 6fd687cc90
4 changed files with 95 additions and 23 deletions

View file

@ -87,6 +87,8 @@ class AlertmanagerClient:
fingerprint: str,
user: Optional[str] = None,
duration_seconds: Optional[int] = None,
*,
force: bool = False,
) -> str:
logger.debug(
f"Reading silence for alert with fingerprint {fingerprint} from cache"
@ -107,11 +109,12 @@ class AlertmanagerClient:
f"Updating silence with ID {silence_id} for alert with fingerprint {fingerprint}"
)
if duration_seconds is None:
if expire_time is not None:
raise SilenceExtendError(
f"Cannot extend silence ID {silence_id} with static duration."
)
# If silence in cache had a duration, and the new silence doesn't have a duration
# then we cannot update this silence.
if not force and duration_seconds is None and expire_time is not None:
raise SilenceExtendError(
f"Cannot extend silence ID {silence_id} with static duration."
)
silence = await self.get_silence(silence_id)
if user is None:
@ -123,10 +126,17 @@ class AlertmanagerClient:
)
async def create_or_update_silence(
self, fingerprint: str, user: str, duration_seconds: Optional[int] = None
self,
fingerprint: str,
user: str,
duration_seconds: Optional[int] = None,
*,
force: bool = False,
) -> str:
try:
silence_id = await self.update_silence(fingerprint, user, duration_seconds)
silence_id = await self.update_silence(
fingerprint, user, duration_seconds, force=force
)
except SilenceNotFoundError:
silence_id = await self.create_silence(fingerprint, user, duration_seconds)
return silence_id

View file

@ -135,6 +135,7 @@ class AckAlertCommand(BaseAlertCommand):
alert_fingerprint,
self.room.user_name(self.sender),
duration_seconds,
force=True
)
except AlertNotFoundError as e:
logger.warning(f"Unable to create silence: {e}")

View file

@ -25,7 +25,7 @@ from matrix_alertbot.errors import (
async def update_silence_raise_silence_not_found(
fingerprint: str, user: str, duration_seconds: int
fingerprint: str, user: str, duration_seconds: int, *, force: bool = False
) -> str:
raise SilenceNotFoundError
@ -439,7 +439,7 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
fake_cache.set.assert_called_once_with("fingerprint1", "silence1", expire=86400)
@freeze_time(datetime.utcfromtimestamp(0))
async def test_update_silence_with_duration(self) -> None:
async def test_update_silence_raise_extend_error(self) -> None:
fake_cache = FakeCache()
async with FakeAlertmanagerServerWithoutSilence() as fake_alertmanager_server:
@ -455,6 +455,47 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
await alertmanager_client.get_silence("silence2")
self.assertEqual({"fingerprint1": ("silence1", 86400)}, fake_cache.cache)
@freeze_time(datetime.utcfromtimestamp(0))
async def test_update_silence_remove_duration(self) -> None:
fake_cache = FakeCache()
async with FakeAlertmanagerServerWithoutSilence() as fake_alertmanager_server:
port = fake_alertmanager_server.port
alertmanager_client = AlertmanagerClient(
f"http://localhost:{port}", fake_cache
)
async with aiotools.closing_async(alertmanager_client):
silence_id1 = await alertmanager_client.create_silence(
"fingerprint1", "user", 86400
)
silence_id2 = await alertmanager_client.update_silence(
"fingerprint1", force=True
)
silence2 = await alertmanager_client.get_silence("silence2")
self.assertEqual("silence1", silence_id1)
self.assertEqual("silence2", silence_id2)
self.assertEqual(
{
"id": "silence2",
"status": {"state": "active"},
"matchers": [
{
"name": "alertname",
"value": "alert1",
"isRegex": False,
"isEqual": True,
}
],
"createdBy": "user",
"startsAt": "1970-01-01T00:00:00",
"endsAt": "1970-01-01T03:00:00",
"comment": "Acknowledge alert from Matrix",
},
silence2,
)
self.assertEqual({"fingerprint1": ("silence2", None)}, fake_cache.cache)
@freeze_time(datetime.utcfromtimestamp(0))
async def test_update_silence_override_user_and_duration(self) -> None:
fake_cache = FakeCache()
@ -509,7 +550,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
)
self.assertEqual("silence1", silence_id1)
fake_update_silence.assert_called_once_with("fingerprint1", "user", 86400)
fake_update_silence.assert_called_once_with(
"fingerprint1", "user", 86400, force=False
)
fake_create_silence.assert_called_once_with("fingerprint1", "user", 86400)
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
@ -527,7 +570,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
)
self.assertEqual("silence1", silence_id1)
fake_update_silence.assert_called_once_with("fingerprint1", "user", 86400)
fake_update_silence.assert_called_once_with(
"fingerprint1", "user", 86400, force=False
)
fake_create_silence.assert_not_called()
@freeze_time(datetime.utcfromtimestamp(0))
@ -623,7 +668,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
)
self.assertEqual("silence1", silence_id1)
fake_update_silence.assert_called_once_with("fingerprint1", "user", None)
fake_update_silence.assert_called_once_with(
"fingerprint1", "user", None, force=False
)
fake_create_silence.assert_called_once_with("fingerprint1", "user", None)
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
@ -641,7 +688,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
)
self.assertEqual("silence1", silence_id1)
fake_update_silence.assert_called_once_with("fingerprint1", "user", None)
fake_update_silence.assert_called_once_with(
"fingerprint1", "user", None, force=False
)
fake_create_silence.assert_not_called()
@freeze_time(datetime.utcfromtimestamp(0))

View file

@ -32,7 +32,11 @@ def cache_get_item(key: str) -> str:
async def create_silence(
fingerprint: str, user: str, duration_seconds: Optional[int] = None
fingerprint: str,
user: str,
duration_seconds: Optional[int] = None,
*,
force: bool = True,
) -> str:
if fingerprint == "fingerprint1":
return "silence1"
@ -42,7 +46,11 @@ async def create_silence(
async def create_silence_raise_alertmanager_error(
fingerprint: str, user: str, duration_seconds: Optional[int] = None
fingerprint: str,
user: str,
duration_seconds: Optional[int] = None,
*,
force: bool = True,
) -> str:
if fingerprint == "fingerprint1":
raise AlertmanagerError
@ -50,7 +58,11 @@ async def create_silence_raise_alertmanager_error(
async def create_silence_raise_alert_not_found_error(
fingerprint: str, user: str, duration_seconds: Optional[int] = None
fingerprint: str,
user: str,
duration_seconds: Optional[int] = None,
*,
force: bool = True,
) -> str:
if fingerprint == "fingerprint1":
raise AlertNotFoundError
@ -80,7 +92,9 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
self.fake_cache.__contains__.return_value = True
self.fake_alertmanager_client = Mock(spec=AlertmanagerClient)
self.fake_alertmanager_client.create_silence.side_effect = create_silence
self.fake_alertmanager_client.create_or_update_silence.side_effect = (
create_silence
)
# Create a fake room to play with
self.fake_room = Mock(spec=nio.MatrixRoom)
@ -208,7 +222,6 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
fake_cache_dict = {self.fake_alert_event_id: "fingerprint1"}
self.fake_cache.__getitem__.side_effect = fake_cache_dict.__getitem__
self.fake_alertmanager_client.create_or_update_silence.return_value = "silence1"
command = AckAlertCommand(
self.fake_matrix_client,
@ -224,7 +237,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
# Check that we attempted to create silences
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
"fingerprint1", self.fake_sender, None
"fingerprint1", self.fake_sender, None, force=True
)
fake_send_text_to_room.assert_called_once_with(
self.fake_matrix_client,
@ -241,7 +254,6 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
"""Tests the callback for InviteMemberEvents"""
# Tests that the bot attempts to join a room after being invited to it
fake_cache_dict = {self.fake_alert_event_id: "fingerprint1"}
self.fake_alertmanager_client.create_or_update_silence.return_value = "silence1"
self.fake_cache.__getitem__.side_effect = fake_cache_dict.__getitem__
@ -260,7 +272,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
# Check that we attempted to create silences
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
"fingerprint1", self.fake_sender, 864000
"fingerprint1", self.fake_sender, 864000, force=True
)
fake_send_text_to_room.assert_called_once_with(
self.fake_matrix_client,
@ -301,7 +313,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
# Check that we attempted to create silences
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
"fingerprint1", self.fake_sender, None
"fingerprint1", self.fake_sender, None, force=True
)
fake_send_text_to_room.assert_called_once_with(
self.fake_matrix_client,
@ -340,7 +352,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
# Check that we attempted to create silences
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
"fingerprint1", self.fake_sender, None
"fingerprint1", self.fake_sender, None, force=True
)
fake_send_text_to_room.assert_called_once_with(
self.fake_matrix_client,