zephir.backend.lib_backend

Package zephir :: Package backend :: Module lib_backend |
[frames] | no frames]

# Source Code for Module zephir.backend.lib_backend

       1  # -*- coding: UTF-8 -*-
       2  ###########################################################################
       3  # Eole NG - 2007
       4  # Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
       5  # Licence CeCill  cf /root/LicenceEole.txt
       6  # eole@ac-dijon.fr
       7  #
       8  # lib_backend.py
       9  #
      10  # classes de base pour la gestion des serveurs sous zephir
      11  #
      12  ###########################################################################
      13  """fonctions utiles pour l'accès à la base de données (via adbapi)
      14  """
      15  from zephir.backend import config
      16  from zephir.backend.config import log
      17  try:
      18      from migration_perso import migration_perso, destinations_perso
      19  except:
      20      migration_perso = {}
      21      destinations_perso = []
      22  from zephir.lib_zephir import lock, unlock, is_locked, lock_dir
      23  from zephir.utils.creolewrap import ZephirDict
      24  from zephir.monitor.agentmanager.util import md5files
      25  from twisted.internet.utils import getProcessOutputAndValue
      26  import psycopg2 as PgSQL
      27  import os, sys, time, string, traceback, apt_pkg, re, shutil
      28  import base64
      29  from hashlib import md5
      30  from ConfigParser import ConfigParser
      31  from glob import glob
      32  from cStringIO import StringIO
      33  import xmlrpclib, cjson
      34
      35 -class ResourceAuthError(Exception):
      36      pass
      37
      38 -class ParamsLock:
      39 -    def __init__(self, id_serveur):
      40          self.lockname = 'server_params_%s' % str(id_serveur)
      41 -    def __enter__(self):
      42          wait_time = 0
      43          while is_locked(self.lockname) and (wait_time <= 20):
      44              # on attend au maximum 20 secondes que la ressource soit libérée
      45              # après 20 secondes, on considére que l'appel concurrent est en échec
      46              time.sleep(0.25)
      47              wait_time += 0.25
      48          # on interdit temporairement d'autres modification des paramètres du serveur
      49          lock(self.lockname)
      50 -    def __exit__(self, type, value, traceback):
      51          unlock(self.lockname)
      52
      53 -class CxPool(dict):
      54      """dictionnaire des connexions postgresql en cours"""
      55
      56 -    def create(self):
      57          cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD)
      58          cu = cx.cursor()
      59          self[cu] = cx
      60          return cu
      61
      62 -    def commit(self,cu):
      63          cu.close()
      64          self[cu].commit()
      65          self[cu].close()
      66          del(self[cu])
      67
      68 -    def rollback(self,cu):
      69          cu.close()
      70          self[cu].rollback()
      71          self[cu].close()
      72          del(self[cu])
      73
      74 -    def close(self,cu):
      75          cu.close()
      76          self[cu].close()
      77          del(self[cu])
      78
      79 -class AptChecker:
      80      """gestionnaire de vérification d'état des paquets d'un serveur
      81      """
      82 -    def __init__(self):
      83          self.pkg_file = {}
      84          self.packages = {}
      85          self.timestamp = {}
      86          for zephir_version, data in config.DISTRIBS.items():
      87              if zephir_version != 1:
      88                  codename, version, maintained = data
      89                  # lecture des fichiers générés pour les différents serveurs de mise à jour
      90                  for serv_maj in config.SERVEURS_MAJ_CLIENTS:
      91                      if zephir_version not in self.pkg_file:
      92                          self.pkg_file[zephir_version] = {}
      93                          self.packages[zephir_version] = {}
      94                          self.timestamp[zephir_version] = {}
      95                      self.pkg_file[zephir_version][serv_maj] = os.path.join(os.path.abspath(config.PATH_ZEPHIR),'packages_%s_%s.ini' % (codename, serv_maj))
      96                      self.packages[zephir_version][serv_maj] = ConfigParser()
      97                      if not os.path.isfile(self.pkg_file[zephir_version][serv_maj]):
      98                          f = file(self.pkg_file[zephir_version][serv_maj],'w')
      99                          f.close()
     100                          # la liste des paquets n'a jamais été vérifiée, on lance la procédure de recherche
     101                          log.msg("** récupération de la liste des paquets disponibles en mise à jour", serv_maj)
     102                          os.system('/usr/share/eole/check_maj_eole.py')
     103                      self.timestamp[zephir_version][serv_maj] = os.path.getmtime(self.pkg_file[zephir_version][serv_maj])
     104                      self.packages[zephir_version][serv_maj].read(self.pkg_file[zephir_version][serv_maj])
     105          # création d'une regexp compilée pour les paquets à ignorer
     106          if len(config.held_packages) > 0:
     107              self.held_pattern = re.compile("|".join(config.held_packages))
     108          else:
     109              self.held_pattern = None
     110
     111 -    def check_min_version(self, current_version, min_version):
     112          apt_pkg.InitSystem()
     113          if apt_pkg.VersionCompare(current_version, min_version) >= 0:
     114              return True
     115          return False
     116
     117 -    def check_packages(self, maj_infos, pkg_file, debnames, version, serv_maj, type_maj = 'complete', show_installed = False):
     118          """vérifie l'état de mise à jour des paquets
     119          type_maj : type de mise à jour (minimale/complete)
     120          show_installed : si True, renvoie la liste de tous les paquets installés
     121                           par défaut, seulement les paquets non à jour
     122          """
     123          # si serveur de maj inconnu, on utilise le premier de la liste
     124          if serv_maj not in self.packages[version]:
     125              config.log.msg("Serveur de mise à jour", serv_maj, "inconnu : utilisation de", config.SERVEURS_MAJ_CLIENTS[0])
     126              serv_maj = config.SERVEURS_MAJ_CLIENTS[0]
     127          depot_changed = True
     128          client_changed = True
     129          if os.path.isfile(pkg_file):
     130              md5_packs = md5(file(pkg_file).read()).hexdigest()
     131          else:
     132              # pas de fichier remonté par le serveur !
     133              if maj_infos is not None:
     134                  return maj_infos[0], maj_infos
     135              else:
     136                  return [], None
     137
     138          depot_timestamp = os.path.getmtime(self.pkg_file[version][serv_maj])
     139          if maj_infos:
     140              # on regarde si les données ont changé depuis la dernière vérification de ce serveur
     141              if maj_infos[1] == type_maj and maj_infos[2] == md5_packs and maj_infos[3] == serv_maj:
     142                  client_changed = False
     143              if maj_infos[4] == depot_timestamp:
     144                  depot_changed = False
     145
     146          if debnames == [] and not show_installed:
     147              # vérification globale de l'état de mise à jour du serveur
     148              # si on a déjà des infos et que rien n'a changé, on ne fait pas de traitements
     149              if not depot_changed and not client_changed:
     150                  return maj_infos[0], maj_infos
     151
     152          # creation de la liste des paquets installés (/à vérifier si debnames non vide)
     153          pkg_liste = []
     154          if os.path.isfile(pkg_file):
     155              for line in file(pkg_file):
     156                  pak_info = line.split()
     157                  if debnames != []:
     158                      # travail sur des paquets particuliers
     159                      if pak_info[0] in debnames:
     160                          pkg_liste.append(pak_info)
     161                          if len(pkg_liste) == len(debnames):
     162                              # on a trouvé tous les paquets demandés : on sort
     163                              break
     164                  else:
     165                      pkg_liste.append(line.split())
     166          # md5 des paquets installés
     167          check_needed = False
     168          if maj_infos is None or client_changed == True or debnames != [] or show_installed == True:
     169              # Des informations ne sont pas à jour ou on a demandé les infos sur des paquets particuliers
     170              check_needed = True
     171          if depot_changed:
     172              # la liste des paquets dispos a changé, on la recharge
     173              self.packages[version][serv_maj].read(self.pkg_file[version][serv_maj])
     174              self.timestamp[version][serv_maj] = depot_timestamp
     175              check_needed = True
     176          liste_pack = []
     177          if check_needed:
     178              outdated = []
     179              apt_pkg.InitSystem()
     180              for pkg_name, pkg_version in pkg_liste:
     181                  if (self.held_pattern is None) or (not self.held_pattern.match(pkg_name)):
     182                      try:
     183                          # les paquets n'ayant jamais eu de mise à jour ne sont pas présents
     184                          if self.packages[version][serv_maj].has_section(pkg_name):
     185                              try:
     186                                  maj_version = self.packages[version][serv_maj].get(pkg_name, type_maj)
     187                              except:
     188                                  if type_maj != 'minimum':
     189                                      log.msg('Informations de version du paquet %s non trouvées pour %s' % (pkg_name, serv_maj))
     190                                      traceback.print_exc()
     191                              if apt_pkg.VersionCompare(maj_version, pkg_version) > 0:
     192                                  # on renvoie, le paquet, la version installée, et la version sur le serveur de maj
     193                                  liste_pack.append((pkg_name, pkg_version, maj_version))
     194                                  outdated.append((pkg_name, pkg_version, maj_version))
     195                                  continue
     196                              elif show_installed == True:
     197                                  liste_pack.append((pkg_name, pkg_version, maj_version))
     198                                  continue
     199                      except:
     200                          traceback.print_exc()
     201                      # listing des paquets installés, on renvoie le paquet
     202                      # même si il n'est pas dans les repository de maj
     203                      if show_installed == True:
     204                          liste_pack.append((pkg_name, pkg_version, pkg_version))
     205              maj_infos = (outdated, type_maj, md5_packs, serv_maj, depot_timestamp)
     206          else:
     207              # pas de changement, on reprend la liste précédente
     208              liste_pack = maj_infos[0]
     209          return liste_pack, maj_infos
     210
     211  cx_pool = CxPool()
     212  # maj_checker = AptChecker()
     213
     214 -class Serveur:
     215      """classe utilitaire pour récupérer diverses données sur un serveur"""
     216
     217 -    def __init__(self, pool, id_s, cu=None, data=None):
     218          """initialise l'objet serveur et récupère les infos
     219          """
     220          self.version = 'creole2'
     221          # récupération des serveurs
     222          self.id_s = int(id_s)
     223          # date de dernière modification du serveur
     224          self.modified = time.time()
     225          # date de création de l'objet
     226          self.created = time.time()
     227          # serveur inactif ? (pas d'alerte)
     228          self.no_alert = False
     229          # lien sur le pool de serveurs
     230          self.pool = pool
     231          # liste des paquets non à jour
     232          self.maj_infos = None
     233          # cache de la configuration Creole
     234          self.dico = None
     235          self.dico_mtime = None
     236          self.last_mode = None
     237          cursor = cu
     238          if cu == None:
     239              cursor = cx_pool.create()
     240          try:
     241              if data == None:
     242                  # le rne ne peut pas être modifié : on le stocke une fois pour toutes
     243                  cursor.execute("select rne from serveurs where id=%s", (int(self.id_s),))
     244                  data = cursor.fetchone()
     245                  self.rne = data[0]
     246                  # appel de la fonction update_data pour les données modifiables
     247                  self.update_data(cursor)
     248              else:
     249                  self.rne = data[0]
     250              self.confdir = os.path.join(config.PATH_ZEPHIR,'conf',self.rne, str(self.id_s))
     251              if cu == None:
     252                  cx_pool.close(cursor)
     253          except:
     254              traceback.print_exc()
     255              if cu == None:
     256                  cx_pool.close(cursor)
     257
     258 -    def update_data(self, cu=None, data=None):
     259          """recharge les données des serveurs
     260          """
     261          # récupération de l'établissement et de l'état
     262          cursor = cu
     263          if cu == None:
     264              cursor = cx_pool.create()
     265          try:
     266              if data == None:
     267                  cursor.execute("select libelle, module_actuel, variante, timeout, etat, md5s, maj, no_alert from serveurs where id=%s", (int(self.id_s),))
     268                  data = cursor.fetchone()
     269              # données du serveur
     270              self.libelle = data[0]
     271              self.id_mod = int(data[1])
     272              self.id_var = int(data[2])
     273              try:
     274                  self.md5s = int(data[5])
     275              except:
     276                  self.md5s = -1
     277              try:
     278                  self.maj = int(data[6])
     279              except:
     280                  self.maj = -1
     281              try:
     282                  self.timeout = int(data[3])
     283              except:
     284                  self.timeout = 0
     285              if data[4] == None:
     286                  self.status = -1
     287              else:
     288                  self.status = int(data[4])
     289              try:
     290                  if str(data[7]) == '1':
     291                      self.no_alert = True
     292                  else:
     293                      self.no_alert = False
     294              except:
     295                  pass
     296              # libelle etablissement
     297              cursor.execute("select libelle from etablissements where rne=%s", (self.rne,))
     298              data = cursor.fetchone()
     299              self.etab = data[0]
     300              # libelle module
     301              cursor.execute("select libelle, version from modules where id=%s", (int(self.id_mod),))
     302              data = cursor.fetchone()
     303              self.module = data[0]
     304              # numéro de distribution Eole (1:Eole 1.X, 2:Eole 2.0, 3:Eole 2.1, ...)
     305              try:
     306                  self.module_version = int(data[1])
     307              except:
     308                  self.module_version = 5
     309              # détection de la version de creole utilisée
     310              self.version = config.CREOLE_VERSIONS[self.module_version]
     311              # libelle variante
     312              cursor.execute("select libelle from variantes where id=%s", (int(self.id_var),))
     313              data = cursor.fetchone()
     314              self.variante = data[0]
     315              self.modified = time.time()
     316              if cu == None:
     317                  cx_pool.close(cursor)
     318          except:
     319              traceback.print_exc()
     320              if cu == None:
     321                  cx_pool.close(cursor)
     322
     323 -    def __repr__(self):
     324          """affichage du serveur
     325          """
     326          return """%s => %s (%s)""" % (self.id_s, self.module, self.rne)
     327
     328 -    def __str__(self):
     329          """affichage du serveur
     330          """
     331          return """%s => %s (%s) - %s (%s)""" % (self.id_s, self.libelle, self.module, self.etab, self.rne)
     332
     333      #####################
     334      ## LECTURE DE DONNEES
     335
     336 -    def get_libelle(self):
     337          return self.libelle
     338
     339 -    def get_rne(self):
     340          return self.rne
     341
     342 -    def get_etab(self):
     343          return self.etab
     344
     345 -    def get_module(self):
     346          return self.module
     347
     348 -    def get_variante(self):
     349          return self.variante
     350
     351 -    def get_timeout(self):
     352          return self.timeout
     353
     354 -    def get_confdir(self):
     355          return self.confdir
     356
     357 -    def get_config(self, mode="modif_config", encode=False):
     358          """retourne la configuration eole du serveur (zephir.eol)
     359          """
     360          # actualisation si des dictionnaires ont changé
     361          dico = self.check_dict(mode, encode)
     362          # vérification des valeurs chargées en mémoire
     363          return self.load_conf(mode, dico)
     364
     365 -    def check_dict(self, mode, encode=False):
     366          """récupération des dictionnaires de configuration du serveur
     367          """
     368          # vérification de la date de mise à jour des dictionnaires
     369          if self.version == 'creole1':
     370              # on recherche la liste des dictionnaires à charger
     371              dicts = [self.confdir+os.sep+'dictionnaire']
     372              # dictionnaire de la variante
     373              dicts.extend(glob(self.confdir+os.sep+'dicos/variante/*.eol'))
     374              # dictionnaire locaux
     375              dicts.extend(glob(self.confdir+os.sep+'dicos/*.eol'))
     376          else:
     377              dicts = glob('%s/dicos/*/*.xml' % self.confdir)
     378          last_mtime = 0.0
     379          # on enregistre la liste des dictionnaires pris en compte
     380          # et leur dernière date de modification
     381          mtimes = set()
     382          for d in dicts:
     383              d_mtime = os.stat(d).st_mtime
     384              mtimes.add((d, d_mtime))
     385          if config.CREOLE_CACHE:
     386              # gestion de la date de dernière mise à jour du cache creole
     387              if self.dico_mtime is None or mtimes != self.dico_mtime:
     388                  self.dico_mtime = mtimes
     389                  # dictionnaires non à jour, on réinitialise
     390                  self.dico = None
     391          if self.dico is None or config.CREOLE_CACHE == False:
     392              if self.version == 'creole1':
     393                  dicos = []
     394                  for dic in dicts:
     395                      try:
     396                          # lecture du contenu des dictionnaires
     397                          fic = open(dic,'r')
     398                          lines = fic.readlines()
     399                          fic.close()
     400                          if encode == True:
     401                              data = [ unicode(line, 'ISO-8859-1').encode('UTF-8') for line in lines ]
     402                          else:
     403                              data = lines
     404                          # stockage du contenu du dictionnaire
     405                          dicos.append(data)
     406                      except OSError:
     407                          pass
     408              else:
     409                  # Des dictionnaires ont été modifiés : on réinitialise l'objet dictionnaire
     410                  # + chargement de la configuration dans le bon mode
     411                  dicos = []
     412                  for rep in ['module','variante','local','package','var_package']:
     413                      if os.path.exists(os.path.join(self.confdir,'dicos',rep)):
     414                          dicos.append(os.path.join(self.confdir,'dicos',rep))
     415              dico = ZephirDict(dicos, self.confdir, mode, self.version)
     416              if config.CREOLE_CACHE:
     417                  self.dico = dico
     418              return dico
     419          else:
     420              # le dictionnaire est déjà en cache
     421              return self.dico
     422
     423 -    def parsedico(self, mode='modif_config', separator="| ", encode=False):
     424          if self.dico is not None:
     425              if config.CREOLE_CACHE and self.dico.mode == mode:
     426                  # dans tous les cas, on appelle check_dict
     427                  # au cas ou un dictionnaires aurait été modifié
     428                  dico = self.check_dict(mode, encode)
     429                  return dico.parsedico(separator=separator)
     430              if config.CREOLE_CACHE == False and self.last_mode == mode:
     431                  if separator != "| ":
     432                      # cache partiel, les valeurs sont stockées avec le séparateur "| "
     433                      final_dict = {}
     434                      for varname, values in self.dico.items():
     435                          final_dict[varname] = separator.join([val.strip() for val in values.split("| ")])
     436                      return final_dict
     437                  return self.dico
     438          dico = self.get_config(mode, encode)
     439          return dico.parsedico(separator=separator)
     440
     441 -    def load_conf(self, mode, dico=None):
     442          """vérifie que les valeurs déjà chargées correspondent au mode demandé
     443          """
     444          if config.CREOLE_CACHE:
     445              if self.dico.mode != mode or not mode.startswith('modif'):
     446                  # rechargement des valeurs dans le mode demandé
     447                  # on recharge si on change de mode ou si on veut repartir des
     448                  # valeurs d'origine (le fichier de module/variante est susceptible d'avoir changé)
     449                  self.dico.load_values(mode)
     450              return self.dico
     451          else:
     452              if self.last_mode != mode or not mode.startswith('modif'):
     453                  dico.load_values(mode)
     454                  # mode de cache réduit, on ne conserve que le dictionnaire de valeurs
     455                  self.dico = dico.parsedico(separator="| ")
     456                  self.last_mode = mode
     457          return dico
     458
     459 -    def save_config(self, dico_zeph, mode='config', encode=False, force=False, new_method=True):
     460          """sauvegarde la configuration eole du serveur (zephir.eol)
     461          force : pas de validation des contraintes (pour une variante, la conf est incomplète)
     462          new_method : utiliser le nouveau calcul du md5 de la configuration
     463          """
     464          try:
     465              if mode in ['config','modif_config']:
     466                  fic_zephir = os.path.join(self.confdir,'zephir.eol')
     467                  key = 'config_ok'
     468                  dict_mode = 'modif_config'
     469              elif mode in ['dico','modif_dico']:
     470                  # si gen_dico, sauvegarde de dico.eol dans la variante
     471                  fic_zephir = os.path.abspath(config.PATH_MODULES)+os.sep+str(self.id_mod)+os.sep+'variantes'+os.sep+str(self.id_var)+os.sep+'dico.eol'
     472                  key = 'dico_ok'
     473                  dict_mode = 'modif_dico'
     474              elif mode in ['migration','modif_migration']:
     475                  fic_zephir = os.path.join(self.confdir,'migration.eol')
     476                  key = 'migration_ok'
     477                  dict_mode = 'modif_migration'
     478              # sauvegarde des données dans le fichier de configuration
     479              dico_zeph.save(fic_zephir,encode=encode,force=force)
     480              # mise à jour du cache de configuration du serveur
     481              if config.CREOLE_CACHE:
     482                  self.dico.load_values(dict_mode)
     483              else:
     484                  self.dico = dico_zeph.parsedico(separator="| ")
     485                  self.last_mode = dict_mode
     486              if key != '':
     487                  self.maj_params({key:1})
     488              self.check_md5conf(new_method)
     489          except:
     490              traceback.print_exc()
     491              raise IOError("serveur %s : erreur de sauvegarde de %s" % (self.id_s, os.path.basename(fic_zephir)))
     492          return ""
     493
     494 -    def get_status(self):
     495          """renvoie le dernier état enregistré du serveur
     496          """
     497          try:
     498              assert self.status in range (5)
     499          except:
     500              return -1
     501          else:
     502              return self.status
     503
     504 -    def set_status(self, status):
     505          """Met à jour l'état du serveur
     506          """
     507          self.status = int(status)
     508          cu = cx_pool.create()
     509          try:
     510              cu.execute("update serveurs set etat=%s where id=%s", (int(self.status), int(self.id_s)))
     511              cx_pool.commit(cu)
     512          except:
     513              traceback.print_exc()
     514              cx_pool.rollback(cu)
     515          return self.status
     516
     517 -    def update_ip_pub(self, ip_publique):
     518          """Conserve la dernière adresse de connexion du serveur
     519          """
     520          cu = cx_pool.create()
     521          try:
     522              cu.execute("update serveurs set ip_publique=%s where id=%s", (ip_publique, int(self.id_s)))
     523              cx_pool.commit(cu)
     524          except:
     525              traceback.print_exc()
     526              cx_pool.rollback(cu)
     527              return False
     528          return True
     529
     530 -    def get_params(self, params=None):
     531          """renvoie le champ paramètres du serveur
     532          """
     533          try:
     534              if params is None:
     535                  cu = cx_pool.create()
     536                  try:
     537                      cu.execute("select params from serveurs where id=%s", (int(self.id_s),))
     538                      data = cu.fetchone()
     539                      cx_pool.close(cu)
     540                  except:
     541                      traceback.print_exc()
     542                      cx_pool.close(cu)
     543                  params = {}
     544                  try:
     545                      params = eval(data[0])
     546                      # RQE : si ajout de nouveaux champs dans params,
     547                      # remplacer le nom du champ ci-dessous par le dernier ajouté
     548                      assert type(params) == dict and params.has_key('perso_ok')
     549                  except:
     550                      # met à jour le champ param si il n'est pas encore renseigné
     551                      params = self.update_params(params)
     552                      # sauvegarde du champs params
     553                      self.save_params(params)
     554              else:
     555                  if type(params) == str:
     556                      params = eval(params)
     557
     558              # nombre de commandes et transferts uucp en attente
     559              id_uucp = self.rne+'-'+str(self.id_s)
     560              params['uucp_transfert']=0
     561              params['uucp_cmd']=0
     562              if os.path.isdir('/var/spool/uucp/%s/D.' % id_uucp):
     563                  params['uucp_transfert']=len(os.listdir('/var/spool/uucp/%s/D.' % id_uucp))
     564              if os.path.isdir('/var/spool/uucp/%s/D.X' % id_uucp):
     565                  params['uucp_cmd']=len(os.listdir('/var/spool/uucp/%s/D.X' % id_uucp))
     566              # si la configuration n'était pas présénte, on vérifie si c'est toujours le cas
     567              if params['config_ok'] == 0:
     568                  if os.path.isfile(self.confdir+os.sep+'zephir.eol'):
     569                      params['config_ok'] = 1
     570              if params['dico_ok'] == 0:
     571                  if os.path.isfile(self.confdir+os.sep+'dico.eol'):
     572                      params['dico_ok'] = 1
     573              if os.path.isfile(self.confdir+os.sep+'new_key.pub'):
     574                  if os.path.isfile(os.path.join(self.confdir,'new_addr')):
     575                      params['new_key'] = (2,file(os.path.join(self.confdir,'new_addr')).read().strip())
     576                  elif os.path.isfile(os.path.join(self.confdir,'new_addr_ok')):
     577                      params['new_key'] = (3,file(os.path.join(self.confdir,'new_addr_ok')).read().strip())
     578                  else:
     579                      params['new_key'] = (1, '')
     580              else:
     581                  params['new_key'] = (0, '')
     582              if self.module_version not in config.allowed_migrations:
     583                  #if self.version != 'creole1':
     584                  params['migration_ok'] = 1
     585              elif os.path.isfile(self.confdir+os.sep+'migration.eol'):
     586                  params['migration_ok'] = 0
     587              else:
     588                  params['migration_ok'] = -1
     589              return params
     590          except:
     591              traceback.print_exc()
     592              return {}
     593
     594 -    def edit_serveur(self, dico_modifs):
     595          # on vérifie que l'identifiant n'est pas modifié
     596          if 'id' in dico_modifs.keys():
     597              return 0, config.u("""L'identifiant ne peut pas être modifié""")
     598          # idem pour le rne et le module
     599          if 'rne' in dico_modifs.keys():
     600              return 0, config.u("""Le rne ne peut pas être modifié""")
     601          if 'module_initial' in dico_modifs.keys():
     602              return 0, config.u("""Le module initial ne peut pas être modifié""")
     603          if 'module_actuel' in dico_modifs.keys() and int(dico_modifs['module_actuel']) != self.id_mod:
     604              # modification amon <-> amonecole permis
     605              mod_name = self.module[:self.module.rindex('-')]
     606              allowed_edits = config.allowed_mod_edits.get(self.module_version, {})
     607              if mod_name in allowed_edits:
     608                  # recherche de la variante par défaut et du libellé pour le modules de destination
     609                  query = """select modules.libelle, variantes.id, modules.version from modules, variantes where modules.id=%s and modules.id=variantes.module and variantes.libelle='standard'"""
     610                  cu = cx_pool.create()
     611                  try:
     612                      cu.execute(query, (int(dico_modifs['module_actuel']),))
     613                      data = cu.fetchone()
     614                      cx_pool.close(cu)
     615                  except:
     616                      traceback.print_exc()
     617                      cx_pool.close(cu)
     618                      return 0, config.u("""Le module n'a pas été retrouvé""")
     619                  if (not data[0][:data[0].rindex('-')] in allowed_edits[mod_name]) or (int(data[2]) != int(self.module_version)):
     620                      return 0, config.u("""Le module demandé n'est pas compatible avec ce serveur""")
     621                  # cas spécial : si on modifie le module et pas la variante, mettre variante standard par défaut
     622                  if not 'variante' in dico_modifs.keys():
     623                      dico_modifs['variante'] = data[1]
     624              else:
     625                  return 0, config.u("""Le module ne peut pas être modifié""")
     626          # construction de la requête SQL de modification
     627          if dico_modifs == {}:
     628              return 1, config.u("""Aucune modification demandée""")
     629          else:
     630              params = []
     631              requete=["update serveurs set "]
     632              for cle in dico_modifs.keys():
     633                  requete.append(str(cle))
     634                  requete.append("=%s, ")
     635                  if cle in ('module_initial', 'module_actuel', 'variante', 'timeout', 'etat', 'maj', 'md5s', 'no_alert'):
     636                      params.append(int(dico_modifs[cle]))
     637                  else:
     638                      params.append(str(dico_modifs[cle]))
     639              query = "".join(requete)[:-2]
     640              query += """ where id=%s"""
     641              params.append(int(self.id_s))
     642              # modification dans la base et appel à la fonction de mise à jour dans l'arborescence
     643          try:
     644              cu = cx_pool.create()
     645              cu.execute(query, params)
     646              cx_pool.commit(cu)
     647          except:
     648              return 0, config.u("""Erreur lors de la modification dans la base""")
     649
     650          serveur_dir_ori = self.confdir
     651          if 'variante' in dico_modifs.keys():
     652              if int(dico_modifs['variante']) != int(self.id_var):
     653                  # on logue le changement de variante
     654                  try:
     655                      params = (int(self.id_s), str(time.ctime()), int(self.id_var), int(dico_modifs['variante']))
     656                      cu = cx_pool.create()
     657                      cu.execute("""insert into log_serveur (id_serveur,date,type,message,etat) values (%s,%s,'ZEPHIR','Modification de la variante (%s -> %s)',0)""", params)
     658                      cx_pool.commit(cu)
     659                  except:
     660                      # on ne bloque pas si le log échoue
     661                      pass
     662
     663              if 'module_actuel' in dico_modifs.keys() and int(dico_modifs['module_actuel']) != self.id_mod:
     664                  code, msg = self._cree_arbo_serveur(new_module=int(dico_modifs['module_actuel']),new_variante=int(dico_modifs['variante']))
     665              else:
     666                  code, msg = self._cree_arbo_serveur(new_variante=int(dico_modifs['variante']))
     667              if code == 0:
     668                  return 0, config.u(msg)
     669
     670              # mise à jour des statistiques des variantes
     671              self.pool.stats['serv_variantes'][str(self.id_var)] = self.pool.stats['serv_variantes'][str(self.id_var)] - 1
     672              self.pool.stats['serv_variantes'][str(dico_modifs['variante'])] = self.pool.stats['serv_variantes'].get(str(dico_modifs['variante']), 0) + 1
     673          if 'module_actuel' in dico_modifs.keys() and int(dico_modifs['module_actuel']) != self.id_mod:
     674              # mise à jour des statistiques des modules
     675              self.pool.stats['serv_modules'][str(self.id_mod)] = self.pool.stats['serv_modules'][str(self.id_mod)] - 1
     676              self.pool.stats['serv_modules'][str(dico_modifs['module_actuel'])] = self.pool.stats['serv_modules'].get(str(dico_modifs['module_actuel']), 0) + 1
     677          self.update_data()
     678          # tout s'est bien passé (on peut toujours rêver)
     679          return 1, config.u('ok')
     680
     681 -    def _cree_arbo_serveur(self,new_module=None,new_variante=None):
     682          """crée l'arborescence zephir d'un nouveau serveur"""
     683          # création des différents répertoires du serveur sur zéphir
     684          edit_mode = False
     685          if new_module is not None:
     686              edit_mode = True
     687              module = new_module
     688          else:
     689              module = self.id_mod
     690          if new_variante is not None:
     691              edit_mode = True
     692              variante = new_variante
     693          else:
     694              variante = self.id_var
     695          serveur_dir = self.confdir
     696
     697          if not edit_mode:
     698              try:
     699                  os.makedirs(serveur_dir)
     700              except:
     701                  return 0, """erreur de création du répertoire du serveur"""
     702              # création du répertoire de stockage des fichiers spécifiques au module
     703              try:
     704                  os.makedirs(serveur_dir+os.sep+'fichiers_zephir')
     705                  os.makedirs(serveur_dir+os.sep+'fichiers_perso')
     706                  os.makedirs(serveur_dir+os.sep+'dicos')
     707                  os.makedirs(serveur_dir+os.sep+'patchs')
     708                  os.makedirs(serveur_dir+os.sep+'uucp')
     709              except:
     710                  shutil.rmtree(serveur_dir)
     711                  return 0, """erreur de création du répertoire des fichiers spécifiques au module"""
     712
     713          if (not edit_mode) or new_module:
     714              # création du lien vers le dictionnaire du module
     715              try:
     716                  if os.path.isdir(os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/dicos'):
     717                      # module Eole2
     718                      if not edit_mode:
     719                          os.makedirs(serveur_dir+os.sep+'dicos/local')
     720                      assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/dicos '+serveur_dir+'/dicos/module') == 0
     721                      assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/module.eol '+serveur_dir+'/module.eol') == 0
     722                  else:
     723                      # module Eole1
     724                      assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/dictionnaire'+' '+serveur_dir+'/dictionnaire') == 0
     725              except:
     726                  shutil.rmtree(serveur_dir)
     727                  return 0, """erreur de lien sur le dictionnaire"""
     728
     729          if (not edit_mode) or new_variante:
     730              # création des liens vers les patchs et dicos des variantes (ou du module si pas de variante)
     731              # dico.eol
     732              try:
     733                  assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+os.sep+'dico.eol'+' '+serveur_dir+os.sep+'dico.eol') == 0
     734                  assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+os.sep+'droits_zephir'+' '+serveur_dir+os.sep+'droits_variante') == 0
     735                  # patchs
     736                  assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+'/patchs'+' '+serveur_dir+'/patchs/variante') == 0
     737                  # dicos
     738                  assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+'/dicos'+' '+serveur_dir+'/dicos/variante') == 0
     739                  if os.path.isdir(os.path.join(config.PATH_MODULES, str(module), 'variantes', str(variante), 'package')):
     740                      assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+'/package'+' '+serveur_dir+'/dicos/var_package') == 0
     741                  # fichiers additionnels (définis dans les dictionnaires locaux)
     742                  assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+'/fichiers_perso'+' '+serveur_dir+'/fichiers_perso/variante') == 0
     743                  # fichiers spécifiques au module (définis dans le dictionnaire zephir)
     744                  assert os.system('ln -nsf '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+'/fichiers_zephir'+' '+serveur_dir+'/fichiers_zephir/variante') == 0
     745              except:
     746                  shutil.rmtree(serveur_dir)
     747                  return 0, """erreur de création des liens vers la variante"""
     748          return 1, 'ok'
     749
     750 -    def update_params(self,params_ori):
     751          # le champ params n'est pas initialisé
     752          if self.module_version in config.allowed_migrations:
     753              #if self.version == 'creole1':
     754              migration_ok = -1
     755          else:
     756              # pour les serveurs sans migration, on considère que la migration est déjà faite
     757              migration_ok = 1
     758          params = {'agents':1
     759                    ,'dico_ok':0
     760                    ,'config_ok':0
     761                    ,'migration_ok':migration_ok
     762                    ,'cle_ok':0
     763                    ,'new_key':(0,'')
     764                    #,'uucp_transfert':0
     765                    #,'uucp_cmd':0
     766                    ,'maj_ok':[-2,'']
     767                    ,'reboot_ok':[-2,'']
     768                    ,'service_restart_ok':[-2,'']
     769                    ,'query_maj':[-2,'']
     770                    ,'reconfigure_ok':[-2,'']
     771                    ,'configure_ok':[-2,'']
     772                    ,'sauvegarde_ok':[-2,'']
     773                    ,'upgrade_ok':[-2,'']
     774                    ,'perso_ok':[-2,'']
     775                    ,'lock_ok':[1,'']
     776                    ,'timeout':[1,'']
     777                    ,'md5s':[-1,'']
     778                    ,'last_log':'journal vide'
     779                  }
     780          try:
     781              params['agents'] = params_ori['agents']
     782          except:
     783              # le serveur n'a pas encore d'info sur les agents
     784              pass
     785          # présence de zephir.eol et clé d'enregistrement
     786          if os.path.isfile(os.path.join(self.confdir,'zephir.eol')):
     787              params['config_ok']=1
     788          if os.path.isfile(os.path.join(self.confdir,'cle_publique')):
     789              params['cle_ok']=1
     790          if os.path.isfile(os.path.join(self.confdir,'new_key.pub')):
     791              if os.path.isfile(os.path.join(self.confdir,'new_addr')):
     792                  params['new_key'] = (2,file(os.path.join(self.confdir,'new_addr')).read().strip())
     793              elif os.path.isfile(os.path.join(self.confdir,'new_addr_ok')):
     794                  params['new_key'] = (3,file(os.path.join(self.confdir,'new_addr_ok')).read().strip())
     795              else:
     796                  params['new_key'] = (1,'')
     797          # vérification des logs pour maj et reconfigure
     798          query = """select type,etat,date,message from last_log_serveur where id_serveur = %s order by date desc,id desc limit 1"""
     799          cu = cx_pool.create()
     800          try:
     801              cu.execute(query, (int(self.id_s),))
     802              data = cu.fetchone()
     803              # on stocke la date du dernier log remonté
     804              if data is not None:
     805                  params['last_log']=str(data[2])
     806              query = """select type,etat,date,message from last_log_serveur where id_serveur = %s and type != 'SURVEILLANCE' order by date desc,id desc"""
     807              cu.execute(query, (int(self.id_s),))
     808              data = cu.fetchall()
     809              cx_pool.close(cu)
     810              # on parse les logs
     811              not_found = ['maj','reconfigure','configure','lock','sauvegarde','reboot','service_restart','upgrade','perso']
     812              for log in data:
     813                  # on regarde si le serveur n'a pas remonté un bloquage des tâches zephir
     814                  # (pb : procédure pour remonter la résolution du problème)
     815                  if log[0] == 'LOCK':
     816                      if 'lock' in not_found:
     817                          not_found.remove('lock')
     818                          if log[1] == 1:
     819                              params['lock_ok'] = [2,str(log[2]),log[3]]
     820                  else:
     821                      for type_log in ['maj','configure','reconfigure','sauvegarde','reboot','service_restart','upgrade','perso']:
     822                          # état des actions
     823                          if log[0] == type_log.upper() and int(log[1]) != -2:
     824                              # on ne stocke que le dernier etat de chaque action
     825                              if type_log in not_found:
     826                                  not_found.remove(type_log)
     827                                  if log[1] == -1:
     828                                      params['%s_ok' % type_log] = [2,str(log[2]),log[3]]
     829                                  elif log[1] > 0:
     830                                      params['%s_ok' % type_log] = [0,str(log[2]),log[3]]
     831                                  elif log[1] == 0:
     832                                      params['%s_ok' % type_log] = [1,str(log[2]),log[3]]
     833                          break
     834                  if not_found == []:
     835                      break
     836          except:
     837              traceback.print_exc()
     838              cx_pool.close(cu)
     839          return params
     840
     841 -    def maj_params(self, param_updates):
     842          """modifie le champ param d'un serveur
     843          @param_updates : dictionnaire contenant les modifications
     844          """
     845          # on interdit d'autres modifications sur les paramètres de ce serveur
     846          # pendant la procédure de mise à jour
     847          with ParamsLock(self.id_s):
     848              params_ori = self.get_params()
     849              params_ori.update(param_updates)
     850              self.save_params(params_ori)
     851
     852 -    def save_params(self, params):
     853          query = """update serveurs set params=%s where id=%s"""
     854          sql_params = (str(params), int(self.id_s))
     855          cu = cx_pool.create()
     856          try:
     857              cu.execute(query, sql_params)
     858              cx_pool.commit(cu)
     859          except:
     860              traceback.print_exc()
     861              cx_pool.rollback(cu)
     862
     863 -    def check_md5conf(self, new_method=True):
     864          # création de la liste des fichiers présents sur zephir
     865          modifs = []
     866          fics=[]
     867          files=md5files[self.module_version]
     868          # cas particulier : zephir.eol
     869          # creole 1 : suppression des lignes sans variables
     870          # creole 2 : valeurs précédentes ignorées
     871          orig_eol = os.path.join(self.confdir,'zephir.eol')
     872          var_eol = os.path.join(self.confdir,'variables.eol')
     873          if os.path.isfile(orig_eol):
     874              f_var = file(var_eol, 'w')
     875              if self.version == 'creole3':
     876                  # création d'un fichier ordonné variable:valeur
     877                  conf_orig = cjson.decode(file(orig_eol).read())
     878                  eole_vars = conf_orig.keys()
     879                  eole_vars.sort()
     880                  for var_name in eole_vars:
     881                      if var_name != 'mode_zephir':
     882                          var_data = u"{0}:{1}\n".format(var_name, conf_orig[var_name].get('val'))
     883                          f_var.write(var_data.encode(config.charset))
     884              elif self.version == 'creole2':
     885                  if new_method:
     886                      # on crée un fichier avec variable:valeur ordonné par nom de variable
     887                      conf = ConfigParser()
     888                      conf.read(orig_eol)
     889                      var_names = conf.sections()
     890                      var_names.sort()
     891                      for var_name in var_names:
     892                          # 1 ligne par variable avec valeurs concaténées
     893                          # (évite les problèmes avec les chaines vide)
     894                          # on ne tient pas compte de mode_zephir qui est
     895                          # à oui seulement sur Zéphir
     896                          if var_name != 'mode_zephir':
     897                              f_var.write("%s:%s\n" % (var_name, ''.join(eval(conf.get(var_name, 'val')))))
     898                  else:
     899                      for line in file(orig_eol).readlines():
     900                          # ancienne méthode
     901                          if not "valprec =" in line:
     902                              f_var.write(line)
     903              elif self.version == 'creole1':
     904                  for line in file(orig_eol).readlines():
     905                      if "@@" in line:
     906                          f_var.write(line)
     907              f_var.close()
     908          for src, dst, pattern in files:
     909              if os.path.isdir(os.path.join(self.confdir,dst)):
     910                  for fic in os.listdir(os.path.join(self.confdir,dst)):
     911                      if os.path.isfile(os.path.join(self.confdir,dst,fic)):
     912                          if pattern == None or fic.endswith(pattern):
     913                              fics.append(os.path.join(dst,fic))
     914              else:
     915                  fics.append(dst)
     916          md5s = []
     917          md5file = os.path.join(os.path.abspath(config.PATH_ZEPHIR),'data','config%s.md5' % self.id_s)
     918          if os.path.isfile(md5file):
     919              # liste des fichiers remontés par le serveur
     920              data = file(md5file).read().strip().split('\n')
     921              # comparaison
     922              for line in data:
     923                  fic = line.split()[1]
     924                  if fic not in fics:
     925                      modifs.append("absent sur zephir : %s" % fic)
     926                  else:
     927                      md5s.append(fic)
     928              for fic in fics:
     929                  if fic not in md5s:
     930                      # erreur : fichier non présent sur la machine distante
     931                      modifs.append("non envoyé : %s" % fic)
     932              # test du contenu des fichiers
     933              cmd_md5 = getProcessOutputAndValue("/usr/bin/md5sum",
     934                                          args = ["-c",md5file],
     935                                          path = self.confdir,
     936                                          env = {'LC_ALL': 'C'})
     937              cmd_md5.addCallback(self._check_md5_res, md5s, modifs)
     938              cmd_md5.addErrback(self._check_md5_res, md5s, modifs)
     939          else:
     940              # pas d'infos md5 pour ce serveur
     941              self.maj_params({'md5s':[-1,""]})
     942              self.edit_serveur({'md5s':-1})
     943
     944 -    def _check_md5_res(self, result, md5s, modifs):
     945          # on effectue une vérification md5 des fichiers de configuration si disponible
     946          out, err, code = result
     947          for fic in md5s:
     948              if not "%s: OK" % fic in out.split('\n'):
     949                  if fic == 'variables.eol':
     950                      # cas particulier des variables creole 1, on indique une modification sur zephir.eol
     951                      modifs.append("contenu modifié : zephir.eol")
     952                  else:
     953                      modifs.append("contenu modifié : %s" % fic)
     954                  md5_ok = False
     955          if modifs != []:
     956              self.edit_serveur({'md5s':0})
     957              self.maj_params({'md5s':[0,";".join(modifs).strip()]})
     958          else:
     959              self.edit_serveur({'md5s':1})
     960              self.maj_params({'md5s':[1,""]})
     961
     962 -    def check_maj_status(self, maj_checker, show_installed = False, debnames = []):
     963          """vérifie l'état de mise à jour d'un serveur
     964          """
     965          if self.version == 'creole1':
     966              return []
     967          # liste des paquets remontés par le serveur
     968          if type(debnames) != list:
     969              debnames = [debnames]
     970          liste_pkgs = []
     971          # on regarde le type de mise à jour configurée (minimale/complète) et le serveur de mise à jour
     972          dico = self.parsedico()
     973          type_maj = dico['type_maj'].split('| ')[0]
     974          serv_maj = dico['serveur_maj'].split('| ')[0]
     975          version = self.module_version
     976          pkg_file = os.path.join(os.path.abspath(config.PATH_ZEPHIR),'data','packages%s.list' % self.id_s)
     977          # on compare les paquets installés avec ceux disponibles sur le serveur de maj
     978          liste_pkgs, maj_infos = maj_checker.check_packages(self.maj_infos, pkg_file, debnames, version, serv_maj, type_maj, show_installed)
     979          if maj_infos is not None and not debnames and not show_installed and maj_infos != self.maj_infos:
     980              # la liste des paquets non à jour a changé, on met à jour l'état du serveur
     981              try:
     982                  nb_pack = len(maj_infos[0])
     983                  if len(maj_infos[0]) > 0:
     984                      self.edit_serveur({'maj':len(maj_infos[0])})
     985                      self.maj_params({'query_maj':[len(maj_infos[0]),time.ctime()]})
     986                  else:
     987                      self.edit_serveur({'maj':0})
     988                      self.maj_params({'query_maj':[0,time.ctime()]})
     989                  self.maj_infos = maj_infos
     990              except:
     991                  traceback.print_exc()
     992                  pass
     993          return liste_pkgs
     994
     995 -    def check_min_version(self, maj_checker, debname, min_version):
     996          # recherche de la version actuelle du paquet sur ce serveur
     997          if maj_checker:
     998              pkg_file = os.path.join(os.path.abspath(config.PATH_ZEPHIR),'data','packages%s.list' % self.id_s)
     999              if os.path.isfile(pkg_file):
    1000                  for line in file(pkg_file):
    1001                      pak_name, pak_version = line.split()
    1002                      if pak_name == debname:
    1003                          return maj_checker.check_min_version(pak_version, min_version)
    1004          # information non trouvée, on retourne False par défaut
    1005          return False
    1006
    1007 -    def regen_key(self, new_addr=None):
    1008          """prépare une nouvelle clé ssh pour la connexion uucp à zephir
    1009          """
    1010          new_key = os.path.join(self.confdir, 'new_key')
    1011          addr_file = os.path.join(self.confdir, 'new_addr')
    1012          if os.path.exists(new_key):
    1013              os.unlink(new_key)
    1014          if os.path.exists("%s.pub" % new_key):
    1015              os.unlink("%s.pub" % new_key)
    1016          for f_addr in [addr_file, '%s_ok' % addr_file]:
    1017              if os.path.exists(f_addr):
    1018                  os.unlink(f_addr)
    1019          zephir_addr =  new_addr or config.ADRESSE_ZEPHIR
    1020          res = os.system("""/usr/bin/ssh-keygen -N "" -b 1024 -t rsa -f %s -C uucp@%s""" % (new_key, zephir_addr))
    1021          # si nouvelle adresse à envoyer, on crée un fichier new_addr
    1022          if new_addr:
    1023              f_adr = open(addr_file, 'w')
    1024              f_adr.write(new_addr)
    1025              f_adr.close()
    1026          return res
    1027
    1028 -    def get_key(self, old_key, new_key, confirm_ip):
    1029          """envoie une nouvelle clé à un serveur.
    1030          les 2 clés publiques (ancienne et nouvelles) doivent être passées en paramètre.
    1031          """
    1032          try:
    1033              old_key_path = os.path.join(self.confdir, 'cle_publique')
    1034              new_key_path = os.path.join(self.confdir, 'new_key.pub')
    1035              new_key_priv_path = os.path.join(self.confdir, 'new_key')
    1036              new_addr_path = os.path.join(self.confdir, 'new_addr')
    1037              old_data = file(old_key_path).read().strip()
    1038              old_data = base64.encodestring(old_data[old_data.index('ssh-rsa'):])
    1039              if old_data == old_key:
    1040                  # la clé correspond, on renvoie les nouvelles clés
    1041                  data_keys = []
    1042                  new_data = file(new_key_path).read().strip()
    1043                  new_data = base64.encodestring(new_data[new_data.index('ssh-rsa'):])
    1044                  if new_data != new_key:
    1045                      return 0, "nouvelle clé publique non reconnue"
    1046                  if confirm_ip == True:
    1047                      if os.path.isfile(new_addr_path):
    1048                          os.rename(new_addr_path, '%s_ok' % new_addr_path)
    1049                          return 1, ''
    1050                      else:
    1051                          return 0, "changement d'adresse non détecté sur zephir"
    1052                  new_data_priv = base64.encodestring(file(new_key_priv_path).read().strip())
    1053                  os.unlink(new_key_priv_path)
    1054                  return 1, new_data_priv
    1055              else:
    1056                  return 0, "ancienne clé publique non reconnue"
    1057          except:
    1058              return 0, "erreur de récupération des données"
    1059
    1060 -    def get_last_contact(self):
    1061          """renvoie la date de dernier contact avec le serveur
    1062          """
    1063          cu = cx_pool.create()
    1064          try:
    1065              cu.execute("select last_contact from serveurs where id=%s", (int(self.id_s),))
    1066              data = cu.fetchone()
    1067              cx_pool.close(cu)
    1068          except:
    1069              traceback.print_exc()
    1070              cx_pool.close(cu)
    1071              return 0.0
    1072          return float(data[0])
    1073
    1074 -    def migrate_config(self,module_dest,variante_dest,mode="migration",dest_version=None):
    1075          """crée un dictionnaire creole2 et importe les valeurs du serveur"""
    1076          assert self.module_version in config.allowed_migrations
    1077          assert int(module_dest) >= 1
    1078          assert int(variante_dest) >= 1
    1079          # on stocke la variante choisie dans le répertoire de conf
    1080          f_var = open(os.path.join(self.confdir, 'variante_migration'), 'w')
    1081          f_var.write(str(variante_dest))
    1082          f_var.close()
    1083          # chemin vers les dictionnaires du module
    1084          creoledirs = [os.path.join(os.path.abspath(config.PATH_MODULES),str(module_dest),'dicos')]
    1085          creoledirs.append(os.path.join(os.path.abspath(config.PATH_MODULES),str(module_dest),'variantes',str(variante_dest),'dicos'))
    1086          # création du dictionnaire
    1087          dico = ZephirDict(creoledirs, self.confdir, mode, dest_version or self.version)
    1088          return dico
    1089
    1090 -    def migrate_data(self, check=False):
    1091          """fonction de récupération des données d'un serveur migré
    1092          check : vérifie seulement si des données sont migrables sur ce serveur
    1093          """
    1094          # fichiers à migrer : fichiers par défaut
    1095          migration_files = {}
    1096          module = self.module[:self.module.rindex('-')]
    1097          if module in config.migration_files:
    1098              migration_files.update(config.migration_files[module])
    1099          # définitions supplémentaires
    1100          if module in migration_perso:
    1101              for section in migration_perso[module].keys():
    1102                  migration_files[section].extend(migration_perso[module][section])
    1103          dir_serv = os.path.join(self.confdir,'fichiers_zephir')
    1104          dir_bak = os.path.join(self.confdir+'-backup','fichiers_zephir')
    1105          # mode check : indique si des fichiers sont gérés pour ce serveur
    1106          if check == True:
    1107              if len(migration_files.keys()) > 0 and os.path.isdir(dir_bak):
    1108                  return 1, True
    1109              else:
    1110                  return 1, False
    1111          # liste des fichiers à copier
    1112          if not len(migration_files.keys()) > 0:
    1113              return 1, config.u("""pas de fichiers à migrer""")
    1114          if not os.path.isdir(dir_bak):
    1115              return 0, config.u("répertoire backup de migration non trouvé")
    1116          not_found = []
    1117          errors = []
    1118          # copie des fichiers avec conversion de l'encoding si besoin
    1119          for src, dst, convert in migration_files['files']:
    1120              fic_src = os.path.join(dir_bak,src)
    1121              fic_dst = os.path.join(dir_serv,dst)
    1122              if os.path.isdir(fic_src):
    1123                  # répertoire
    1124                  os.path.walk(fic_src, self.tree_copy, (fic_src, fic_dst, convert, errors, migration_files))
    1125              elif os.path.isfile(fic_src):
    1126                  self.copy_fic(fic_src, fic_dst, convert, errors)
    1127              else:
    1128                  not_found.append(src)
    1129          # application des droits
    1130          droits_zephir = []
    1131          dests=[]
    1132          for dest, options, user, group, mode in migration_files['rights']:
    1133              if dest.endswith("*"):
    1134                  # cas "repertoire/*" : on recherche tous les fichiers
    1135                  dests = glob(os.path.join(dir_serv,dest))
    1136              else:
    1137                  if os.path.exists(os.path.join(dir_serv,dest)):
    1138                      dests = [os.path.join(dir_serv,dest)]
    1139              for fic_dest in dests:
    1140                  if os.path.basename(fic_dest) not in migration_files['exclude']:
    1141                      cmd_rights = 'chmod %s %s %s;chown %s %s.%s %s' % (options, mode, fic_dest, options, user, group, fic_dest)
    1142                      res = os.system(cmd_rights)
    1143                      if res != 0:
    1144                          errors.append('application des droits impossible : %s' % fic_dest)
    1145                      else:
    1146                          # ajout de la ligne pour droits_zephir
    1147                          droits_zephir.append("%s#%s#%s#%s#%s" % (fic_dest[fic_dest.index('fichiers_zephir'):],mode,user,group,'-R' in options))
    1148
    1149          # création du fichier droits_zephir
    1150          fic_droits = open(os.path.join(self.confdir, 'droits_zephir'),'w')
    1151          fic_droits.write('\n'.join(droits_zephir))
    1152          fic_droits.close()
    1153          # mise en place du fichier fichiers_zephir (copie de fichiers_module + destinations personnalisées)
    1154          # on utilise toujours le fichier de la version 2.0 pour une migration
    1155          module_ng_orig = '%s-2.0' % self.module[:self.module.rindex('-')]
    1156          module_file = '/usr/share/zephir/dictionnaires/fichiers_%s' % module_ng_orig
    1157          serveur_file = os.path.join(self.confdir,'fichiers_zephir','fichiers_zephir')
    1158          if os.path.isfile(module_file):
    1159              # lecture du fichier du module
    1160              data = file(module_file).read().strip()
    1161          if module in destinations_perso:
    1162              data += "\n# fichiers ajoutés lors de la migration Eole 1 vers Eole NG"
    1163              for dest in destinations_perso[module]:
    1164                  data += "\n%s" % dest
    1165
    1166          # écriture en utilisant les templates définis dans config.py
    1167          final_data = "%s\n%s\n%%%%\n%s" % (config.FILE_SECTION,data,config.RPM_SECTION)
    1168
    1169          # écriture du fichier final
    1170          dests = file(serveur_file,'w')
    1171          dests.write(final_data)
    1172          dests.close()
    1173
    1174          return 1, config.u((not_found,errors))
    1175
    1176 -    def variante_migration(self):
    1177          path_var = os.path.join(self.confdir, 'variante_migration')
    1178          if os.path.isfile(path_var):
    1179              return open(path_var).read().strip()
    1180          else:
    1181              return ''
    1182
    1183 -    def add_packages(self, paq_names):
    1184          """ajoute un(des) paquet(s) aux paquets à installer d'un serveur
    1185          """
    1186          added = []
    1187          f_perso = os.path.join(self.get_confdir(), 'fichiers_zephir', 'fichiers_zephir')
    1188          fichiers, paqs = self.pool.get_fic_perso(f_perso)
    1189          # ajout des nouveau paquet
    1190          for paq in paq_names:
    1191              # on ajoute le paquet si il n'est pas présent
    1192              if paq not in paqs:
    1193                  paqs.append(paq)
    1194                  added.append(paq)
    1195          self.pool.save_fic_perso(fichiers, paqs, f_perso)
    1196          return added
    1197
    1198 -    def remove_packages(self, paq_names):
    1199          """ajoute un paquet aux paquets à installer d'un serveur
    1200          """
    1201          removed = []
    1202          f_perso = os.path.join(self.get_confdir(), 'fichiers_zephir', 'fichiers_zephir')
    1203          fichiers, paqs = self.pool.get_fic_perso(f_perso)
    1204          # ajout des nouveau paquet
    1205          for paq in paq_names:
    1206              # on ajoute le paquet si il n'est pas présent
    1207              if paq in paqs:
    1208                  paqs.remove(paq)
    1209                  removed.append(paq)
    1210              else:
    1211                  log.msg("Suppression d'un paquet non défini sur le serveur %s : %s" % (str(self.id_s), paq))
    1212          self.pool.save_fic_perso(fichiers, paqs, f_perso)
    1213          return removed
    1214
    1215 -    def add_info_etab(self, rne, id_client, f_conf):
    1216          # lecture du fichier d'info etablissments
    1217          repl_dir = os.path.join(self.confdir, 'replication')
    1218          data_etab = ConfigParser()
    1219          data_etab.read(os.path.join(repl_dir, 'etabs.ini'))
    1220          # ajout d'informations sur l'établissement et le portail
    1221          serv_client = dict.get(self.pool, id_client)
    1222          if not data_etab.has_section(rne):
    1223              data_etab.add_section(rne)
    1224          data = self.pool.get_info_etab(serv_client.rne)
    1225          if len(data) > 0:
    1226              data_etab.set(rne, "type_etab", data[0][0])
    1227              data_etab.set(rne, "libelle_etab", data[0][1])
    1228          else:
    1229              # infos non trouvées dans la base (mauvais rne renseigné ?)
    1230              # Dans ce cas, on utilise le commentaire inseré par scribe
    1231              # pour le libellé établissement
    1232              log.msg("etabs.ini : les informations sur l'établissement %s ne sont pas disponibles" % rne)
    1233              repl_lines = open(f_conf).strip().split('\n')
    1234              libelle = ''
    1235              for line in repl_lines:
    1236                  if line.startswith('#'):
    1237                      libelle = line
    1238                      break
    1239              data_etab.set(rne, "libelle_etab", libelle)
    1240              data_etab.set(rne, "type_etab", "")
    1241          # recherche de l'adresse du portail dans la configuration
    1242          # des serveurs de cet établissement
    1243          portail_etab = self.pool.get_portail_etab(id_client)
    1244          if portail_etab:
    1245              if not portail_etab.startswith('http'):
    1246                  portail_etab = "https://%s" % portail_etab
    1247              data_etab.set(rne, "portail_etab", portail_etab)
    1248          # sauvegarde des infos etablissement
    1249          fichier_etab = open(os.path.join(repl_dir, 'etabs.ini'), 'w')
    1250          data_etab.write(fichier_etab)
    1251          fichier_etab.close()
    1252
    1253 -    def remove_info_etab(self, rne):
    1254          # lecture du fichier d'info etablissments
    1255          repl_dir = os.path.join(self.confdir, 'replication')
    1256          data_etab = ConfigParser()
    1257          data_etab.read(os.path.join(repl_dir, 'etabs.ini'))
    1258          if data_etab.has_section(rne):
    1259              # infos à supprimer trouvées
    1260              data_etab.remove_section(rne)
    1261              # sauvegarde
    1262              fichier_etab = open(os.path.join(repl_dir, 'etabs.ini'), 'w')
    1263              data_etab.write(fichier_etab)
    1264              fichier_etab.close()
    1265
    1266 -    def add_replication(self, rne, content, id_client):
    1267          """ajoute une configuration de réplication LDAP
    1268          """
    1269          # chemin de sauvegarde de l'archive contenant la conf de réplication
    1270          repl_dir = os.path.join(self.confdir, 'replication')
    1271          if not os.path.exists(repl_dir):
    1272              os.makedirs(repl_dir)
    1273          script = os.path.join(repl_dir, 'replication-%s.conf' % rne)
    1274          try:
    1275              bin_file = StringIO()
    1276              data = base64.decodestring(content)
    1277              fd = open(script,'wb')
    1278              # sauvegarde du fichier
    1279              bin_file.write(data)
    1280              bin_file.seek(0)
    1281              fd.write(bin_file.read())
    1282              fd.close()
    1283          except:
    1284              traceback.print_exc()
    1285              return 0, config.u("erreur de l'écriture du fichier %s" % script)
    1286          # stockage des infos sur l'établissement pour envoi sur le serveur de réplication
    1287          try:
    1288              self.add_info_etab(rne.upper(), id_client, script)
    1289          except:
    1290              log.msg('Erreur lors de la mise à jour du fichier etabs.ini')
    1291              traceback.print_exc()
    1292          return 1, "OK"
    1293
    1294 -    def del_replication(self, filename):
    1295          repl_dir = os.path.join(self.confdir, 'replication')
    1296          try:
    1297              assert os.path.isfile(os.path.join(repl_dir, filename))
    1298              os.unlink(os.path.join(repl_dir, filename))
    1299              # création d'un fichier .modified pour indiquer que la conf est modifiée manuellement
    1300              file(os.path.join(self.confdir, 'replication', '.modified'), 'w').close()
    1301          except:
    1302              return 0, config.u("Erreur lors de la suppression du fichier %s" % filename)
    1303          try:
    1304              # supression des eventuelles informations dans etabs.ini
    1305              rne = filename[filename.index('-')+1:filename.rindex('.')]
    1306              self.remove_info_etab(rne.upper())
    1307          except:
    1308              log.msg('Erreur lors de la supression des informations dans etabs.ini')
    1309              traceback.print_exc()
    1310
    1311          return 1, "OK"
    1312
    1313 -    def check_replication(self):
    1314          # vérification du répertoire
    1315          if not os.path.isdir(os.path.join(self.confdir, 'replication')):
    1316              repl_state = 0
    1317          elif os.path.isfile(os.path.join(self.confdir, 'replication', '.modified')):
    1318              repl_state = 2
    1319          else:
    1320              repl_state = 1
    1321          return 1, repl_state
    1322
    1323 -    def get_replication(self):
    1324          # définition du répertoire du serveur
    1325          conf_repl = []
    1326          # lecture de la liste des fichiers enregistrés
    1327          if os.path.isdir(os.path.join(self.confdir, 'replication')):
    1328              search_path = os.path.join(self.confdir, 'replication', 'replication-*.conf')
    1329              try:
    1330                  for conf_file in glob(search_path):
    1331                      conf_repl.append(os.path.basename(conf_file))
    1332              except:
    1333                  return 0, config.u("Erreur lors de la recherche des configurations de réplication")
    1334          return 1, config.u(conf_repl)
    1335
    1336 -    def get_replication_infos(self):
    1337          """renvoie les données du fichier etabs.ini
    1338          """
    1339          data_etabs = ""
    1340          fic_etab = os.path.join(self.confdir, 'replication', 'etabs.ini')
    1341          if os.path.isfile(fic_etab):
    1342              data_etabs = open(fic_etab).read()
    1343          return data_etabs
    1344
    1345
    1346 -    def tree_copy(self, args, dirname, fnames):
    1347          fic_src, fic_dst, convert, errors, migration_files = args
    1348          if not os.path.isdir(fic_dst):
    1349              os.makedirs(fic_dst)
    1350          for fic in fnames:
    1351              if fic not in migration_files['exclude']:
    1352                  src = os.path.join(dirname, fic)
    1353                  dst = src.replace(fic_src, fic_dst)
    1354                  if os.path.exists(src):
    1355                      self.copy_fic(src, dst, convert, errors)
    1356
    1357 -    def copy_fic(self, src, dst, convert, errors):
    1358          """copie du fichier src sur dst
    1359          convert: si True, convertit le fichier d'ISO-8859-1 vers UTF-8
    1360          """
    1361          if convert == True:
    1362              cmd = '/usr/bin/iconv -f ISO-8859-1 -t UTF-8 -o "%s" "%s"' % (dst, src)
    1363          else:
    1364              cmd = '/bin/cp -f "%s" "%s"' % (src, dst)
    1365          res = os.system(cmd)
    1366          if res != 0:
    1367              log.msg("erreur lors de la migration des données, la commande suivante a échoué :", cmd)
    1368              errors.append(src)
    1369
    1370
    1371 -class ServeurPool(dict):
    1372      """dictionnaire des serveurs existants gérant les autorisations d'accès
    1373      """
    1374
    1375 -    def __init__(self):
    1376
    1377          self._groupes_serveurs = {}
    1378          self._restrictions = {}
    1379          self.stats = {}
    1380          # self.update_groupes()
    1381          # dictionnaire des variantes et leur module
    1382          self.purge_locks()
    1383          self._mod_var = self.get_mod_var()
    1384          try:
    1385              self.update_auths()
    1386          except:
    1387              # pas encore de table de restriction sur cette version
    1388              pass
    1389
    1390 -    def purge_locks(self):
    1391          # nettoie les eventuels locks non supprimés à l'initialisation
    1392          for lock_file in glob(os.path.join(lock_dir, 'server_params_*')):
    1393              os.unlink(lock_file)
    1394
    1395 -    def update_groupes(self):
    1396          cu = cx_pool.create()
    1397          # récupération des groupes de serveurs
    1398          try:
    1399              cu.execute("select id, libelle, serveurs from groupes_serveurs")
    1400              data = cu.fetchall()
    1401              need_commit = False
    1402              for groupe in data:
    1403                  id = int(groupe[0])
    1404                  libelle = str(groupe[1])
    1405                  serveurs = []
    1406                  # suppression des éventuels serveurs inexistants
    1407                  update_gr = False
    1408                  for serveur in eval(groupe[2]):
    1409                      if serveur in self:
    1410                          serveurs.append(serveur)
    1411                      else:
    1412                          update_gr = True
    1413                  if update_gr:
    1414                      # des serveurs ne sont plus valides, on les supprime du groupe dans la base de données
    1415                      cu.execute("update groupes_serveurs set serveurs=%s where id=%s", (str(serveurs), int(id)))
    1416                      need_commit = True
    1417                  timestamp = time.time()
    1418                  date_creat = timestamp
    1419                  if self._groupes_serveurs.has_key(id):
    1420                      date_creat = self._groupes_serveurs[id][2][0]
    1421                  self._groupes_serveurs[id] = [libelle, serveurs, [date_creat, timestamp]]
    1422              if need_commit:
    1423                  cx_pool.commit(cu)
    1424              else:
    1425                  cx_pool.close(cu)
    1426          except:
    1427              traceback.print_exc()
    1428              cx_pool.close(cu)
    1429
    1430 -    def get_mod_var(self):
    1431          """récupére les variantes et leur module"""
    1432          cu = cx_pool.create()
    1433          try:
    1434              cu.execute("select id, module from variantes")
    1435              data = cu.fetchall()
    1436              cx_pool.close(cu)
    1437          except:
    1438              data = []
    1439              traceback.print_exc()
    1440              cx_pool.close(cu)
    1441          return dict(data)
    1442
    1443 -    def update_auths(self, user=None):
    1444          params = []
    1445          if user != None:
    1446              user_clause = " where login=%s"
    1447              params.append(user)
    1448          else:
    1449              user_clause = ""
    1450
    1451          cu = cx_pool.create()
    1452          try:
    1453              # récupération des types de contraintes spécifiées
    1454              cu.execute("select login, id_res, type_res from restrictions %s" % user_clause, params)
    1455              data = cu.fetchall()
    1456              for restriction in data:
    1457                  login, id_res, type_res = restriction
    1458                  if not self._restrictions.has_key(login):
    1459                      self._restrictions[login] = {}
    1460                  if self._restrictions[login].has_key(type_res):
    1461                      self._restrictions[login][type_res].append(id_res)
    1462                  else:
    1463                      self._restrictions[login][type_res] = [id_res]
    1464              cx_pool.close(cu)
    1465          except:
    1466              traceback.print_exc()
    1467              cx_pool.close(cu)
    1468
    1469 -    def add_restriction(self, credential, type_res, id_res):
    1470          """ajoute une restriction pour un utilisateur et une ressource donnés
    1471          type_res : nature des objets à restreindre
    1472          id_res ; identifiant de l'objet autorisé
    1473          les différents types reconnus sont : 'rne, group, id_mod, id_var' et les attributs
    1474          de la classe serveur (id_s, module, version, ...)
    1475          """
    1476          # ajout dans la base
    1477          id_res = str(id_res)
    1478          try:
    1479              assert id_res in self._restrictions[credential][type_res]
    1480          except:
    1481              cu = cx_pool.create()
    1482              # validation de l'existence
    1483              libelle, table, field = config.type_res_label[type_res]
    1484              if field in ('rne','libelle'):
    1485                  # données de type str
    1486                  query = "select * from %s where %s ilike %%s" % (table, field)
    1487                  params = (id_res,)
    1488              else:
    1489                  # type entier
    1490                  query = "select * from %s where %s = %%s" % (table, field)
    1491                  params = (int(id_res),)
    1492              try:
    1493                  cu.execute(query, params)
    1494                  # pas de données correspondante trouvée
    1495                  if cu.fetchone() == None:
    1496                      raise ValueError('identifiant de ressource inconnu')
    1497              except Exception, e:
    1498                  cx_pool.close(cu)
    1499                  return False
    1500              try:
    1501                  params = (credential, type_res, id_res)
    1502                  cu.execute("""insert into restrictions (login, type_res, id_res) values (%s,%s,%s)""", params)
    1503              except:
    1504                  # erreur d'insertion dans la base
    1505                  cx_pool.rollback(cu)
    1506                  return False
    1507              cx_pool.commit(cu)
    1508              if not self._restrictions.has_key(credential):
    1509                  self._restrictions[credential] = {}
    1510              if not self._restrictions[credential].has_key(type_res):
    1511                  self._restrictions[credential][type_res] = []
    1512              self._restrictions[credential][type_res].append(id_res)
    1513          else:
    1514              # restriction déjà existante
    1515              pass
    1516          return True
    1517
    1518 -    def get_restrictions(self, credential, type_res=None):
    1519          """renvoie la liste des restrictions d'un utilisateur
    1520          """
    1521          if not self._restrictions.has_key(credential):
    1522              return []
    1523          if type_res == None:
    1524              # toutes les restrictions : dictionnaire
    1525              return self._restrictions[credential]
    1526          else:
    1527              # si restrictions d'un type précis, on renvoie une liste de ressources
    1528              if self._restrictions[credential].has_key(type_res):
    1529                  return self._restrictions[credential][type_res]
    1530              else:
    1531                  return []
    1532
    1533 -    def del_restriction(self, credential, type_res, id_res):
    1534          """enleve une restriction d'un utilisateur
    1535          """
    1536          id_res = str(id_res)
    1537          try:
    1538              liste_res = self._restrictions[credential][type_res]
    1539              assert id_res in liste_res
    1540          except:
    1541              # restriction non existante
    1542              return False
    1543          # suppression dans la base
    1544          cu = cx_pool.create()
    1545          try:
    1546              cu.execute("""delete from restrictions where login=%s and type_res=%s and id_res=%s""", (credential, type_res, id_res))
    1547              cx_pool.commit(cu)
    1548          except:
    1549              traceback.print_exc()
    1550              cx_pool.rollback(cu)
    1551              return False
    1552          # supression en mémoire
    1553          self._restrictions[credential][type_res].remove(id_res)
    1554          if self._restrictions[credential][type_res] == []:
    1555              del(self._restrictions[credential][type_res])
    1556          return True
    1557
    1558 -    def get_file_perms(self, data_dir, filepath=""):
    1559          """renvoie les informations de permissions associées à un fichier
    1560          """
    1561          # lecture des informations sur le fichier si disponibles
    1562          permsfile = data_dir+os.sep+'droits_zephir'
    1563          if os.path.isfile(permsfile):
    1564              f_rights = file(permsfile)
    1565              data = f_rights.read().strip().split('\n')
    1566              f_rights.close()
    1567          else:
    1568              data = []
    1569          mode = user = group = ""
    1570          recursive = False
    1571          if filepath != "":
    1572              result = {filepath:[mode, user, group, recursive]}
    1573          else:
    1574              result = {}
    1575          for line in data:
    1576              if line.startswith(filepath+'#') or filepath == "":
    1577                  try:
    1578                      filename, mode, user, group, recursive = line.split('#')
    1579                      if recursive != '':
    1580                          recursive = eval(recursive)
    1581                      result[filename] = [mode, user, group, recursive]
    1582                      if filepath != "":
    1583                          break
    1584                  except:
    1585                      # fichier vide ?
    1586                      pass
    1587          return result
    1588
    1589 -    def get_fic_perso(self, fic_perso):
    1590          """renvoie la liste des fichiers personnalisés et paquets d'un serveur
    1591          """
    1592          # on reprend la liste des paquets supplémentaires définis
    1593          try:
    1594              f = open(fic_perso)
    1595              old_content = f.read()
    1596              f.close()
    1597              fichiers = old_content.split('%%\n')[0].strip()
    1598              paqs = old_content.split('%%\n')[1].strip()
    1599          except:
    1600              fichiers = config.FILE_SECTION
    1601              paqs = config.RPM_SECTION
    1602          fichiers = fichiers.split('\n')
    1603          paqs = paqs.split('\n')
    1604          return fichiers, paqs
    1605
    1606 -    def save_fic_perso(self, fichiers, paquets, fic_perso):
    1607          """sauvegarde la liste des fichiers personnalisés et paquets d'un serveur
    1608          """
    1609          # écriture du contenu du fichier
    1610          f=open(fic_perso, 'w')
    1611          f.write('\n'.join(fichiers) + "\n%%\n" + '\n'.join(paquets) + '\n')
    1612          f.close()
    1613
    1614 -    def set_file_perms(self, rights, data_dir):
    1615          """enregistre les informations de permissions associées à un(des) fichier(s)
    1616          @param data_dir: chemin ou trouver le fichier droits_zephir
    1617          """
    1618          # lecture des données existantes
    1619          permsfile = data_dir+os.sep+'droits_zephir'
    1620          data = self.get_file_perms(data_dir)
    1621          data.update(rights)
    1622          # stockage des informations
    1623          lines = []
    1624          for filepath in data.keys():
    1625              # vérification des données
    1626              lines.append("%s#%s#%s#%s#%s" % (filepath, data[filepath][0], data[filepath][1], data[filepath][2],data[filepath][3]))
    1627          # écriture des informations
    1628          f_rights = file(permsfile,'w')
    1629          f_rights.write('\n'.join(lines))
    1630          f_rights.close()
    1631          return True
    1632
    1633 -    def del_file_perms(self, data_dir, filepath="", recurse=False):
    1634          """supprime les informations de permissions associées à un fichier (ou tous)
    1635          """
    1636          # lecture des informations sur le fichier si disponibles
    1637          permsfile = data_dir+os.sep+'droits_zephir'
    1638          if not os.path.exists(permsfile):
    1639              # pas de permissions exitantes ou mauvais chemin
    1640              return False
    1641          if filepath != "":
    1642              f_rights = file(permsfile)
    1643              data = f_rights.read().strip().split('\n')
    1644              f_rights.close()
    1645              if recurse == True:
    1646                  search_pattern = filepath
    1647              else:
    1648                  search_pattern = filepath + '#'
    1649              for line in data:
    1650                  if line.startswith(search_pattern):
    1651                      data.remove(line)
    1652          else:
    1653              data = []
    1654          # écriture des informations
    1655          try:
    1656              f_rights = file(permsfile,'w')
    1657              f_rights.write('\n'.join(data))
    1658              f_rights.close()
    1659          except:
    1660              return False
    1661          return True
    1662
    1663 -    def get_allowed_servers(self, credential):
    1664          """récupération de la liste des serveurs accessibles par un utilisateur
    1665          Vérifie les restrictions définies pour l'utilisateur 'credential'
    1666          en terme de groupe/etablissement/serveur/module/variante
    1667          """
    1668          serveurs = []
    1669          # récupération de la liste de tous les serveurs
    1670          gr_denied = set()
    1671          restrictions = {}
    1672          # groupe, id_serveur, module, rne, variante
    1673          if self._restrictions.has_key(credential):
    1674              # liste des serveurs interdits par groupe
    1675              restrictions = self._restrictions[credential]
    1676              for id_gr in restrictions.get('groupe',[]):
    1677                  if self._groupes_serveurs.has_key(int(id_gr)):
    1678                      gr_denied.update(self._groupes_serveurs[int(id_gr)][1])
    1679          # création de la liste des serveurs autorisés
    1680          for id_serv, infos in self.items():
    1681              if id_serv not in gr_denied:
    1682                  # vérification des attributs du serveur
    1683                  if infos.rne not in restrictions.get('rne', [infos.rne]):
    1684                      continue
    1685                  if str(infos.id_s) not in restrictions.get('id_s', [str(infos.id_s)]):
    1686                      continue
    1687                  if str(infos.id_mod) not in restrictions.get('id_mod', [str(infos.id_mod)]):
    1688                      # serveur non accessible, on passe au serveur suivant
    1689                      continue
    1690                  if str(infos.id_var) not in restrictions.get('id_var', [str(infos.id_var)]):
    1691                      continue
    1692                  # pas de restrictions pour ce serveur, on le valide
    1693                  serveurs.append(id_serv)
    1694          return serveurs
    1695
    1696 -    def check_serv_credential(self, credential, key):
    1697          # vérification des restrictions sur les attributs du serveur
    1698          # (id_s, rne, id_mod, variante)
    1699          serv = dict.get(self, key)
    1700          if self._restrictions.has_key(credential):
    1701              for type_res, res in self._restrictions[credential].items():
    1702                  if res == []:
    1703                      # ce cas ne devrait pas arriver car si on passe toujours par del_restriction
    1704                      continue
    1705                  res_ok = True
    1706                  # si la ressource n'est pas autorisée
    1707                  # cas particuliers : rne et groupes
    1708                  if type_res == 'rne':
    1709                      rne_ok = False
    1710                      for rne in res:
    1711                          # cas des rne avec wildcard (%)
    1712                          if rne.endswith('%'):
    1713                              if serv.rne.startswith(rne.split('%')[0]):
    1714                                  # ce rne correspond à l'expression
    1715                                  rne_ok = True
    1716                                  break
    1717                      if not rne_ok:
    1718                          if not serv.rne in res:
    1719                              res_ok = False
    1720                  elif type_res == 'groupe':
    1721                      # test d'appartenance à un groupe autorisé
    1722                      serv_in_groupes = False
    1723                      for groupe in res:
    1724                          if serv.id_s in self._groupes_serveurs[int(groupe)][1]:
    1725                              serv_in_groupes = True
    1726                              break
    1727                      if serv_in_groupes == False:
    1728                          res_ok = False
    1729                  else:
    1730                      # test attribut correspondant du serveur dans les valeurs autorisées
    1731                      if not str(getattr(serv,type_res)) in [str(i) for i in res]:
    1732                          res_ok = False
    1733                  if not res_ok:
    1734                      # on interdit l'accès
    1735                      raise ResourceAuthError("Serveur interdit : %s" % key)
    1736
    1737 -    def check_gr_credential(self, credential, groupe):
    1738          # validation des droits d'accès à un groupe
    1739          if self._restrictions.has_key(credential):
    1740              if self._restrictions[credential].has_key('groupe'):
    1741                  if self._restrictions[credential]['groupe'] != []:
    1742                      if str(groupe) not in self._restrictions[credential]['groupe']:
    1743                          # accès refusé
    1744                          # FIXME vérification suffisante ou regarder les serveurs ou rne du groupe ?
    1745                          raise ResourceAuthError("Groupe interdit : %s" % groupe)
    1746
    1747 -    def check_mod_credential(self, credential, id_mod):
    1748          # validation des droits d'accès à un module
    1749          if self._restrictions.has_key(credential):
    1750              if self._restrictions[credential].has_key('id_mod'):
    1751                  if self._restrictions[credential]['id_mod'] != []:
    1752                      if str(id_mod) not in self._restrictions[credential]['id_mod']:
    1753                          # accès refusé
    1754                          raise ResourceAuthError("Module interdit : %s" % id_mod)
    1755
    1756 -    def check_var_credential(self, credential, id_var):
    1757          # validation des droits d'accès à une variante
    1758          if self._restrictions.has_key(credential):
    1759              try:
    1760                  var_mod = str(self._mod_var[int(id_var)])
    1761              except:
    1762                  # on met à jour si la variante n'est pas trouvée
    1763                  self._mod_var = self.get_mod_var()
    1764                  var_mod = str(self._mod_var[int(id_var)])
    1765              # on commence par vérifier le module auquel la variante appartient
    1766              if self._restrictions[credential].has_key('id_mod'):
    1767                  if self._restrictions[credential]['id_mod'] != []:
    1768                      if var_mod not in self._restrictions[credential]['id_mod']:
    1769                          raise ResourceAuthError("module %s interdit" % var_mod)
    1770              # vérification de la variante elle-même
    1771              if self._restrictions[credential].has_key('id_var'):
    1772                  if self._restrictions[credential]['id_var'] != []:
    1773                      if str(id_var) not in self._restrictions[credential]['id_var']:
    1774                          # accès refusé
    1775                          raise ResourceAuthError("variante %s interdite" % id_var)
    1776
    1777 -    def check_etab_credential(self, credential, rne):
    1778          # validation des droits d'accès à un établissement
    1779          rne_ok = True
    1780          if self._restrictions.has_key(credential):
    1781              if self._restrictions[credential].has_key('rne'):
    1782                  if self._restrictions[credential]['rne'] != []:
    1783                      if str(rne) not in self._restrictions[credential]['rne']:
    1784                          rne_ok = False
    1785                          for etab in self._restrictions[credential]['rne']:
    1786                              if etab.endswith('%'):
    1787                                  if str(rne).startswith(etab.split('%')[0]):
    1788                                      rne_ok = True
    1789          if not rne_ok:
    1790              # accès refusé
    1791              raise ResourceAuthError("Etablissement interdit : %s" % rne)
    1792
    1793 -    def get(self, credential, key):
    1794          if key in self.keys():
    1795              self.check_serv_credential(credential, key)
    1796          else:
    1797              raise KeyError, "serveur inexistant"
    1798          return dict.get(self,key)
    1799
    1800 -    def get_stats(self):
    1801          self.stats['nb_serv'] = len(self)
    1802          return self.stats
    1803
    1804 -    def get_alertes(self, credential):
    1805          """renvoie la liste des serveurs en alerte
    1806          """
    1807          servs=[]
    1808          for id_serv in self.keys():
    1809              try:
    1810                  serv = self.get(credential, int(id_serv))
    1811              except ResourceAuthError:
    1812                  # accès à ce serveur non autorisé
    1813                  continue
    1814              if serv.get_status() not in [1, -1]:
    1815                  servs.append(serv)
    1816          return servs
    1817
    1818 -    def get_migration_status(self, credential):
    1819          """renvoie la liste des serveurs en cours de migration/non migrés
    1820          """
    1821          migration_st = {}
    1822          for id_serv in self.keys():
    1823              try:
    1824                  serv = self.get(credential, int(id_serv))
    1825              except ResourceAuthError:
    1826                  # accès à ce serveur non autorisé
    1827                  continue
    1828              if serv.module_version in config.allowed_migrations:
    1829                  params = serv.get_params()
    1830                  if params['migration_ok'] == 0:
    1831                      servs = migration_st.get(str(serv.module_version), [[],[]])
    1832                      servs[0].append(serv)
    1833                      migration_st[str(serv.module_version)] = servs
    1834                  elif params['migration_ok'] == -1:
    1835                      servs = migration_st.get(str(serv.module_version), [[],[]])
    1836                      servs[1].append(serv)
    1837                      migration_st[str(serv.module_version)] = servs
    1838          return migration_st
    1839
    1840 -    def check_serveurs(self, credential, serveurs, last_check=None):
    1841          """vérifie si des serveurs ont été modifiés
    1842          @param serveurs : dictionnaires {idserveur:timestamp}
    1843          @param last_check : Si != None, on renvoie les serveurs créés après cette date (timestamp)
    1844          @return : liste d'id de serveurs
    1845          """
    1846          modifs = {}
    1847          serv_pool = []
    1848          for id_serv in [str(cle) for cle in self.keys()]:
    1849              try:
    1850                  serv = self.get(credential, int(id_serv))
    1851              except ResourceAuthError:
    1852                  # serveur non existant ou non accessible
    1853                  log.msg("server %s not authorized" % id_serv)
    1854                  if serveurs.has_key(id_serv):
    1855                      modifs[id_serv] = "deleted"
    1856              else:
    1857                  serv_pool.append(str(serv.id_s))
    1858                  if serveurs.has_key(id_serv):
    1859                      if serv.modified > serveurs[id_serv]:
    1860                          # serveur modifié
    1861                          modifs[id_serv] = serv.modified
    1862                  elif last_check != None:
    1863                      if serv.created > last_check:
    1864                          # si le serveur a été créé après la dernière mise à jour du client
    1865                          # on l'ajoute comme nouveau serveur
    1866                          modifs[id_serv] = serv.modified
    1867
    1868          for id_serv in serveurs.keys():
    1869              if id_serv not in serv_pool:
    1870                  modifs[id_serv] = "deleted"
    1871
    1872          return modifs
    1873
    1874 -    def check_groupes(self, credential, groupes, last_check=None):
    1875          """vérifie si des groupes ont été modifiés
    1876          @param groupes : dictionnaires {idgroupe:timestamp}
    1877          @param last_check : Si != None, on renvoie les serveurs créés après cette date (timestamp)
    1878          @return : dictionnaire  {id_gr:[libelle, serveurs, [date_creat, date_modif]]}
    1879          """
    1880          modifs = {}
    1881
    1882          for id_gr, data in self._groupes_serveurs.items():
    1883              try:
    1884                  group = self.get_groupes(credential, id_gr)
    1885              except KeyError, ResourceAuthError:
    1886                  # groupe non existant ou non accessible
    1887                  log.msg("group %s no longer exists or not authorized" % id_gr)
    1888                  modifs[str(id_gr)] = "deleted"
    1889              else:
    1890                  # la clé des dictionnaires doit être une chaine pour xmlrpc
    1891                  id_gr = str(id_gr)
    1892                  if groupes.has_key(id_gr):
    1893                      if data[2][1] > groupes[id_gr]:
    1894                          # groupe modifié
    1895                          modifs[id_gr] = data
    1896                  elif last_check != None:
    1897                      if data[2][0] > last_check:
    1898                          # nouveau groupe
    1899                          modifs[id_gr] = data
    1900          return modifs
    1901
    1902 -    def add_groupe(self, credential, libelle, serveurs):
    1903          query = """insert into groupes_serveurs (libelle,serveurs) values (%s, %s)"""
    1904          params = (libelle, str(serveurs))
    1905          cu = cx_pool.create()
    1906          try:
    1907              cu.execute(query, params)
    1908          except:
    1909              traceback.print_exc()
    1910              cx_pool.rollback(cu)
    1911              return False
    1912          cx_pool.commit(cu)
    1913          self.update_groupes()
    1914          # ajout automatique du groupe pour l'utilisateur l'ayant créé si il a des restrictions de groupes
    1915          if self._restrictions.has_key(credential):
    1916              if self._restrictions[credential].has_key('groupe'):
    1917                  # on recherche l'id du groupe ajouté
    1918                  for id_gr in self._groupes_serveurs.keys():
    1919                      if self._groupes_serveurs[id_gr][0] == libelle:
    1920                          self.add_restriction(credential,'groupe',str(id_gr))
    1921          return True
    1922
    1923 -    def get_groupes(self, credential, id_groupe=None, alertes=False):
    1924          if id_groupe != None:
    1925              groupes = [int(id_groupe)]
    1926          else:
    1927              groupes = self._groupes_serveurs.keys()
    1928          # vérification des restrictions sur les groupes
    1929          res = []
    1930          for groupe in groupes:
    1931              try:
    1932                  self.check_gr_credential(credential, groupe)
    1933              except:
    1934                  # groupe non autorisé, on passe au suivant
    1935                  continue
    1936              libelle, serveurs, timestamps = self._groupes_serveurs[groupe]
    1937              # sinon on ajoute le groupe à la liste
    1938              res.append([int(groupe), libelle, serveurs])
    1939          return res
    1940
    1941 -    def edit_groupe(self, credential, id_groupe, libelle, serveurs):
    1942          # vérification des droits sur le groupe
    1943          id_groupe = int(id_groupe)
    1944          self.check_gr_credential(credential, id_groupe)
    1945          # mise à jour de la base
    1946          cu = cx_pool.create()
    1947          query = """update groupes_serveurs set libelle=%s, serveurs=%s where id=%s"""
    1948          params = (libelle,str(serveurs),int(id_groupe))
    1949          try:
    1950              cu.execute(query, params)
    1951          except:
    1952              traceback.print_exc()
    1953              cx_pool.rollback(cu)
    1954              return False
    1955          cx_pool.commit(cu)
    1956          # mise à jour interne
    1957          date_creat = self._groupes_serveurs[id_groupe][2][0]
    1958          self._groupes_serveurs[id_groupe] = [libelle, serveurs, [date_creat,time.time()]]
    1959          return True
    1960
    1961 -    def del_groupe(self, credential, id_groupe):
    1962          # vérification des droits sur le groupe
    1963          id_groupe = int(id_groupe)
    1964          self.check_gr_credential(credential, id_groupe)
    1965          # on supprime le groupe des groupes surveillés par les utilisateurs
    1966          rech_params = ('[%d]' % id_groupe, '[%%, %d, %%]' % id_groupe, '[%%, %d]' % id_groupe, '[%d, %%]' % id_groupe)
    1967          cursor = cx_pool.create()
    1968          try:
    1969              cursor.execute("""select login,groupes from users where groupes like %s or groupes like %s or groupes like %s or groupes like %s""", rech_params)
    1970              data=cursor.fetchall()
    1971              # pour chaque utilisateur
    1972              for user in data:
    1973                  # modification de la liste des groupes
    1974                  groupes = eval(user[1])
    1975                  if id_groupe in groupes:
    1976                      groupes.remove(id_groupe)
    1977                      sql_update = """update users set groupes=%s where login=%s"""
    1978                      params = (str(groupes), user[0])
    1979                      cursor.execute(sql_update, params)
    1980              # suppression du groupe dans la base
    1981              cursor.execute("""delete from groupes_serveurs where id = %s""", (int(id_groupe),))
    1982              cx_pool.commit(cursor)
    1983          except:
    1984              traceback.print_exc()
    1985              cx_pool.rollback(cursor)
    1986              return False
    1987          # suppression du groupe en mémoire
    1988          del(self._groupes_serveurs[id_groupe])
    1989          return True
    1990
    1991
    1992 -    def extend_groupe(self, credential, id_groupe, serveurs):
    1993          # vérification des droits sur le groupe
    1994          id_groupe = int(id_groupe)
    1995          self.check_gr_credential(credential, id_groupe)
    1996          # extension des serveurs du groupe
    1997          # dans le dictionnaire interne
    1998          for serv in serveurs:
    1999              if serv not in self._groupes_serveurs[id_groupe][1]:
    2000                  self._groupes_serveurs[id_groupe][1].append(serv)
    2001          self._groupes_serveurs[id_groupe][2] = [time.time(),time.time()]
    2002          cu = cx_pool.create()
    2003          # dans la base de données
    2004          try:
    2005              query = """update groupes_serveurs set serveurs=%s where id=%s"""
    2006              params = (str(self._groupes_serveurs[id_groupe][1]), id_groupe)
    2007              cu.execute(query, params)
    2008              cx_pool.commit(cu)
    2009          except:
    2010              traceback.print_exc()
    2011              cx_pool.rollback(cu)
    2012
    2013 -    def add_serveur(self, credential, rne, libelle, materiel, processeur, disque_dur, date_install, installateur, tel, remarques, module_initial, module_actuel, variante, timestamp_serveur, timeout):
    2014          # on vérifie si l'accès au rne , module et variante est permis
    2015          if self._restrictions.has_key(credential):
    2016              if self._restrictions[credential].has_key('rne'):
    2017                  self.check_etab_credential(credential, rne)
    2018              if self._restrictions[credential].has_key('id_mod'):
    2019                  if module_actuel not in self._restrictions[credential]['id_mod']:
    2020                      raise ResourceAuthError("Module interdit : %s" % module_actuel)
    2021              if self._restrictions[credential].has_key('variante'):
    2022                  cu = cx_pool.create()
    2023                  cu.execute('select libelle from variantes where id=%s', (int(variante),))
    2024                  libel_var = cu.fetchone()[0]
    2025                  cx_pool.close(cu)
    2026                  # dans le cas d'une variante standard, on l'autorise toujours
    2027                  if libel_var != 'standard' and variante not in self._restrictions[credential]['variante']:
    2028                      raise ResourceAuthError("Variante interdit : %s" % variante)
    2029          # insertion dans la base de données
    2030          cu = cx_pool.create()
    2031          query = """insert into serveurs (rne,libelle,materiel,processeur,disque_dur,date_install,installateur,tel,remarques,module_initial,module_actuel,variante,timestamp,timeout) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"""
    2032          params = (rne, libelle, materiel, processeur, disque_dur, date_install, installateur, tel, remarques, int(module_initial), int(module_actuel), int(variante), timestamp_serveur, int(timeout))
    2033          cu.execute(query, params)
    2034          # récupération de l'identifiant attribué par la base
    2035          query = """select id from serveurs where rne=%s and libelle=%s and date_install=%s and installateur=%s and remarques=%s and module_actuel=%s and variante=%s and timestamp=%s"""
    2036          params = (rne, libelle, date_install, installateur, remarques, int(module_actuel), int(variante), timestamp_serveur)
    2037          cu.execute(query, params)
    2038          id_serveur = int(cu.fetchone()[0])
    2039          self[id_serveur] = Serveur(self, id_serveur,cu)
    2040          self.stats['no_contact'].append(id_serveur)
    2041          self.stats['serv_modules'][str(module_actuel)] = self.stats['serv_modules'].get(str(module_actuel),0) + 1
    2042          self.stats['serv_variantes'][str(variante)] = self.stats['serv_variantes'].get(str(variante),0) + 1
    2043          cx_pool.commit(cu)
    2044          return self[id_serveur]
    2045
    2046 -    def del_serveur(self, credential, id_serveur):
    2047          """Supression d'un serveur de la base
    2048          """
    2049          # vérification des restrictions
    2050          self.check_serv_credential(credential, id_serveur)
    2051          cu = cx_pool.create()
    2052          # on supprime le serveur dans la base
    2053          try:
    2054              cu.execute("""delete from serveurs where id=%s""", (int(id_serveur),))
    2055              cx_pool.commit(cu)
    2056              # supression interne
    2057              self.stats['serv_modules'][str(self[id_serveur].id_mod)] = self.stats['serv_modules'][str(self[id_serveur].id_mod)] - 1
    2058              self.stats['serv_variantes'][str(self[id_serveur].id_var)] = self.stats['serv_variantes'][str(self[id_serveur].id_var)] - 1
    2059              del(self[id_serveur])
    2060              if int(id_serveur) in self.stats['no_contact']:
    2061                  self.stats['no_contact'].remove(int(id_serveur))
    2062          except:
    2063              traceback.print_exc()
    2064              cx_pool.rollback(cu)
    2065
    2066 -    def edit_serveur(self, id_serveur, dico_modifs):
    2067          # modification d'un serveur dans la base
    2068          serv = self[id_serveur]
    2069          return serv.edit_serveur(dico_modifs)
    2070
    2071 -    def update_contact(self, id_serveur):
    2072          """mise à jour de la date de contact d'un serveur"""
    2073          id_serveur = int(id_serveur)
    2074          cu = cx_pool.create()
    2075          try:
    2076              # on met à jour le serveur dans la base
    2077              query = """update serveurs set last_contact=%s where id=%s"""
    2078              params = (str(time.time()), int(id_serveur))
    2079              cu.execute(query, params)
    2080              cx_pool.commit(cu)
    2081              # mise à jour des statistiques
    2082              if int(id_serveur) in self.stats['no_contact']:
    2083                  self.stats['no_contact'].remove(int(id_serveur))
    2084          except:
    2085              traceback.print_exc()
    2086              cx_pool.rollback(cu)
    2087
    2088 -    def get_portail_etab(self, id_client):
    2089          """recherche l'adresse du portail etablissement dans la configuration d'un serveur
    2090          variables recherchées (cf var_portail dans config.py commun)
    2091          """
    2092          client = dict.get(self, id_client)
    2093          portail_etab = self._get_portail_etab(client.id_s)
    2094          if portail_etab == '':
    2095              # pas de portail trouvé, on vérifie les autres serveurs de l'établissement
    2096              for serv_id in self.etabs[client.rne]:
    2097                  if serv_id != id_client:
    2098                      portail_etab = self._get_portail_etab(serv_id)
    2099                      if portail_etab:
    2100                          # portail trouvé
    2101                          break
    2102          return portail_etab
    2103
    2104 -    def _get_portail_etab(self, id_client):
    2105          client = dict.get(self, id_client)
    2106          for mod in config.mod_portail:
    2107              if client.module.startswith(mod):
    2108                  # recherche des variables renseignant l'adresse du portail
    2109                  config_serv =  client.parsedico()
    2110                  for v_portail in config.var_portail:
    2111                      if config_serv.get(v_portail, '') != '':
    2112                          # les variables sont en priorité décroissante, on s'arrête
    2113                          # à la première occurence trouvée
    2114                          return config_serv.get(v_portail)
    2115          return ''
    2116
    2117 -    def get_info_etab(self, rne):
    2118          query = """select distinct types_etab.libelle, etablissements.libelle from types_etab, etablissements where \
    2119          types_etab.id = etablissements.type and etablissements.rne = %s"""
    2120          sql_params = (rne,)
    2121          cu = cx_pool.create()
    2122          try:
    2123              cu.execute(query, sql_params)
    2124              data = cu.fetchall()
    2125              cx_pool.close(cu)
    2126          except:
    2127              traceback.print_exc()
    2128              data = []
    2129          return data
    2130
    2131 -    def check_replication_infos(self, id_serv):
    2132          """Génère un fichier d'information sur les établissements répliqués
    2133          sur le serveur id_serv (réplication LDAP)
    2134          --> type / libelle / adresse du portail si disponible
    2135          """
    2136          # serveur de réplication
    2137          serv = dict.get(self,id_serv)
    2138          # lecture du fichier d'information sur les établissements répliqués
    2139
    2140          # récupération des RNEs des établissements répliqués. Nécessite qu'ils aient été saisis correctement
    2141          search_path = os.path.join(serv.confdir, 'replication', 'replication-*.conf')
    2142          f_confs = glob(search_path)
    2143          for f_conf in f_confs:
    2144              # on recherche le rne dans le fichier de replication
    2145              rne = ""
    2146              for line in file(f_conf):
    2147                  if line.strip().startswith('searchbase='):
    2148                      rne = line[line.index('ou=')+3:]
    2149                      rne = rne[:rne.index(',')]
    2150                      break
    2151              if rne == "":
    2152                  # RNE non trouvé dans le fichier de réplication, ne devrait pas arriver
    2153                  # dans ce cas on utilise celui présent dans le nom du fichier
    2154                  rne = f_conf[f_conf.index('-')+1:f_conf.rindex('.')]
    2155              # vérification des informations stockées dans etabs.ini
    2156              self.check_info_etab(serv, rne, f_conf)
    2157
    2158 -    def check_info_etab(self, serv, rne, f_conf):
    2159          """vérifie la disponibilité des informations sur le portail/établissement répliqué
    2160          """
    2161          repl_dir = os.path.join(serv.confdir, 'replication')
    2162          data_etab = ConfigParser()
    2163          data_etab.read(os.path.join(repl_dir, 'etabs.ini'))
    2164          rne = rne.upper()
    2165          if not data_etab.has_section(rne):
    2166              # on appelle la fonction de mise à jour des infos etablissement
    2167              # sur le premier serveur trouvé dans l'établissement
    2168              try:
    2169                  id_client = self.etabs[rne][0]
    2170                  serv.add_info_etab(rne, id_client, f_conf)
    2171              except:
    2172                  log.msg("Aucun serveur trouvé pour l'établissement %s" % rne)
    2173                  return
    2174
    2175 -def serveur_pool():
    2176      """crée un pool de tous les serveurs existants
    2177      """
    2178      # création du pool de serveurs en mémoire
    2179      pool = ServeurPool()
    2180      cu = cx_pool.create()
    2181      try:
    2182          cu.execute("select id, rne, libelle, module_actuel, variante, timeout, etat, md5s, maj, no_alert, last_contact from serveurs")
    2183          data = cu.fetchall()
    2184          nbserv = len(data)
    2185          no_contact = []
    2186          # Instanciation des serveurs
    2187          pool.stats['serv_modules'] = {}
    2188          pool.stats['serv_variantes'] = {}
    2189          pool.etabs = {}
    2190          # initialisation des statistiques des modules/variantes
    2191          for var, module in pool._mod_var.items():
    2192              if str(module) not in pool.stats['serv_modules']:
    2193                  pool.stats['serv_modules'][str(module)] = 0
    2194              if str(var) not in pool.stats['serv_variantes']:
    2195                  pool.stats['serv_variantes'][str(var)] = 0
    2196          for serv in data:
    2197              # liste des serveurs n'ayant jamais contacté zephir
    2198              if serv[10] == None:
    2199                  no_contact.append(int(serv[0]))
    2200              # nombre total de serveurs
    2201              pool[serv[0]] = Serveur(pool, serv[0], cu, serv[1:2])
    2202              pool[serv[0]].update_data(cu, serv[2:10])
    2203              # on conserve une liste des serveurs par établissement
    2204              rne_serv = pool[serv[0]].rne
    2205              if rne_serv in pool.etabs:
    2206                  pool.etabs[rne_serv].append(serv[0])
    2207              else:
    2208                  pool.etabs[rne_serv] = [serv[0]]
    2209              # décompte par module et variante
    2210              pool.stats['serv_modules'][str(serv[3])] = pool.stats['serv_modules'].get(str(serv[3]),0) + 1
    2211              pool.stats['serv_variantes'][str(serv[4])] = pool.stats['serv_variantes'].get(str(serv[4]),0) + 1
    2212          pool.stats['no_contact'] = no_contact
    2213          pool.stats['nb_serv'] = len(pool)
    2214          # chargement des groupes
    2215          pool.update_groupes()
    2216          cx_pool.close(cu)
    2217      except:
    2218          traceback.print_exc()
    2219          cx_pool.close(cu)
    2220      return pool
    2221
    2222  # utility functions
    2223
    2224  text_characters = "".join(map(chr, range(32, 255)) + list("\n\r\t\b"))
    2225  _null_trans = string.maketrans("", "")
    2226
    2227 -def istextfile(filename, blocksize = 1024):
    2228      return istext(open(filename).read(blocksize))
    2229
    2230 -def istext(s):
    2231      if "\0" in s:
    2232          return 0
    2233
    2234      if not s:  # Empty files are considered text
    2235          return 1
    2236
    2237      # Get the non-text characters (maps a character to itself then
    2238      # use the 'remove' option to get rid of the text characters.)
    2239      t = s.translate(_null_trans, text_characters)
    2240
    2241      # If more than 10% non-text characters, then
    2242      # this is considered a binary file
    2243      if len(t)/len(s) > 0.10:
    2244          return 0
    2245      return 1
    2246