Exemple #1
0
    def _fetch_db(result):
        LOGGER.debug('Open aggregate for item #%d: %r', item_id, result)
        # Si l'info se trouvait dans le cache,
        # on utilise cette valeur là.
        if result is not None:
            # La valeur 0 est utilisée à la place de None
            # dans le cache. On fait la conversion inverse ici.
            if not result:
                return None
            return result

        # Sinon on récupère l'information
        # depuis la base de données...
        state_ok = StateName.statename_to_value('OK')
        state_up = StateName.statename_to_value('UP')
        aggregate = database.run(
            DBSession.query(
                CorrEvent.idcorrevent
            ).join(
                (Event, CorrEvent.idcause == Event.idevent)
            ).filter(
                # Ici, on ne prend pas en compte l'état d'acquittement :
                # on n'agrège jamais une alerte dans un agrégat OK/UP
                # (voir le ticket #1027 pour plus d'information).
                not_(Event.current_state.in_([state_ok, state_up]))
            ).filter(Event.idsupitem == item_id
            ).scalar)

        # ...et on met à jour le cache avant de retourner l'ID.
        # NB: la valeur 0 est utilisée à la place de None pour que
        # le cache puisse réellement servir à l'appel suivant.
        ctx.setShared('open_aggr:%d' % item_id, aggregate or 0)
        return aggregate
Exemple #2
0
 def get_data(self, event):
     state = StateName.value_to_statename(event[0].cause.current_state)
     peak_state = StateName.value_to_statename(event[0].cause.peak_state)
     init_state = StateName.value_to_statename(event[0].cause.initial_state)
     return {
         'state': state,
         'peak_state': peak_state,
         'initial_state': init_state,
         'id': event[0].idcorrevent,
     }
    def test_insert_lls_event(self):
        """Insertion d'un évènement brut concernant un SBN"""

        self.make_dependencies()

        # Création d'un message d'événement portant sur un SBN.
        info_dictionary = {
                "type": "event",
                "timestamp": datetime.fromtimestamp(1239104006),
                "host": "server.example.com",
                "service": "Load",
                "state": u"WARNING",
                "message": u"WARNING: Load average is above 4 (4.5)",
                }
        info_dictionary['idsupitem'] = SupItem.get_supitem(
            info_dictionary['host'],
            info_dictionary['service']
        )

        # Insertion de l'événement dans la BDD
        idevent = insert_event(info_dictionary)

        assert idevent is not None
        event = DBSession.query(Event).one()

        # Vérification des informations de l'événement dans la BDD.
        self.assertEquals(LowLevelService, type(event.supitem))
        self.assertEquals(1239104006, time.mktime(event.timestamp.timetuple()))
        self.assertEquals(u'server.example.com', event.supitem.host.name)
        self.assertEquals(u'Load', event.supitem.servicename)
        self.assertEquals(u'WARNING',
            StateName.value_to_statename(event.current_state))
        self.assertEquals(u'WARNING',
            StateName.value_to_statename(event.initial_state))
        self.assertEquals(u'WARNING',
            StateName.value_to_statename(event.peak_state))
        self.assertEquals(u'WARNING: Load average is above 4 (4.5)',
                            event.message)

        # Insertion de l'état dans la BDD
        state = DBSession.query(State).get(info_dictionary['idsupitem'])
        # le timestamp par défaut est plus récent et insert_state refusera la
        # mise à jour
        state.timestamp = info_dictionary['timestamp']
        insert_state(info_dictionary)

        # Vérification des informations de l'état dans la BDD.
        self.assertEquals(LowLevelService, type(state.supitem))
        self.assertEquals(1239104006, time.mktime(state.timestamp.timetuple()))
        self.assertEquals('server.example.com', state.supitem.host.name)
        self.assertEquals('Load', state.supitem.servicename)
        self.assertEquals('WARNING',
            StateName.value_to_statename(state.state))
        self.assertEquals('WARNING: Load average is above 4 (4.5)',
                            state.message)
