def perform_secure_deletion_of_files(self): # Delete files that are marked for secure deletion files_to_delete = yield self.get_files_to_secure_delete() for file_to_delete in files_to_delete: overwrite_and_remove(file_to_delete) if files_to_delete: yield self.commit_files_deletion(files_to_delete) # Delete the outdated AES files older than 1 day files_to_remove = [ f for f in os.listdir(self.state.settings.tmp_path) if fnmatch.fnmatch(f, '*.aes') ] for f in files_to_remove: path = os.path.join(self.state.settings.tmp_path, f) timestamp = datetime.datetime.fromtimestamp(os.path.getmtime(path)) if is_expired(timestamp, days=1): os.remove(path) # Delete the backups older than 15 days for f in os.listdir(self.state.settings.backups_path): path = os.path.join(self.state.settings.backups_path, f) timestamp = datetime.datetime.fromtimestamp(os.path.getmtime(path)) if is_expired(timestamp, days=15): os.remove(path)
def operation(self): """ This function, checks all the InternalTips and their expiration date. if expired InternalTips are found, it removes that along with all the related DB entries comment and tip related. """ # Reset the exception tracking variable of GLSetting GLSetting.exceptions = {} tip_list = yield get_tip_timings() log.debug("Tip(s) subject to the timings check: %d" % len(tip_list)) for tip in tip_list: if is_expired(ISO8601_to_datetime(tip['expiration_date'])): log.info("Deleting an expired Tip (creation date: %s, expiration %s) files %d comments %d" % (tip['creation_date'], tip['expiration_date'], tip['files'], tip['comments'])) yield itip_cleaning(tip['id']) continue # check if the tip is gonna to expire in 48 hours (hard-coded value above) if is_expired(ISO8601_to_datetime(tip['upcoming_expiration_date'])): log.debug("Spotted a Tip matching the upcoming expiration date and " "triggering email notifications") expiring_tips_events = ExpiringTipEvent() yield expiring_tips_events.notify(tip['id']) yield save_events_on_db(expiring_tips_events.events)
def operation(): """ Goal of this function is to check all the submission not finalized, and, if the expiration time sets in the context has been reached, then clean the submission_gus along with the fields, and, if present, the uploaded folder/files. Second goal of this function, is to check all the InternalTip(s) and their expiration date, if match, remove that, all the folder, comment and tip related. """ try: submissions = yield get_tiptime_by_marker(InternalTip._marker[0]) # Submission log.debug("(Cleaning routines) %d unfinished Submission are check if expired" % len(submissions)) for submission in submissions: if is_expired(iso2dateobj(submission["creation_date"]), seconds=submission["submission_life_seconds"]): log.info( "Deleting an unfinalized Submission (creation date: %s) files %d" % (submission["creation_date"], submission["files"]) ) yield itip_cleaning(submission["id"]) tips = yield get_tiptime_by_marker(InternalTip._marker[2]) # First log.debug("(Cleaning routines) %d Tips stored are check if expired" % len(tips)) for tip in tips: if is_expired(iso2dateobj(tip["creation_date"]), seconds=tip["tip_life_seconds"]): log.info( "Deleting an expired Tip (creation date: %s) files %d comments %d" % (tip["creation_date"], tip["files"], tip["comments"]) ) yield itip_cleaning(tip["id"]) except Exception as excep: log.err("Exception failure in submission/tip cleaning routine (%s)" % excep.message) sys.excepthook(*sys.exc_info())
def operation(self): """ Goal of this function is to check all the submission not finalized, and, if the expiration time sets in the context has been reached, then clean the submission_id along with the fields, and, if present, the uploaded folder/files. Second goal of this function, is to check all the InternalTip(s) and their expiration date, if match, remove that, all the folder, comment and tip related. Third goal of this function is to reset the exception counter that acts as limit for mail storm """ try: # First Goal submissions = yield get_tiptime_by_marker( InternalTip._marker[0]) # Submission log.debug( "(Cleaning routines) %d unfinished Submission are check if expired" % len(submissions)) for submission in submissions: if is_expired(ISO8601_to_datetime(submission['creation_date']), GLSetting.defaults.submission_seconds_of_life): log.info( "Deleting an unfinalized Submission (creation %s expiration %s) files %d" % (submission['creation_date'], submission['expiration_date'], submission['files'])) yield itip_cleaning(submission['id']) # Second Goal tips = yield get_tiptime_by_marker(InternalTip._marker[2]) # First log.debug( "(Cleaning routines) %d Tips stored are check if expired" % len(tips)) for tip in tips: if is_expired(ISO8601_to_datetime(tip['expiration_date'])): log.info( "Deleting an expired Tip (creation date: %s, expiration %s) files %d comments %d" % (tip['creation_date'], tip['expiration_date'], tip['files'], tip['comments'])) yield itip_cleaning(tip['id']) # Third Goal: Reset of GLSetting.exceptions GLSetting.exceptions = {} except Exception as excep: log.err( "Exception failure in submission/tip cleaning routine (%s)" % excep.message) sys.excepthook(*sys.exc_info())
def generate_admin_alert_mail(self, event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ do_not_stress_admin_with_more_than_an_email_every_minutes = 120 if not (self.stress_levels['activity'] or self.stress_levels['disk_space']): # we are lucky! no stress activities detected, no mail needed return if GLSettings.memory_copy.notif.disable_admin_notification_emails: return if not is_expired( self.last_alarm_email, minutes= do_not_stress_admin_with_more_than_an_email_every_minutes): return alert = { 'stress_levels': copy.deepcopy(self.stress_levels), 'latest_measured_freespace': copy.deepcopy(self.latest_measured_freespace), 'latest_measured_totalspace': copy.deepcopy(self.latest_measured_totalspace), 'event_matrix': copy.deepcopy(event_matrix) } self.last_alarm_email = datetime_now() return generate_admin_alert_mail(alert)
def perform_secure_deletion_of_temporary_files(self): # Delete the outdated temp files if older than 1 day for f in os.listdir(self.state.settings.tmp_path): path = os.path.join(self.state.settings.tmp_path, f) timestamp = datetime.fromtimestamp(os.path.getmtime(path)) if is_expired(timestamp, days=1): overwrite_and_remove(path)
def operation(self): """ This scheduler is responsible of: - Removal of expired sessions - Reset of failed login attempts counters """ # Removal of expired sessions try: # this list is needed because we can't do "del" # on a list during a loop on it without breaking the loop. sid_to_remove = [] for session_id in GLSetting.sessions: checkd_session = GLSetting.sessions[session_id] if is_expired(checkd_session.refreshdate, seconds=GLSetting.defaults.lifetimes[checkd_session.role]): sid_to_remove.append(session_id) for expired_sid in sid_to_remove: del GLSetting.sessions[expired_sid] if len(sid_to_remove): log.debug("Expired %d sessions" % len(sid_to_remove)) except Exception as excep: log.err("Exception failure in session cleaning routine (%s)" % excep.message) sys.excepthook(*sys.exc_info()) # Reset of failed login attempts counters GLSetting.failed_login_attempts = 0
def update_session(user): """ Returns True if the session is still valid, False instead. Timed out sessions are destroyed. """ session_info = GLSetting.sessions[user.id] if utility.is_expired(session_info.refreshdate, seconds=GLSetting.defaults.lifetimes[user.role]): log.debug("Authentication Expired (%s) %s seconds" % ( user.role, GLSetting.defaults.lifetimes[user.role] )) del GLSetting.sessions[user.id] return False else: # update the access time to the latest GLSetting.sessions[user.id].refreshdate = utility.datetime_now() GLSetting.sessions[user.id].expirydate = utility.get_future_epoch( seconds=GLSetting.defaults.lifetimes[user.role]) return True
def operation(self): """ This scheduler is responsible of: - Removal of expired sessions - Reset of failed login attempts counters """ # Removal of expired sessions try: # this list is needed because we can't do "del" # on a list during a loop on it without breaking the loop. sid_to_remove = [] for session_id in GLSetting.sessions: checkd_session = GLSetting.sessions[session_id] if is_expired(checkd_session.refreshdate, seconds=GLSetting.defaults.lifetimes[ checkd_session.role]): sid_to_remove.append(session_id) for expired_sid in sid_to_remove: del GLSetting.sessions[expired_sid] if len(sid_to_remove): log.debug("Expired %d sessions" % len(sid_to_remove)) except Exception as excep: log.err("Exception failure in session cleaning routine (%s)" % excep.message) sys.excepthook(*sys.exc_info()) # Reset of failed login attempts counters GLSetting.failed_login_attempts = 0
def check_tenant_anomalies(self, tid): """ This function update the Alarm level. """ self.number_of_anomalies = 0 self.event_matrix.clear() for event in State.tenant_state[tid].RecentEventQ: self.event_matrix.setdefault(event.event_type, 0) self.event_matrix[event.event_type] += 1 for event_name, threshold in ANOMALY_MAP.items(): if event_name in self.event_matrix: if self.event_matrix[event_name] > threshold: self.number_of_anomalies += 1 previous_activity_sl = self.alarm_levels['activity'] log_function = log.debug self.alarm_levels['activity'] = 0 if self.number_of_anomalies == 1: log_function = log.info self.alarm_levels['activity'] = 1 elif self.number_of_anomalies > 1: log_function = log.info self.alarm_levels['activity'] = 2 # if there are some anomaly or we're nearby, record it. if self.number_of_anomalies >= 1 or self.alarm_levels['activity'] >= 1: State.tenant_state[tid].AnomaliesQ.append([datetime_now(), self.event_matrix, self.alarm_levels['activity']]) if previous_activity_sl != self.alarm_levels['activity']: log_function("Alarm level changed from %d => %d" % (previous_activity_sl, self.alarm_levels['activity'])) if State.tenant_cache[1].notification.disable_admin_notification_emails: return if not (self.alarm_levels['activity'] or self.alarm_levels['disk_space']): return if not is_expired(self.last_alarm_email, minutes=120): return self.last_alarm_email = datetime_now() alert = { 'alarm_levels': self.alarm_levels, 'measured_freespace': self.measured_freespace, 'measured_totalspace': self.measured_totalspace, 'event_matrix': self.event_matrix } yield generate_admin_alert_mail(tid, alert)
def perform_secure_deletion_of_attachments(self, valid_files): # Delete the attachment files not associated to the database for f in os.listdir(self.state.settings.attachments_path): if f in valid_files: continue path = os.path.join(self.state.settings.attachments_path, f) timestamp = datetime.fromtimestamp(os.path.getmtime(path)) if is_expired(timestamp, days=1): overwrite_and_remove(path)
def generate_admin_alert_mail(self, event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ do_not_stress_admin_with_more_than_an_email_every_minutes = 120 if not (self.stress_levels['activity'] or self.stress_levels['disk_space']): # we are lucky! no stress activities detected, no mail needed return if GLSettings.memory_copy.notif.disable_admin_notification_emails: return if self.last_alarm_email and not is_expired( self.last_alarm_email, minutes= do_not_stress_admin_with_more_than_an_email_every_minutes): return alert = { 'stress_levels': copy.deepcopy(self.stress_levels), 'latest_measured_freespace': copy.deepcopy(self.latest_measured_freespace), 'latest_measured_totalspace': copy.deepcopy(self.latest_measured_totalspace), 'event_matrix': copy.deepcopy(event_matrix) } @transact def _generate_admin_alert_mail(store, alert): for user_desc in db_get_admin_users(store): user_language = user_desc['language'] data = { 'type': u'admin_anomaly', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'alert': alert } subject, body = Templating().get_mail_subject_and_body(data) db_schedule_email(store, user_desc['mail_address'], subject, body) self.last_alarm_email = datetime_now() yield _generate_admin_alert_mail(alert)
def operation(self): """ This function, checks all the InternalTips and their expiration date. if expired InternalTips are found, it removes that along with all the related DB entries comment and tip related. """ # Reset the exception trackiging variable of GLSetting GLSetting.exceptions = {} # Check1: check for expired InternalTips (new tips) new_tips = yield get_tip_timings(True) log.debug("[Tip timings routines / new / expiration ] #%d Tips" % len(new_tips)) for tip in new_tips: if is_expired(ISO8601_to_datetime(tip['expiration_date'])): log.info("Deleting an expired Tip (creation date: %s, expiration %s) files %d comments %d" % (tip['creation_date'], tip['expiration_date'], tip['files'], tip['comments'])) yield itip_cleaning(tip['id']) # Check2: check for expired InternalTips (old tips) old_tips = yield get_tip_timings(False) log.debug("[Tip timings routines / old / expiration upcoming / expire ] #%d Tips" % len(old_tips)) for tip in old_tips: # Check2.1: check if the tip is expired if is_expired(ISO8601_to_datetime(tip['expiration_date'])): log.info("Deleting an expired Tip (creation date: %s, expiration %s) files %d comments %d" % (tip['creation_date'], tip['expiration_date'], tip['files'], tip['comments'])) yield itip_cleaning(tip['id']) # Check2.2: check if the tip is expiring elif is_expired(ISO8601_to_datetime(tip['upcoming_expiration_date'])): log.debug("Spotted a Tip matching the upcoming expiration date and " "triggering email notifications") expiring_tips_events = ExpiringTipEvent() yield expiring_tips_events.notify(tip['id']) yield save_events_on_db(expiring_tips_events.events)
def operation(self): """ Goal of this function is to check all the submission not finalized, and, if the expiration time sets in the context has been reached, then clean the submission_id along with the fields, and, if present, the uploaded folder/files. Second goal of this function, is to check all the InternalTip(s) and their expiration date, if match, remove that, all the folder, comment and tip related. Third goal of this function is to reset the exception counter that acts as limit for mail storm """ try: # First Goal submissions = yield get_tiptime_by_marker(InternalTip._marker[0]) # Submission log.debug("(Cleaning routines) %d unfinished Submission are check if expired" % len(submissions)) for submission in submissions: if is_expired(ISO8601_to_datetime(submission['creation_date']), GLSetting.defaults.submission_seconds_of_life): log.info("Deleting an unfinalized Submission (creation %s expiration %s) files %d" % (submission['creation_date'], submission['expiration_date'], submission['files']) ) yield itip_cleaning(submission['id']) # Second Goal tips = yield get_tiptime_by_marker(InternalTip._marker[2]) # First log.debug("(Cleaning routines) %d Tips stored are check if expired" % len(tips)) for tip in tips: if is_expired(ISO8601_to_datetime(tip['expiration_date'])): log.info("Deleting an expired Tip (creation date: %s, expiration %s) files %d comments %d" % (tip['creation_date'], tip['expiration_date'], tip['files'], tip['comments']) ) yield itip_cleaning(tip['id']) # Third Goal: Reset of GLSetting.exceptions GLSetting.exceptions = {} except Exception as excep: log.err("Exception failure in submission/tip cleaning routine (%s)" % excep.message) sys.excepthook(*sys.exc_info())
def submission_not_expired(self): """ Submission is intended the non-finalized Tip, with a shorter life than completed Tips, and not yet delivered to anyone. (marker 0) """ sub_list = yield cleaning_sched.get_tiptime_by_marker(models.InternalTip._marker[0]) self.assertEqual(len(sub_list), 1) self.assertFalse( is_expired( cleaning_sched.iso2dateobj(sub_list[0]['creation_date']), sub_list[0]['submission_life_seconds']) )
def tip_not_expired(self): """ Tip is intended InternalTip notified and delivered (marker 2, 'first' layer of deliverance) and their life depends by context policies """ tip_list = yield cleaning_sched.get_tiptime_by_marker(models.InternalTip._marker[2]) self.assertEqual(len(tip_list), 1) self.assertFalse( is_expired( cleaning_sched.iso2dateobj(tip_list[0]['creation_date']), tip_list[0]['tip_life_seconds']) )
def perform_secure_deletion_of_files(self): # Delete files that are marked for secure deletion files_to_delete = yield self.get_files_to_secure_delete() for file_to_delete in files_to_delete: overwrite_and_remove(file_to_delete) if files_to_delete: yield self.commit_files_deletion(files_to_delete) # Delete the outdated AES files older than 1 day files_to_remove = [f for f in os.listdir(self.state.settings.tmp_path) if fnmatch.fnmatch(f, '*.aes')] for f in files_to_remove: path = os.path.join(self.state.settings.tmp_path, f) timestamp = datetime.fromtimestamp(os.path.getmtime(path)) if is_expired(timestamp, days=1): overwrite_and_remove(path)
def force_submission_expire(self): sub_list = yield cleaning_sched.get_tiptime_by_marker(models.InternalTip._marker[0]) self.assertEqual(len(sub_list), 1) sub_desc = sub_list[0] sub_desc['submission_life_seconds'] = 0 self.assertTrue( is_expired( cleaning_sched.iso2dateobj(sub_desc['creation_date']), sub_desc['submission_life_seconds']) ) # and then, delete the expired submission yield cleaning_sched.itip_cleaning(sub_desc['id']) new_list = yield cleaning_sched.get_tiptime_by_marker(models.InternalTip._marker[0]) self.assertEqual(len(new_list), 0)
def generate_admin_alert_mail(self, event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ do_not_stress_admin_with_more_than_an_email_every_minutes = 120 if not (self.stress_levels['activity'] or self.stress_levels['disk_space']): # we are lucky! no stress activities detected, no mail needed return if GLSettings.memory_copy.disable_admin_notification_emails: return if self.last_alarm_email and not is_expired(self.last_alarm_email, minutes=do_not_stress_admin_with_more_than_an_email_every_minutes): return alert = { 'stress_levels': copy.deepcopy(self.stress_levels), 'latest_measured_freespace': copy.deepcopy(self.latest_measured_freespace), 'latest_measured_totalspace': copy.deepcopy(self.latest_measured_totalspace), 'event_matrix': copy.deepcopy(event_matrix) } @transact def _generate_admin_alert_mail(store, alert): for user_desc in db_get_admin_users(store): user_language = user_desc['language'] data = { 'address': user_desc['mail_address'], 'type': u'admin_anomaly', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'alert': alert } Templating().db_prepare_mail(store, data) self.last_alarm_email = datetime_now() yield _generate_admin_alert_mail(alert)
def admin_alarm_notification(event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ # import here in order to avoid circular import error from globaleaks.handlers.admin.notification import get_notification do_not_stress_admin_with_more_than_an_email_after_minutes = 15 @transact_ro def _get_node_admin_email(store): node = store.find(models.Node).one() return node.email @transact_ro def _get_admin_user_language(store): admin_user = store.find(models.User, models.User.username == u'admin').one() return admin_user.language @transact_ro def _get_message_template(store): admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() template = notif.admin_anomaly_template if admin_user.language in template: return template[admin_user.language] elif GLSetting.memory_copy.language in template: return template[GLSetting.memory_copy.language] else: raise Exception("Cannot find any language for admin notification") def _activity_alarm_level(): return "%s" % Alarm.stress_levels['activity'] def _activity_dump(): retstr = "" for event, amount in event_matrix.iteritems(): retstr = "%s: %d\n%s" % (event, amount, retstr) return retstr def _disk_alarm_level(): return "%s" % Alarm.stress_levels['disk_space'] def _disk_dump(): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_freespace) def _disk_status_message(): if Alarm.stress_levels['disk_message']: return unicode(Alarm.stress_levels['disk_message']) else: return "Disk space OK" @transact_ro def _node_name(store): node = store.find(models.Node).one() return unicode(node.name) KeyWordTemplate = { "%ActivityAlarmLevel%": _activity_alarm_level, "%ActivityDump%": _activity_dump, "%DiskAlarmLevel%": _disk_alarm_level, "%DiskDump%": _disk_dump, "%DiskErrorMessage%": _disk_status_message, "%NodeName%": _node_name } # ------------------------------------------------------------------ # Here start the Anomaly Notification code, before checking if we have to send email if not (Alarm.stress_levels['activity'] or Alarm.stress_levels['disk_space']): # lucky, no stress activities recorded: no mail needed defer.returnValue(None) if not GLSetting.memory_copy.admin_notif_enable: # event_matrix is {} if we are here only for disk log.debug("Anomaly to be reported %s, but Admin has Notification disabled" % "[%s]" % event_matrix if event_matrix else "") defer.returnValue(None) if Alarm.last_alarm_email: if not is_expired(Alarm.last_alarm_email, minutes=do_not_stress_admin_with_more_than_an_email_after_minutes): log.debug("Alert email want be send, but the threshold of %d minutes is not yet reached since %s" % ( do_not_stress_admin_with_more_than_an_email_after_minutes, datetime_to_ISO8601(Alarm.last_alarm_email))) defer.returnValue(None) # and now, processing the template message = yield _get_message_template() for keyword, templ_funct in KeyWordTemplate.iteritems(): where = message.find(keyword) if where == -1: continue # based on the type of templ_funct, we've to use 'yield' or not # cause some returns a deferred. if isinstance(templ_funct, type(sendmail)): content = templ_funct() else: content = yield templ_funct() message = "%s%s%s" % ( message[:where], content, message[where + len(keyword):]) admin_email = yield _get_node_admin_email() admin_language = yield _get_admin_user_language() notification_settings = yield get_notification(admin_language) message = MIME_mail_build(GLSetting.memory_copy.notif_source_email, GLSetting.memory_copy.notif_source_email, admin_email, admin_email, notification_settings['admin_anomaly_mail_title'], message) log.debug('Alarm Email for admin (%s): connecting to [%s:%d], ' 'the next mail should be in %d minutes' % (event_matrix, GLSetting.memory_copy.notif_server, GLSetting.memory_copy.notif_port, do_not_stress_admin_with_more_than_an_email_after_minutes)) Alarm.last_alarm_email = datetime_now()
def force_tip_expire(self, store): tips = store.find(models.InternalTip) for tip in tips: tip.expiration_date = datetime_null() self.assertTrue(is_expired(tip.expiration_date))
def check_tip_not_expired(self, store): tips = store.find(models.InternalTip) for tip in tips: self.assertFalse(is_expired(tip.expiration_date))
def admin_alarm_generate_mail(event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ do_not_stress_admin_with_more_than_an_email_every_minutes = 120 # if emergency is set to True, the previous time check is ignored. emergency_notification = False @transact_ro def _get_node_admin_email(store): node = store.find(models.Node).one() return node.email @transact_ro def _get_admin_user_language(store): admin_user = store.find(models.User, models.User.username == u'admin').one() return admin_user.language # THE THREE FUNCTIONS BELOW ARE POORLY SUBOPTIMAL, # AND THIS IS BAD: REFACTOR TO BE DONE ON THIS SUBJECT @transact_ro def _get_message_template(store): admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() template = notif.admin_anomaly_mail_template if admin_user.language in template: localized_template = template[admin_user.language] elif GLSettings.memory_copy.default_language in template: localized_template = template[GLSettings.memory_copy.default_language] else: raise Exception("Cannot find any language for admin notification") return localized_template @transact_ro def _disk_anomaly_detail(store): # This happen all the time anomalies are present but disk is ok if Alarm.stress_levels['disk_space'] == 0: return u'' admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() if Alarm.stress_levels['disk_space'] == 1: template = notif.admin_anomaly_disk_low elif Alarm.stress_levels['disk_space'] == 2: template = notif.admin_anomaly_disk_medium elif Alarm.stress_levels['disk_space'] == 3: template = notif.admin_anomaly_disk_high else: raise Exception("Invalid disk stess level %d" % Alarm.stress_levels['disk_space']) if admin_user.language in template: localized_template = template[admin_user.language] elif GLSettings.memory_copy.default_language in template: localized_template = template[GLSettings.memory_copy.default_language] else: raise Exception("Cannot find any language for Admin disk alarm (level %d)" % Alarm.stress_levels['disk_space']) return localized_template @transact_ro def _activities_anomaly_detail(store): # This happen all the time there is not anomalous traffic if Alarm.stress_levels['activity'] == 0: return u'' admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() template = notif.admin_anomaly_activities if admin_user.language in template: localized_template = template[admin_user.language] elif GLSettings.memory_copy.default_language in template: localized_template = template[GLSettings.memory_copy.default_language] else: raise Exception("Cannot find any language for admin notification") return localized_template # END OF THE SUB-OPTIMAL SECTION OF CODE THAT HAS TO BE RESTRUCTURED def _activity_alarm_level(): return "%s" % Alarm.stress_levels['activity'] def _activity_dump(): retstr = "" for event, amount in event_matrix.iteritems(): if not amount: continue retstr = "%s%s%d\n%s" % \ (event, (25 - len(event)) * " ", amount, retstr) return retstr @transact_ro def _node_name(store): node = store.find(models.Node).one() return unicode(node.name) def _free_disk_space(): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_freespace) def _total_disk_space(): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_totalspace) def _notification_suppressed(): if Alarm.stress_levels['notification'] == []: return u'' emergency_notification = True return "** %s **" % Alarm.stress_levels['notification'] KeyWordTemplate = { "%AnomalyDetailDisk%": _disk_anomaly_detail, "%AnomalyDetailActivities%": _activities_anomaly_detail, "%ActivityAlarmLevel%": _activity_alarm_level, "%ActivityDump%": _activity_dump, "%NotificationSuppressed%": _notification_suppressed, "%NodeName%": _node_name, "%FreeMemory%": _free_disk_space, "%TotalMemory%": _total_disk_space, } # ------------------------------------------------------------------ # Independently from the event_matrix, the status of the stress level can # be in non-0 value. # Here start the Anomaly Notification code, before checking if we have to send email if not (Alarm.stress_levels['activity'] or Alarm.stress_levels['disk_space'] or Alarm.stress_levels['notification']): # lucky, no stress activities recorded: no mail needed defer.returnValue(None) if GLSettings.memory_copy.disable_admin_notification_emails: # event_matrix is {} if we are here only for disk log.debug("Anomaly to be reported %s, but Admin has Notification disabled" % "[%s]" % event_matrix if event_matrix else "") defer.returnValue(None) if Alarm.last_alarm_email and not emergency_notification: if not is_expired(Alarm.last_alarm_email, minutes=do_not_stress_admin_with_more_than_an_email_every_minutes): defer.returnValue(None) # This is skipped then: log.debug("Alert [%s] want be sent, but the threshold of %d minutes still unexpired %s" % ( Alarm.stress_levels, do_not_stress_admin_with_more_than_an_email_every_minutes, datetime_to_ISO8601(Alarm.last_alarm_email))) admin_email = yield _get_node_admin_email() admin_language = yield _get_admin_user_language() notification_settings = yield get_notification(admin_language) # and now, processing the template message = yield _get_message_template() message_title = notification_settings['admin_anomaly_mail_title'] recursion_time = 2 # since the ActivityDetails, we've to manage recursion while recursion_time: recursion_time -= 1 for keyword, templ_funct in KeyWordTemplate.iteritems(): where = message.find(keyword) if where == -1: continue # based on the type of templ_funct, we've to use 'yield' or not # cause some returns a deferred. if isinstance(templ_funct, type(sendmail)): content = templ_funct() else: content = yield templ_funct() message = "%s%s%s" % ( message[:where], content, message[where + len(keyword):]) # message title, we can't put the loop together at the moment for keyword, templ_funct in KeyWordTemplate.iteritems(): where = message_title.find(keyword) if where == -1: continue if isinstance(templ_funct, type(sendmail)): content = templ_funct() else: content = yield templ_funct() message_title = "%s%s%s" % ( message_title[:where], content, message_title[where + len(keyword):]) message = MIME_mail_build(GLSettings.memory_copy.notif_source_name, GLSettings.memory_copy.notif_source_email, admin_email, admin_email, message_title, message) log.debug('Alarm Email generated for Admin (%s): connecting to [%s:%d], ' 'the next mail should be in %d minutes' % (event_matrix, GLSettings.memory_copy.notif_server, GLSettings.memory_copy.notif_port, do_not_stress_admin_with_more_than_an_email_every_minutes)) defer.returnValue({ 'admin_email': admin_email, 'message': message, })
def admin_alarm_generate_mail(event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ ret = [] do_not_stress_admin_with_more_than_an_email_every_minutes = 120 def replace_keywords(text): iterations = 3 stop = False while (stop == False and iterations > 0): iterations -= 1 count = 0 for keyword, function in KeywordTemplate.iteritems(): where = text.find(keyword) if where == -1: continue count += 1 text = "%s%s%s" % (text[:where], function(notification_dict), text[where + len(keyword):]) if count == 0: # finally! stop = True break return text def _disk_anomaly_detail(notification_dict): # This happens all the time anomalies are present but disk is ok if Alarm.stress_levels['disk_space'] == 0: return u'' if Alarm.stress_levels['disk_space'] == 1: return notification_dict['admin_anomaly_disk_low'] elif Alarm.stress_levels['disk_space'] == 2: return notification_dict['admin_anomaly_disk_medium'] else: return notification_dict['admin_anomaly_disk_high'] def _activities_anomaly_detail(notification_dict): # This happens all the time there is not anomalous traffic if Alarm.stress_levels['activity'] == 0: return u'' return notification_dict['admin_anomaly_activities'] def _activity_alarm_level(notification_dict): return "%s" % Alarm.stress_levels['activity'] def _activity_dump(notification_dict): retstr = "" for event, amount in event_matrix.iteritems(): if not amount: continue retstr = "%s%s%d\n%s" % \ (event, (25 - len(event)) * " ", amount, retstr) return retstr def _node_name(notification_dict): return unicode(GLSettings.memory_copy.nodename) def _free_disk_space(notification_dict): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_freespace) def _total_disk_space(notification_dict): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_totalspace) def _notifications_suppressed(notification_dict): if Alarm.stress_levels['notification'] == []: return u'' return "** %s **" % Alarm.stress_levels['notification'] KeywordTemplate = { "%AnomalyDetailDisk%": _disk_anomaly_detail, "%AnomalyDetailActivities%": _activities_anomaly_detail, "%ActivityAlarmLevel%": _activity_alarm_level, "%ActivityDump%": _activity_dump, "%NotificationsSuppressed%": _notifications_suppressed, "%NodeName%": _node_name, "%FreeMemory%": _free_disk_space, "%TotalMemory%": _total_disk_space, } # ------------------------------------------------------------------ if not (Alarm.stress_levels['activity'] or Alarm.stress_levels['disk_space'] or Alarm.stress_levels['notification']): # we are lucky! no stress activities detected, no mail needed defer.returnValue([]) if GLSettings.memory_copy.disable_admin_notification_emails: defer.returnValue([]) if Alarm.last_alarm_email: if not is_expired(Alarm.last_alarm_email, minutes=do_not_stress_admin_with_more_than_an_email_every_minutes): defer.returnValue([]) admin_users = yield get_admin_users() for u in admin_users: notification_dict = yield get_notification(u['language']) subject = notification_dict['admin_anomaly_mail_title'] body = notification_dict['admin_anomaly_mail_template'] subject = replace_keywords(subject) body = replace_keywords(body) ret.append({ 'mail_address': u['mail_address'], 'subject': subject, 'body': body }) defer.returnValue(ret)
def admin_alarm_generate_mail(event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ ret = [] do_not_stress_admin_with_more_than_an_email_every_minutes = 120 def replace_keywords(text): iterations = 3 stop = False while (stop == False and iterations > 0): iterations -= 1 count = 0 for keyword, function in KeywordTemplate.iteritems(): where = text.find(keyword) if where == -1: continue count += 1 text = "%s%s%s" % (text[:where], function(notification_dict), text[where + len(keyword):]) if count == 0: # finally! stop = True break def _disk_anomaly_detail(notification_dict): # This happens all the time anomalies are present but disk is ok if Alarm.stress_levels['disk_space'] == 0: return u'' if Alarm.stress_levels['disk_space'] == 1: return notification_dict['admin_anomaly_disk_low'] elif Alarm.stress_levels['disk_space'] == 2: return notification_dict['admin_anomaly_disk_medium'] else: return notification_dict['admin_anomaly_disk_high'] def _activities_anomaly_detail(notification_dict): # This happens all the time there is not anomalous traffic if Alarm.stress_levels['activity'] == 0: return u'' return notification_dict['admin_anomaly_activities'] def _activity_alarm_level(notification_dict): return "%s" % Alarm.stress_levels['activity'] def _activity_dump(notification_dict): retstr = "" for event, amount in event_matrix.iteritems(): if not amount: continue retstr = "%s%s%d\n%s" % \ (event, (25 - len(event)) * " ", amount, retstr) return retstr def _node_name(notification_dict): return unicode(GLSettings.memory_copy.nodename) def _free_disk_space(notification_dict): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_freespace) def _total_disk_space(notification_dict): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_totalspace) def _notifications_suppressed(notification_dict): if Alarm.stress_levels['notification'] == []: return u'' return "** %s **" % Alarm.stress_levels['notification'] KeywordTemplate = { "%AnomalyDetailDisk%": _disk_anomaly_detail, "%AnomalyDetailActivities%": _activities_anomaly_detail, "%ActivityAlarmLevel%": _activity_alarm_level, "%ActivityDump%": _activity_dump, "%NotificationsSuppressed%": _notifications_suppressed, "%NodeName%": _node_name, "%FreeMemory%": _free_disk_space, "%TotalMemory%": _total_disk_space, } # ------------------------------------------------------------------ if not (Alarm.stress_levels['activity'] or Alarm.stress_levels['disk_space'] or Alarm.stress_levels['notification']): # we are lucky! no stress activities detected, no mail needed defer.returnValue([]) if GLSettings.memory_copy.disable_admin_notification_emails: defer.returnValue([]) if Alarm.last_alarm_email: if not is_expired( Alarm.last_alarm_email, minutes= do_not_stress_admin_with_more_than_an_email_every_minutes): defer.returnValue([]) admin_users = yield get_admin_users() for u in admin_users: notification_dict = yield get_notification(u['language']) subject = notification_dict['admin_anomaly_mail_title'] body = notification_dict['admin_anomaly_mail_template'] replace_keywords(subject) replace_keywords(body) ret.append({ 'mail_address': u['mail_address'], 'subject': subject, 'body': body }) defer.returnValue(ret)
def admin_alarm_notification(event_matrix): """ This function put a mail in queue for the Admin, if the configured threshold has been reached for Alarm notification. TODO put a GLSetting + Admin configuration variable, now is hardcoded to notice at >= 1 """ @transact_ro def _get_admin_email(store): node = store.find(models.Node).one() return node.email @transact_ro def _get_message_template(store): admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() template = notif.admin_anomaly_template if admin_user.language in template: return template[admin_user.language] elif GLSetting.memory_copy.default_language in template: return template[GLSetting.memory_copy.default_language] else: raise Exception("Cannot find any language for admin notification") def _aal(): return "%s" % Alarm.stress_levels['activity'] def _ad(): retstr = "" for event, amount in event_matrix.iteritems(): retstr = "%s: %d\n%s" % (event, amount, retstr) return retstr def _dal(): return "%s" % Alarm.stress_levels['disk_space'] def _dd(): return "%s Megabytes" % Alarm.latest_measured_freespace message_required = False if Alarm.stress_levels['activity'] >= 1: message_required = True if Alarm.stress_levels['disk_space'] >= 1: message_required = True if not message_required: # luckly, no mail needed return KeyWordTemplate = { "%ActivityAlarmLevel%" : _aal, "%ActivityDump%" : _ad, "%DiskAlarmLevel%" : _dal, "%DiskDump%" : _dd, } message = yield _get_message_template() for keyword, function in KeyWordTemplate.iteritems(): where = message.find(keyword) message = "%s%s%s" % ( message[:where], function(), message[where + len(keyword):]) if Alarm.last_alarm_email: if not is_expired(Alarm.last_alarm_email, minutes=10): log.debug("Alert email want be send, but the threshold of 10 minutes is not yet reached since %s" % datetime_to_ISO8601(Alarm.last_alarm_email)) return to_address = yield _get_admin_email() message = MIME_mail_build(GLSetting.memory_copy.notif_source_name, GLSetting.memory_copy.notif_source_email, "Tester", to_address, "ALERT: Anomaly detection", message) log.debug('Alarm Email for admin: connecting to [%s:%d]' % (GLSetting.memory_copy.notif_server, GLSetting.memory_copy.notif_port) ) Alarm.last_alarm_email = datetime_now() yield sendmail(authentication_username=GLSetting.memory_copy.notif_username, authentication_password=GLSetting.memory_copy.notif_password, from_address=GLSetting.memory_copy.notif_source_email, to_address=to_address, message_file=message, smtp_host=GLSetting.memory_copy.notif_server, smtp_port=GLSetting.memory_copy.notif_port, security=GLSetting.memory_copy.notif_security, event=None)
def test_is_expired(self): self.assertTrue(utility.is_expired(utility.datetime_null())) self.assertTrue(utility.is_expired(utility.datetime_now())) self.assertFalse(utility.is_expired(utility.datetime_never()))
def login(session, tid, username, password, receiver_second_login, receiver_auth_code, client_using_tor, client_ip, token=''): """ login returns a tuple (user_id, state, role, pcn, authCodePrepared) """ if token: user = session.query(User).filter(User.auth_token == token, \ User.state != u'disabled', \ User.tid == tid).one_or_none() else: user = session.query(User).filter(User.username == username, \ User.state != u'disabled', \ User.tid == tid).one_or_none() if user is None or (not token and not security.check_password( password, user.salt, user.password)): log.debug("Login: Invalid credentials") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication if not client_using_tor and not mystate.tenant_cache[tid]['https_' + user.role]: log.err("Denied login request over Web for role '%s'" % user.role) raise errors.TorNetworkRequired # Check if we're doing IP address checks today if mystate.tenant_cache[tid]['ip_filter_authenticated_enable']: ip_networks = parse_csv_ip_ranges_to_ip_networks( mystate.tenant_cache[tid]['ip_filter_authenticated']) client_ip = text_type(client_ip) client_ip_obj = ipaddress.ip_address(client_ip) # Safety check, we always allow localhost to log in success = False if client_ip_obj.is_loopback is True: success = True for ip_network in ip_networks: if client_ip_obj in ip_network: success = True if success is not True: raise errors.AccessLocationInvalid # se sono arrivato qui il primo login è andato a buon fine # il login (username, password) per un ricevente viene rieseguito anche al secondo passaggio # per motivi di sicurezza # A QUESTO PUNTO: # SE receiver2ndStepLoginState = 'N': # 1 - genero il codice # 2 - memorizzo record in ReceiverAuthCode # 3 - invio mail # ELSE: # verifico la correttenza del secondo codice if user.role == 'receiver': receiver = session.query(Receiver).filter( Receiver.id == user.id).one_or_none() if receiver.two_step_login_enabled and not user.password_change_needed: if receiver_second_login == 'first_login_to_complete': yyyy = str(datetime_now().year) mm = str(datetime_now().month).zfill(2) dd = str(datetime_now().day).zfill(2) result_query = session.query(ReceiverAuthCode).filter( ReceiverAuthCode.receiver_id == user.id, func.strftime("%Y-%m-%d", ReceiverAuthCode.creation_date) == yyyy + '-' + mm + '-' + dd).all() # genero il codice #chiamo la funzione generate_authcode_password che genera la password con l'utilizzo della funzione os.urandom #randnum = ''.join(["%s" % SystemRandom().randint(0, 9) for num in range(0, 12)]) randnum = generate_authcode_password(12) #print randnum log.debug(randnum[0:4] + ' ' + randnum[4:8] + ' ' + randnum[8:12]) # inserisco il record nel db newAuthCode = models.ReceiverAuthCode() newAuthCode.receiver_id = receiver.id newAuthCode.salt = security.generateRandomSalt() newAuthCode.auth_code = security.hash_password( randnum, newAuthCode.salt) session.add(newAuthCode) session.flush() # invio i tre pezzi del codice alle tre mail specificate nel profilo del ricevente email_prg = str(len(result_query) + 1) day = dd + '/' + mm + '/' + yyyy mystate.sendmail( 1, receiver.control_mail_1, "Receiver Auth Code #" + email_prg + " - " + day, randnum[0:4]) mystate.sendmail( 1, receiver.control_mail_2, "Receiver Auth Code #" + email_prg + " - " + day, randnum[4:8]) mystate.sendmail( 1, receiver.control_mail_3, "Receiver Auth Code #" + email_prg + " - " + day, randnum[8:12]) log.debug("Invio delle mail effettuato con successo") receiver_second_login = '******' elif receiver_second_login == 'second_login_to_complete': auth_code_item = session.query(ReceiverAuthCode).filter(ReceiverAuthCode.receiver_id == user.id) \ .order_by(ReceiverAuthCode.creation_date.desc()).first() # se non sono passati TOT minuti dall'ultimo codice emesso si può controllare la validità del codice if auth_code_item is not None and auth_code_item.is_valid and not is_expired( auth_code_item.creation_date, 0, AUTH_CODE_EXPIRATION_IN_MINUTES, 0, 0): # qui devo verificare che il codice inviato dall'utente sia uguale a una delle permutazioni dei tre blocchi # da quattro cifre che si ottengono dal codice salvato sul db firstBlock = receiver_auth_code[0:4] secondBlock = receiver_auth_code[4:8] thirdBlock = receiver_auth_code[8:12] combList = [] combList.insert(0, firstBlock + secondBlock + thirdBlock) combList.insert(1, firstBlock + thirdBlock + secondBlock) combList.insert(2, secondBlock + firstBlock + thirdBlock) combList.insert(3, secondBlock + thirdBlock + firstBlock) combList.insert(4, thirdBlock + firstBlock + secondBlock) combList.insert(5, thirdBlock + secondBlock + firstBlock) auth_code_match = False for authCode in combList: if security.check_password(authCode, auth_code_item.salt, auth_code_item.auth_code): auth_code_match = True # POSSO ANCHE FARE UNA UPDATE del campo is_valid PER IL RECORD UTILIZZATO NELLA VALIDAZIONE auth_code_item.is_valid = False session.add(auth_code_item) session.flush() #objs = session.query(ReceiverAuthCode).filter(ReceiverAuthCode.receiver_id == auth_code_item.receiver_id) \ # .order_by(ReceiverAuthCode.creation_date.desc(), ReceiverAuthCode.daily_prg.desc()) #for obj in objs: # session.delete(obj) # session.flush() #session.delete(auth_code_item) receiver_second_login = '******' break if not auth_code_match: log.debug("Login: Invalid authentication code") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication else: log.debug( "Login: authentication code is expired. Please repeat login" ) Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication else: log.debug( "receiver_auth_code diverso da first_login_to_complete e second_login_to_complete" ) receiver_second_login = '******' else: receiver_second_login = '******' #da tenere sotto controllo else: receiver_second_login = '******' # da tenere sotto controllo log.debug("Login: Success (%s)" % user.role) user.last_login = datetime_now() return user.id, user.state, user.role, user.password_change_needed, receiver_second_login
def admin_alarm_generate_mail(event_matrix): """ This function put a mail in queue for the Admin, if the Admin notification is disable or if another Anomaly has been raised in the last 15 minutes, email is not send. """ do_not_stress_admin_with_more_than_an_email_every_minutes = 120 # if emergency is set to True, the previous time check is ignored. emergency_notification = False @transact_ro def _get_node_admin_email(store): node = store.find(models.Node).one() return node.email @transact_ro def _get_admin_user_language(store): admin_user = store.find(models.User, models.User.username == u'admin').one() return admin_user.language # THE THREE FUNCTIONS BELOW ARE POORLY SUBOPTIMAL, # AND THIS IS BAD: REFACTOR TO BE DONE ON THIS SUBJECT @transact_ro def _get_message_template(store): admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() template = notif.admin_anomaly_mail_template if admin_user.language in template: localized_template = template[admin_user.language] elif GLSettings.memory_copy.default_language in template: localized_template = template[ GLSettings.memory_copy.default_language] else: raise Exception( "Cannot find any language for admin notification") return localized_template @transact_ro def _disk_anomaly_detail(store): # This happen all the time anomalies are present but disk is ok if Alarm.stress_levels['disk_space'] == 0: return u'' admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() if Alarm.stress_levels['disk_space'] == 1: template = notif.admin_anomaly_disk_low elif Alarm.stress_levels['disk_space'] == 2: template = notif.admin_anomaly_disk_medium elif Alarm.stress_levels['disk_space'] == 3: template = notif.admin_anomaly_disk_high else: raise Exception("Invalid disk stess level %d" % Alarm.stress_levels['disk_space']) if admin_user.language in template: localized_template = template[admin_user.language] elif GLSettings.memory_copy.default_language in template: localized_template = template[ GLSettings.memory_copy.default_language] else: raise Exception( "Cannot find any language for Admin disk alarm (level %d)" % Alarm.stress_levels['disk_space']) return localized_template @transact_ro def _activities_anomaly_detail(store): # This happen all the time there is not anomalous traffic if Alarm.stress_levels['activity'] == 0: return u'' admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() template = notif.admin_anomaly_activities if admin_user.language in template: localized_template = template[admin_user.language] elif GLSettings.memory_copy.default_language in template: localized_template = template[ GLSettings.memory_copy.default_language] else: raise Exception( "Cannot find any language for admin notification") return localized_template # END OF THE SUB-OPTIMAL SECTION OF CODE THAT HAS TO BE RESTRUCTURED def _activity_alarm_level(): return "%s" % Alarm.stress_levels['activity'] def _activity_dump(): retstr = "" for event, amount in event_matrix.iteritems(): if not amount: continue retstr = "%s%s%d\n%s" % \ (event, (25 - len(event)) * " ", amount, retstr) return retstr @transact_ro def _node_name(store): node = store.find(models.Node).one() return unicode(node.name) def _free_disk_space(): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_freespace) def _total_disk_space(): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_totalspace) def _notification_suppressed(): if Alarm.stress_levels['notification'] == []: return u'' emergency_notification = True return "** %s **" % Alarm.stress_levels['notification'] KeyWordTemplate = { "%AnomalyDetailDisk%": _disk_anomaly_detail, "%AnomalyDetailActivities%": _activities_anomaly_detail, "%ActivityAlarmLevel%": _activity_alarm_level, "%ActivityDump%": _activity_dump, "%NotificationSuppressed%": _notification_suppressed, "%NodeName%": _node_name, "%FreeMemory%": _free_disk_space, "%TotalMemory%": _total_disk_space, } # ------------------------------------------------------------------ # Independently from the event_matrix, the status of the stress level can # be in non-0 value. # Here start the Anomaly Notification code, before checking if we have to send email if not (Alarm.stress_levels['activity'] or Alarm.stress_levels['disk_space'] or Alarm.stress_levels['notification']): # lucky, no stress activities recorded: no mail needed defer.returnValue(None) if GLSettings.memory_copy.disable_admin_notification_emails: # event_matrix is {} if we are here only for disk log.debug( "Anomaly to be reported %s, but Admin has Notification disabled" % "[%s]" % event_matrix if event_matrix else "") defer.returnValue(None) if Alarm.last_alarm_email and not emergency_notification: if not is_expired( Alarm.last_alarm_email, minutes= do_not_stress_admin_with_more_than_an_email_every_minutes): defer.returnValue(None) # This is skipped then: log.debug( "Alert [%s] want be sent, but the threshold of %d minutes still unexpired %s" % (Alarm.stress_levels, do_not_stress_admin_with_more_than_an_email_every_minutes, datetime_to_ISO8601(Alarm.last_alarm_email))) admin_email = yield _get_node_admin_email() admin_language = yield _get_admin_user_language() notification_settings = yield get_notification(admin_language) # and now, processing the template message = yield _get_message_template() message_title = notification_settings['admin_anomaly_mail_title'] recursion_time = 2 # since the ActivityDetails, we've to manage recursion while recursion_time: recursion_time -= 1 for keyword, templ_funct in KeyWordTemplate.iteritems(): where = message.find(keyword) if where == -1: continue # based on the type of templ_funct, we've to use 'yield' or not # cause some returns a deferred. if isinstance(templ_funct, type(sendmail)): content = templ_funct() else: content = yield templ_funct() message = "%s%s%s" % (message[:where], content, message[where + len(keyword):]) # message title, we can't put the loop together at the moment for keyword, templ_funct in KeyWordTemplate.iteritems(): where = message_title.find(keyword) if where == -1: continue if isinstance(templ_funct, type(sendmail)): content = templ_funct() else: content = yield templ_funct() message_title = "%s%s%s" % (message_title[:where], content, message_title[where + len(keyword):]) message = MIME_mail_build(GLSettings.memory_copy.notif_source_name, GLSettings.memory_copy.notif_source_email, admin_email, admin_email, message_title, message) log.debug( 'Alarm Email generated for Admin (%s): connecting to [%s:%d], ' 'the next mail should be in %d minutes' % (event_matrix, GLSettings.memory_copy.notif_server, GLSettings.memory_copy.notif_port, do_not_stress_admin_with_more_than_an_email_every_minutes)) defer.returnValue({ 'admin_email': admin_email, 'message': message, })
def test_is_expired(self): self.assertFalse(utility.is_expired(None)) self.assertTrue(utility.is_expired(utility.datetime_null())) self.assertTrue(utility.is_expired(utility.datetime_now())) self.assertFalse(utility.is_expired(utility.utc_future_date(seconds=1337)))
def admin_alarm_notification(event_matrix): """ This function put a mail in queue for the Admin, if the configured threshold has been reached for Alarm notification. TODO put a GLSetting + Admin configuration variable, now is hardcoded to notice at >= 1 """ @transact_ro def _get_node_name(store): node = store.find(models.Node).one() return node.email @transact_ro def _get_admin_email(store): node = store.find(models.Node).one() return node.email node_name = yield _get_node_name() admin_email = yield _get_admin_email() @transact_ro def _get_message_template(store): admin_user = store.find(models.User, models.User.username == u'admin').one() notif = store.find(models.Notification).one() template = notif.admin_anomaly_template if admin_user.language in template: return template[admin_user.language] elif GLSetting.memory_copy.language in template: return template[GLSetting.memory_copy.language] else: raise Exception( "Cannot find any language for admin notification") def _aal(): return "%s" % Alarm.stress_levels['activity'] def _ad(): retstr = "" for event, amount in event_matrix.iteritems(): retstr = "%s: %d\n%s" % (event, amount, retstr) return retstr def _dal(): return "%s" % Alarm.stress_levels['disk_space'] def _dd(): return "%s" % bytes_to_pretty_str(Alarm.latest_measured_freespace) def _nn(): return "%s" % node_name message_required = False if Alarm.stress_levels['activity'] >= 1: message_required = True if Alarm.stress_levels['disk_space'] >= 1: message_required = True if not message_required: # luckly, no mail needed return KeyWordTemplate = { "%ActivityAlarmLevel%": _aal, "%ActivityDump%": _ad, "%DiskAlarmLevel%": _dal, "%DiskDump%": _dd, "%NodeSignature%": _nn } message = yield _get_message_template() for keyword, function in KeyWordTemplate.iteritems(): where = message.find(keyword) message = "%s%s%s" % (message[:where], function(), message[where + len(keyword):]) if Alarm.last_alarm_email: if not is_expired(Alarm.last_alarm_email, minutes=10): log.debug( "Alert email want be send, but the threshold of 10 minutes is not yet reached since %s" % datetime_to_ISO8601(Alarm.last_alarm_email)) return message = MIME_mail_build(GLSetting.memory_copy.notif_source_name, GLSetting.memory_copy.notif_source_email, "Admin", admin_email, "ALERT: Anomaly detection", message) log.debug('Alarm Email for admin: connecting to [%s:%d]' % (GLSetting.memory_copy.notif_server, GLSetting.memory_copy.notif_port)) Alarm.last_alarm_email = datetime_now() yield sendmail( authentication_username=GLSetting.memory_copy.notif_username, authentication_password=GLSetting.memory_copy.notif_password, from_address=GLSetting.memory_copy.notif_source_email, to_address=admin_email, message_file=message, smtp_host=GLSetting.memory_copy.notif_server, smtp_port=GLSetting.memory_copy.notif_port, security=GLSetting.memory_copy.notif_security, event=None)