add force option for update silence
This commit is contained in:
parent
f284486570
commit
6fd687cc90
4 changed files with 95 additions and 23 deletions
|
@ -87,6 +87,8 @@ class AlertmanagerClient:
|
||||||
fingerprint: str,
|
fingerprint: str,
|
||||||
user: Optional[str] = None,
|
user: Optional[str] = None,
|
||||||
duration_seconds: Optional[int] = None,
|
duration_seconds: Optional[int] = None,
|
||||||
|
*,
|
||||||
|
force: bool = False,
|
||||||
) -> str:
|
) -> str:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Reading silence for alert with fingerprint {fingerprint} from cache"
|
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}"
|
f"Updating silence with ID {silence_id} for alert with fingerprint {fingerprint}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if duration_seconds is None:
|
# If silence in cache had a duration, and the new silence doesn't have a duration
|
||||||
if expire_time is not None:
|
# then we cannot update this silence.
|
||||||
raise SilenceExtendError(
|
if not force and duration_seconds is None and expire_time is not None:
|
||||||
f"Cannot extend silence ID {silence_id} with static duration."
|
raise SilenceExtendError(
|
||||||
)
|
f"Cannot extend silence ID {silence_id} with static duration."
|
||||||
|
)
|
||||||
|
|
||||||
silence = await self.get_silence(silence_id)
|
silence = await self.get_silence(silence_id)
|
||||||
if user is None:
|
if user is None:
|
||||||
|
@ -123,10 +126,17 @@ class AlertmanagerClient:
|
||||||
)
|
)
|
||||||
|
|
||||||
async def create_or_update_silence(
|
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:
|
) -> str:
|
||||||
try:
|
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:
|
except SilenceNotFoundError:
|
||||||
silence_id = await self.create_silence(fingerprint, user, duration_seconds)
|
silence_id = await self.create_silence(fingerprint, user, duration_seconds)
|
||||||
return silence_id
|
return silence_id
|
||||||
|
|
|
@ -135,6 +135,7 @@ class AckAlertCommand(BaseAlertCommand):
|
||||||
alert_fingerprint,
|
alert_fingerprint,
|
||||||
self.room.user_name(self.sender),
|
self.room.user_name(self.sender),
|
||||||
duration_seconds,
|
duration_seconds,
|
||||||
|
force=True
|
||||||
)
|
)
|
||||||
except AlertNotFoundError as e:
|
except AlertNotFoundError as e:
|
||||||
logger.warning(f"Unable to create silence: {e}")
|
logger.warning(f"Unable to create silence: {e}")
|
||||||
|
|
|
@ -25,7 +25,7 @@ from matrix_alertbot.errors import (
|
||||||
|
|
||||||
|
|
||||||
async def update_silence_raise_silence_not_found(
|
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:
|
) -> str:
|
||||||
raise SilenceNotFoundError
|
raise SilenceNotFoundError
|
||||||
|
|
||||||
|
@ -439,7 +439,7 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_cache.set.assert_called_once_with("fingerprint1", "silence1", expire=86400)
|
fake_cache.set.assert_called_once_with("fingerprint1", "silence1", expire=86400)
|
||||||
|
|
||||||
@freeze_time(datetime.utcfromtimestamp(0))
|
@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()
|
fake_cache = FakeCache()
|
||||||
|
|
||||||
async with FakeAlertmanagerServerWithoutSilence() as fake_alertmanager_server:
|
async with FakeAlertmanagerServerWithoutSilence() as fake_alertmanager_server:
|
||||||
|
@ -455,6 +455,47 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
await alertmanager_client.get_silence("silence2")
|
await alertmanager_client.get_silence("silence2")
|
||||||
self.assertEqual({"fingerprint1": ("silence1", 86400)}, fake_cache.cache)
|
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))
|
@freeze_time(datetime.utcfromtimestamp(0))
|
||||||
async def test_update_silence_override_user_and_duration(self) -> None:
|
async def test_update_silence_override_user_and_duration(self) -> None:
|
||||||
fake_cache = FakeCache()
|
fake_cache = FakeCache()
|
||||||
|
@ -509,7 +550,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual("silence1", silence_id1)
|
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)
|
fake_create_silence.assert_called_once_with("fingerprint1", "user", 86400)
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
|
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
|
||||||
|
@ -527,7 +570,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual("silence1", silence_id1)
|
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()
|
fake_create_silence.assert_not_called()
|
||||||
|
|
||||||
@freeze_time(datetime.utcfromtimestamp(0))
|
@freeze_time(datetime.utcfromtimestamp(0))
|
||||||
|
@ -623,7 +668,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual("silence1", silence_id1)
|
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)
|
fake_create_silence.assert_called_once_with("fingerprint1", "user", None)
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
|
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
|
||||||
|
@ -641,7 +688,9 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual("silence1", silence_id1)
|
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()
|
fake_create_silence.assert_not_called()
|
||||||
|
|
||||||
@freeze_time(datetime.utcfromtimestamp(0))
|
@freeze_time(datetime.utcfromtimestamp(0))
|
||||||
|
|
|
@ -32,7 +32,11 @@ def cache_get_item(key: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
async def create_silence(
|
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:
|
) -> str:
|
||||||
if fingerprint == "fingerprint1":
|
if fingerprint == "fingerprint1":
|
||||||
return "silence1"
|
return "silence1"
|
||||||
|
@ -42,7 +46,11 @@ async def create_silence(
|
||||||
|
|
||||||
|
|
||||||
async def create_silence_raise_alertmanager_error(
|
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:
|
) -> str:
|
||||||
if fingerprint == "fingerprint1":
|
if fingerprint == "fingerprint1":
|
||||||
raise AlertmanagerError
|
raise AlertmanagerError
|
||||||
|
@ -50,7 +58,11 @@ async def create_silence_raise_alertmanager_error(
|
||||||
|
|
||||||
|
|
||||||
async def create_silence_raise_alert_not_found_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:
|
) -> str:
|
||||||
if fingerprint == "fingerprint1":
|
if fingerprint == "fingerprint1":
|
||||||
raise AlertNotFoundError
|
raise AlertNotFoundError
|
||||||
|
@ -80,7 +92,9 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_cache.__contains__.return_value = True
|
self.fake_cache.__contains__.return_value = True
|
||||||
|
|
||||||
self.fake_alertmanager_client = Mock(spec=AlertmanagerClient)
|
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
|
# Create a fake room to play with
|
||||||
self.fake_room = Mock(spec=nio.MatrixRoom)
|
self.fake_room = Mock(spec=nio.MatrixRoom)
|
||||||
|
@ -208,7 +222,6 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_cache_dict = {self.fake_alert_event_id: "fingerprint1"}
|
fake_cache_dict = {self.fake_alert_event_id: "fingerprint1"}
|
||||||
|
|
||||||
self.fake_cache.__getitem__.side_effect = fake_cache_dict.__getitem__
|
self.fake_cache.__getitem__.side_effect = fake_cache_dict.__getitem__
|
||||||
self.fake_alertmanager_client.create_or_update_silence.return_value = "silence1"
|
|
||||||
|
|
||||||
command = AckAlertCommand(
|
command = AckAlertCommand(
|
||||||
self.fake_matrix_client,
|
self.fake_matrix_client,
|
||||||
|
@ -224,7 +237,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
# Check that we attempted to create silences
|
# Check that we attempted to create silences
|
||||||
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
|
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(
|
fake_send_text_to_room.assert_called_once_with(
|
||||||
self.fake_matrix_client,
|
self.fake_matrix_client,
|
||||||
|
@ -241,7 +254,6 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
"""Tests the callback for InviteMemberEvents"""
|
"""Tests the callback for InviteMemberEvents"""
|
||||||
# Tests that the bot attempts to join a room after being invited to it
|
# Tests that the bot attempts to join a room after being invited to it
|
||||||
fake_cache_dict = {self.fake_alert_event_id: "fingerprint1"}
|
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__
|
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
|
# Check that we attempted to create silences
|
||||||
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
|
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(
|
fake_send_text_to_room.assert_called_once_with(
|
||||||
self.fake_matrix_client,
|
self.fake_matrix_client,
|
||||||
|
@ -301,7 +313,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
# Check that we attempted to create silences
|
# Check that we attempted to create silences
|
||||||
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
|
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(
|
fake_send_text_to_room.assert_called_once_with(
|
||||||
self.fake_matrix_client,
|
self.fake_matrix_client,
|
||||||
|
@ -340,7 +352,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
# Check that we attempted to create silences
|
# Check that we attempted to create silences
|
||||||
self.fake_alertmanager_client.create_or_update_silence.assert_called_once_with(
|
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(
|
fake_send_text_to_room.assert_called_once_with(
|
||||||
self.fake_matrix_client,
|
self.fake_matrix_client,
|
||||||
|
|
Loading…
Add table
Reference in a new issue