Exemple #4
0
def close_green(logger, options):
    """
    Cette fonction ferme les événements qui apparaissent
    en vert dans VigiBoard (c'est-à-dire ceux dans l'état
    "OK" ou "UP").

    @param logger: Logger à utiliser pour afficher des messages.
    @type logger: C{logging.Logger}
    @param options: Liste d'options demandées par l'utilisateur
        du script.
    @type options: C{optparse.Values}
    @return: Nombre d'événements qui ont été fermés automatiquement.
    @rtype: C{int}
    """
    from vigilo.models.session import DBSession
    from vigilo.models.tables import Event, CorrEvent, StateName, EventHistory

    sought_states = []
    if options.state_up:
        sought_states.append(StateName.statename_to_value(u'UP'))
    if options.state_ok:
        sought_states.append(StateName.statename_to_value(u'OK'))

    query = DBSession.query(
            CorrEvent
        ).join(
            (Event, Event.idevent == CorrEvent.idcause),
        ).filter(Event.current_state.in_(sought_states)
        ).filter(CorrEvent.ack != CorrEvent.ACK_CLOSED)
    if options.days is not None and options.days > 0:
        # Génère une date qui se trouve options.days jours dans le passé.
        old_date = datetime.fromtimestamp(time.time() - options.days * 86400)
        query = query.filter(CorrEvent.timestamp_active <= old_date)

    events = query.all()
    username = unicode(pwd.getpwuid(os.getuid())[0])
    for event in events:
        logger.info(_('closing event on %s') % event.cause.supitem)

        # On ajoute un message dans l'historique pour la traçabilité.
        history = EventHistory(
                type_action=u"Acknowledgement change state",
                idevent=event.idcause,
                value=u"",
                text=u"Automatically marked the event as closed",
                username=username,
                timestamp=datetime.now(),
            )
        DBSession.add(history)

        # On referme l'événement.
        event.ack = CorrEvent.ACK_CLOSED
        DBSession.flush()
    return len(events)
    def test_insert_host_event(self):
        """Insertion d'un évènement brut concernant un hôte"""

        self.make_dependencies()

        # Création d'un message d'événement portant sur un hôte.
        info_dictionary = {
                "type": "event",
                "timestamp": datetime.fromtimestamp(1239104006),
                "host": "server.example.com",
                "state": u"DOWN",
                "message": u"DOWN: No ping response",
                }
        info_dictionary['idsupitem'] = SupItem.get_supitem(
            info_dictionary['host'], None,
        )

        # Insertion de l'événement dans la BDD
        idevent = insert_event(info_dictionary)

        assert idevent is not None
        event = DBSession.query(Event).one()

        # Vérification des informations de l'événement dans la BDD.
        self.assertEquals(Host, type(event.supitem))
        self.assertEquals(1239104006, time.mktime(event.timestamp.timetuple()))
        self.assertEquals(u'server.example.com', event.supitem.name)
        self.assertEquals(u'DOWN',
            StateName.value_to_statename(event.current_state))
        self.assertEquals(u'DOWN',
            StateName.value_to_statename(event.initial_state))
        self.assertEquals(u'DOWN',
            StateName.value_to_statename(event.peak_state))
        self.assertEquals(u'DOWN: No ping response',
                            event.message)

        # Insertion de l'état dans la BDD
        state = DBSession.query(State).get(info_dictionary['idsupitem'])
        # le timestamp par défaut est plus récent et insert_state refusera la
        # mise à jour
        state.timestamp = info_dictionary['timestamp']
        insert_state(info_dictionary)

        # Vérification des informations de l'état dans la BDD.
        self.assertEquals(Host, type(state.supitem))
        self.assertEquals(1239104006, time.mktime(state.timestamp.timetuple()))
        self.assertEquals('server.example.com', state.supitem.name)
        self.assertEquals('DOWN',
            StateName.value_to_statename(state.state))
        self.assertEquals('DOWN: No ping response', state.message)
Exemple #6
0
def insert_hls_history(info_dictionary):
    """
    Insère le nouvel état du service de haut niveau dans HLSHistory
    afin de conserver une trace.

    @param info_dictionary: Dictionnaire contenant les informations
        extraites du message d'alerte reçu par le rule dispatcher.
    @type info_dictionary: C{dict}
    """

    if not info_dictionary['idsupitem']:
        LOGGER.error(_('Got a reference to a non configured high-level '
                        'service (%(service)r)'), {
                            "service": info_dictionary["service"],
                        })
        return None

    history = HLSHistory()
    history.idhls = info_dictionary['idsupitem']
    # On enregistre l'heure à laquelle le message a
    # été traité plutôt que le timestamp du message.
    history.timestamp = datetime.now()
    history.idstatename = StateName.statename_to_value(
                            info_dictionary['state'])
    DBSession.add(history)
