Skip to content

Commit

Permalink
Implement the interface with the AlertManager
Browse files Browse the repository at this point in the history
Implement a class with the functionalities to call AlertManager.
This is a first implementation with methods to:
* Schedule a Silence
* Removed a previously scheduled Silence

The code has been written using the existing one for
icinga as guidance.
  • Loading branch information
jose-caballero committed Jan 16, 2025
1 parent ab198aa commit 33b040a
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 3 deletions.
Empty file.
148 changes: 148 additions & 0 deletions lib/alertmanager_api/silence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import logging
import requests
from exceptions.missing_mandatory_param_error import MissingMandatoryParamError
from requests.auth import HTTPBasicAuth
from requests.exceptions import RequestException

Check warning on line 5 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L1-L5

Added lines #L1 - L5 were not covered by tests


class AlertManagerAPI:

Check warning on line 8 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L8

Added line #L8 was not covered by tests
"""
class implementing an interface to the Kayobe's alertmanager
functionalities:
* create a silence
* remove an existing silence
"""

def __init__(self, alertmanager_account):

Check warning on line 16 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L16

Added line #L16 was not covered by tests
"""
:param alertmanager_account: object with credentials
:type alertmanager_account: AlertManagerAccount
"""
self.log = logging.getLogger("AlertManagerAPI")
self.alertmanager_account = alertmanager_account
self.auth = HTTPBasicAuth(

Check warning on line 23 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L21-L23

Added lines #L21 - L23 were not covered by tests
alertmanager_account.username, alertmanager_account.password
)
self.api_url = f"{alertmanager_account.alertmanager_endpoint}/api/v2/silences"

Check warning on line 26 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L26

Added line #L26 was not covered by tests

def schedule_silence(self, silence):

Check warning on line 28 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L28

Added line #L28 was not covered by tests
"""
Schedules a silence in alertmanager
:param silence: object with the specs to create a silence
:type silence: SilenceDetails
:return: a new silence object, including the silence_id
:rtype: SilenceDetails
:raises MissingMandatoryParamError:
if any of the required attributes are missing
in the silence object:
instance_name
start time
end time
author
comment
:raises requests.exceptions.RequestException:
when the request to the AlertManager failed
"""
if not silence.instance_name:
msg = "Missing silence instance name"
self.log.critical(msg)
raise MissingMandatoryParamError(msg)

Check warning on line 50 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L48-L50

Added lines #L48 - L50 were not covered by tests
if not silence.start_time:
msg = "Missing silence start time"
self.log.critical(msg)
raise MissingMandatoryParamError(msg)

Check warning on line 54 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L52-L54

Added lines #L52 - L54 were not covered by tests
if not silence.end_time:
msg = "Missing silence end time"
self.log.critical(msg)
raise MissingMandatoryParamError(msg)

Check warning on line 58 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L56-L58

Added lines #L56 - L58 were not covered by tests
if not silence.author:
msg = "Missing silence author"
self.log.critical(msg)
raise MissingMandatoryParamError(msg)

Check warning on line 62 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L60-L62

Added lines #L60 - L62 were not covered by tests
if not silence.comment:
msg = "Missing silence comment"
self.log.critical(msg)
raise MissingMandatoryParamError(msg)

Check warning on line 66 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L64-L66

Added lines #L64 - L66 were not covered by tests

payload = {

Check warning on line 68 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L68

Added line #L68 was not covered by tests
"matchers": [
{
"name": "instance_name",
"value": silence.instance_name,
"isRegex": False,
}
],
"startsAt": silence.start_time,
"endsAt": silence.end_time,
"createdBy": silence.author,
"comment": silence.comment,
}
try:
response = requests.post(

Check warning on line 82 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L81-L82

Added lines #L81 - L82 were not covered by tests
self.api_url,
auth=self.auth,
headers={"Accept": "application/json"},
json=payload,
timeout=10,
)
if response.status_code != 200:
msg = (

Check warning on line 90 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L90

Added line #L90 was not covered by tests
"Failed to create silence. "
f"Response status code: {response.status_code} "
f"Response text: {response.text}"
)
self.log.error(msg)
raise RequestException(msg, response=response)
silence_id = response.json()["silenceID"]
silence.silence_id = silence_id
return silence

Check warning on line 99 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L95-L99

Added lines #L95 - L99 were not covered by tests

