This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository mum. See http://git.chorem.org/mum.git commit 30f20df0170bef36e2f6e809e05c8f9c70a53768 Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Tue Mar 24 11:41:21 2015 +0100 envoi de notification par e-mail fonctionnel (sans prendre en compte le nombre d'ittérations) --- app/app.py | 2 + app/module_loader.py | 51 ++++++++++++---- app/modules/monitoring_modules/disk.py | 2 +- app/modules/monitoring_modules/memory.py | 2 +- app/modules/monitoring_modules/ping.py | 2 +- app/modules/monitoring_modules/updated_packages.py | 2 +- app/modules/notification_modules/email_notif.py | 29 +++++---- app/modules/storage_modules/shelve_db.py | 71 +++++++++++++++++----- install.sh | 3 + 9 files changed, 118 insertions(+), 46 deletions(-) diff --git a/app/app.py b/app/app.py index e1afd3a..be74737 100755 --- a/app/app.py +++ b/app/app.py @@ -183,6 +183,8 @@ if __name__ == '__main__': ml.load_all_detection_modules() ml.load_all_notification_modules() wsc = WebSocketContainer(ml.get_db()) + #dict_notif = ml.db.add_check('127.0.0.1', "ping", False) + #ml.run_notification_modules(dict_notif) process_monitoring.init(ml, wsc) port = int(os.environ.get('PORT', 1337)) run(host='0.0.0.0', port=port, debug=True, server=GeventWebSocketServer) diff --git a/app/module_loader.py b/app/module_loader.py index 9ee6ac4..97ce3be 100644 --- a/app/module_loader.py +++ b/app/module_loader.py @@ -22,16 +22,18 @@ class ModuleLoader: and contains several methods in order to call the methods once these modules loaded. """ def __init__(self, add_func, rem_func): - dict_conf = {} # See conf.txt + self.conf = {} # See conf.txt fconf = open('mum.conf', 'r') for line in fconf.read().splitlines(): fields = line.split('=') - dict_conf[fields[0]] = fields[1] + self.conf[fields[0]] = fields[1] fconf.close() + ''' self.db_loc = dict_conf['db_location'] self.external_mod_loc = dict_conf['external_modules_location'] self.public_keys_loc = dict_conf['keys_location'] - self.db = self.load_db(add_func, rem_func, self.public_keys_loc) + ''' + self.db = self.load_db(add_func, rem_func, self.conf['keys_location']) self.loaded_mod_moni = {} # See load_all_monitoring_modules self.loaded_mod_detect = {} # See load_all_detection_modules self.loaded_mod_conn = {} # See load_all_connection_modules @@ -44,14 +46,14 @@ class ModuleLoader: """ db_name = "shelve_db" db = __import__("modules.storage_modules." + db_name, fromlist=modules.storage_modules) - db_instance = getattr(db, db_name)(self.db_loc, add_func, rem_func, key_loc) + db_instance = getattr(db, db_name)(self.conf['db_location'], add_func, rem_func, key_loc) return db_instance def get_db(self): return self.db def get_public_keys_loc(self): - return self.public_keys_loc + return self.conf['keys_location'] @staticmethod def run_nmap_detection(param, opt, db, ws, list_mod_conn, dict_mod_monitoring): @@ -84,7 +86,7 @@ class ModuleLoader: mod_inst = getattr(self.loaded_mod_conn[conn['conn_mod_name']]['imported'], self.loaded_mod_conn[conn['conn_mod_name']]['class_name'])(addr_host, conn['args'], - self.public_keys_loc, + self.conf['keys_location'], modules.CommandNotFoundException) else: print "Error: no connection have been configured yet" @@ -152,8 +154,8 @@ class ModuleLoader: print "Error : internal monitoring module " + mod_name + " could not have been loaded. " # Now for external modules: - sys.path.insert(0, self.external_mod_loc) # Adding the external diretory into pythonpath - for importer, mod_name, ispkg in pkgutil.iter_modules([self.external_mod_loc]): + sys.path.insert(0, self.conf['external_modules_location']) # Adding the external diretory into pythonpath + for importer, mod_name, ispkg in pkgutil.iter_modules([self.conf['external_modules_location']]): if mod_name not in sys.modules: try: loaded_mod = __import__(mod_name, fromlist=[mod_name]) @@ -192,7 +194,8 @@ class ModuleLoader: self.loaded_mod_moni[mod_name]['class_name'])(conn, db, modules.ModuleNotCompatibleException) try: - mod_inst.check() + dict_notif = mod_inst.check() + self.run_notification_modules(dict_notif) except modules.ModuleNotCompatibleException.ModuleNotCompatibleException as mnce: print mnce.__str__() except modules.CommandNotFoundException.CommandNotFoundException as cnfe: @@ -302,11 +305,10 @@ class ModuleLoader: try: loaded_mod = __import__("modules.notification_modules." + mod_name, fromlist=[mod_name]) class_name = getattr(loaded_mod, "get_class_name")() - mod_inst = getattr(loaded_mod, class_name)(None, None) + mod_inst = getattr(loaded_mod, class_name)(None, None, None, None) infos_mod = {} infos_mod['imported'] = loaded_mod infos_mod['class_name'] = getattr(mod_inst, 'get_name')() - infos_mod['params'] = getattr(mod_inst, 'get_parameters')() self.loaded_mod_notif[mod_name] = infos_mod except AttributeError: print "Error : internal notification module " + mod_name + " could not have been loaded. " @@ -326,9 +328,32 @@ class ModuleLoader: """ res = {} for mod in self.loaded_mod_notif: - res[mod] = self.loaded_mod_notif[mod]['params'] + res[mod] = '' return json.dumps(res) + def run_notification_modules(self, dict_notif): + """ + Runs the notifications modules specified in the dict_notif parameter. (called by run_one_monitoring_module) + :param dict_notif: + { + notif_mod: [{'username': string, 'moni_mod': string, 'title': string, 'msg': string}, ...], + ... + } + :return: + """ + for notif_mod in dict_notif: + while len(dict_notif[notif_mod]) > 0: + instr = dict_notif[notif_mod].pop() + mod_inst = getattr(self.loaded_mod_notif[notif_mod]['imported'], + self.loaded_mod_notif[notif_mod]['class_name'])(instr['user'], + instr['title'], + instr['msg'], + self.conf) + try: + mod_inst.notify() + except KeyError: + print 'Missing setting for notification module ' + notif_mod + def update_global_conf(self): """ Asks the database to update the configuration if new monitoring modules are added in function of the @@ -364,4 +389,4 @@ class ModuleLoader: self.db.config_mod_activation(args, self.get_monitoring_modules_list()) def get_public_keys_list(self): - return json.dumps(os.listdir(self.public_keys_loc)) \ No newline at end of file + return json.dumps(os.listdir(self.conf['keys_location'])) \ No newline at end of file diff --git a/app/modules/monitoring_modules/disk.py b/app/modules/monitoring_modules/disk.py index 15c734c..93a1e32 100644 --- a/app/modules/monitoring_modules/disk.py +++ b/app/modules/monitoring_modules/disk.py @@ -51,4 +51,4 @@ class Disk: ) raise exception_inst res_check = int(disk_used) - self.db.add_check(self.conn.get_addr_host(), 'disk', res_check) \ No newline at end of file + return self.db.add_check(self.conn.get_addr_host(), 'disk', res_check) \ No newline at end of file diff --git a/app/modules/monitoring_modules/memory.py b/app/modules/monitoring_modules/memory.py index 521fcf8..87c69f6 100644 --- a/app/modules/monitoring_modules/memory.py +++ b/app/modules/monitoring_modules/memory.py @@ -50,4 +50,4 @@ class Memory: ) raise exception_inst res_check = memused * 100 / int(memtotal) - self.db.add_check(self.conn.get_addr_host(), "memory", res_check) \ No newline at end of file + return self.db.add_check(self.conn.get_addr_host(), "memory", res_check) \ No newline at end of file diff --git a/app/modules/monitoring_modules/ping.py b/app/modules/monitoring_modules/ping.py index f7467a8..b9ad35a 100644 --- a/app/modules/monitoring_modules/ping.py +++ b/app/modules/monitoring_modules/ping.py @@ -43,4 +43,4 @@ class Ping: except pexpect.TIMEOUT: res_check = False finally: - self.db.add_check(self.addr_host, "ping", res_check) \ No newline at end of file + return self.db.add_check(self.addr_host, "ping", res_check) \ No newline at end of file diff --git a/app/modules/monitoring_modules/updated_packages.py b/app/modules/monitoring_modules/updated_packages.py index 87953fd..d511039 100644 --- a/app/modules/monitoring_modules/updated_packages.py +++ b/app/modules/monitoring_modules/updated_packages.py @@ -31,4 +31,4 @@ class UpdatedPackages: stdout = self.conn.exec_command(cmd) tab_res = stdout.split(':') res_check = len(tab_res) <= 2 - self.db.add_check(self.conn.get_addr_host(), "updated_packages", res_check) \ No newline at end of file + return self.db.add_check(self.conn.get_addr_host(), "updated_packages", res_check) \ No newline at end of file diff --git a/app/modules/notification_modules/email_notif.py b/app/modules/notification_modules/email_notif.py index 09f495e..9769242 100644 --- a/app/modules/notification_modules/email_notif.py +++ b/app/modules/notification_modules/email_notif.py @@ -9,25 +9,24 @@ def get_class_name(): class EMail: - def __init__(self, msg, params): + def __init__(self, user_data, title, msg, settings): self.name = get_class_name() + self.user_data = user_data # {'email': val, ...} + self.title = title self.msg = msg - self.params = params - self.parameters = {"users": "dict", "smtp_server": "string"} # dict = {user: {'username': val, 'email'; val}} + self.settings = settings # = conf attribute on ModuleLoader class def get_name(self): return self.name - def get_parameters(self): - return self.parameters - def notify(self): - for user in self.params["users"]: - msg_to_send = MIMEText(self.msg) - msg_to_send['Subject'] = self.params["users"][user]['subject'] - msg_to_send['From'] = "mum@mum.com" - msg_to_send['To'] = self.params["users"][user]['email'] - - s = smtplib.SMTP(self.params['smtp_server']) - s.sendmail(msg_to_send['From'], [msg_to_send['To']], msg_to_send.as_string()) - s.quit() \ No newline at end of file + msg_to_send = MIMEText(self.msg) + msg_to_send['Subject'] = self.title + msg_to_send['From'] = self.settings['smtp_address'] + msg_to_send['To'] = self.user_data['email'] + if self.settings['smtp_port'] == '': + s = smtplib.SMTP(self.settings['smtp_server']) + else: + s = smtplib.SMTP(self.settings['smtp_server'], int(self.settings['smtp_port'])) + s.sendmail(msg_to_send['From'], [msg_to_send['To']], msg_to_send.as_string()) + s.quit() \ No newline at end of file diff --git a/app/modules/storage_modules/shelve_db.py b/app/modules/storage_modules/shelve_db.py index 15b9482..685f7c0 100644 --- a/app/modules/storage_modules/shelve_db.py +++ b/app/modules/storage_modules/shelve_db.py @@ -656,8 +656,13 @@ class shelve_db: :param addr_host: the IP adress of the host checked :param mod_name: the name of the monitoring_module which have done the check :param val: the value observed + :return: data that will be used to launch the notification modules in the form : + { + notif_mod: [{'username': string, 'moni_mod': string, 'title': string, 'msg': string}, ...], + ... + } """ - #failure = None + dict_notif = {} self.open_db() new_val = {"date": str(datetime.now()), "value": val} try: @@ -700,19 +705,9 @@ class shelve_db: and not state == 'danger': state = 'warning' self.db['hosts'][addr_host]['status']['state'] = state - # create a notify structure if the state is not a success - """ + # create a notification structure if the state is not a success if not new_val['state'] == 'success': - failure = {} - failure['addr_host'] = addr_host - failure['mod_name'] = mod_name - failure['state'] = new_val['state'] - failure['subscribers'] = {} - for subscriber in self.db['hosts'][addr_host]['conf']['subscribers']: - failure['subscribers'][subscriber] = {} - failure['subscribers'][subscriber][''] - failure['groups_to_notify'] = self.db['hosts'][addr_host]['conf']['groups'] - """ + dict_notif = self.create_notif_structure(addr_host, mod_name, new_val['state']) # now performing archiving """ if mod_name in self.db['hosts'][addr_host]['archive']: @@ -723,7 +718,7 @@ class shelve_db: print e.__str__() finally: self.close_db() - #return failure + return dict_notif def update_stats(self, stats, val): """ @@ -746,6 +741,53 @@ class shelve_db: stats['M2'] += stats['delta'] * (val - stats['mean']) return stats + def create_notif_structure(self, addr_host, moni_mod, status): + """ + Creates and returns a data structure that will be used by the notification modules + :param addr_host: the IP address of the host + :param moni_mod: the name of the monitoring module which have been launched + :param status: the status of the last check + :return: data that will be used to launch the notification modules in the form : + { + notif_mod: [{'user': dict, 'moni_mod': string, 'title': string, 'msg': string}, ...], + ... + } + """ + title = "[Mum] " + status + " on " + addr_host + msg = "Mum repported a " + status + " value by the " + moni_mod + " mod " + dict_notif = {} + notif_type = "" + if status == 'warning': + notif_type = 'minor' + else: + notif_type = 'major' + for username in self.db['hosts'][addr_host]['conf']['subscribers']: + # creates a message for all subscribers in the host + for notif_mod in self.db['hosts'][addr_host]['conf']['subscribers'][username][notif_type]: + #{'priority': int, 'activated': bool} + param_notif = self.db['hosts'][addr_host]['conf']['subscribers'][username][notif_type][notif_mod] + if param_notif['activated']: + if notif_mod not in dict_notif: + dict_notif[notif_mod] = [] + dict_notif[notif_mod].append({'user': self.db['users'][username]['settings'], + 'moni_mod': moni_mod, + 'title': "[Mum] " + status + " on " + addr_host, + 'msg': msg}) + for group in self.db['groups']: + # creates a message for all subscribers in a group which the host is member + if addr_host in self.db['groups'][group]: + for username in self.db['groups'][group]['subscribers']: + for notif_mod in self.db['groups'][group]['subscribers'][username][notif_type]: + param_notif = self.db['groups'][group]['subscribers'][username][notif_type][notif_mod] + if param_notif['activated']: + if notif_mod not in dict_notif: + dict_notif[notif_mod] = [] + dict_notif[notif_mod].append({'user': self.db['users'][username]['settings'], + 'moni_mod': moni_mod, + 'title': title, + 'msg': msg}) + return dict_notif + def add_host_list_to_group(self, args): """ Add given hosts to a group. If the group doesn't exists on the database, it will be created. @@ -900,6 +942,7 @@ class shelve_db: self.db['users'][username]['preferences']['minor_notifications'] = {} self.db['users'][username]['preferences']['major_notifications'] = {} self.db['users'][username]['account'] = {} + self.db['users'][username]['settings'] = {} except Exception as e: print e.__str__() finally: diff --git a/install.sh b/install.sh index 589c9be..090594e 100755 --- a/install.sh +++ b/install.sh @@ -14,6 +14,9 @@ touch mum.conf echo "db_location=$HOME/.mum/mum.db" >> mum.conf echo "external_modules_location=$HOME/.mum/external" >> mum.conf echo "keys_location=$HOME/.mum/keys/" >> mum.conf +echo "smtp_server=" >> mum.conf +echo "smtp_port=" >> mum.conf +echo "smtp_address=" >> mum.conf # creating the basic folders mkdir $HOME/.mum -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.