Exemple #7
0
    def get_data(self, event):
        cause = event[0].cause
        ack = event[0].ack
        state = StateName.value_to_statename(cause.current_state)

        trouble_ticket_id = None
        trouble_ticket_link = None
        if event[0].trouble_ticket:
            trouble_ticket_id = event[0].trouble_ticket
            trouble_ticket_link = tg.config['vigiboard_links.tt'] % {
                'id': event[0].idcorrevent,
                'host': event[1] and urllib.quote(event[1].encode('utf8'), '') or event[1],
                'service': event[2] and urllib.quote(event[2].encode('utf8'), '') or event[2],
                'tt': trouble_ticket_id and \
                        urllib.quote(trouble_ticket_id.encode('utf8'), '') or \
                        trouble_ticket_id,
            }

        return {
            'trouble_ticket_link': trouble_ticket_link,
            'trouble_ticket_id': trouble_ticket_id,
            'state': state,
            'id': event[0].idcorrevent,
            'ack': ack,
        }
    def process(self, link, msg_id):
        """
        Traitement du message par la règle.

        @param link: Objet servant de lien avec le dispatcher et pouvant
            par exemple être utilisé pour envoyer des messages sur le bus.
        @type link: C{vigilo.correlator.actors.rule_runner.RuleRunner}
        @param msg_id: Identifiant de l'alerte brute traitée.
        @type  msg_id: C{unicode}
        """

        ctx = self._get_context(msg_id)
        hostname = ctx.get('hostname')
        servicename = ctx.get('servicename')

        if servicename or not hostname:
            return # On ne traite que les évènements sur les hôtes

        statename = ctx.get('statename')
        previous_state = ctx.get('previous_state')
        if previous_state is None:
            previous_statename = "UP" # inconnu = UP
        else:
            previous_statename = StateName.value_to_statename(previous_state)
        if statename == previous_statename:
            return # Pas de changement

        if previous_statename == "UP" and statename in ("DOWN", "UNREACHABLE"):
            link.registerCallback(fn=on_host_down, idnt=msg_id)
        elif previous_statename in ("DOWN", "UNREACHABLE") and statename == "UP":
            self._on_host_up(hostname, link)
        else:
            LOGGER.info(_("Unsupported transition: %(from)s -> %(to)s"),
                        {"from": previous_statename, "to": statename})
def insert_deps():
    """Insère les dépendances nécessaires aux tests."""
    timestamp = datetime.now()

    host = Host(
        name=u'bar',
        description=u'',
        hosttpl=u'',
        address=u'127.0.0.1',
        snmpport=42,
        snmpcommunity=u'public',
        snmpversion=u'3',
        weight=42,
    )
    DBSession.add(host)
    DBSession.flush()

    hostgroup = SupItemGroup(name=u'foo', parent=None)
    hostgroup.supitems.append(host)
    DBSession.add(hostgroup)
    DBSession.flush()

    event = Event(
        supitem=host,
        timestamp=timestamp,
        current_state=StateName.statename_to_value(u'WARNING'),
        message=u'Hello world',
    )
    DBSession.add(event)
    DBSession.flush()

    correvent = CorrEvent(
        priority=42,
        trouble_ticket=u'FOO BAR BAZ éçà',
        ack=CorrEvent.ACK_NONE,
        occurrence=42,
        timestamp_active=timestamp,
        cause=event,
    )
    correvent.events.append(event)
    DBSession.add(correvent)
    DBSession.flush()

    # On donne l'accès aux données.
    usergroup = UserGroup.by_group_name(u'users')
    DBSession.add(DataPermission(
        group=hostgroup,
        usergroup=usergroup,
        access=u'r',
    ))
    DBSession.flush()
    return timestamp
