예제 #1
0
    def send_pgp_alerts(self, node_desc, receiver_desc, notification_settings):
        fakeevent = OD()
        fakeevent.type = u'pgp_expiration_alert'
        fakeevent.node_info = node_desc
        fakeevent.context_info = None
        fakeevent.steps_info = None
        fakeevent.receiver_info = receiver_desc
        fakeevent.tip_info = None
        fakeevent.subevent_info = None

        body = Templating().format_template(
            notification_settings['pgp_alert_mail_template'], fakeevent)
        title = Templating().format_template(
            notification_settings['pgp_alert_mail_title'], fakeevent)

        to_address = receiver_desc['mail_address']
        message = MIME_mail_build(GLSetting.memory_copy.notif_source_name,
                                  GLSetting.memory_copy.notif_source_email,
                                  to_address,
                                  to_address,
                                  title,
                                  body)

        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)
예제 #2
0
    def ping_mail_flush(self, notification_settings, receivers_synthesis):
        """
        TODO This function should be implemented as a clean and testable plugin in the
        way defined in plugin/base.py and plugin/notification.py, and/or is the opportunity
        to review these classes, at the moment is a simplified version that just create a
        ping email and send it via sendmail.
        """
        for _, data in receivers_synthesis.iteritems():

            receiver_dict, winks = data

            receiver_name = receiver_dict['name']
            receiver_email = receiver_dict['ping_mail_address']

            fakeevent = OD()
            fakeevent.type = u'ping_mail'
            fakeevent.node_info = None
            fakeevent.context_info = None
            fakeevent.receiver_info = receiver_dict
            fakeevent.tip_info = None
            fakeevent.subevent_info = {'counter': winks}

            body = Templating().format_template(
                notification_settings['ping_mail_template'], fakeevent)
            title = Templating().format_template(
                notification_settings['ping_mail_title'], fakeevent)

            # so comfortable for a developer!! :)
            source_mail_name = GLSettings.developer_name if GLSettings.devel_mode \
                else GLSettings.memory_copy.notif_source_name
            message = MIME_mail_build(source_mail_name,
                                      GLSettings.memory_copy.notif_source_email,
                                      receiver_name,
                                      receiver_email,
                                      title,
                                      body)

            fakeevent2 = OD()
            fakeevent2.type = "Ping mail for %s (%d info)" % (receiver_email, winks)

            return sendmail(authentication_username=GLSettings.memory_copy.notif_username,
                            authentication_password=GLSettings.memory_copy.notif_password,
                            from_address= GLSettings.memory_copy.notif_source_email,
                            to_address= [receiver_email],
                            message_file=message,
                            smtp_host=GLSettings.memory_copy.notif_server,
                            smtp_port=GLSettings.memory_copy.notif_port,
                            security=GLSettings.memory_copy.notif_security,
                            event=fakeevent2)
예제 #3
0
    def do_notify(self, event):

        if event.type == 'digest':
            body = event.tip_info['body']
            title = event.tip_info['title']
        else:
            body, title = self.get_mail_body_and_title(event)

        if not self.validate_admin_opt(event.notification_settings):
            log.err('Invalid Mail Settings, no mail can be deliver')
            return None

        # If the receiver has encryption enabled (for notification), encrypt the mail body
        if event.receiver_info['pgp_key_status'] == u'enabled':

            gpob = GLBPGP()
            try:
                gpob.load_key(event.receiver_info['pgp_key_public'])
                body = gpob.encrypt_message(event.receiver_info['pgp_key_fingerprint'], body)
            except Exception as excep:
                log.err("Error in PGP interface object (for %s: %s)! (notification+encryption)" %
                        (event.receiver_info['username'], str(excep)))

                # On this condition (PGP enabled but key invalid) the only
                # thing to do is to return None;
                # It will be duty of the PGP check schedule will disable the key
                # and advise the user and the admin about that action.
                return None
            finally:
                # the finally statement is always called also if
                # except contains a return or a raise
                gpob.destroy_environment()

        receiver_mail = event.receiver_info['mail_address']

        message = MIME_mail_build(GLSettings.memory_copy.notif_source_name,
                                  GLSettings.memory_copy.notif_source_email,
                                  event.receiver_info['name'],
                                  receiver_mail,
                                  title,
                                  body)

        return self.mail_flush(event.notification_settings['source_email'],
                               [receiver_mail], message, event)
