11# pylint: disable=invalid-name
22# pylint: disable=logging-fstring-interpolation
3+
34import json
45import logging
56import os
67import sys
78import warnings
89from time import sleep
10+ from typing import Any , Dict , Optional , Tuple
911
1012import requests
1113import yaml
1214from environs import Env , EnvError
1315from requests .exceptions import HTTPError
16+ from requests .sessions import Session
1417from tenacity import (
1518 before_log ,
1619 retry ,
2225from yaml .loader import SafeLoader
2326
2427logging .basicConfig (level = "INFO" )
25- logger = logging .getLogger ()
26-
28+ logger : logging .Logger = logging .getLogger ()
2729warnings .filterwarnings (
2830 "ignore" ,
2931 ".*Adding certificate verification is strongly advised.*" ,
3234env = Env ()
3335env .read_env ("./../.env" , recurse = False )
3436
35- SUPPORTED_GRAYLOG_MAJOR_VERSION = 6
36-
37- MACHINE_FQDN = env .str ("MACHINE_FQDN" )
38- GRAYLOG_BASE_DOMAIN = "https://monitoring." + MACHINE_FQDN + "/graylog"
39- GRAYLOG_WAIT_ONLINE_TIMEOUT_SEC = env .int ("GRAYLOG_WAIT_ONLINE_TIMEOUT_SEC" , 30 )
40- REQUESTS_AUTH = (env .str ("SERVICES_USER" ), env .str ("SERVICES_PASSWORD" ))
41- GRAYLOG_SYSLOG_CAPTURE_PORT = env .int ("GRAYLOG_SYSLOG_CAPTURE_PORT" )
42- GRAYLOG_LOG_MAX_DAYS_IN_STORAGE = env .int ("GRAYLOG_LOG_MAX_DAYS_IN_STORAGE" )
43- GRAYLOG_LOG_MIN_DAYS_IN_STORAGE = env .int ("GRAYLOG_LOG_MIN_DAYS_IN_STORAGE" )
44- GRAYLOG_SLACK_WEBHOOK_URL = env .str ("GRAYLOG_SLACK_WEBHOOK_URL" )
45- GRAYLOG_ALERT_MAIL_ADDRESS = env .str ("GRAYLOG_ALERT_MAIL_ADDRESS" )
46- GRAYLOG_SLACK_WEBHOOK_ICON_URL = env .str ("GRAYLOG_SLACK_WEBHOOK_ICON_URL" )
47- GRAYLOG_SLACK_WEBHOOK_CHANNEL = env .str ("GRAYLOG_SLACK_WEBHOOK_CHANNEL" )
37+ SUPPORTED_GRAYLOG_MAJOR_VERSION : int = 6
38+ MACHINE_FQDN : str = env .str ("MACHINE_FQDN" )
39+ GRAYLOG_BASE_DOMAIN : str = f"https://monitoring.{ MACHINE_FQDN } /graylog"
40+ GRAYLOG_WAIT_ONLINE_TIMEOUT_SEC : int = env .int ("GRAYLOG_WAIT_ONLINE_TIMEOUT_SEC" , 30 )
41+ REQUESTS_AUTH : Tuple [str , str ] = (
42+ env .str ("SERVICES_USER" ),
43+ env .str ("SERVICES_PASSWORD" ),
44+ )
45+ GRAYLOG_SYSLOG_CAPTURE_PORT : int = env .int ("GRAYLOG_SYSLOG_CAPTURE_PORT" )
46+ GRAYLOG_LOG_MAX_DAYS_IN_STORAGE : int = env .int ("GRAYLOG_LOG_MAX_DAYS_IN_STORAGE" )
47+ GRAYLOG_LOG_MIN_DAYS_IN_STORAGE : int = env .int ("GRAYLOG_LOG_MIN_DAYS_IN_STORAGE" )
48+ GRAYLOG_SLACK_WEBHOOK_URL : str = env .str ("GRAYLOG_SLACK_WEBHOOK_URL" )
49+ GRAYLOG_ALERT_MAIL_ADDRESS : str = env .str ("GRAYLOG_ALERT_MAIL_ADDRESS" )
50+ GRAYLOG_SLACK_WEBHOOK_ICON_URL : str = env .str ("GRAYLOG_SLACK_WEBHOOK_ICON_URL" )
51+ GRAYLOG_SLACK_WEBHOOK_CHANNEL : str = env .str ("GRAYLOG_SLACK_WEBHOOK_CHANNEL" )
52+
4853assert MACHINE_FQDN
4954assert REQUESTS_AUTH
5055assert GRAYLOG_SYSLOG_CAPTURE_PORT
5358
5459
5560@retry (
56- stop = stop_after_attempt (GRAYLOG_WAIT_ONLINE_TIMEOUT_SEC / 5 ),
61+ stop = stop_after_attempt (GRAYLOG_WAIT_ONLINE_TIMEOUT_SEC // 5 ),
5762 wait = wait_fixed (5 ),
5863 retry = retry_if_exception_type (HTTPError ),
5964 before = before_log (logger , logging .INFO ),
6065)
61- def wait_graylog_is_online ():
62- _r = requests .get (
66+ def wait_graylog_is_online () -> None :
67+ _r : requests . Response = requests .get (
6368 GRAYLOG_BASE_DOMAIN + "/api/system" ,
6469 auth = REQUESTS_AUTH ,
6570 verify = False ,
6671 timeout = 10 ,
6772 )
68-
6973 if _r .status_code == 401 :
7074 raise TypeError (f"Graylog unauthorized HTTP response: { _r } " )
71-
7275 _r .raise_for_status ()
7376 logger .info ("Graylog is online" )
7477
7578
76- def validate_graylog_version_is_supported ():
77- _r = requests .get (
78- GRAYLOG_BASE_DOMAIN + "/api/system" , auth = REQUESTS_AUTH , verify = False
79+ def validate_graylog_version_is_supported () -> None :
80+ _r : requests .Response = requests .get (
81+ GRAYLOG_BASE_DOMAIN + "/api/system" ,
82+ auth = REQUESTS_AUTH ,
83+ verify = False ,
84+ timeout = 30 ,
7985 )
8086 _r .raise_for_status ()
81-
82- graylog_version = _r .json ()["version" ]
83- major_version = int (graylog_version .split ("." )[0 ])
84-
87+ graylog_version : str = _r .json ()["version" ]
88+ major_version : int = int (graylog_version .split ("." )[0 ])
8589 if major_version != SUPPORTED_GRAYLOG_MAJOR_VERSION :
8690 raise TypeError (
8791 f"Graylog major version { major_version } is not supported by this script. "
@@ -90,14 +94,16 @@ def validate_graylog_version_is_supported():
9094
9195
9296@retry (stop = stop_after_attempt (5 ), wait = wait_random (min = 1 , max = 10 ))
93- def get_graylog_inputs (_session , _headers , _url ):
97+ def get_graylog_inputs (
98+ _session : Session , _headers : Dict [str , str ], _url : str
99+ ) -> requests .Response :
94100 # We check if graylog has inputs, if not we add a new one
95- _r = _session .get (_url , headers = _headers , verify = False )
101+ _r : requests . Response = _session .get (_url , headers = _headers , verify = False )
96102 # DEBUG
97103 if _r .status_code == 200 :
98104 print ("Successfully send GET /api/system/inputs" )
99105 return _r
100- error_message = (
106+ error_message : str = (
101107 "Error while sending GET /api/system/inputs. Status code of the request : "
102108 + str (_r .status_code )
103109 + " "
@@ -107,7 +113,7 @@ def get_graylog_inputs(_session, _headers, _url):
107113 raise RuntimeError (error_message )
108114
109115
110- def configure_email_notifications (_session , _headers ) :
116+ def configure_email_notifications (_session : requests . Session , _headers : dict ) -> str :
111117 _url = GRAYLOG_BASE_DOMAIN + "/api/events/notifications"
112118 _r = _session .get (_url , headers = _headers , verify = False )
113119 if (
@@ -137,7 +143,7 @@ def configure_email_notifications(_session, _headers):
137143 + " "
138144 + _r .text
139145 )
140- sys .exit (1 )
146+ sys .exit (os . EX_USAGE )
141147 else :
142148 print ("Graylog Mail Notification already present - skipping..." )
143149 # Keeping notification ID
@@ -151,7 +157,7 @@ def configure_email_notifications(_session, _headers):
151157 return _mail_notification_id
152158
153159
154- def configure_slack_notification_channel (_session , _hed ) -> str :
160+ def configure_slack_notification_channel (_session : requests . Session , _hed : dict ) -> str :
155161 # Configure sending Slack notifications
156162 if GRAYLOG_SLACK_WEBHOOK_URL != "" :
157163 assert GRAYLOG_SLACK_WEBHOOK_CHANNEL
@@ -220,7 +226,7 @@ def configure_slack_notification_channel(_session, _hed) -> str:
220226 + " "
221227 + r .text
222228 )
223- sys .exit (1 )
229+ sys .exit (os . EX_USAGE )
224230 print ("Graylog Slack Notification already present - skipping..." )
225231 _r = _session .get (_url , headers = _hed , verify = False )
226232 _slack_notification_id = [
@@ -232,7 +238,7 @@ def configure_slack_notification_channel(_session, _hed) -> str:
232238 return ""
233239
234240
235- def configure_log_retention (_session , _headers ) :
241+ def configure_log_retention (_session : requests . Session , _headers : dict ) -> None :
236242 _url = (
237243 "https://monitoring." + MACHINE_FQDN + "/graylog/api/system/indices/index_sets"
238244 )
@@ -272,7 +278,7 @@ def configure_log_retention(_session, _headers):
272278 )
273279
274280
275- def configure_syslog_capture (_session , _headers ) :
281+ def configure_syslog_capture (_session : requests . Session , _headers : dict ) -> None :
276282 try :
277283 _url = (
278284 "https://monitoring." + MACHINE_FQDN + "/graylog/api/system/cluster/nodes"
@@ -313,11 +319,11 @@ def configure_syslog_capture(_session, _headers):
313319
314320
315321def configure_alerts (
316- _session ,
317- _headers ,
318- _mail_notification_id : str | None = None ,
319- _slack_notification_id : str | None = None ,
320- ):
322+ _session : requests . Session ,
323+ _headers : dict ,
324+ _mail_notification_id : Optional [ str ] = None ,
325+ _slack_notification_id : Optional [ str ] = None ,
326+ ) -> None :
321327 print ("Configuring Graylog Alerts..." )
322328 with open ("alerts.yaml" ) as f :
323329 data = yaml .load (f , Loader = SafeLoader )
@@ -336,7 +342,7 @@ def configure_alerts(
336342 print (
337343 "Could not determine ID of stream containing all events. Is graylog misconfigured? Exiting with error!"
338344 )
339- sys .exit (1 )
345+ sys .exit (os . EX_USAGE )
340346 _url = "https://monitoring." + MACHINE_FQDN + "/graylog/api/events/definitions"
341347 # Deleting existing alerts - this ensures idemptency
342348 _r = _session .get (
@@ -363,7 +369,7 @@ def configure_alerts(
363369 )
364370 print (resp .status_code )
365371 print (resp .json ())
366- sys .exit (1 )
372+ sys .exit (os . EX_USAGE )
367373 for i in data :
368374 i ["notifications" ] = []
369375 if GRAYLOG_ALERT_MAIL_ADDRESS != "" and _mail_notification_id :
@@ -382,11 +388,13 @@ def configure_alerts(
382388 else :
383389 print ("Could not add alert. Failure:" , resp .status_code )
384390 print (resp .json ())
385- sys .exit (1 )
391+ sys .exit (os . EX_USAGE )
386392
387393
388- def configure_content_packs (_session , _headers , base_url ):
389- def get_installation (content_pack ):
394+ def configure_content_packs (
395+ _session : Session , _headers : Dict [str , str ], base_url : str
396+ ) -> None :
397+ def get_installation (content_pack : Dict [str , Any ]) -> Optional [Dict [str , Any ]]:
390398 logger .debug (f"Getting installations for content pack { content_pack ['id' ]} " )
391399 resp = _session .get (
392400 base_url + "/system/content_packs/" + content_pack ["id" ] + "/installations"
@@ -404,7 +412,9 @@ def get_installation(content_pack):
404412
405413 return installations [0 ] if installations else None
406414
407- def delete_installation (content_pack , installation ):
415+ def delete_installation (
416+ content_pack : Dict [str , Any ], installation : Dict [str , Any ]
417+ ) -> None :
408418 logger .debug (f"Deleting installation { installation ['_id' ]} " )
409419
410420 resp = _session .delete (
@@ -421,7 +431,7 @@ def delete_installation(content_pack, installation):
421431 f"Error while deleting installation { installation ['_id' ]} for content pack { content_pack ['id' ]} "
422432 )
423433
424- def create_content_pack_revision (content_pack ) :
434+ def create_content_pack_revision (content_pack : Dict [ str , Any ]) -> None :
425435 logger .debug (
426436 f"Uploading content pack { content_pack ['id' ]} revision { content_pack ['rev' ]} "
427437 )
@@ -440,7 +450,7 @@ def create_content_pack_revision(content_pack):
440450 f"Unexpected { resp .status_code = } while uploading content pack { content_pack ['id' ]} revision { content_pack ['rev' ]} . Error: { resp .text } "
441451 )
442452
443- def install_content_pack_revision (content_pack ) :
453+ def install_content_pack_revision (content_pack : Dict [ str , Any ]) -> None :
444454 logger .debug (
445455 f"Installing content pack { content_pack ['id' ]} revision { content_pack ['rev' ]} "
446456 )
@@ -459,7 +469,7 @@ def install_content_pack_revision(content_pack):
459469
460470 for file in os .listdir ("../data/contentpacks" ):
461471 with open (f"../data/contentpacks/{ file } " ) as f :
462- logger .debug (f"Configuring content pack { f . name } " )
472+ logger .debug (f"Configuring content pack { file } " )
463473 content_pack = json .loads (f .read ())
464474
465475 create_content_pack_revision (content_pack )
@@ -476,7 +486,7 @@ def install_content_pack_revision(content_pack):
476486 "This revision of content pack is already installed. Nothing to do..."
477487 )
478488
479- logging .info (f"{ f . name } content pack has been configured" )
489+ logging .info (f"{ file } content pack has been configured" )
480490
481491
482492if __name__ == "__main__" :
0 commit comments