Exemple #10
0
    def check_connectors_freshness(self):
        """
        Vérifie dans la base de données la date de dernière mise à jour de
        l'état des connecteurs Nagios. Retourne la liste des machines dont le
        connecteur Nagios n'a pas donné signe de vie depuis plus d'une certaine
        durée (modifiable dans le fichier de settings de l'application).
        """

        threshold = int(config['freshness_threshold'])
        if threshold <= 0:
            return []

        # On récupère dans la BDD la liste des connecteurs nagios
        # avec leur état et leur date de dernière mise à jour
        collectors = DBSession.query(
            Host.name,
            State.state,
            State.timestamp
        ).join(
            (LowLevelService, Host.idhost == LowLevelService.idhost)
        ).join(
            (State, LowLevelService.idservice == State.idsupitem)
        ).filter(
            LowLevelService.servicename == 'vigilo-connector-nagios'
        ).all()

        # En partant de cette première liste on en construit une
        # seconde ne contenant que les noms des connecteurs en panne
        collectors_down = []
        for c in collectors :
            if c.state not in [
                StateName.statename_to_value('OK'),
                StateName.statename_to_value('WARNING')
            ] or c.timestamp <= datetime.now() - timedelta(seconds=threshold):
                collectors_down.append(c.name)

        # On retourne cette seconde liste
        return collectors_down
    def test_reuse_event_with_no_correvent(self):
        """Ne pas créer de nouvel événement brut sans CorrEvent (#908)."""
        self.make_dependencies()
        host = DBSession.query(Host).first()
        ts = int(time.time())

        # On crée un événement brut, qu'on ne rattache
        # à aucun événement corrélé.
        DBSession.add(
            Event(
                supitem=host,
                current_state=StateName.statename_to_value(u"WARNING"),
                message="WARNING: ping",
                timestamp=datetime.fromtimestamp(ts - 42),
            )
        )
        DBSession.flush()

        # Préparation des informations du messages
        # et mise à jour de l'événement brut en base.
        info_dictionary = {
            "timestamp": datetime.fromtimestamp(ts),
            "host": host.name,
            "service": None,
            "state": u"CRITICAL",
            "message": u"CRITICAL: even worse",
            "idsupitem": SupItem.get_supitem(host.name, None),
        }
        insert_event(info_dictionary)

        # Aucun nouvel événement brut ne doit avoir été créé.
        event = DBSession.query(Event).one()
        # À la place, l'événement initial doit avoir été mis à jour.
        self.assertEquals(datetime.fromtimestamp(ts), event.timestamp)
        self.assertEquals(StateName.statename_to_value(u"CRITICAL"), event.current_state)
        self.assertEquals(StateName.statename_to_value(u"CRITICAL"), event.peak_state)
        self.assertEquals(StateName.statename_to_value(u"WARNING"), event.initial_state)
        self.assertEquals(info_dictionary["message"], event.message)
Exemple #12
0
    def process(self, link, msg_id):
        """
        Traitement du message par la règle.

        @param link: Objet servant de lien avec le dispatcher et pouvant
            par exemple être utilisé pour envoyer des messages sur le bus.
        @type link: C{vigilo.correlator.actors.rule_runner.RuleRunner}
        @param msg_id: Identifiant de l'alerte brute traitée.
        @type  msg_id: C{unicode}
        """
        ctx = self._get_context(msg_id)
        priority = ctx.get('priority')
        item_id = ctx.get('idsupitem')

        state_ok = StateName.statename_to_value(u'OK')
        state_up = StateName.statename_to_value(u'UP')
        curr_priority = self._database.run(
            DBSession.query(
                CorrEvent.priority
            ).join(
                (Event, CorrEvent.idcause == Event.idevent),
                (SupItem, SupItem.idsupitem == Event.idsupitem),
            ).filter(SupItem.idsupitem == item_id
            ).filter(
                not_(and_(
                    Event.current_state.in_([state_ok, state_up]),
                    CorrEvent.ack == CorrEvent.ACK_CLOSED
                ))
            ).scalar)

        if curr_priority is None or priority is None:
            return

        if settings['correlator']['priority_order'] == 'asc':
            priority = min(priority, curr_priority)
        else:
            priority = max(priority, curr_priority)
        ctx.set('priority', priority)