except RequestException as req_ex:
msg = f"Failed to create silence in Alertmanager: {req_ex} "

Check warning on line 102 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L101-L102

Added lines #L101 - L102 were not covered by tests
if req_ex.response is not None:
msg += (

Check warning on line 104 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L104

Added line #L104 was not covered by tests
f"Response status code: {req_ex.response.status_code} "
f"Response text: {req_ex.response.text}"
)
self.log.critical(msg)
raise req_ex

Check warning on line 109 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L108-L109

Added lines #L108 - L109 were not covered by tests

def remove_silence(self, silence):

Check warning on line 111 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L111

Added line #L111 was not covered by tests
"""
Removes a previously scheduled silence in alertmanager
:param silence: object including the silence_id to be removed
:type silence: SilenceDetails
:raises MissingMandatoryParamError: when the silence_id is missing
:raises requests.exceptions.RequestException:
when the request to the AlertManager failed
"""
if not silence.silence_id:
msg = "Missing silence silence_id"
self.log.critical(msg)
raise MissingMandatoryParamError(msg)

Check warning on line 124 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L122-L124

Added lines #L122 - L124 were not covered by tests

try:
response = requests.delete(

Check warning on line 127 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L126-L127

Added lines #L126 - L127 were not covered by tests
self.api_url,
auth=self.auth,
timeout=10,
)
if response.status_code != 200:
msg = (

Check warning on line 133 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L133

Added line #L133 was not covered by tests
f"Failed to delete silence with ID {silence.silence_id}. "
f"Response status code: {response.status_code} "
f"Response text: {response.text}"
)
self.log.critical(msg)
raise RequestException(msg, response=response)
except RequestException as req_ex:
msg = f"Failed to delete silence in Alertmanager: {req_ex} "

Check warning on line 141 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L138-L141

Added lines #L138 - L141 were not covered by tests
if req_ex.response is not None:
msg += (

Check warning on line 143 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L143

Added line #L143 was not covered by tests
f"Response status code: {req_ex.response.status_code} "
f"Response text: {req_ex.response.text}"
)
self.log.critical(msg)
raise req_ex

Check warning on line 148 in lib/alertmanager_api/silence.py

View check run for this annotation

Codecov / codecov/patch

lib/alertmanager_api/silence.py#L147-L148

Added lines #L147 - L148 were not covered by tests
11 changes: 8 additions & 3 deletions lib/structs/alertmanager/alertmanager_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,20 @@ def from_pack_config(pack_config: dict, alertmanager_account_name: str):
:param alertmanager_account_name: The account name to get from the config
:raises ValueError: When the pack config does not have alertmanager_accounts defined
:raises KeyError: When the account does not appear in the given config
:return: (Dictionary) alertmanager account names and properties
:return: alertmanager account names and properties
:rtype: dictionary
"""
alertmanager_accounts_config = pack_config.get("alertmanager_accounts", None)

Check warning on line 40 in lib/structs/alertmanager/alertmanager_account.py

View check run for this annotation

Codecov / codecov/patch

lib/structs/alertmanager/alertmanager_account.py#L40

Added line #L40 was not covered by tests

if alertmanager_accounts_config is None:
raise ValueError("Pack config must contain the 'alertmanager_accounts' field")
raise ValueError(

Check warning on line 43 in lib/structs/alertmanager/alertmanager_account.py

View check run for this annotation

Codecov / codecov/patch

lib/structs/alertmanager/alertmanager_account.py#L43

Added line #L43 was not covered by tests
"Pack config must contain the 'alertmanager_accounts' field"
)

try:

Check warning on line 47 in lib/structs/alertmanager/alertmanager_account.py

View check run for this annotation

Codecov / codecov/patch

lib/structs/alertmanager/alertmanager_account.py#L47

Added line #L47 was not covered by tests
key_value = {config["name"]: config for config in alertmanager_accounts_config}
key_value = {
config["name"]: config for config in alertmanager_accounts_config
}
account_data = key_value[alertmanager_account_name]
except KeyError as exc:
raise KeyError(

Check warning on line 53 in lib/structs/alertmanager/alertmanager_account.py

View check run for this annotation

Codecov / codecov/patch

lib/structs/alertmanager/alertmanager_account.py#L51-L53

Added lines #L51 - L53 were not covered by tests
Expand Down

0 comments on commit 33b040a

Please sign in to comment.