def dbmtime(self): change = Change.by_table_name(u"Graph") if change is None: return {"mtime": None} mtime = change.last_modified.replace(microsecond=0) return {"mtime": mtime}
def load_conf(self): LOGGER.info(_("Loading hosts")) # On récupère d'abord la liste de tous les hôtes # précédemment définis en base et le fichier XML # auquels ils appartiennent. previous_hosts = {} for conffile in DBSession.query(ConfFile).all(): self.conffiles[conffile.idconffile] = conffile self.conffiles[conffile.name] = conffile db_hosts = DBSession.query( Host.name, Host.idconffile, ).all() for db_host in db_hosts: previous_hosts[db_host.name] = self.conffiles[db_host.idconffile] hostnames = [] # On ne s'interresse qu'à ceux sur lesquels une modification # a eu lieu (ajout ou modification). On génère en même temps # un cache des instances des fichiers de configuration. for hostname in conf.hostsConf.keys(): filename = conf.hostsConf[hostname]["filename"] relfilename = filename[len(settings["vigiconf"].get("confdir"))+1:] if self.rev_mgr.file_changed(filename, exclude_removed=True): hostnames.append(hostname) # Peuple le cache en créant les instances à la volée si # nécessaire. if relfilename not in self.conffiles: LOGGER.debug(_("Registering new configuration file " "'%(relative)s' (from %(absolute)s)"), { 'relative': relfilename, 'absolute': filename, }) conffile = ConfFile(name=unicode(relfilename)) DBSession.flush() self.conffiles[unicode(relfilename)] = conffile self.conffiles[conffile.idconffile] = conffile # Utile pendant la migration des données : # les hôtes pour lesquels on ne possédait pas d'informations # quant au fichier de définition doivent être mis à jour. for hostname, conffile in previous_hosts.iteritems(): if conffile is None: hostnames.append(hostname) del previous_hosts # Fera office de cache des instances d'hôtes # entre les deux étapes de la synchronisation. hosts = {} hostnames = sorted(list(set(hostnames))) for hostname in hostnames: hostdata = conf.hostsConf[hostname] relfilename = hostdata['filename'] \ [len(settings["vigiconf"].get("confdir"))+1:] LOGGER.debug(_("Loading host %s"), hostname) hostname = unicode(hostname) host = dict(name=hostname, hosttpl=unicode(hostdata['hostTPL']), snmpcommunity=unicode(hostdata['snmpCommunity']), address=unicode(hostdata['address']), snmpport=hostdata['snmpPort'], snmpoidsperpdu=hostdata['snmpOIDsPerPDU'], weight=hostdata['weight'], snmpversion=unicode(hostdata['snmpVersion']), conffile=self.conffiles[unicode(relfilename)], ) host = self.add(host) hosts[hostname] = host # Synchronisation des tags de l'hôte. tag_loader = TagLoader(host, hostdata.get('tags', {})) tag_loader.load() if hostnames: LOGGER.debug("Preparing group cache") groups = DBSession.query(GroupPath).join( (Group, Group.idgroup == GroupPath.idgroup) ).filter(Group.grouptype == u'supitemgroup').all() for g in groups: self.group_cache[g.idgroup] = g.path self.group_cache[g.path] = g.idgroup for part in parse_path(g.path): self.group_parts_cache.setdefault(part, []).append(g.path) # Cache de l'association entre le nom d'un groupe de graphes # et son identifiant. graphgroups = {} for graphgroup in DBSession.query(GraphGroup).all(): graphgroups[graphgroup.name] = graphgroup for hostname in hostnames: hostdata = conf.hostsConf[hostname] host = hosts[hostname] # groupes LOGGER.debug("Loading groups for host %s", hostname) self._load_groups(host, hostdata) # services LOGGER.debug("Loading services for host %s", hostname) service_loader = ServiceLoader(host) service_loader.load() # directives Nagios de l'hôte LOGGER.debug("Loading nagios conf for host %s", hostname) nagiosconf_loader = NagiosConfLoader(host, hostdata['nagiosDirectives']) nagiosconf_loader.load() # données de performance LOGGER.debug("Loading perfdatasources for host %s", hostname) pds_loader = PDSLoader(host) pds_loader.load() # graphes LOGGER.debug("Loading graphs for host %s", hostname) graph_loader = GraphLoader(host, graphgroups) graph_loader.load() # Suppression des fichiers de configuration retirés du SVN # ainsi que de leurs hôtes (par CASCADE). LOGGER.debug("Cleaning up old hosts") removed = self.rev_mgr.get_removed() for filename in removed: relfilename = filename[len(settings["vigiconf"].get("confdir"))+1:] # Si un dossier est supprimé avec rm -rf, SVN ne signale que le # dossier, pas tous ses fichiers/sous-dossiers -> on doit utiliser # un LIKE pour les attrapper DBSession.query(ConfFile).filter(or_( ConfFile.name == unicode(relfilename), ConfFile.name.like(unicode(relfilename) + u"/%") )).delete(synchronize_session='fetch') LOGGER.debug("Done cleaning up old hosts") # Ghostbusters # 1- Hosts qui n'ont plus de fichier de configuration. nb_ghosts = DBSession.query( SupItem.__table__ ).filter( SupItem.__table__.c.idsupitem.in_( DBSession.query( Host.__table__.c.idhost ).filter(Host.__table__.c.idconffile == None) ) ).delete(synchronize_session=False) LOGGER.debug("Deleted %d ghosts [Host]", nb_ghosts) # 2a- SupItems censés être des hôtes, mais qui n'ont pas d'entrée # dans la table Host. nb_ghosts = DBSession.query( SupItem.__table__ ).filter( SupItem.__table__.c.idsupitem.in_( DBSession.query( SupItem.idsupitem ).outerjoin( (Host.__table__, Host.__table__.c.idhost == SupItem.__table__.c.idsupitem) ).filter( SupItem.__table__.c.itemtype == Host.__mapper_args__['polymorphic_identity'] ).filter(Host.__table__.c.idhost == None) ) ).delete(synchronize_session=False) # 2b- SupItems censés être des LLS, mais qui n'ont pas d'entrée # dans la table LowLevelService. nb_ghosts += DBSession.query( SupItem.__table__ ).filter( SupItem.__table__.c.idsupitem.in_( DBSession.query( SupItem.idsupitem ).outerjoin( (LowLevelService.__table__, LowLevelService.__table__.c.idservice == SupItem.__table__.c.idsupitem) ).filter( SupItem.__table__.c.itemtype == LowLevelService.__mapper_args__['polymorphic_identity'] ).filter(LowLevelService.__table__.c.idservice == None) ) ).delete(synchronize_session=False) # 2c- SupItems censés être des HLS, mais qui n'ont pas d'entrée # dans la table HighLevelService. nb_ghosts += DBSession.query( SupItem.__table__ ).filter( SupItem.__table__.c.idsupitem.in_( DBSession.query( SupItem.idsupitem ).outerjoin( (HighLevelService.__table__, HighLevelService.__table__.c.idservice == SupItem.__table__.c.idsupitem) ).filter( SupItem.__table__.c.itemtype == HighLevelService.__mapper_args__['polymorphic_identity'] ).filter(HighLevelService.__table__.c.idservice == None) ) ).delete(synchronize_session=False) LOGGER.debug("Deleted %d ghosts [SupItem]", nb_ghosts) # 3a- MapLinks censés être des MapServiceLink mais qui n'ont # pas d'entrée dans la table MapServiceLink. nb_ghosts = DBSession.query( MapLink.__table__ ).filter( MapLink.__table__.c.idmaplink.in_( DBSession.query( MapLink.idmaplink ).outerjoin( (MapServiceLink.__table__, MapServiceLink.__table__.c.idmapservicelink == MapLink.__table__.c.idmaplink) ).filter( MapLink.__table__.c.type_link.in_([ MapLlsLink.__mapper_args__['polymorphic_identity'], MapHlsLink.__mapper_args__['polymorphic_identity'], ]) ).filter(MapServiceLink.__table__.c.idmapservicelink == None) ) ).delete(synchronize_session=False) # 3b- MapLinks censés être des MapSegment mais qui n'ont # pas d'entrée dans la table MapSegment. nb_ghosts += DBSession.query( MapLink.__table__ ).filter( MapLink.__table__.c.idmaplink.in_( DBSession.query( MapLink.idmaplink ).outerjoin( (MapSegment.__table__, MapSegment.__table__.c.idmapsegment == MapLink.__table__.c.idmaplink) ).filter( MapLink.__table__.c.type_link == MapSegment.__mapper_args__['polymorphic_identity'] ).filter(MapSegment.__table__.c.idmapsegment == None) ) ).delete(synchronize_session=False) LOGGER.debug("Deleted %d ghosts [MapLink]", nb_ghosts) # 4a- MapNodes qui sont censés être des MapNodeHost mais qui # n'ont pas d'entrée dans la sous-table. nb_ghosts = DBSession.query( MapNode.__table__ ).filter( MapNode.__table__.c.idmapnode.in_( DBSession.query( MapNode.idmapnode ).outerjoin( (MapNodeHost.__table__, MapNodeHost.__table__.c.idmapnode == MapNode.__table__.c.idmapnode) ).filter( MapNode.__table__.c.type_node == MapNodeHost.__mapper_args__['polymorphic_identity'] ).filter(MapNodeHost.__table__.c.idmapnode == None) ) ).delete(synchronize_session=False) # 4b- MapNodes qui sont censés être des MapNodeService mais qui # n'ont pas d'entrée dans la sous-table. nb_ghosts += DBSession.query( MapNode.__table__ ).filter( MapNode.__table__.c.idmapnode.in_( DBSession.query( MapNode.idmapnode ).outerjoin( (MapNodeService.__table__, MapNodeService.__table__.c.idmapnode == MapNode.__table__.c.idmapnode) ).filter( MapNode.__table__.c.type_node.in_([ MapNodeLls.__mapper_args__['polymorphic_identity'], MapNodeHls.__mapper_args__['polymorphic_identity'], ]) ).filter(MapNodeService.__table__.c.idmapnode == None) ) ).delete(synchronize_session=False) LOGGER.debug("Deleted %d ghosts [MapNode]", nb_ghosts) # Suppression des hôtes qui ont été supprimés dans les fichiers # modifiés. deleted_hosts = [] for conffilename in self.conffiles: if not isinstance(conffilename, basestring): continue filename = os.path.join(settings["vigiconf"].get("confdir"), conffilename) if not self.rev_mgr.file_changed(filename): continue # ce fichier n'a pas bougé for host in self.conffiles[conffilename].hosts: if host.name not in hostnames: LOGGER.debug("Deleting '%s'", host.name) deleted_hosts.append(host) DBSession.delete(host) # Nettoyage des graphes et des groupes de graphes vides LOGGER.debug("Cleaning up old graphs") empty_graphs = DBSession.query( Graph ).filter( Graph.idgraph.in_( DBSession.query( Graph.idgraph ).outerjoin( (GRAPH_PERFDATASOURCE_TABLE, GRAPH_PERFDATASOURCE_TABLE.c.idgraph == Graph.idgraph ), ).filter(GRAPH_PERFDATASOURCE_TABLE.c.idgraph == None ) ) ).delete(synchronize_session=False) LOGGER.debug("Removed %r obsolete graphs", empty_graphs) # Si on a changé quelque chose, on le note en BDD. if hostnames or removed or deleted_hosts or empty_graphs: Change.mark_as_modified(u"Host") Change.mark_as_modified(u"Service") Change.mark_as_modified(u"Graph") DBSession.flush() LOGGER.info(_("Done loading hosts"))