예제 #4
0
    def do_notify(self, event):

        # check if exists the conf
        if not self.validate_admin_opt(event.notification_settings):
            log.info('invalid configuration for admin email!')
            return None

        # At the moment the language used is a system language, not
        # Receiver preferences language ?
        if event.type == u'encrypted_tip':
            body = Templating().format_template(
                event.notification_settings['encrypted_tip_template'], event)
            title = Templating().format_template(
                event.notification_settings['encrypted_tip_mail_title'], event)
        elif event.type == u'plaintext_tip':
            body = Templating().format_template(
                event.notification_settings['plaintext_tip_template'], event)
            title = Templating().format_template(
                event.notification_settings['plaintext_tip_mail_title'], event)
        elif event.type == u'encrypted_file':
            body = Templating().format_template(
                event.notification_settings['encrypted_file_template'], event)
            title = Templating().format_template(
                event.notification_settings['encrypted_file_mail_title'],
                event)
        elif event.type == u'plaintext_file':
            body = Templating().format_template(
                event.notification_settings['plaintext_file_template'], event)
            title = Templating().format_template(
                event.notification_settings['plaintext_file_mail_title'],
                event)
        elif event.type == u'encrypted_comment':
            body = Templating().format_template(
                event.notification_settings['encrypted_comment_template'],
                event)
            title = Templating().format_template(
                event.notification_settings['encrypted_comment_mail_title'],
                event)
        elif event.type == u'plaintext_comment':
            body = Templating().format_template(
                event.notification_settings['plaintext_comment_template'],
                event)
            title = Templating().format_template(
                event.notification_settings['plaintext_comment_mail_title'],
                event)
        elif event.type == u'encrypted_message':
            body = Templating().format_template(
                event.notification_settings['encrypted_message_template'],
                event)
            title = Templating().format_template(
                event.notification_settings['encrypted_message_mail_title'],
                event)
        elif event.type == u'plaintext_message':
            body = Templating().format_template(
                event.notification_settings['plaintext_message_template'],
                event)
            title = Templating().format_template(
                event.notification_settings['plaintext_message_mail_title'],
                event)
        else:
            raise NotImplementedError("At the moment, only Tip expected")

        # If the receiver has encryption enabled (for notification), encrypt the mail body
        if event.receiver_info['gpg_key_status'] == Receiver._gpg_types[1] and \
           event.receiver_info['gpg_enable_notification']:

            try:
                gpob = GLBGPG(event.receiver_info)

                if not gpob.validate_key(event.receiver_info['gpg_key_armor']):
                    log.err("unable to validated GPG key for receiver %s" %
                            event.receiver_info['username'])
                    return None

                body = gpob.encrypt_message(body)
                gpob.destroy_environment()

            except Exception as excep:
                log.err(
                    "Error in GPG interface object (for %s: %s)! (notification+encryption)"
                    % (event.receiver_info['username'], str(excep)))
                return None

        receiver_mail = event.receiver_info['mail_address']

        # XXX here can be catch the subject (may change if encrypted or whatever)
        message = MIME_mail_build(GLSetting.memory_copy.notif_source_name,
                                  GLSetting.memory_copy.notif_source_email,
                                  event.receiver_info['name'], receiver_mail,
                                  title, body)

        if not message:
            log.err("Unable to format (and then notify!) email for %s" %
                    receiver_mail)
            log.debug(body)
            return None

        self.finished = self.mail_flush(
            event.notification_settings['source_email'], [receiver_mail],
            message, event)

        return self.finished
예제 #5
0
    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,
        })
예제 #6
0
    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)
예제 #7
0
    def do_notify(self, event):
        if not self.validate_admin_opt(event.notification_settings):
            log.info('invalid mail settings for admin')
            return None

        # At the moment the language used is a system language, not
        # Receiver preferences language ?
        if event.type == u'encrypted_tip':
            body = Templating().format_template(
                event.notification_settings['encrypted_tip_template'], event)
            title = Templating().format_template(
                event.notification_settings['encrypted_tip_mail_title'], event)
        elif event.type == u'plaintext_tip':
            body = Templating().format_template(
                event.notification_settings['plaintext_tip_template'], event)
            title = Templating().format_template(
                event.notification_settings['plaintext_tip_mail_title'], event)
        elif event.type == u'encrypted_file':
            body = Templating().format_template(
                event.notification_settings['encrypted_file_template'], event)
            title = Templating().format_template(
                event.notification_settings['encrypted_file_mail_title'], event)
        elif event.type == u'plaintext_file':
            body = Templating().format_template(
                event.notification_settings['plaintext_file_template'], event)
            title = Templating().format_template(
                event.notification_settings['plaintext_file_mail_title'], event)
        elif event.type == u'encrypted_comment':
            body = Templating().format_template(
                event.notification_settings['encrypted_comment_template'], event)
            title = Templating().format_template(
                event.notification_settings['encrypted_comment_mail_title'], event)
        elif event.type == u'plaintext_comment':
            body = Templating().format_template(
                event.notification_settings['plaintext_comment_template'], event)
            title = Templating().format_template(
                event.notification_settings['plaintext_comment_mail_title'], event)
        elif event.type == u'encrypted_message':
            body = Templating().format_template(
                event.notification_settings['encrypted_message_template'], event)
            title = Templating().format_template(
                event.notification_settings['encrypted_message_mail_title'], event)
        elif event.type == u'plaintext_message':
            body = Templating().format_template(
                event.notification_settings['plaintext_message_template'], event)
            title = Templating().format_template(
                event.notification_settings['plaintext_message_mail_title'], event)
        else:
            raise NotImplementedError("At the moment, only Tip expected")

        # If the receiver has encryption enabled (for notification), encrypt the mail body
        if event.receiver_info['gpg_key_status'] == u'enabled':

            gpob = GLBGPG()
            try:
                gpob.load_key(event.receiver_info['gpg_key_armor'])
                body = gpob.encrypt_message(event.receiver_info['gpg_key_fingerprint'], body)
            except Exception as excep:
                log.err("Error in GPG interface object (for %s: %s)! (notification+encryption)" %
                        (event.receiver_info['username'], str(excep) ))
                return None # We return None and the mail will be delayed
                            # If GPG is enabled and the key is invalid this
                            # is the only possiibly thing to do.
                            # The PGP check schedule will disable the key
                            # and alert the user and the admin
            finally:
                # the finally statement is always called also if
                # except contains a return or a raise
                gpob.destroy_environment()

        receiver_mail = event.receiver_info['mail_address']

        # XXX here can be catch the subject (may change if encrypted or whatever)
        message = MIME_mail_build(GLSetting.memory_copy.notif_source_name,
                                  GLSetting.memory_copy.notif_source_email,
                                  event.receiver_info['name'],
                                  receiver_mail,
                                  title,
                                  body)

        return self.mail_flush(event.notification_settings['source_email'],
                               [receiver_mail], message, event)