Exemple #13
0
def insert_state(info_dictionary):
    """
    Insère l'état fourni par un message d'événement dans la BDD.

    Retourne cet état instancié.

    @param info_dictionary: Dictionnaire contenant les informations
    extraites du message d'alerte reçu par le rule dispatcher.
    @type info_dictionary: C{dict}
    """

    if not info_dictionary['idsupitem']:
        LOGGER.error(_('Got a reference to a non configured item '
                       '(%(host)r, %(service)r), skipping state'), {
                            "host": info_dictionary["host"],
                            "service": info_dictionary["service"],
                        })
        return None

    # On vérifie s'il existe déjà un état
    # enregistré dans la BDD pour cet item.
    state = DBSession.query(State).get(info_dictionary['idsupitem'])

    # Le cas échéant, on le crée.
    if not state:
        state = State(idsupitem=info_dictionary['idsupitem'])
    elif state and state.timestamp > info_dictionary["timestamp"]:
        return OldStateReceived(state.timestamp, info_dictionary["timestamp"])

    previous_state = state.state

    # On met à jour l'état dans la BDD
    state.message = info_dictionary["message"]
    state.timestamp = info_dictionary["timestamp"]
    state.state = StateName.statename_to_value(info_dictionary["state"])

    DBSession.add(state)
    return previous_state
    def test_reuse_correvent_if_possible(self):
        """Privilégier la réutilisation des CorrEvents (#908)."""
        self.make_dependencies()
        host = DBSession.query(Host).first()
        ts = int(time.time())

        # On crée un événement brut, qu'on ne rattache
        # à aucun événement corrélé.
        DBSession.add(
            Event(
                supitem=host,
                current_state=StateName.statename_to_value(u"WARNING"),
                message="WARNING: ping",
                timestamp=datetime.fromtimestamp(ts - 42),
            )
        )
        DBSession.flush()

        # On crée un deuxième événement brut correspondant au même
        # élément supervisé, cette fois rattaché à un événement corrélé.
        event = Event(
            supitem=host,
            current_state=StateName.statename_to_value(u"WARNING"),
            message="WARNING: ping2",
            timestamp=datetime.fromtimestamp(ts - 21),
        )
        correvent = CorrEvent(
            cause=event,
            priority=1,
            trouble_ticket=u"azerty1234",
            ack=CorrEvent.ACK_CLOSED,
            occurrence=1,
            timestamp_active=datetime.fromtimestamp(ts - 21),
        )
        correvent.events = [event]
        DBSession.add(event)
        DBSession.add(correvent)
        DBSession.flush()

        # Préparation des informations du messages
        # et mise à jour de l'événement brut en base.
        info_dictionary = {
            "timestamp": datetime.fromtimestamp(ts),
            "host": host.name,
            "service": None,
            "state": u"CRITICAL",
            "message": u"CRITICAL: even worse",
            "idsupitem": SupItem.get_supitem(host.name, None),
        }
        insert_event(info_dictionary)

        # On doit toujours avoir 2 événements bruts en base.
        self.assertEquals(2, DBSession.query(Event).count())
        # On doit avoir un seul événement corrélé.
        correvent = DBSession.query(CorrEvent).one()
        # La cause de cet événement corrélé
        # doit toujours être la même.
        DBSession.refresh(event)
        self.assertEquals(event, correvent.cause)

        # L'événement brut associé à l'événement
        # corrélé doit avoir été mis à jour.
        self.assertEquals(datetime.fromtimestamp(ts), event.timestamp)
        self.assertEquals(StateName.statename_to_value(u"CRITICAL"), event.current_state)
        self.assertEquals(StateName.statename_to_value(u"CRITICAL"), event.peak_state)
        self.assertEquals(StateName.statename_to_value(u"WARNING"), event.initial_state)
        self.assertEquals(info_dictionary["message"], event.message)

        # L'autre événement brut ne doit pas avoir changé.
        event = DBSession.query(Event).filter(Event.idevent != event.idevent).one()
        self.assertEquals(datetime.fromtimestamp(ts - 42), event.timestamp)
        self.assertEquals(StateName.statename_to_value(u"WARNING"), event.current_state)
        self.assertEquals(StateName.statename_to_value(u"WARNING"), event.peak_state)
        self.assertEquals(StateName.statename_to_value(u"WARNING"), event.initial_state)
        self.assertEquals("WARNING: ping", event.message)
Exemple #15
0
 def test_default_state(self):
     """L'état initial d'un hôte est 'UP'."""
     assert_equals(u'UP', StateName.value_to_statename(
         DBSession.query(self.klass).one().state.state))
Exemple #16
0
 def do_get_dependencies(self):
     """Création des dépendances du test."""
     super(TestHLSHistory, self).do_get_dependencies()
     hls = functions.add_highlevelservice(u"HLS")
     idstatename = StateName.statename_to_value(u"WARNING")
     return dict(hls=hls, idstatename=idstatename)
