Esempio n. 1
0
    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"))