def add_dependencies(self): """ Ajout de quelques dépendances entre services de bas niveau dans la BDD, préalable à certains des test. """ dep_group1 = functions.add_dependency_group(None, self.service1, u'topology', u'|') dep_group2 = functions.add_dependency_group(None, self.service2, u'topology', u'|') dep_group3 = functions.add_dependency_group(None, self.service3, u'topology', u'|') dep_group4 = functions.add_dependency_group(None, self.service4, u'topology', u'|') self.dependency1 = functions.add_dependency(dep_group1, self.service2, 1) self.dependency2 = functions.add_dependency(dep_group1, self.service3, 1) self.dependency3 = functions.add_dependency(dep_group2, self.service4, 1) self.dependency4 = functions.add_dependency(dep_group3, self.service4, 1) self.dependency5 = functions.add_dependency(dep_group4, self.service5, 1)
def test_parents_directive(self): """Nagios: parents""" # On ajoute un 2ème hôte et on génère une dépendance topologique # de "testserver1" sur "testserver2". Host(conf.hostsConf, "host/localhost.xml", u"testserver2", "192.168.1.2", "Servers") add_host("testserver2", ConfFile.get_or_create("dummy.xml")) dep_group = add_dependency_group('testserver1', None, 'topology') add_dependency(dep_group, ("testserver2", None)) # "testserver2" doit apparaître comme parent de "testserver1" # dans le fichier de configuration généré pour Nagios. self._generate() nagiosconffile = os.path.join(self.basedir, "localhost", "nagios", "nagios.cfg") self.assert_(os.path.exists(nagiosconffile), "Nagios conf file was not generated") nagiosconf = open(nagiosconffile).read() print nagiosconf self.assertTrue(re.search("^\s*parents\s+testserver2\s*$", nagiosconf, re.M))
def test_desaggregate2(self): """Désagrégation d'une vraie alerte d'un agrégat OK/UP (#1027).""" # Ajout des dépendances topologiques : # - Host 3 dépend de Host 1. dep_group = functions.add_dependency_group( self.hosts[3], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[1], 1) # Host 1 est dans l'état UP (pour cela, on génère déjà une alerte # DOWN qu'on fait ensuite repasser UP). res, idcorrevent1 = yield self.handle_alert(self.hosts[1], 'DOWN') self.assertNotEquals(res, None) res, idcorrevent1 = yield self.handle_alert(self.hosts[1], 'UP') self.assertNotEquals(res, None) # Host 3 est DOWN. event = functions.add_event(self.hosts[3], 'DOWN', 'DOWN') functions.add_host_state(self.hosts[3], 'DOWN') # Par erreur, l'alerte sur Host 3 s'est retrouvée masquée # par celle sur Host 1 (#1027). correvent = DBSession.query(tables.CorrEvent).filter( tables.CorrEvent.idcorrevent == idcorrevent1).one() correvent.events.append(event) DBSession.flush() # On reçoit une notification sur Host 3 qui confirme le problème. # L'événement doit être retiré de l'agrégat d'Host 1 et placé # dans un nouvel agrégat. res, idcorrevent2 = yield self.handle_alert(self.hosts[3], 'DOWN') self.assertNotEquals(res, None) self.assertNotEquals(idcorrevent2, idcorrevent1) # On vérifie que les événements sont bien dans les bons agrégats. correvent = DBSession.query(tables.CorrEvent).filter( tables.CorrEvent.idcorrevent == idcorrevent1).one() self.assertEquals(len(correvent.events), 1) correvent2 = DBSession.query(tables.CorrEvent).filter( tables.CorrEvent.idcorrevent == idcorrevent2).one() self.assertEquals( [event.idevent], [e.idevent for e in correvent2.events] )
def test_aggregate_3_levels(self): """ Agrégation sur 3 niveaux. """ # Ajout des dépendances topologiques : # - Host 2 dépend de Host 1 # - Host 3 dépend de Host 2 dep_group = functions.add_dependency_group( self.hosts[2], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[1], 1) dep_group = functions.add_dependency_group( self.hosts[3], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[2], 1) functions.add_dependency(dep_group, self.hosts[1], 2) # Simule la chute de "Host 3" puis "Host 1", puis "Host 2". res, idcorrevent3 = yield self.handle_alert(self.hosts[3], 'UNREACHABLE') self.assertNotEquals(res, None) res, idcorrevent1 = yield self.handle_alert(self.hosts[1], 'DOWN') self.assertNotEquals(res, None) res, idcorrevent2 = yield self.handle_alert( self.hosts[2], 'UNREACHABLE', preds=[idcorrevent1], succs=[idcorrevent3], ) self.assertEquals(res, None) # Pas de nouvel agrégat créé. # On s'attend à trouver 3 événements bruts et 1 agrégat. self.assertEquals(3, DBSession.query(tables.Event).count()) self.assertEquals(1, DBSession.query(tables.CorrEvent).count()) events = DBSession.query(tables.Event).all() events.sort(key=lambda x: x.supitem.name) self.assertEquals(u'Host 1', events[0].supitem.name) self.assertEquals(u'Host 2', events[1].supitem.name) self.assertEquals(u'Host 3', events[2].supitem.name)
def test_reaggregate2(self): """Réagrégation des événements corrélés.""" # Host 2 dépend de Host 1 dep_group = functions.add_dependency_group( self.hosts[2], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[1], 1) # 1. Un 1er agrégat doit avoir été créé. LOGGER.debug('Step 1') res, idcorrevent1 = yield self.handle_alert( self.hosts[1], 'DOWN') # Aucune erreur n'a été levée. self.assertNotEquals(res, None) # 2. L'événement brut doit avoir été fusionné # dans l'agrégat précédent. LOGGER.debug('Step 2') res, idcorrevent2 = yield self.handle_alert( self.hosts[2], 'UNREACHABLE', preds=[idcorrevent1]) # Aucune erreur, mais correvent agrégé. self.assertEquals(res, None) self.assertEquals(idcorrevent2, None) # On a 2 événements bruts et 1 agrégat en base. LOGGER.debug("Checking events") self.assertEquals(2, DBSession.query(tables.Event).count()) LOGGER.debug("Checking correvents") db_correvents = DBSession.query(tables.CorrEvent).all() self.assertEquals(1, len(db_correvents)) # 3. L'agrégat de l'étape 2 doit avoir été désagrégé. LOGGER.debug('Step 3') res, idcorrevent3 = yield self.handle_alert( self.hosts[1], 'UP') # Aucune erreur n'a été levée. self.assertNotEquals(res, None) # On a 2 événements bruts et 2 agrégats en base. LOGGER.debug("Checking events") self.assertEquals(2, DBSession.query(tables.Event).count()) LOGGER.debug("Checking correvents") db_correvents = DBSession.query(tables.CorrEvent).all() self.assertEquals(2, len(db_correvents)) db_correvents.sort(key=lambda x: x.cause.supitem.name) # Le premier à l'état "UP" et porte sur "Host 1". self.assertEquals(self.hosts[1].idhost, db_correvents[0].cause.idsupitem) self.assertEquals( u'UP', tables.StateName.value_to_statename( db_correvents[0].cause.current_state) ) # Le 2nd est "UNREACHABLE" et porte sur "Host 2". self.assertEquals(self.hosts[2].idhost, db_correvents[1].cause.idsupitem) self.assertEquals( u'UNREACHABLE', tables.StateName.value_to_statename( db_correvents[1].cause.current_state) ) # 4. Les événements doivent avoir été réagrégés. LOGGER.debug('Step 4') # 2 = id du nouveau correvent après désagrégation res, idcorrevent4 = yield self.handle_alert( self.hosts[1], 'DOWN', succs=[2]) # Aucune erreur n'a été levée. self.assertNotEquals(res, None) self.assertEquals(idcorrevent4, idcorrevent1) # On a 2 événements bruts et 1 agrégat en base. LOGGER.debug("Checking events") self.assertEquals(2, DBSession.query(tables.Event).count()) LOGGER.debug("Checking correvents") db_correvents = DBSession.query(tables.CorrEvent).all() self.assertEquals(1, len(db_correvents)) # Il a l'état "DOWN", porte sur "Host 1" # et contient les 2 événements bruts. self.assertEquals(self.hosts[1].idhost, db_correvents[0].cause.idsupitem) self.assertEquals( u'DOWN', tables.StateName.value_to_statename( db_correvents[0].cause.current_state) ) self.assertEquals( [u'Host 1', u'Host 2'], sorted([ev.supitem.name for ev in db_correvents[0].events]) )
def test_pseudo_triangle(self): """ Désagrégation avec événements en pseudo-triangle. Lorsque 2 hôtes tombent et qu'un 3ème hôte dépendant des 2 premiers au sens de la topologie devient indisponible, l'événement brut sur ce 3ème hôte doit être agrégé dans les agrégats des 2 premiers. Lorsque le 1er hôte remonte, un agrégat séparé doit être créé pour sa dépendance. L'agrégat n'est pas affecté lorsque le 2nd hôte redevient opérationnel. On finit donc avec 3 agrégats actifs. """ # Ajout des dépendances topologiques : # - Host 3 dépend de Host 1 et Host 2 (triangle). dep_group = functions.add_dependency_group( self.hosts[3], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[1], 1) functions.add_dependency(dep_group, self.hosts[2], 2) # Simule la chute des hôtes "Host 1" et "Host 2", # puis l'indisponibilité de l'hôte "Host 3" # qui dépend des 2 autres topologiquement. res, idcorrevent1 = yield self.handle_alert(self.hosts[1], 'DOWN') self.assertNotEquals(res, None) res, idcorrevent2 = yield self.handle_alert(self.hosts[2], 'DOWN') self.assertNotEquals(res, None) res, idcorrevent3 = yield self.handle_alert( self.hosts[3], 'UNREACHABLE', preds=[idcorrevent1, idcorrevent2], ) self.assertEquals(res, None) # Pas de nouvel agrégat créé. print "Finished step 1\n" self.assertNotEquals(idcorrevent1, None) self.assertNotEquals(idcorrevent2, None) self.assertEquals(idcorrevent3, None) # On s'attend à trouver 3 événements bruts et 2 agrégats. self.assertEquals(3, DBSession.query(tables.Event).count()) self.assertEquals(2, DBSession.query(tables.CorrEvent).count()) # L'événement brut sur "Host 3" a été agrégé dans les 2 autres. event3 = DBSession.query(tables.Event).filter( tables.Event.idsupitem == self.hosts[3].idhost).one() # ... donc il appartient à l'agrégat de l'hôte 1. correvent = DBSession.query(tables.CorrEvent).get(idcorrevent1) self.assertTrue(event3 in correvent.events) # ... ainsi qu'à celui de l'hôte 2. correvent = DBSession.query(tables.CorrEvent).get(idcorrevent2) self.assertTrue(event3 in correvent.events) # Simule la remontée de "Host 1" : # l'événement brut concernant "Host 3" doit être retiré # des agrégats de l'hôte 1 et de l'hôte 2. # Un nouvel agrégat doit avoir été créé pour l'accueillir. res, _idcorrevent = yield self.handle_alert(self.hosts[1], 'UP') print "Finished step 2\n" self.assertNotEquals(res, None) # On s'attend à trouver 3 événements bruts et 3 agrégats. self.assertEquals(3, DBSession.query(tables.Event).count()) self.assertEquals(3, DBSession.query(tables.CorrEvent).count()) # L'événement brut sur "Host 3" n'est plus l'agrégat de l'hôte 1. correvent = DBSession.query(tables.CorrEvent).get(idcorrevent1) self.assertFalse(event3 in correvent.events) # ... ni dans celui de l'hôte 2. correvent = DBSession.query(tables.CorrEvent).get(idcorrevent2) self.assertFalse(event3 in correvent.events) # ... en revanche, il dispose de son propre agrégat. correvent = DBSession.query( tables.CorrEvent ).join( (tables.Event, tables.Event.idevent == tables.CorrEvent.idcause), ).filter(tables.Event.idsupitem == self.hosts[3].idhost ).one() # "Host 2" remonte : rien ne change. res, _idcorrevent = yield self.handle_alert(self.hosts[2], 'UP') print "Finished step 3\n" self.assertNotEquals(res, None) # On s'attend à trouver 3 événements bruts et 3 agrégats. self.assertEquals(3, DBSession.query(tables.Event).count()) self.assertEquals(3, DBSession.query(tables.CorrEvent).count()) # L'événement brut sur "Host 3" n'est plus l'agrégat de l'hôte 1. correvent = DBSession.query(tables.CorrEvent).get(idcorrevent1) self.assertFalse(event3 in correvent.events) # ... ni dans celui de l'hôte 2. correvent = DBSession.query(tables.CorrEvent).get(idcorrevent2) self.assertFalse(event3 in correvent.events) # ... en revanche, il dispose de son propre agrégat. correvent = DBSession.query( tables.CorrEvent ).join( (tables.Event, tables.Event.idevent == tables.CorrEvent.idcause), ).filter(tables.Event.idsupitem == self.hosts[3].idhost ).one()
def test_desaggregate(self): """Désagrégation des événements corrélés (#467).""" # Ajout des dépendances topologiques : # - Host 2 dépend de Host 1 # - Host 4 dépend de Host 1 # - Host 3 dépend de Host 4 dep_group = functions.add_dependency_group( self.hosts[2], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[1], 1) dep_group = functions.add_dependency_group( self.hosts[4], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[1], 1) dep_group = functions.add_dependency_group( self.hosts[3], None, u'topology', u'|') functions.add_dependency(dep_group, self.hosts[4], 1) functions.add_dependency(dep_group, self.hosts[1], 2) # 1. Un 1er agrégat doit avoir été créé. res, idcorrevent1 = yield self.handle_alert( self.hosts[2], 'UNREACHABLE') print "Finished step 1\n" # Aucune erreur n'a été levée. self.assertNotEquals(res, None) self.assertNotEquals(idcorrevent1, None) # Un agrégat a été créé sur cet hôte... db_correvent = DBSession.query(tables.CorrEvent).get(idcorrevent1) self.assertEquals(self.hosts[2].idhost, db_correvent.cause.idsupitem) # ... dans l'état indiqué. self.assertEquals( u'UNREACHABLE', tables.StateName.value_to_statename( db_correvent.cause.current_state) ) # ... contenant uniquement un événement (cause hôte 2). self.assertEquals( [u'Host 2'], [ev.supitem.name for ev in db_correvent.events] ) # 2. Un nouvel agrégat doit avoir été créé et l'agrégat # précédent doit avoir été fusionné dans celui-ci. res, idcorrevent2 = yield self.handle_alert( self.hosts[1], 'DOWN', succs=[idcorrevent1]) print "Finished step 2\n" # Aucune erreur n'a été levée. self.assertNotEquals(res, None) self.assertNotEquals(idcorrevent2, None) # Il ne doit rester qu'un seul agrégat (le 1er a été fusionné). db_correvent = DBSession.query(tables.CorrEvent).one() self.assertEquals(db_correvent.idcorrevent, idcorrevent2) # ... dont la cause est l'hôte 1. self.assertEquals(self.hosts[1].idhost, db_correvent.cause.idsupitem) # ... dans l'état indiqué. self.assertEquals( u'DOWN', tables.StateName.value_to_statename( db_correvent.cause.current_state) ) # ... ayant 2 événements bruts rattachés (cause hôte 1 + hôte 2). self.assertEquals( [u'Host 1', u'Host 2'], sorted([ev.supitem.name for ev in db_correvent.events]) ) # 3. Pas de nouvel agrégat, mais un nouvel événement brut (hôte 4) # ajouté à l'agrégat de l'étape 2. res, idcorrevent3 = yield self.handle_alert( self.hosts[4], 'UNREACHABLE', preds=[idcorrevent2]) print "Finished step 3\n" # Aucune erreur n'a été levée. self.assertEquals(res, None) self.assertEquals(idcorrevent3, None) # ajouté dans l'agrégat 2. # Toujours un seul agrégat. db_correvent = DBSession.query(tables.CorrEvent).one() self.assertEquals(db_correvent.idcorrevent, idcorrevent2) # ... dont la cause est l'hôte 1. self.assertEquals(self.hosts[1].idhost, db_correvent.cause.idsupitem) # ... dans l'état indiqué. self.assertEquals( u'DOWN', tables.StateName.value_to_statename( db_correvent.cause.current_state) ) # ... ayant 3 événements bruts. self.assertEquals( [u'Host 1', u'Host 2', u'Host 4'], sorted([ev.supitem.name for ev in db_correvent.events]) ) # 4. Pas de nouvel agrégat, mais un nouvel événement brut (hôte 3) # ajouté à l'agrégat de l'étape 2. res, idcorrevent4 = yield self.handle_alert( self.hosts[3], 'UNREACHABLE', preds=[idcorrevent2]) print "Finished step 4\n" # Aucune erreur n'a été levée. self.assertEquals(res, None) self.assertEquals(idcorrevent4, None) # ajouté dans l'agrégat 2. # On a 4 événements bruts en base. self.assertEquals(4, DBSession.query(tables.Event).count()) # On a toujours un seul agrégat. db_correvent = DBSession.query(tables.CorrEvent).one() self.assertEquals(db_correvent.idcorrevent, idcorrevent2) # ... dont la cause est l'hôte 1. self.assertEquals(self.hosts[1].idhost, db_correvent.cause.idsupitem) # ... dans l'état indiqué. self.assertEquals( u'DOWN', tables.StateName.value_to_statename( db_correvent.cause.current_state) ) # ... ayant 3 événements bruts. self.assertEquals( [u'Host 1', u'Host 2', u'Host 3', u'Host 4'], sorted([ev.supitem.name for ev in db_correvent.events]) ) # 5. L'agrégat de l'étape 2 doit avoir été désagrégé # en 3 agrégats, l'un signalant que l'hôte 1 est UP, # un autre indiquant que l'hôte 2 est UNREACHABLE, # le dernier donnant les hôtes 4 et 3 UNREACHABLE. res, idcorrevent5 = yield self.handle_alert(self.hosts[1], 'UP') print "Finished step 5\n" # Aucune erreur n'a été levée. self.assertNotEquals(res, None) # Désagrégé à partir de l'agrégat 2. self.assertEquals(idcorrevent5, idcorrevent2) # On a 4 événements bruts et 3 agrégats en base. print "events" self.assertEquals(4, DBSession.query(tables.Event).count()) db_correvents = DBSession.query(tables.CorrEvent).all() print "correvents" self.assertEquals(3, len(db_correvents)) db_correvents.sort(key=lambda x: x.cause.supitem.name) # L'un porte sur l'hôte 1 qui doit être dans l'état "UP" # et ne contient qu'un seul événement brut sur host 1. self.assertEquals(self.hosts[1].idhost, db_correvents[0].cause.idsupitem) self.assertEquals( u'UP', tables.StateName.value_to_statename( db_correvents[0].cause.current_state) ) self.assertEquals( [u'Host 1'], sorted([ev.supitem.name for ev in db_correvents[0].events]) ) # Le second porte sur l'hôte 2, qui se trouve toujours dans # l'état "UNREACHABLE" et n'a qu'un seul événement brut (host 2). self.assertEquals(self.hosts[2].idhost, db_correvents[1].cause.idsupitem) self.assertEquals( u'UNREACHABLE', tables.StateName.value_to_statename( db_correvents[1].cause.current_state) ) self.assertEquals( [u'Host 2'], sorted([ev.supitem.name for ev in db_correvents[1].events]) ) # Le dernier des agrégats porte sur l'hôte 4 # qui se trouve dans l'état UNREACHABLE et # contient 2 événements bruts (host 4 et host 3). self.assertEquals(self.hosts[4].idhost, db_correvents[2].cause.idsupitem) self.assertEquals( u'UNREACHABLE', tables.StateName.value_to_statename( db_correvents[2].cause.current_state) ) self.assertEquals( [u'Host 3', u'Host 4'], sorted([ev.supitem.name for ev in db_correvents[2].events]) )