Exemple #17
0
    def get_json_data(self, idcorrevent, *args, **kwargs):
        """
        Renvoie les éléments pour l'affichage de la fenêtre de dialogue
        contenant des détails sur un événement corrélé.

        @param idcorrevent: identifiant de l'événement corrélé.
        @type idcorrevent: C{int}
        """

        # Obtention de données sur l'événement et sur son historique
        host_query = DBSession.query(
            Host.idhost.label("idsupitem"),
            Host.idhost.label("idhost"),
            Host.name.label("host"),
            expr_null().label("service"),
        )
        lls_query = DBSession.query(
            LowLevelService.idservice.label("idsupitem"),
            Host.idhost.label("idhost"),
            Host.name.label("host"),
            LowLevelService.servicename.label("service"),
        ).join(
            (Host, Host.idhost == LowLevelService.idhost),
        )
        supitems = union_all(lls_query, host_query, correlate=False).alias()
        event = DBSession.query(
            CorrEvent.idcorrevent,
            CorrEvent.idcause,
            supitems.c.idhost,
            supitems.c.host,
            supitems.c.service,
            Event.message,
            Event.initial_state,
            Event.current_state,
            Event.peak_state
        ).join(
            (Event, Event.idevent == CorrEvent.idcause),
            (supitems, supitems.c.idsupitem == Event.idsupitem),
        ).filter(CorrEvent.idcorrevent == idcorrevent
        ).first()

        # On détermine les cartes auxquelles cet utilisateur a accès.
        user_maps = []
        max_maps = int(config['max_maps'])
        is_manager = config.is_manager.is_met(request.environ)
        if max_maps != 0 and (is_manager or
            has_permission('vigimap-access').is_met(request.environ)):
            items = DBSession.query(
                    Map.idmap,
                    Map.title,
                    func.lower(Map.title),
                ).distinct(
                ).join(
                    (MAP_GROUP_TABLE, MAP_GROUP_TABLE.c.idmap == Map.idmap),
                    (MapGroup, MapGroup.idgroup == MAP_GROUP_TABLE.c.idgroup),
                    (MapNodeHost, MapNodeHost.idmap == Map.idmap),
                ).order_by(func.lower(Map.title).asc()
                ).filter(MapNodeHost.idhost == event.idhost)

            if not is_manager:
                mapgroups = get_current_user().mapgroups(only_direct=True)
                # pylint: disable-msg=E1103
                items = items.filter(MapGroup.idgroup.in_(mapgroups))

            # La valeur -1 supprime la limite.
            if max_maps > 0:
                # On limite au nombre maximum de cartes demandés + 1.
                # Un message sera affiché s'il y a effectivement plus
                # de cartes que la limite configurée.
                items = items.limit(max_maps + 1)

            user_maps = [(m.idmap, m.title) for m in items.all()]

        context = {
            'idcorrevent': idcorrevent,
            'host': event.host,
            'service': event.service,
            'message': event.message,
            'maps': user_maps,
            'current_state': StateName.value_to_statename(event.current_state),
            'initial_state': StateName.value_to_statename(event.initial_state),
            'peak_state': StateName.value_to_statename(event.peak_state),
        }

        eventdetails = {}
        for edname, edlink in enumerate(config['vigiboard_links.eventdetails']):
            # Évite que les gardes ne se polluent entre elles.
            local_ctx = context.copy()

            # Les liens peuvent être conditionnés à l'aide
            # d'une expression ou d'un callable qui agira
            # comme un prédicat de test.
            if 'only_if' in edlink:
                if callable(edlink['only_if']):
                    display_link = edlink['only_if'](local_ctx)
                else:
                    display_link = edlink['only_if']
                if not display_link:
                    continue

            if callable(edlink['uri']):
                uri = edlink['uri'](local_ctx)
            else:
                uri = edlink['uri'] % local_ctx

            eventdetails[unicode(edname)] = {
                'url': url(uri),
                'target': edlink.get('target', '_blank')
            }

        return dict(
                current_state = StateName.value_to_statename(
                                    event.current_state),
                initial_state = StateName.value_to_statename(
                                    event.initial_state),
                peak_state = StateName.value_to_statename(
                                    event.peak_state),
                idcorrevent = idcorrevent,
                host = event.host,
                service = event.service,
                eventdetails = eventdetails,
                maps = user_maps,
                idcause = event.idcause,
            )
