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
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)
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)
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)
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
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)
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)
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)
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))
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)
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, )
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
def get_data(self, event): state = StateName.value_to_statename(event[0].cause.current_state) return { 'state': state, 'occurrences': event[0].occurrence, }
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))
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()