Exemple #18
0
def insert_event(info_dictionary):
    """
    Insère un événement dans la BDD.
    Retourne l'identifiant de cet événement.

    @param info_dictionary: Dictionnaire contenant les informations
    extraites du message d'alerte reçu par le rule dispatcher.
    @type info_dictionary: C{dict}
    @return: L'identifiant de l'événement dans la BDD.
    @rtype: C{int}
    """

    # S'il s'agit d'un événement concernant un HLS.
    if not info_dictionary["host"]:
        LOGGER.error(_('Received request to add an event on HLS "%s"'),
                            info_dictionary["service"])
        return None

    if not info_dictionary['idsupitem']:
        LOGGER.error(_('Got a reference to a non configured item '
                       '(%(host)r, %(service)r), skipping event'), {
                            "host": info_dictionary["host"],
                            "service": info_dictionary["service"],
                        })
        return None

    # On recherche un éventuel évènement brut concernant cet item.
    # L'événement doit être associé à un événement corrélé ouvert
    # ou bien ne pas être à rattaché à un événement corrélé du tout.
    cause_event = aliased(Event)
    current_event = aliased(Event)
    # On privilégie les événements bruts associés à un événement corrélé.
    order_clause = (CorrEvent.idcorrevent != None)
    event = DBSession.query(
                current_event,
                order_clause,   # Doit être présent dans le SELECT
                                # pour satisfaire PostgreSQL.
            ).outerjoin(
                (EVENTSAGGREGATE_TABLE, EVENTSAGGREGATE_TABLE.c.idevent ==
                    current_event.idevent),
                (CorrEvent, CorrEvent.idcorrevent ==
                    EVENTSAGGREGATE_TABLE.c.idcorrevent),
                (cause_event, cause_event.idevent == CorrEvent.idcause),
            ).filter(current_event.idsupitem == info_dictionary['idsupitem']
            ).filter(
                or_(
                    # Soit l'événement brut n'est pas
                    # rattaché à un événement corrélé.
                    CorrEvent.idcorrevent == None,

                    # Soit l'événement corrélé auquel
                    # il est rattaché est toujours ouvert.
                    not_(
                        and_(
                            cause_event.current_state.in_([
                                StateName.statename_to_value(u'OK'),
                                StateName.statename_to_value(u'UP')
                            ]),
                            CorrEvent.ack == CorrEvent.ACK_CLOSED
                        )
                    )
                )
            ).order_by(order_clause.desc()
            ).distinct().limit(2).all()

    # Si aucun événement correpondant à cet item ne figure dans la base
    if not event:
        # Si l'état de cette alerte est 'OK', on l'ignore
        if info_dictionary["state"] == "OK" or \
            info_dictionary["state"] == "UP":
            LOGGER.info(_('Ignoring request to create a new event '
                            'with state "%s" (nothing alarming here)'),
                            info_dictionary['state'])
            raise NoProblemException(info_dictionary.copy())
        # Sinon, il s'agit d'un nouvel incident, on le prépare.
        event = Event()
        event.idsupitem = info_dictionary['idsupitem']
        LOGGER.debug(_('Creating new event'))

    # Si plusieurs événements ont été trouvés
    else:
        if len(event) > 1:
            LOGGER.warning(_('Multiple raw events found, '
                             'using the first one available.'))
        # On sélectionne le premier Event parmi la liste
        # des tuples (Event, CorrEvent.idcorrevent != None).
        event = event[0][0]
        LOGGER.debug(_('Updating event %r'), event.idevent)

    # Nouvel état.
    new_state_value = StateName.statename_to_value(info_dictionary['state'])
    is_new_event = event.idevent is None

    # S'agit-il d'un événement important ?
    # Un événement est important s'il s'agit d'un nouvel événement
    # ou si un champ autre que le timestamp ou le message a changé.
    info_dictionary['important'] = is_new_event or \
                                    event.current_state != new_state_value or \
                                    event.message != info_dictionary['message']


    # Mise à jour de l'évènement.
    event.timestamp = info_dictionary['timestamp']
    event.current_state = new_state_value
    event.message = info_dictionary['message']

    # Sauvegarde de l'évènement.
    DBSession.add(event)

    # Les événements importants donnent lieu à l'ajout
    # d'une entrée dans l'historique.
    if info_dictionary['important']:
        history = EventHistory()

        history.type_action = is_new_event and \
                                u'New occurrence' or \
                                u'Nagios update state'

        try:
            history.state = \
                StateName.statename_to_value(info_dictionary['state'])
        except KeyError:
            # Si le nom d'état n'est pas reconnu, on ne fait rien.
            pass

        history.value = info_dictionary['state']
        history.text = info_dictionary['message']
        history.timestamp = info_dictionary['timestamp']
        history.username = None
        history.event = event
        DBSession.add(history)

    DBSession.flush()
    return event.idevent
Exemple #19
0
 def get_data(self, event):
     state = StateName.value_to_statename(event[0].cause.current_state)
     return {
         'state': state,
         'occurrences': event[0].occurrence,
     }
Exemple #20
0
 def test_default_state(self):
     """L'état initial d'un service de haut niveau est 'UNKNOWN'."""
     assert_equals(u'UNKNOWN', StateName.value_to_statename(
         DBSession.query(self.klass).one().state.state))
Exemple #21
0
def clean_vigiboard(logger, options, url):
    """
    Cette fonction supprime les événements les plus anciens et
    correspondant à des agrégats fermés des tables utilisées
    par VigiBoard.

    @param logger: Logger à utiliser pour afficher des messages.
    @type logger: C{logging.Logger}
    @param options: Liste d'options demandées par l'utilisateur
        du script.
    @type options: C{optparse.Values}
    @param url: Adresse de la base de données, sous la forme d'une URL
        déjà pré-traitée par SQLAlchemy.
    @type url: C{sqlalchemy.engine.url.URL}
    """
    from vigilo.models.session import DBSession
    from vigilo.models.tables import Event, CorrEvent, StateName, HLSHistory

    sought_states = [
        StateName.statename_to_value(u'OK'),
        StateName.statename_to_value(u'UP'),
    ]

    if options.days is not None:
        if options.days >= 0:
            # Génère une date qui se trouve options.days jours dans le passé.
            old_date = datetime.fromtimestamp(
                time.time() - options.days * 86400)

            # On supprime tous les événements dont l'idevent correspond à
            # un événement corrélé dont la dernière date d'activation est
            # plus vieille que old_date.
            # Comme les relations/FK sont créées en CASCADE, la suppression
            # des événements entraine aussi la suppression des événements
            # corrélés, des agrégats et de l'historique des événements.
            ids = DBSession.query(
                    Event.idevent
                ).join(
                    (CorrEvent, Event.idevent == CorrEvent.idcause)
                ).filter(Event.current_state.in_(sought_states)
                ).filter(CorrEvent.ack == CorrEvent.ACK_CLOSED
                ).filter(CorrEvent.timestamp_active <= old_date).all()
            ids = [event.idevent for event in ids]
            if ids:
                nb_deleted = DBSession.query(Event
                            ).filter(Event.idevent.in_(ids)
                            ).delete(synchronize_session='fetch')
            else:
                nb_deleted = 0
            logger.info(_("Deleted %(nb_deleted)d closed events which were "
                            "at least %(days)d days old.") % {
                            'nb_deleted': nb_deleted,
                            'days': options.days,
                        })

            # On supprime les entrées d'historique concernant les changements
            # d'état des services de haut niveau qui ont été ajoutées avant
            # old_date.
            nb_deleted = DBSession.query(
                                HLSHistory
                            ).filter(HLSHistory.timestamp <= old_date
                            ).delete(synchronize_session='fetch')
            logger.info(_("Deleted %(nb_deleted)d entries in the history "
                        "for high level services which were at least "
                        "%(days)d days old.") % {
                            'nb_deleted': nb_deleted,
                            'days': options.days,
                        })

    if options.size is not None:
        if options.size >= 0:
            # Calcule la taille actuelle de la base de données Vigilo.
            dbsize = DBSession.query(pg_database_size(url.database)).scalar()

            if dbsize > options.size:
                logger.info(_("The database is %(size)d bytes big, which is "
                    "more than the limit (%(limit)d bytes). I will now delete "
                    "old closed events and history entries to make room for "
                    "new ones.") % {
                        'size': dbsize,
                        'limit': options.size,
                    })

            # On supprime les événements clos en commençant par
            # les plus anciens.
            total_deleted = 0
            while dbsize > options.size:
                idevent = DBSession.query(
                        Event.idevent
                    ).join(
                        (CorrEvent, Event.idevent == CorrEvent.idcause)
                    ).filter(Event.current_state.in_(sought_states)
                    ).filter(CorrEvent.ack == CorrEvent.ACK_CLOSED
                    ).order_by(CorrEvent.timestamp_active.asc()).scalar()

                # Il n'y a plus aucun événement corrélé pouvant être supprimé.
                if idevent is None:
                    break

                nb_deleted = DBSession.query(Event
                                ).filter(Event.idevent == idevent
                                ).delete(synchronize_session='fetch')
                logger.info(_("Deleted closed event #%d to make room for "
                                "new events.") % idevent)
                if not nb_deleted:
                    break
                total_deleted += nb_deleted

                # On met à jour la taille connue de la base de données.
                dbsize = DBSession.query(
                            pg_database_size(url.database)
                        ).scalar()


            # Affiche quelques statistiques.
            logger.info(_("Deleted %(nb_deleted)d closed events. "
                "The database is now %(size)d bytes big (limit: "
                "%(limit)d bytes)") % {
                    'nb_deleted': total_deleted,
                    'size': dbsize,
                    'limit': options.size,
                })

            # On supprime les entrées d'historique concernant les changements
            # d'état des services de haut niveau, en commençant par les plus
            # anciens.
            total_deleted = 0
            while dbsize > options.size:
                idhistory = DBSession.query(HLSHistory.idhistory
                                ).order_by(HLSHistory.timestamp.asc()
                                ).scalar()

                # Il n'y a plus d'entrée d'historique concernant un service
                # de haut niveau pouvant être supprimée.
                if idhistory is None:
                    break

                nb_deleted = DBSession.query(HLSHistory
                                ).filter(HLSHistory.idhistory == idhistory
                                ).delete(synchronize_session='fetch')
                if not nb_deleted:
                    break
                total_deleted += nb_deleted

                # On met à jour la taille connue de la base de données.
                dbsize = DBSession.query(
                            pg_database_size(url.database)
                        ).scalar()

            # Affichage de statistiques actualisées.
            logger.info(_("Deleted %(nb_deleted)d history entries on "
                        "high level services. The database is now %(size)d "
                        "bytes big (limit: %(limit)d bytes)") % {
                            'nb_deleted': total_deleted,
                            'size': dbsize,
                            'limit': options.size,
                        })
    DBSession.flush()